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 /* TO DO:
     18  *   1. Re-direct fsck output to the kernel log?
     19  *
     20  */
     21 
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <unistd.h>
     26 #include <fcntl.h>
     27 #include <ctype.h>
     28 #include <sys/mount.h>
     29 #include <sys/stat.h>
     30 #include <errno.h>
     31 #include <sys/types.h>
     32 #include <sys/wait.h>
     33 #include <libgen.h>
     34 #include <time.h>
     35 
     36 #include <private/android_filesystem_config.h>
     37 #include <cutils/partition_utils.h>
     38 #include <cutils/properties.h>
     39 
     40 #include "fs_mgr_priv.h"
     41 
     42 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
     43 #define KEY_IN_FOOTER  "footer"
     44 
     45 #define E2FSCK_BIN      "/system/bin/e2fsck"
     46 
     47 struct flag_list {
     48     const char *name;
     49     unsigned flag;
     50 };
     51 
     52 static struct flag_list mount_flags[] = {
     53     { "noatime",    MS_NOATIME },
     54     { "noexec",     MS_NOEXEC },
     55     { "nosuid",     MS_NOSUID },
     56     { "nodev",      MS_NODEV },
     57     { "nodiratime", MS_NODIRATIME },
     58     { "ro",         MS_RDONLY },
     59     { "rw",         0 },
     60     { "remount",    MS_REMOUNT },
     61     { "defaults",   0 },
     62     { 0,            0 },
     63 };
     64 
     65 static struct flag_list fs_mgr_flags[] = {
     66     { "wait",        MF_WAIT },
     67     { "check",       MF_CHECK },
     68     { "encryptable=",MF_CRYPT },
     69     { "defaults",    0 },
     70     { 0,             0 },
     71 };
     72 
     73 /*
     74  * gettime() - returns the time in seconds of the system's monotonic clock or
     75  * zero on error.
     76  */
     77 static time_t gettime(void)
     78 {
     79     struct timespec ts;
     80     int ret;
     81 
     82     ret = clock_gettime(CLOCK_MONOTONIC, &ts);
     83     if (ret < 0) {
     84         ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
     85         return 0;
     86     }
     87 
     88     return ts.tv_sec;
     89 }
     90 
     91 static int wait_for_file(const char *filename, int timeout)
     92 {
     93     struct stat info;
     94     time_t timeout_time = gettime() + timeout;
     95     int ret = -1;
     96 
     97     while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
     98         usleep(10000);
     99 
    100     return ret;
    101 }
    102 
    103 static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
    104                        char *fs_options, int fs_options_len)
    105 {
    106     int f = 0;
    107     int i;
    108     char *p;
    109     char *savep;
    110 
    111     /* initialize key_loc to null, if we find an MF_CRYPT flag,
    112      * then we'll set key_loc to the proper value */
    113     if (key_loc) {
    114         *key_loc = NULL;
    115     }
    116     /* initialize fs_options to the null string */
    117     if (fs_options && (fs_options_len > 0)) {
    118         fs_options[0] = '\0';
    119     }
    120 
    121     p = strtok_r(flags, ",", &savep);
    122     while (p) {
    123         /* Look for the flag "p" in the flag list "fl"
    124          * If not found, the loop exits with fl[i].name being null.
    125          */
    126         for (i = 0; fl[i].name; i++) {
    127             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
    128                 f |= fl[i].flag;
    129                 if ((fl[i].flag == MF_CRYPT) && key_loc) {
    130                     /* The encryptable flag is followed by an = and the
    131                      * location of the keys.  Get it and return it.
    132                      */
    133                     *key_loc = strdup(strchr(p, '=') + 1);
    134                 }
    135                 break;
    136             }
    137         }
    138 
    139         if (!fl[i].name) {
    140             if (fs_options) {
    141                 /* It's not a known flag, so it must be a filesystem specific
    142                  * option.  Add it to fs_options if it was passed in.
    143                  */
    144                 strlcat(fs_options, p, fs_options_len);
    145                 strlcat(fs_options, ",", fs_options_len);
    146             } else {
    147                 /* fs_options was not passed in, so if the flag is unknown
    148                  * it's an error.
    149                  */
    150                 ERROR("Warning: unknown flag %s\n", p);
    151             }
    152         }
    153         p = strtok_r(NULL, ",", &savep);
    154     }
    155 
    156 out:
    157     if (fs_options && fs_options[0]) {
    158         /* remove the last trailing comma from the list of options */
    159         fs_options[strlen(fs_options) - 1] = '\0';
    160     }
    161 
    162     return f;
    163 }
    164 
    165 /* Read a line of text till the next newline character.
    166  * If no newline is found before the buffer is full, continue reading till a new line is seen,
    167  * then return an empty buffer.  This effectively ignores lines that are too long.
    168  * On EOF, return null.
    169  */
    170 static char *getline(char *buf, int size, FILE *file)
    171 {
    172     int cnt = 0;
    173     int eof = 0;
    174     int eol = 0;
    175     int c;
    176 
    177     if (size < 1) {
    178         return NULL;
    179     }
    180 
    181     while (cnt < (size - 1)) {
    182         c = getc(file);
    183         if (c == EOF) {
    184             eof = 1;
    185             break;
    186         }
    187 
    188         *(buf + cnt) = c;
    189         cnt++;
    190 
    191         if (c == '\n') {
    192             eol = 1;
    193             break;
    194         }
    195     }
    196 
    197     /* Null terminate what we've read */
    198     *(buf + cnt) = '\0';
    199 
    200     if (eof) {
    201         if (cnt) {
    202             return buf;
    203         } else {
    204             return NULL;
    205         }
    206     } else if (eol) {
    207         return buf;
    208     } else {
    209         /* The line is too long.  Read till a newline or EOF.
    210          * If EOF, return null, if newline, return an empty buffer.
    211          */
    212         while(1) {
    213             c = getc(file);
    214             if (c == EOF) {
    215                 return NULL;
    216             } else if (c == '\n') {
    217                 *buf = '\0';
    218                 return buf;
    219             }
    220         }
    221     }
    222 }
    223 
    224 static struct fstab_rec *read_fstab(char *fstab_path)
    225 {
    226     FILE *fstab_file;
    227     int cnt, entries;
    228     int len;
    229     char line[256];
    230     const char *delim = " \t";
    231     char *save_ptr, *p;
    232     struct fstab_rec *fstab;
    233     char *key_loc;
    234 #define FS_OPTIONS_LEN 1024
    235     char tmp_fs_options[FS_OPTIONS_LEN];
    236 
    237     fstab_file = fopen(fstab_path, "r");
    238     if (!fstab_file) {
    239         ERROR("Cannot open file %s\n", fstab_path);
    240         return 0;
    241     }
    242 
    243     entries = 0;
    244     while (getline(line, sizeof(line), fstab_file)) {
    245         /* if the last character is a newline, shorten the string by 1 byte */
    246         len = strlen(line);
    247         if (line[len - 1] == '\n') {
    248             line[len - 1] = '\0';
    249         }
    250         /* Skip any leading whitespace */
    251         p = line;
    252         while (isspace(*p)) {
    253             p++;
    254         }
    255         /* ignore comments or empty lines */
    256         if (*p == '#' || *p == '\0')
    257             continue;
    258         entries++;
    259     }
    260 
    261     if (!entries) {
    262         ERROR("No entries found in fstab\n");
    263         return 0;
    264     }
    265 
    266     fstab = calloc(entries + 1, sizeof(struct fstab_rec));
    267 
    268     fseek(fstab_file, 0, SEEK_SET);
    269 
    270     cnt = 0;
    271     while (getline(line, sizeof(line), fstab_file)) {
    272         /* if the last character is a newline, shorten the string by 1 byte */
    273         len = strlen(line);
    274         if (line[len - 1] == '\n') {
    275             line[len - 1] = '\0';
    276         }
    277 
    278         /* Skip any leading whitespace */
    279         p = line;
    280         while (isspace(*p)) {
    281             p++;
    282         }
    283         /* ignore comments or empty lines */
    284         if (*p == '#' || *p == '\0')
    285             continue;
    286 
    287         /* If a non-comment entry is greater than the size we allocated, give an
    288          * error and quit.  This can happen in the unlikely case the file changes
    289          * between the two reads.
    290          */
    291         if (cnt >= entries) {
    292             ERROR("Tried to process more entries than counted\n");
    293             break;
    294         }
    295 
    296         if (!(p = strtok_r(line, delim, &save_ptr))) {
    297             ERROR("Error parsing mount source\n");
    298             return 0;
    299         }
    300         fstab[cnt].blk_dev = strdup(p);
    301 
    302         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    303             ERROR("Error parsing mnt_point\n");
    304             return 0;
    305         }
    306         fstab[cnt].mnt_point = strdup(p);
    307 
    308         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    309             ERROR("Error parsing fs_type\n");
    310             return 0;
    311         }
    312         fstab[cnt].type = strdup(p);
    313 
    314         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    315             ERROR("Error parsing mount_flags\n");
    316             return 0;
    317         }
    318         tmp_fs_options[0] = '\0';
    319         fstab[cnt].flags = parse_flags(p, mount_flags, 0, tmp_fs_options, FS_OPTIONS_LEN);
    320 
    321         /* fs_options are optional */
    322         if (tmp_fs_options[0]) {
    323             fstab[cnt].fs_options = strdup(tmp_fs_options);
    324         } else {
    325             fstab[cnt].fs_options = NULL;
    326         }
    327 
    328         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    329             ERROR("Error parsing fs_mgr_options\n");
    330             return 0;
    331         }
    332         fstab[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &key_loc, 0, 0);
    333         fstab[cnt].key_loc = key_loc;
    334 
    335         cnt++;
    336     }
    337     fclose(fstab_file);
    338 
    339     return fstab;
    340 }
    341 
    342 static void free_fstab(struct fstab_rec *fstab)
    343 {
    344     int i = 0;
    345 
    346     while (fstab[i].blk_dev) {
    347         /* Free the pointers return by strdup(3) */
    348         free(fstab[i].blk_dev);
    349         free(fstab[i].mnt_point);
    350         free(fstab[i].type);
    351         free(fstab[i].fs_options);
    352         free(fstab[i].key_loc);
    353 
    354         i++;
    355     }
    356 
    357     /* Free the actual fstab array created by calloc(3) */
    358     free(fstab);
    359 }
    360 
    361 static void check_fs(char *blk_dev, char *type, char *target)
    362 {
    363     pid_t pid;
    364     int status;
    365     int ret;
    366     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
    367     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
    368 
    369     /* Check for the types of filesystems we know how to check */
    370     if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) {
    371         /*
    372          * First try to mount and unmount the filesystem.  We do this because
    373          * the kernel is more efficient than e2fsck in running the journal and
    374          * processing orphaned inodes, and on at least one device with a
    375          * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
    376          * to do what the kernel does in about a second.
    377          *
    378          * After mounting and unmounting the filesystem, run e2fsck, and if an
    379          * error is recorded in the filesystem superblock, e2fsck will do a full
    380          * check.  Otherwise, it does nothing.  If the kernel cannot mount the
    381          * filesytsem due to an error, e2fsck is still run to do a full check
    382          * fix the filesystem.
    383          */
    384         ret = mount(blk_dev, target, type, tmpmnt_flags, tmpmnt_opts);
    385         if (! ret) {
    386             umount(target);
    387         }
    388 
    389         INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev);
    390         pid = fork();
    391         if (pid > 0) {
    392             /* Parent, wait for the child to return */
    393             waitpid(pid, &status, 0);
    394         } else if (pid == 0) {
    395             /* child, run checker */
    396             execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL);
    397 
    398             /* Only gets here on error */
    399             ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
    400         } else {
    401             /* No need to check for error in fork, we can't really handle it now */
    402             ERROR("Fork failed trying to run %s\n", E2FSCK_BIN);
    403         }
    404     }
    405 
    406     return;
    407 }
    408 
    409 static void remove_trailing_slashes(char *n)
    410 {
    411     int len;
    412 
    413     len = strlen(n) - 1;
    414     while ((*(n + len) == '/') && len) {
    415       *(n + len) = '\0';
    416       len--;
    417     }
    418 }
    419 
    420 static int fs_match(char *in1, char *in2)
    421 {
    422     char *n1;
    423     char *n2;
    424     int ret;
    425 
    426     n1 = strdup(in1);
    427     n2 = strdup(in2);
    428 
    429     remove_trailing_slashes(n1);
    430     remove_trailing_slashes(n2);
    431 
    432     ret = !strcmp(n1, n2);
    433 
    434     free(n1);
    435     free(n2);
    436 
    437     return ret;
    438 }
    439 
    440 int fs_mgr_mount_all(char *fstab_file)
    441 {
    442     int i = 0;
    443     int encrypted = 0;
    444     int ret = -1;
    445     int mret;
    446     struct fstab_rec *fstab = 0;
    447 
    448     if (!(fstab = read_fstab(fstab_file))) {
    449         return ret;
    450     }
    451 
    452     for (i = 0; fstab[i].blk_dev; i++) {
    453         if (fstab[i].fs_mgr_flags & MF_WAIT) {
    454             wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
    455         }
    456 
    457         if (fstab[i].fs_mgr_flags & MF_CHECK) {
    458             check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point);
    459         }
    460 
    461         mret = mount(fstab[i].blk_dev, fstab[i].mnt_point, fstab[i].type,
    462                      fstab[i].flags, fstab[i].fs_options);
    463         if (!mret) {
    464             /* Success!  Go get the next one */
    465             continue;
    466         }
    467 
    468         /* mount(2) returned an error, check if it's encrypted and deal with it */
    469         if ((fstab[i].fs_mgr_flags & MF_CRYPT) && !partition_wiped(fstab[i].blk_dev)) {
    470             /* Need to mount a tmpfs at this mountpoint for now, and set
    471              * properties that vold will query later for decrypting
    472              */
    473             if (mount("tmpfs", fstab[i].mnt_point, "tmpfs",
    474                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
    475                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
    476                         fstab[i].mnt_point);
    477                 goto out;
    478             }
    479             encrypted = 1;
    480         } else {
    481             ERROR("Cannot mount filesystem on %s at %s\n",
    482                     fstab[i].blk_dev, fstab[i].mnt_point);
    483             goto out;
    484         }
    485     }
    486 
    487     if (encrypted) {
    488         ret = 1;
    489     } else {
    490         ret = 0;
    491     }
    492 
    493 out:
    494     free_fstab(fstab);
    495     return ret;
    496 }
    497 
    498 /* If tmp_mnt_point is non-null, mount the filesystem there.  This is for the
    499  * tmp mount we do to check the user password
    500  */
    501 int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point)
    502 {
    503     int i = 0;
    504     int ret = -1;
    505     struct fstab_rec *fstab = 0;
    506     char *m;
    507 
    508     if (!(fstab = read_fstab(fstab_file))) {
    509         return ret;
    510     }
    511 
    512     for (i = 0; fstab[i].blk_dev; i++) {
    513         if (!fs_match(fstab[i].mnt_point, n_name)) {
    514             continue;
    515         }
    516 
    517         /* We found our match */
    518         /* First check the filesystem if requested */
    519         if (fstab[i].fs_mgr_flags & MF_WAIT) {
    520             wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
    521         }
    522 
    523         if (fstab[i].fs_mgr_flags & MF_CHECK) {
    524             check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point);
    525         }
    526 
    527         /* Now mount it where requested */
    528         if (tmp_mnt_point) {
    529             m = tmp_mnt_point;
    530         } else {
    531             m = fstab[i].mnt_point;
    532         }
    533         if (mount(n_blk_dev, m, fstab[i].type,
    534                   fstab[i].flags, fstab[i].fs_options)) {
    535             ERROR("Cannot mount filesystem on %s at %s\n",
    536                     n_blk_dev, m);
    537             goto out;
    538         } else {
    539             ret = 0;
    540             goto out;
    541         }
    542     }
    543 
    544     /* We didn't find a match, say so and return an error */
    545     ERROR("Cannot find mount point %s in fstab\n", fstab[i].mnt_point);
    546 
    547 out:
    548     free_fstab(fstab);
    549     return ret;
    550 }
    551 
    552 /*
    553  * mount a tmpfs filesystem at the given point.
    554  * return 0 on success, non-zero on failure.
    555  */
    556 int fs_mgr_do_tmpfs_mount(char *n_name)
    557 {
    558     int ret;
    559 
    560     ret = mount("tmpfs", n_name, "tmpfs",
    561                 MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
    562     if (ret < 0) {
    563         ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
    564         return -1;
    565     }
    566 
    567     /* Success */
    568     return 0;
    569 }
    570 
    571 int fs_mgr_unmount_all(char *fstab_file)
    572 {
    573     int i = 0;
    574     int ret = 0;
    575     struct fstab_rec *fstab = 0;
    576 
    577     if (!(fstab = read_fstab(fstab_file))) {
    578         return -1;
    579     }
    580 
    581     while (fstab[i].blk_dev) {
    582         if (umount(fstab[i].mnt_point)) {
    583             ERROR("Cannot unmount filesystem at %s\n", fstab[i].mnt_point);
    584             ret = -1;
    585         }
    586         i++;
    587     }
    588 
    589     free_fstab(fstab);
    590     return ret;
    591 }
    592 /*
    593  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
    594  *
    595  * real_blk_dev must be at least PROPERTY_VALUE_MAX bytes long
    596  */
    597 int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size)
    598 {
    599     int i = 0;
    600     struct fstab_rec *fstab = 0;
    601 
    602     if (!(fstab = read_fstab(fstab_file))) {
    603         return -1;
    604     }
    605     /* Initialize return values to null strings */
    606     if (key_loc) {
    607         *key_loc = '\0';
    608     }
    609     if (real_blk_dev) {
    610         *real_blk_dev = '\0';
    611     }
    612 
    613     /* Look for the encryptable partition to find the data */
    614     for (i = 0; fstab[i].blk_dev; i++) {
    615         if (!(fstab[i].fs_mgr_flags & MF_CRYPT)) {
    616             continue;
    617         }
    618 
    619         /* We found a match */
    620         if (key_loc) {
    621             strlcpy(key_loc, fstab[i].key_loc, size);
    622         }
    623         if (real_blk_dev) {
    624             strlcpy(real_blk_dev, fstab[i].blk_dev, size);
    625         }
    626         break;
    627     }
    628 
    629     free_fstab(fstab);
    630     return 0;
    631 }
    632 
    633