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