Home | History | Annotate | Download | only in fs_mgr
      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  */
     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 
     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 
     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 
    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  */
    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  */
    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 
    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 
    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 
    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 
    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  */
    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  */
    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  */
    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  */
    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 
    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  */
    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  */
    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