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 
     31 #include <private/android_filesystem_config.h>
     32 #include <cutils/partition_utils.h>
     33 #include <cutils/properties.h>
     34 #include <logwrap/logwrap.h>
     35 
     36 #include "fs_mgr_priv.h"
     37 
     38 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
     39 #define KEY_IN_FOOTER  "footer"
     40 
     41 #define E2FSCK_BIN      "/system/bin/e2fsck"
     42 
     43 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
     44 
     45 struct flag_list {
     46     const char *name;
     47     unsigned flag;
     48 };
     49 
     50 static struct flag_list mount_flags[] = {
     51     { "noatime",    MS_NOATIME },
     52     { "noexec",     MS_NOEXEC },
     53     { "nosuid",     MS_NOSUID },
     54     { "nodev",      MS_NODEV },
     55     { "nodiratime", MS_NODIRATIME },
     56     { "ro",         MS_RDONLY },
     57     { "rw",         0 },
     58     { "remount",    MS_REMOUNT },
     59     { "bind",       MS_BIND },
     60     { "rec",        MS_REC },
     61     { "unbindable", MS_UNBINDABLE },
     62     { "private",    MS_PRIVATE },
     63     { "slave",      MS_SLAVE },
     64     { "shared",     MS_SHARED },
     65     { "defaults",   0 },
     66     { 0,            0 },
     67 };
     68 
     69 static struct flag_list fs_mgr_flags[] = {
     70     { "wait",        MF_WAIT },
     71     { "check",       MF_CHECK },
     72     { "encryptable=",MF_CRYPT },
     73     { "nonremovable",MF_NONREMOVABLE },
     74     { "voldmanaged=",MF_VOLDMANAGED},
     75     { "length=",     MF_LENGTH },
     76     { "recoveryonly",MF_RECOVERYONLY },
     77     { "defaults",    0 },
     78     { 0,             0 },
     79 };
     80 
     81 /*
     82  * gettime() - returns the time in seconds of the system's monotonic clock or
     83  * zero on error.
     84  */
     85 static time_t gettime(void)
     86 {
     87     struct timespec ts;
     88     int ret;
     89 
     90     ret = clock_gettime(CLOCK_MONOTONIC, &ts);
     91     if (ret < 0) {
     92         ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
     93         return 0;
     94     }
     95 
     96     return ts.tv_sec;
     97 }
     98 
     99 static int wait_for_file(const char *filename, int timeout)
    100 {
    101     struct stat info;
    102     time_t timeout_time = gettime() + timeout;
    103     int ret = -1;
    104 
    105     while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
    106         usleep(10000);
    107 
    108     return ret;
    109 }
    110 
    111 static int parse_flags(char *flags, struct flag_list *fl,
    112                        char **key_loc, long long *part_length, char **label, int *partnum,
    113                        char *fs_options, int fs_options_len)
    114 {
    115     int f = 0;
    116     int i;
    117     char *p;
    118     char *savep;
    119 
    120     /* initialize key_loc to null, if we find an MF_CRYPT flag,
    121      * then we'll set key_loc to the proper value */
    122     if (key_loc) {
    123         *key_loc = NULL;
    124     }
    125     /* initialize part_length to 0, if we find an MF_LENGTH flag,
    126      * then we'll set part_length to the proper value */
    127     if (part_length) {
    128         *part_length = 0;
    129     }
    130     if (partnum) {
    131         *partnum = -1;
    132     }
    133     if (label) {
    134         *label = NULL;
    135     }
    136 
    137     /* initialize fs_options to the null string */
    138     if (fs_options && (fs_options_len > 0)) {
    139         fs_options[0] = '\0';
    140     }
    141 
    142     p = strtok_r(flags, ",", &savep);
    143     while (p) {
    144         /* Look for the flag "p" in the flag list "fl"
    145          * If not found, the loop exits with fl[i].name being null.
    146          */
    147         for (i = 0; fl[i].name; i++) {
    148             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
    149                 f |= fl[i].flag;
    150                 if ((fl[i].flag == MF_CRYPT) && key_loc) {
    151                     /* The encryptable flag is followed by an = and the
    152                      * location of the keys.  Get it and return it.
    153                      */
    154                     *key_loc = strdup(strchr(p, '=') + 1);
    155                 } else if ((fl[i].flag == MF_LENGTH) && part_length) {
    156                     /* The length flag is followed by an = and the
    157                      * size of the partition.  Get it and return it.
    158                      */
    159                     *part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
    160                 } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
    161                     /* The voldmanaged flag is followed by an = and the
    162                      * label, a colon and the partition number or the
    163                      * word "auto", e.g.
    164                      *   voldmanaged=sdcard:3
    165                      * Get and return them.
    166                      */
    167                     char *label_start;
    168                     char *label_end;
    169                     char *part_start;
    170 
    171                     label_start = strchr(p, '=') + 1;
    172                     label_end = strchr(p, ':');
    173                     if (label_end) {
    174                         *label = strndup(label_start,
    175                                          (int) (label_end - label_start));
    176                         part_start = strchr(p, ':') + 1;
    177                         if (!strcmp(part_start, "auto")) {
    178                             *partnum = -1;
    179                         } else {
    180                             *partnum = strtol(part_start, NULL, 0);
    181                         }
    182                     } else {
    183                         ERROR("Warning: voldmanaged= flag malformed\n");
    184                     }
    185                 }
    186                 break;
    187             }
    188         }
    189 
    190         if (!fl[i].name) {
    191             if (fs_options) {
    192                 /* It's not a known flag, so it must be a filesystem specific
    193                  * option.  Add it to fs_options if it was passed in.
    194                  */
    195                 strlcat(fs_options, p, fs_options_len);
    196                 strlcat(fs_options, ",", fs_options_len);
    197             } else {
    198                 /* fs_options was not passed in, so if the flag is unknown
    199                  * it's an error.
    200                  */
    201                 ERROR("Warning: unknown flag %s\n", p);
    202             }
    203         }
    204         p = strtok_r(NULL, ",", &savep);
    205     }
    206 
    207 out:
    208     if (fs_options && fs_options[0]) {
    209         /* remove the last trailing comma from the list of options */
    210         fs_options[strlen(fs_options) - 1] = '\0';
    211     }
    212 
    213     return f;
    214 }
    215 
    216 /* Read a line of text till the next newline character.
    217  * If no newline is found before the buffer is full, continue reading till a new line is seen,
    218  * then return an empty buffer.  This effectively ignores lines that are too long.
    219  * On EOF, return null.
    220  */
    221 static char *fs_getline(char *buf, int size, FILE *file)
    222 {
    223     int cnt = 0;
    224     int eof = 0;
    225     int eol = 0;
    226     int c;
    227 
    228     if (size < 1) {
    229         return NULL;
    230     }
    231 
    232     while (cnt < (size - 1)) {
    233         c = getc(file);
    234         if (c == EOF) {
    235             eof = 1;
    236             break;
    237         }
    238 
    239         *(buf + cnt) = c;
    240         cnt++;
    241 
    242         if (c == '\n') {
    243             eol = 1;
    244             break;
    245         }
    246     }
    247 
    248     /* Null terminate what we've read */
    249     *(buf + cnt) = '\0';
    250 
    251     if (eof) {
    252         if (cnt) {
    253             return buf;
    254         } else {
    255             return NULL;
    256         }
    257     } else if (eol) {
    258         return buf;
    259     } else {
    260         /* The line is too long.  Read till a newline or EOF.
    261          * If EOF, return null, if newline, return an empty buffer.
    262          */
    263         while(1) {
    264             c = getc(file);
    265             if (c == EOF) {
    266                 return NULL;
    267             } else if (c == '\n') {
    268                 *buf = '\0';
    269                 return buf;
    270             }
    271         }
    272     }
    273 }
    274 
    275 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
    276 {
    277     FILE *fstab_file;
    278     int cnt, entries;
    279     int len;
    280     char line[256];
    281     const char *delim = " \t";
    282     char *save_ptr, *p;
    283     struct fstab *fstab;
    284     struct fstab_rec *recs;
    285     char *key_loc;
    286     long long part_length;
    287     char *label;
    288     int partnum;
    289 #define FS_OPTIONS_LEN 1024
    290     char tmp_fs_options[FS_OPTIONS_LEN];
    291 
    292     fstab_file = fopen(fstab_path, "r");
    293     if (!fstab_file) {
    294         ERROR("Cannot open file %s\n", fstab_path);
    295         return 0;
    296     }
    297 
    298     entries = 0;
    299     while (fs_getline(line, sizeof(line), fstab_file)) {
    300         /* if the last character is a newline, shorten the string by 1 byte */
    301         len = strlen(line);
    302         if (line[len - 1] == '\n') {
    303             line[len - 1] = '\0';
    304         }
    305         /* Skip any leading whitespace */
    306         p = line;
    307         while (isspace(*p)) {
    308             p++;
    309         }
    310         /* ignore comments or empty lines */
    311         if (*p == '#' || *p == '\0')
    312             continue;
    313         entries++;
    314     }
    315 
    316     if (!entries) {
    317         ERROR("No entries found in fstab\n");
    318         return 0;
    319     }
    320 
    321     /* Allocate and init the fstab structure */
    322     fstab = calloc(1, sizeof(struct fstab));
    323     fstab->num_entries = entries;
    324     fstab->fstab_filename = strdup(fstab_path);
    325     fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
    326 
    327     fseek(fstab_file, 0, SEEK_SET);
    328 
    329     cnt = 0;
    330     while (fs_getline(line, sizeof(line), fstab_file)) {
    331         /* if the last character is a newline, shorten the string by 1 byte */
    332         len = strlen(line);
    333         if (line[len - 1] == '\n') {
    334             line[len - 1] = '\0';
    335         }
    336 
    337         /* Skip any leading whitespace */
    338         p = line;
    339         while (isspace(*p)) {
    340             p++;
    341         }
    342         /* ignore comments or empty lines */
    343         if (*p == '#' || *p == '\0')
    344             continue;
    345 
    346         /* If a non-comment entry is greater than the size we allocated, give an
    347          * error and quit.  This can happen in the unlikely case the file changes
    348          * between the two reads.
    349          */
    350         if (cnt >= entries) {
    351             ERROR("Tried to process more entries than counted\n");
    352             break;
    353         }
    354 
    355         if (!(p = strtok_r(line, delim, &save_ptr))) {
    356             ERROR("Error parsing mount source\n");
    357             return 0;
    358         }
    359         fstab->recs[cnt].blk_device = strdup(p);
    360 
    361         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    362             ERROR("Error parsing mount_point\n");
    363             return 0;
    364         }
    365         fstab->recs[cnt].mount_point = strdup(p);
    366 
    367         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    368             ERROR("Error parsing fs_type\n");
    369             return 0;
    370         }
    371         fstab->recs[cnt].fs_type = strdup(p);
    372 
    373         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    374             ERROR("Error parsing mount_flags\n");
    375             return 0;
    376         }
    377         tmp_fs_options[0] = '\0';
    378         fstab->recs[cnt].flags = parse_flags(p, mount_flags,
    379                                        NULL, NULL, NULL, NULL,
    380                                        tmp_fs_options, FS_OPTIONS_LEN);
    381 
    382         /* fs_options are optional */
    383         if (tmp_fs_options[0]) {
    384             fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
    385         } else {
    386             fstab->recs[cnt].fs_options = NULL;
    387         }
    388 
    389         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    390             ERROR("Error parsing fs_mgr_options\n");
    391             return 0;
    392         }
    393         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
    394                                               &key_loc, &part_length,
    395                                               &label, &partnum,
    396                                               NULL, 0);
    397         fstab->recs[cnt].key_loc = key_loc;
    398         fstab->recs[cnt].length = part_length;
    399         fstab->recs[cnt].label = label;
    400         fstab->recs[cnt].partnum = partnum;
    401         cnt++;
    402     }
    403     fclose(fstab_file);
    404 
    405     return fstab;
    406 }
    407 
    408 void fs_mgr_free_fstab(struct fstab *fstab)
    409 {
    410     int i;
    411 
    412     for (i = 0; i < fstab->num_entries; i++) {
    413         /* Free the pointers return by strdup(3) */
    414         free(fstab->recs[i].blk_device);
    415         free(fstab->recs[i].mount_point);
    416         free(fstab->recs[i].fs_type);
    417         free(fstab->recs[i].fs_options);
    418         free(fstab->recs[i].key_loc);
    419         free(fstab->recs[i].label);
    420         i++;
    421     }
    422 
    423     /* Free the fstab_recs array created by calloc(3) */
    424     free(fstab->recs);
    425 
    426     /* Free the fstab filename */
    427     free(fstab->fstab_filename);
    428 
    429     /* Free fstab */
    430     free(fstab);
    431 }
    432 
    433 static void check_fs(char *blk_device, char *fs_type, char *target)
    434 {
    435     int status;
    436     int ret;
    437     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
    438     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
    439     char *e2fsck_argv[] = {
    440         E2FSCK_BIN,
    441         "-y",
    442         blk_device
    443     };
    444 
    445     /* Check for the types of filesystems we know how to check */
    446     if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
    447         /*
    448          * First try to mount and unmount the filesystem.  We do this because
    449          * the kernel is more efficient than e2fsck in running the journal and
    450          * processing orphaned inodes, and on at least one device with a
    451          * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
    452          * to do what the kernel does in about a second.
    453          *
    454          * After mounting and unmounting the filesystem, run e2fsck, and if an
    455          * error is recorded in the filesystem superblock, e2fsck will do a full
    456          * check.  Otherwise, it does nothing.  If the kernel cannot mount the
    457          * filesytsem due to an error, e2fsck is still run to do a full check
    458          * fix the filesystem.
    459          */
    460         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
    461         if (!ret) {
    462             umount(target);
    463         }
    464 
    465         INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
    466 
    467         ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
    468                                       &status, true, LOG_KLOG, true);
    469 
    470         if (ret < 0) {
    471             /* No need to check for error in fork, we can't really handle it now */
    472             ERROR("Failed trying to run %s\n", E2FSCK_BIN);
    473         }
    474     }
    475 
    476     return;
    477 }
    478 
    479 static void remove_trailing_slashes(char *n)
    480 {
    481     int len;
    482 
    483     len = strlen(n) - 1;
    484     while ((*(n + len) == '/') && len) {
    485       *(n + len) = '\0';
    486       len--;
    487     }
    488 }
    489 
    490 static int fs_match(char *in1, char *in2)
    491 {
    492     char *n1;
    493     char *n2;
    494     int ret;
    495 
    496     n1 = strdup(in1);
    497     n2 = strdup(in2);
    498 
    499     remove_trailing_slashes(n1);
    500     remove_trailing_slashes(n2);
    501 
    502     ret = !strcmp(n1, n2);
    503 
    504     free(n1);
    505     free(n2);
    506 
    507     return ret;
    508 }
    509 
    510 int fs_mgr_mount_all(struct fstab *fstab)
    511 {
    512     int i = 0;
    513     int encrypted = 0;
    514     int ret = -1;
    515     int mret;
    516 
    517     if (!fstab) {
    518         return ret;
    519     }
    520 
    521     for (i = 0; i < fstab->num_entries; i++) {
    522         /* Don't mount entries that are managed by vold */
    523         if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
    524             continue;
    525         }
    526 
    527         /* Skip raw partition entries such as boot, recovery, etc */
    528         if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
    529             !strcmp(fstab->recs[i].fs_type, "mtd")) {
    530             continue;
    531         }
    532 
    533         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
    534             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
    535         }
    536 
    537         if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
    538             check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
    539                      fstab->recs[i].mount_point);
    540         }
    541 
    542         mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
    543                      fstab->recs[i].fs_type, fstab->recs[i].flags,
    544                      fstab->recs[i].fs_options);
    545         if (!mret) {
    546             /* Success!  Go get the next one */
    547             continue;
    548         }
    549 
    550         /* mount(2) returned an error, check if it's encrypted and deal with it */
    551         if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
    552             !partition_wiped(fstab->recs[i].blk_device)) {
    553             /* Need to mount a tmpfs at this mountpoint for now, and set
    554              * properties that vold will query later for decrypting
    555              */
    556             if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
    557                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
    558                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
    559                         fstab->recs[i].mount_point);
    560                 goto out;
    561             }
    562             encrypted = 1;
    563         } else {
    564             ERROR("Cannot mount filesystem on %s at %s\n",
    565                     fstab->recs[i].blk_device, fstab->recs[i].mount_point);
    566             goto out;
    567         }
    568     }
    569 
    570     if (encrypted) {
    571         ret = 1;
    572     } else {
    573         ret = 0;
    574     }
    575 
    576 out:
    577     return ret;
    578 }
    579 
    580 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
    581  * tmp mount we do to check the user password
    582  */
    583 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
    584                     char *tmp_mount_point)
    585 {
    586     int i = 0;
    587     int ret = -1;
    588     char *m;
    589 
    590     if (!fstab) {
    591         return ret;
    592     }
    593 
    594     for (i = 0; i < fstab->num_entries; i++) {
    595         if (!fs_match(fstab->recs[i].mount_point, n_name)) {
    596             continue;
    597         }
    598 
    599         /* We found our match */
    600         /* If this is a raw partition, report an error */
    601         if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
    602             !strcmp(fstab->recs[i].fs_type, "mtd")) {
    603             ERROR("Cannot mount filesystem of type %s on %s\n",
    604                   fstab->recs[i].fs_type, n_blk_device);
    605             goto out;
    606         }
    607 
    608         /* First check the filesystem if requested */
    609         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
    610             wait_for_file(n_blk_device, WAIT_TIMEOUT);
    611         }
    612 
    613         if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
    614             check_fs(n_blk_device, fstab->recs[i].fs_type,
    615                      fstab->recs[i].mount_point);
    616         }
    617 
    618         /* Now mount it where requested */
    619         if (tmp_mount_point) {
    620             m = tmp_mount_point;
    621         } else {
    622             m = fstab->recs[i].mount_point;
    623         }
    624         if (mount(n_blk_device, m, fstab->recs[i].fs_type,
    625                   fstab->recs[i].flags, fstab->recs[i].fs_options)) {
    626             ERROR("Cannot mount filesystem on %s at %s\n",
    627                     n_blk_device, m);
    628             goto out;
    629         } else {
    630             ret = 0;
    631             goto out;
    632         }
    633     }
    634 
    635     /* We didn't find a match, say so and return an error */
    636     ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
    637 
    638 out:
    639     return ret;
    640 }
    641 
    642 /*
    643  * mount a tmpfs filesystem at the given point.
    644  * return 0 on success, non-zero on failure.
    645  */
    646 int fs_mgr_do_tmpfs_mount(char *n_name)
    647 {
    648     int ret;
    649 
    650     ret = mount("tmpfs", n_name, "tmpfs",
    651                 MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
    652     if (ret < 0) {
    653         ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
    654         return -1;
    655     }
    656 
    657     /* Success */
    658     return 0;
    659 }
    660 
    661 int fs_mgr_unmount_all(struct fstab *fstab)
    662 {
    663     int i = 0;
    664     int ret = 0;
    665 
    666     if (!fstab) {
    667         return -1;
    668     }
    669 
    670     while (fstab->recs[i].blk_device) {
    671         if (umount(fstab->recs[i].mount_point)) {
    672             ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
    673             ret = -1;
    674         }
    675         i++;
    676     }
    677 
    678     return ret;
    679 }
    680 /*
    681  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
    682  *
    683  * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
    684  */
    685 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
    686 {
    687     int i = 0;
    688 
    689     if (!fstab) {
    690         return -1;
    691     }
    692     /* Initialize return values to null strings */
    693     if (key_loc) {
    694         *key_loc = '\0';
    695     }
    696     if (real_blk_device) {
    697         *real_blk_device = '\0';
    698     }
    699 
    700     /* Look for the encryptable partition to find the data */
    701     for (i = 0; i < fstab->num_entries; i++) {
    702         /* Don't deal with vold managed enryptable partitions here */
    703         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
    704             continue;
    705         }
    706         if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
    707             continue;
    708         }
    709 
    710         /* We found a match */
    711         if (key_loc) {
    712             strlcpy(key_loc, fstab->recs[i].key_loc, size);
    713         }
    714         if (real_blk_device) {
    715             strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
    716         }
    717         break;
    718     }
    719 
    720     return 0;
    721 }
    722 
    723 /* Add an entry to the fstab, and return 0 on success or -1 on error */
    724 int fs_mgr_add_entry(struct fstab *fstab,
    725                      const char *mount_point, const char *fs_type,
    726                      const char *blk_device, long long length)
    727 {
    728     struct fstab_rec *new_fstab_recs;
    729     int n = fstab->num_entries;
    730 
    731     new_fstab_recs = (struct fstab_rec *)
    732                      realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
    733 
    734     if (!new_fstab_recs) {
    735         return -1;
    736     }
    737 
    738     /* A new entry was added, so initialize it */
    739      memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
    740      new_fstab_recs[n].mount_point = strdup(mount_point);
    741      new_fstab_recs[n].fs_type = strdup(fs_type);
    742      new_fstab_recs[n].blk_device = strdup(blk_device);
    743      new_fstab_recs[n].length = 0;
    744 
    745      /* Update the fstab struct */
    746      fstab->recs = new_fstab_recs;
    747      fstab->num_entries++;
    748 
    749      return 0;
    750 }
    751 
    752 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
    753 {
    754     int i;
    755 
    756     if (!fstab) {
    757         return NULL;
    758     }
    759 
    760     for (i = 0; i < fstab->num_entries; i++) {
    761         int len = strlen(fstab->recs[i].mount_point);
    762         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
    763             (path[len] == '\0' || path[len] == '/')) {
    764             return &fstab->recs[i];
    765         }
    766     }
    767 
    768     return NULL;
    769 }
    770 
    771 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
    772 {
    773     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
    774 }
    775 
    776 int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
    777 {
    778     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
    779 }
    780 
    781 int fs_mgr_is_encryptable(struct fstab_rec *fstab)
    782 {
    783     return fstab->fs_mgr_flags & MF_CRYPT;
    784 }
    785 
    786