• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <libgen.h>
29 #include <time.h>
30 #include <sys/swap.h>
31 
32 #include <linux/loop.h>
33 #include <private/android_filesystem_config.h>
34 #include <cutils/android_reboot.h>
35 #include <cutils/partition_utils.h>
36 #include <cutils/properties.h>
37 #include <logwrap/logwrap.h>
38 
39 #include "mincrypt/rsa.h"
40 #include "mincrypt/sha.h"
41 #include "mincrypt/sha256.h"
42 
43 #include "ext4_utils.h"
44 #include "wipe.h"
45 
46 #include "fs_mgr_priv.h"
47 #include "fs_mgr_priv_verity.h"
48 
49 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
50 #define KEY_IN_FOOTER  "footer"
51 
52 #define E2FSCK_BIN      "/system/bin/e2fsck"
53 #define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
54 #define MKSWAP_BIN      "/system/bin/mkswap"
55 
56 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
57 
58 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
59 
60 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
61 
62 /*
63  * gettime() - returns the time in seconds of the system's monotonic clock or
64  * zero on error.
65  */
gettime(void)66 static time_t gettime(void)
67 {
68     struct timespec ts;
69     int ret;
70 
71     ret = clock_gettime(CLOCK_MONOTONIC, &ts);
72     if (ret < 0) {
73         ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
74         return 0;
75     }
76 
77     return ts.tv_sec;
78 }
79 
wait_for_file(const char * filename,int timeout)80 static int wait_for_file(const char *filename, int timeout)
81 {
82     struct stat info;
83     time_t timeout_time = gettime() + timeout;
84     int ret = -1;
85 
86     while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
87         usleep(10000);
88 
89     return ret;
90 }
91 
check_fs(char * blk_device,char * fs_type,char * target)92 static void check_fs(char *blk_device, char *fs_type, char *target)
93 {
94     int status;
95     int ret;
96     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
97     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
98     char *e2fsck_argv[] = {
99         E2FSCK_BIN,
100         "-y",
101         blk_device
102     };
103 
104     /* Check for the types of filesystems we know how to check */
105     if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
106         /*
107          * First try to mount and unmount the filesystem.  We do this because
108          * the kernel is more efficient than e2fsck in running the journal and
109          * processing orphaned inodes, and on at least one device with a
110          * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
111          * to do what the kernel does in about a second.
112          *
113          * After mounting and unmounting the filesystem, run e2fsck, and if an
114          * error is recorded in the filesystem superblock, e2fsck will do a full
115          * check.  Otherwise, it does nothing.  If the kernel cannot mount the
116          * filesytsem due to an error, e2fsck is still run to do a full check
117          * fix the filesystem.
118          */
119         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
120         INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
121         if (!ret) {
122             umount(target);
123         }
124 
125         /*
126          * Some system images do not have e2fsck for licensing reasons
127          * (e.g. recent SDK system images). Detect these and skip the check.
128          */
129         if (access(E2FSCK_BIN, X_OK)) {
130             INFO("Not running %s on %s (executable not in system image)\n",
131                  E2FSCK_BIN, blk_device);
132         } else {
133             INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
134 
135             ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
136                                         &status, true, LOG_KLOG | LOG_FILE,
137                                         true, FSCK_LOG_FILE);
138 
139             if (ret < 0) {
140                 /* No need to check for error in fork, we can't really handle it now */
141                 ERROR("Failed trying to run %s\n", E2FSCK_BIN);
142             }
143         }
144     } else if (!strcmp(fs_type, "f2fs")) {
145             char *f2fs_fsck_argv[] = {
146                     F2FS_FSCK_BIN,
147                     "-f",
148                     blk_device
149             };
150         INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device);
151 
152         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
153                                       &status, true, LOG_KLOG | LOG_FILE,
154                                       true, FSCK_LOG_FILE);
155         if (ret < 0) {
156             /* No need to check for error in fork, we can't really handle it now */
157             ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
158         }
159     }
160 
161     return;
162 }
163 
remove_trailing_slashes(char * n)164 static void remove_trailing_slashes(char *n)
165 {
166     int len;
167 
168     len = strlen(n) - 1;
169     while ((*(n + len) == '/') && len) {
170       *(n + len) = '\0';
171       len--;
172     }
173 }
174 
175 /*
176  * Mark the given block device as read-only, using the BLKROSET ioctl.
177  * Return 0 on success, and -1 on error.
178  */
fs_set_blk_ro(const char * blockdev)179 static void fs_set_blk_ro(const char *blockdev)
180 {
181     int fd;
182     int ON = 1;
183 
184     fd = open(blockdev, O_RDONLY);
185     if (fd < 0) {
186         // should never happen
187         return;
188     }
189 
190     ioctl(fd, BLKROSET, &ON);
191     close(fd);
192 }
193 
194 /*
195  * __mount(): wrapper around the mount() system call which also
196  * sets the underlying block device to read-only if the mount is read-only.
197  * See "man 2 mount" for return values.
198  */
__mount(const char * source,const char * target,const struct fstab_rec * rec)199 static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
200 {
201     unsigned long mountflags = rec->flags;
202     int ret;
203     int save_errno;
204 
205     /* We need this because sometimes we have legacy symlinks
206      * that are lingering around and need cleaning up.
207      */
208     struct stat info;
209     if (!lstat(target, &info))
210         if ((info.st_mode & S_IFMT) == S_IFLNK)
211             unlink(target);
212     mkdir(target, 0755);
213     ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
214     save_errno = errno;
215     INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
216     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
217         fs_set_blk_ro(source);
218     }
219     errno = save_errno;
220     return ret;
221 }
222 
fs_match(char * in1,char * in2)223 static int fs_match(char *in1, char *in2)
224 {
225     char *n1;
226     char *n2;
227     int ret;
228 
229     n1 = strdup(in1);
230     n2 = strdup(in2);
231 
232     remove_trailing_slashes(n1);
233     remove_trailing_slashes(n2);
234 
235     ret = !strcmp(n1, n2);
236 
237     free(n1);
238     free(n2);
239 
240     return ret;
241 }
242 
device_is_debuggable()243 static int device_is_debuggable() {
244     int ret = -1;
245     char value[PROP_VALUE_MAX];
246     ret = __system_property_get("ro.debuggable", value);
247     if (ret < 0)
248         return ret;
249     return strcmp(value, "1") ? 0 : 1;
250 }
251 
device_is_secure()252 static int device_is_secure() {
253     int ret = -1;
254     char value[PROP_VALUE_MAX];
255     ret = __system_property_get("ro.secure", value);
256     /* If error, we want to fail secure */
257     if (ret < 0)
258         return 1;
259     return strcmp(value, "0") ? 1 : 0;
260 }
261 
device_is_force_encrypted()262 static int device_is_force_encrypted() {
263     int ret = -1;
264     char value[PROP_VALUE_MAX];
265     ret = __system_property_get("ro.vold.forceencryption", value);
266     if (ret < 0)
267         return 0;
268     return strcmp(value, "1") ? 0 : 1;
269 }
270 
271 /*
272  * Tries to mount any of the consecutive fstab entries that match
273  * the mountpoint of the one given by fstab->recs[start_idx].
274  *
275  * end_idx: On return, will be the last rec that was looked at.
276  * attempted_idx: On return, will indicate which fstab rec
277  *     succeeded. In case of failure, it will be the start_idx.
278  * Returns
279  *   -1 on failure with errno set to match the 1st mount failure.
280  *   0 on success.
281  */
mount_with_alternatives(struct fstab * fstab,int start_idx,int * end_idx,int * attempted_idx)282 static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
283 {
284     int i;
285     int mount_errno = 0;
286     int mounted = 0;
287 
288     if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
289       errno = EINVAL;
290       if (end_idx) *end_idx = start_idx;
291       if (attempted_idx) *end_idx = start_idx;
292       return -1;
293     }
294 
295     /* Hunt down an fstab entry for the same mount point that might succeed */
296     for (i = start_idx;
297          /* We required that fstab entries for the same mountpoint be consecutive */
298          i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
299          i++) {
300             /*
301              * Don't try to mount/encrypt the same mount point again.
302              * Deal with alternate entries for the same point which are required to be all following
303              * each other.
304              */
305             if (mounted) {
306                 ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
307                      fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
308                 continue;
309             }
310 
311             if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
312                 check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
313                          fstab->recs[i].mount_point);
314             }
315             if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
316                 *attempted_idx = i;
317                 mounted = 1;
318                 if (i != start_idx) {
319                     ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
320                          fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
321                          fstab->recs[start_idx].fs_type);
322                 }
323             } else {
324                 /* back up errno for crypto decisions */
325                 mount_errno = errno;
326             }
327     }
328 
329     /* Adjust i for the case where it was still withing the recs[] */
330     if (i < fstab->num_entries) --i;
331 
332     *end_idx = i;
333     if (!mounted) {
334         *attempted_idx = start_idx;
335         errno = mount_errno;
336         return -1;
337     }
338     return 0;
339 }
340 
341 /* When multiple fstab records share the same mount_point, it will
342  * try to mount each one in turn, and ignore any duplicates after a
343  * first successful mount.
344  * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
345  */
fs_mgr_mount_all(struct fstab * fstab)346 int fs_mgr_mount_all(struct fstab *fstab)
347 {
348     int i = 0;
349     int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
350     int error_count = 0;
351     int mret = -1;
352     int mount_errno = 0;
353     int attempted_idx = -1;
354 
355     if (!fstab) {
356         return -1;
357     }
358 
359     for (i = 0; i < fstab->num_entries; i++) {
360         /* Don't mount entries that are managed by vold */
361         if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
362             continue;
363         }
364 
365         /* Skip swap and raw partition entries such as boot, recovery, etc */
366         if (!strcmp(fstab->recs[i].fs_type, "swap") ||
367             !strcmp(fstab->recs[i].fs_type, "emmc") ||
368             !strcmp(fstab->recs[i].fs_type, "mtd")) {
369             continue;
370         }
371 
372         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
373             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
374         }
375 
376         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
377             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
378             if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
379                 INFO("Verity disabled");
380             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
381                 ERROR("Could not set up verified partition, skipping!\n");
382                 continue;
383             }
384         }
385         int last_idx_inspected;
386         int top_idx = i;
387 
388         mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
389         i = last_idx_inspected;
390         mount_errno = errno;
391 
392         /* Deal with encryptability. */
393         if (!mret) {
394             /* If this is encryptable, need to trigger encryption */
395             if (   (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)
396                 || (device_is_force_encrypted()
397                     && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) {
398                 if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
399                     if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
400                         ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
401                               fstab->recs[attempted_idx].fs_type);
402                         encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
403                     } else {
404                         ERROR("Only one encryptable/encrypted partition supported\n");
405                         encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
406                     }
407                 } else {
408                     INFO("Could not umount %s - allow continue unencrypted\n",
409                          fstab->recs[attempted_idx].mount_point);
410                     continue;
411                 }
412             }
413             /* Success!  Go get the next one */
414             continue;
415         }
416 
417         /* mount(2) returned an error, handle the encryptable/formattable case */
418         bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
419         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
420             fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
421             /* top_idx and attempted_idx point at the same partition, but sometimes
422              * at two different lines in the fstab.  Use the top one for formatting
423              * as that is the preferred one.
424              */
425             ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__,
426                   fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point,
427                   fstab->recs[top_idx].fs_type);
428             if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
429                 strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
430                 int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644);
431                 if (fd >= 0) {
432                     INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc);
433                     wipe_block_device(fd, get_file_size(fd));
434                     close(fd);
435                 } else {
436                     ERROR("%s(): %s wouldn't open (%s)\n", __func__,
437                           fstab->recs[top_idx].key_loc, strerror(errno));
438                 }
439             }
440             if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
441                 /* Let's replay the mount actions. */
442                 i = top_idx - 1;
443                 continue;
444             }
445         }
446         if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
447             fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
448             if (wiped) {
449                 ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
450                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
451                       fstab->recs[attempted_idx].fs_type);
452                 encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
453                 continue;
454             } else {
455                 /* Need to mount a tmpfs at this mountpoint for now, and set
456                  * properties that vold will query later for decrypting
457                  */
458                 ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
459                       fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
460                       fstab->recs[attempted_idx].fs_type);
461                 if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
462                     ++error_count;
463                     continue;
464                 }
465             }
466             encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
467         } else {
468             ERROR("Failed to mount an un-encryptable or wiped partition on"
469                    "%s at %s options: %s error: %s\n",
470                    fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
471                    fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
472             ++error_count;
473             continue;
474         }
475     }
476 
477     if (error_count) {
478         return -1;
479     } else {
480         return encryptable;
481     }
482 }
483 
484 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
485  * tmp mount we do to check the user password
486  * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
487  * in turn, and stop on 1st success, or no more match.
488  */
fs_mgr_do_mount(struct fstab * fstab,char * n_name,char * n_blk_device,char * tmp_mount_point)489 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
490                     char *tmp_mount_point)
491 {
492     int i = 0;
493     int ret = FS_MGR_DOMNT_FAILED;
494     int mount_errors = 0;
495     int first_mount_errno = 0;
496     char *m;
497 
498     if (!fstab) {
499         return ret;
500     }
501 
502     for (i = 0; i < fstab->num_entries; i++) {
503         if (!fs_match(fstab->recs[i].mount_point, n_name)) {
504             continue;
505         }
506 
507         /* We found our match */
508         /* If this swap or a raw partition, report an error */
509         if (!strcmp(fstab->recs[i].fs_type, "swap") ||
510             !strcmp(fstab->recs[i].fs_type, "emmc") ||
511             !strcmp(fstab->recs[i].fs_type, "mtd")) {
512             ERROR("Cannot mount filesystem of type %s on %s\n",
513                   fstab->recs[i].fs_type, n_blk_device);
514             goto out;
515         }
516 
517         /* First check the filesystem if requested */
518         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
519             wait_for_file(n_blk_device, WAIT_TIMEOUT);
520         }
521 
522         if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
523             check_fs(n_blk_device, fstab->recs[i].fs_type,
524                      fstab->recs[i].mount_point);
525         }
526 
527         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
528             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
529             if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
530                 INFO("Verity disabled");
531             } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
532                 ERROR("Could not set up verified partition, skipping!\n");
533                 continue;
534             }
535         }
536 
537         /* Now mount it where requested */
538         if (tmp_mount_point) {
539             m = tmp_mount_point;
540         } else {
541             m = fstab->recs[i].mount_point;
542         }
543         if (__mount(n_blk_device, m, &fstab->recs[i])) {
544             if (!first_mount_errno) first_mount_errno = errno;
545             mount_errors++;
546             continue;
547         } else {
548             ret = 0;
549             goto out;
550         }
551     }
552     if (mount_errors) {
553         ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
554             n_blk_device, m, strerror(first_mount_errno));
555         if (first_mount_errno == EBUSY) {
556             ret = FS_MGR_DOMNT_BUSY;
557         } else {
558             ret = FS_MGR_DOMNT_FAILED;
559         }
560     } else {
561         /* We didn't find a match, say so and return an error */
562         ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
563     }
564 
565 out:
566     return ret;
567 }
568 
569 /*
570  * mount a tmpfs filesystem at the given point.
571  * return 0 on success, non-zero on failure.
572  */
fs_mgr_do_tmpfs_mount(char * n_name)573 int fs_mgr_do_tmpfs_mount(char *n_name)
574 {
575     int ret;
576 
577     ret = mount("tmpfs", n_name, "tmpfs",
578                 MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
579     if (ret < 0) {
580         ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
581         return -1;
582     }
583 
584     /* Success */
585     return 0;
586 }
587 
fs_mgr_unmount_all(struct fstab * fstab)588 int fs_mgr_unmount_all(struct fstab *fstab)
589 {
590     int i = 0;
591     int ret = 0;
592 
593     if (!fstab) {
594         return -1;
595     }
596 
597     while (fstab->recs[i].blk_device) {
598         if (umount(fstab->recs[i].mount_point)) {
599             ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
600             ret = -1;
601         }
602         i++;
603     }
604 
605     return ret;
606 }
607 
608 /* This must be called after mount_all, because the mkswap command needs to be
609  * available.
610  */
fs_mgr_swapon_all(struct fstab * fstab)611 int fs_mgr_swapon_all(struct fstab *fstab)
612 {
613     int i = 0;
614     int flags = 0;
615     int err = 0;
616     int ret = 0;
617     int status;
618     char *mkswap_argv[2] = {
619         MKSWAP_BIN,
620         NULL
621     };
622 
623     if (!fstab) {
624         return -1;
625     }
626 
627     for (i = 0; i < fstab->num_entries; i++) {
628         /* Skip non-swap entries */
629         if (strcmp(fstab->recs[i].fs_type, "swap")) {
630             continue;
631         }
632 
633         if (fstab->recs[i].zram_size > 0) {
634             /* A zram_size was specified, so we need to configure the
635              * device.  There is no point in having multiple zram devices
636              * on a system (all the memory comes from the same pool) so
637              * we can assume the device number is 0.
638              */
639             FILE *zram_fp;
640 
641             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
642             if (zram_fp == NULL) {
643                 ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
644                 ret = -1;
645                 continue;
646             }
647             fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
648             fclose(zram_fp);
649         }
650 
651         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
652             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
653         }
654 
655         /* Initialize the swap area */
656         mkswap_argv[1] = fstab->recs[i].blk_device;
657         err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
658                                       &status, true, LOG_KLOG, false, NULL);
659         if (err) {
660             ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
661             ret = -1;
662             continue;
663         }
664 
665         /* If -1, then no priority was specified in fstab, so don't set
666          * SWAP_FLAG_PREFER or encode the priority */
667         if (fstab->recs[i].swap_prio >= 0) {
668             flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
669                     SWAP_FLAG_PRIO_MASK;
670             flags |= SWAP_FLAG_PREFER;
671         } else {
672             flags = 0;
673         }
674         err = swapon(fstab->recs[i].blk_device, flags);
675         if (err) {
676             ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
677             ret = -1;
678         }
679     }
680 
681     return ret;
682 }
683 
684 /*
685  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
686  *
687  * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
688  */
fs_mgr_get_crypt_info(struct fstab * fstab,char * key_loc,char * real_blk_device,int size)689 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
690 {
691     int i = 0;
692 
693     if (!fstab) {
694         return -1;
695     }
696     /* Initialize return values to null strings */
697     if (key_loc) {
698         *key_loc = '\0';
699     }
700     if (real_blk_device) {
701         *real_blk_device = '\0';
702     }
703 
704     /* Look for the encryptable partition to find the data */
705     for (i = 0; i < fstab->num_entries; i++) {
706         /* Don't deal with vold managed enryptable partitions here */
707         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
708             continue;
709         }
710         if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
711             continue;
712         }
713 
714         /* We found a match */
715         if (key_loc) {
716             strlcpy(key_loc, fstab->recs[i].key_loc, size);
717         }
718         if (real_blk_device) {
719             strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
720         }
721         break;
722     }
723 
724     return 0;
725 }
726