Home | History | Annotate | Download | only in fs_mgr
      1 /*
      2  * Copyright (C) 2014 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 <ctype.h>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <sys/mount.h>
     22 
     23 #include "fs_mgr_priv.h"
     24 
     25 struct fs_mgr_flag_values {
     26     char *key_loc;
     27     long long part_length;
     28     char *label;
     29     int partnum;
     30     int swap_prio;
     31     unsigned int zram_size;
     32 };
     33 
     34 struct flag_list {
     35     const char *name;
     36     unsigned flag;
     37 };
     38 
     39 static struct flag_list mount_flags[] = {
     40     { "noatime",    MS_NOATIME },
     41     { "noexec",     MS_NOEXEC },
     42     { "nosuid",     MS_NOSUID },
     43     { "nodev",      MS_NODEV },
     44     { "nodiratime", MS_NODIRATIME },
     45     { "ro",         MS_RDONLY },
     46     { "rw",         0 },
     47     { "remount",    MS_REMOUNT },
     48     { "bind",       MS_BIND },
     49     { "rec",        MS_REC },
     50     { "unbindable", MS_UNBINDABLE },
     51     { "private",    MS_PRIVATE },
     52     { "slave",      MS_SLAVE },
     53     { "shared",     MS_SHARED },
     54     { "defaults",   0 },
     55     { 0,            0 },
     56 };
     57 
     58 static struct flag_list fs_mgr_flags[] = {
     59     { "wait",        MF_WAIT },
     60     { "check",       MF_CHECK },
     61     { "encryptable=",MF_CRYPT },
     62     { "forceencrypt=",MF_FORCECRYPT },
     63     { "nonremovable",MF_NONREMOVABLE },
     64     { "voldmanaged=",MF_VOLDMANAGED},
     65     { "length=",     MF_LENGTH },
     66     { "recoveryonly",MF_RECOVERYONLY },
     67     { "swapprio=",   MF_SWAPPRIO },
     68     { "zramsize=",   MF_ZRAMSIZE },
     69     { "verify",      MF_VERIFY },
     70     { "noemulatedsd", MF_NOEMULATEDSD },
     71     { "formattable", MF_FORMATTABLE },
     72     { "defaults",    0 },
     73     { 0,             0 },
     74 };
     75 
     76 static int parse_flags(char *flags, struct flag_list *fl,
     77                        struct fs_mgr_flag_values *flag_vals,
     78                        char *fs_options, int fs_options_len)
     79 {
     80     int f = 0;
     81     int i;
     82     char *p;
     83     char *savep;
     84 
     85     /* initialize flag values.  If we find a relevant flag, we'll
     86      * update the value */
     87     if (flag_vals) {
     88         memset(flag_vals, 0, sizeof(*flag_vals));
     89         flag_vals->partnum = -1;
     90         flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
     91     }
     92 
     93     /* initialize fs_options to the null string */
     94     if (fs_options && (fs_options_len > 0)) {
     95         fs_options[0] = '\0';
     96     }
     97 
     98     p = strtok_r(flags, ",", &savep);
     99     while (p) {
    100         /* Look for the flag "p" in the flag list "fl"
    101          * If not found, the loop exits with fl[i].name being null.
    102          */
    103         for (i = 0; fl[i].name; i++) {
    104             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
    105                 f |= fl[i].flag;
    106                 if ((fl[i].flag == MF_CRYPT) && flag_vals) {
    107                     /* The encryptable flag is followed by an = and the
    108                      * location of the keys.  Get it and return it.
    109                      */
    110                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
    111                 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
    112                     /* The forceencrypt flag is followed by an = and the
    113                      * location of the keys.  Get it and return it.
    114                      */
    115                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
    116                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
    117                     /* The length flag is followed by an = and the
    118                      * size of the partition.  Get it and return it.
    119                      */
    120                     flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
    121                 } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
    122                     /* The voldmanaged flag is followed by an = and the
    123                      * label, a colon and the partition number or the
    124                      * word "auto", e.g.
    125                      *   voldmanaged=sdcard:3
    126                      * Get and return them.
    127                      */
    128                     char *label_start;
    129                     char *label_end;
    130                     char *part_start;
    131 
    132                     label_start = strchr(p, '=') + 1;
    133                     label_end = strchr(p, ':');
    134                     if (label_end) {
    135                         flag_vals->label = strndup(label_start,
    136                                                    (int) (label_end - label_start));
    137                         part_start = strchr(p, ':') + 1;
    138                         if (!strcmp(part_start, "auto")) {
    139                             flag_vals->partnum = -1;
    140                         } else {
    141                             flag_vals->partnum = strtol(part_start, NULL, 0);
    142                         }
    143                     } else {
    144                         ERROR("Warning: voldmanaged= flag malformed\n");
    145                     }
    146                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
    147                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
    148                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
    149                     flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
    150                 }
    151                 break;
    152             }
    153         }
    154 
    155         if (!fl[i].name) {
    156             if (fs_options) {
    157                 /* It's not a known flag, so it must be a filesystem specific
    158                  * option.  Add it to fs_options if it was passed in.
    159                  */
    160                 strlcat(fs_options, p, fs_options_len);
    161                 strlcat(fs_options, ",", fs_options_len);
    162             } else {
    163                 /* fs_options was not passed in, so if the flag is unknown
    164                  * it's an error.
    165                  */
    166                 ERROR("Warning: unknown flag %s\n", p);
    167             }
    168         }
    169         p = strtok_r(NULL, ",", &savep);
    170     }
    171 
    172     if (fs_options && fs_options[0]) {
    173         /* remove the last trailing comma from the list of options */
    174         fs_options[strlen(fs_options) - 1] = '\0';
    175     }
    176 
    177     return f;
    178 }
    179 
    180 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
    181 {
    182     FILE *fstab_file;
    183     int cnt, entries;
    184     ssize_t len;
    185     size_t alloc_len = 0;
    186     char *line = NULL;
    187     const char *delim = " \t";
    188     char *save_ptr, *p;
    189     struct fstab *fstab = NULL;
    190     struct fs_mgr_flag_values flag_vals;
    191 #define FS_OPTIONS_LEN 1024
    192     char tmp_fs_options[FS_OPTIONS_LEN];
    193 
    194     fstab_file = fopen(fstab_path, "r");
    195     if (!fstab_file) {
    196         ERROR("Cannot open file %s\n", fstab_path);
    197         return 0;
    198     }
    199 
    200     entries = 0;
    201     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
    202         /* if the last character is a newline, shorten the string by 1 byte */
    203         if (line[len - 1] == '\n') {
    204             line[len - 1] = '\0';
    205         }
    206         /* Skip any leading whitespace */
    207         p = line;
    208         while (isspace(*p)) {
    209             p++;
    210         }
    211         /* ignore comments or empty lines */
    212         if (*p == '#' || *p == '\0')
    213             continue;
    214         entries++;
    215     }
    216 
    217     if (!entries) {
    218         ERROR("No entries found in fstab\n");
    219         goto err;
    220     }
    221 
    222     /* Allocate and init the fstab structure */
    223     fstab = calloc(1, sizeof(struct fstab));
    224     fstab->num_entries = entries;
    225     fstab->fstab_filename = strdup(fstab_path);
    226     fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
    227 
    228     fseek(fstab_file, 0, SEEK_SET);
    229 
    230     cnt = 0;
    231     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
    232         /* if the last character is a newline, shorten the string by 1 byte */
    233         if (line[len - 1] == '\n') {
    234             line[len - 1] = '\0';
    235         }
    236 
    237         /* Skip any leading whitespace */
    238         p = line;
    239         while (isspace(*p)) {
    240             p++;
    241         }
    242         /* ignore comments or empty lines */
    243         if (*p == '#' || *p == '\0')
    244             continue;
    245 
    246         /* If a non-comment entry is greater than the size we allocated, give an
    247          * error and quit.  This can happen in the unlikely case the file changes
    248          * between the two reads.
    249          */
    250         if (cnt >= entries) {
    251             ERROR("Tried to process more entries than counted\n");
    252             break;
    253         }
    254 
    255         if (!(p = strtok_r(line, delim, &save_ptr))) {
    256             ERROR("Error parsing mount source\n");
    257             goto err;
    258         }
    259         fstab->recs[cnt].blk_device = strdup(p);
    260 
    261         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    262             ERROR("Error parsing mount_point\n");
    263             goto err;
    264         }
    265         fstab->recs[cnt].mount_point = strdup(p);
    266 
    267         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    268             ERROR("Error parsing fs_type\n");
    269             goto err;
    270         }
    271         fstab->recs[cnt].fs_type = strdup(p);
    272 
    273         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    274             ERROR("Error parsing mount_flags\n");
    275             goto err;
    276         }
    277         tmp_fs_options[0] = '\0';
    278         fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
    279                                        tmp_fs_options, FS_OPTIONS_LEN);
    280 
    281         /* fs_options are optional */
    282         if (tmp_fs_options[0]) {
    283             fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
    284         } else {
    285             fstab->recs[cnt].fs_options = NULL;
    286         }
    287 
    288         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    289             ERROR("Error parsing fs_mgr_options\n");
    290             goto err;
    291         }
    292         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
    293                                                     &flag_vals, NULL, 0);
    294         fstab->recs[cnt].key_loc = flag_vals.key_loc;
    295         fstab->recs[cnt].length = flag_vals.part_length;
    296         fstab->recs[cnt].label = flag_vals.label;
    297         fstab->recs[cnt].partnum = flag_vals.partnum;
    298         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
    299         fstab->recs[cnt].zram_size = flag_vals.zram_size;
    300         cnt++;
    301     }
    302     fclose(fstab_file);
    303     free(line);
    304     return fstab;
    305 
    306 err:
    307     fclose(fstab_file);
    308     free(line);
    309     if (fstab)
    310         fs_mgr_free_fstab(fstab);
    311     return NULL;
    312 }
    313 
    314 void fs_mgr_free_fstab(struct fstab *fstab)
    315 {
    316     int i;
    317 
    318     if (!fstab) {
    319         return;
    320     }
    321 
    322     for (i = 0; i < fstab->num_entries; i++) {
    323         /* Free the pointers return by strdup(3) */
    324         free(fstab->recs[i].blk_device);
    325         free(fstab->recs[i].mount_point);
    326         free(fstab->recs[i].fs_type);
    327         free(fstab->recs[i].fs_options);
    328         free(fstab->recs[i].key_loc);
    329         free(fstab->recs[i].label);
    330     }
    331 
    332     /* Free the fstab_recs array created by calloc(3) */
    333     free(fstab->recs);
    334 
    335     /* Free the fstab filename */
    336     free(fstab->fstab_filename);
    337 
    338     /* Free fstab */
    339     free(fstab);
    340 }
    341 
    342 /* Add an entry to the fstab, and return 0 on success or -1 on error */
    343 int fs_mgr_add_entry(struct fstab *fstab,
    344                      const char *mount_point, const char *fs_type,
    345                      const char *blk_device)
    346 {
    347     struct fstab_rec *new_fstab_recs;
    348     int n = fstab->num_entries;
    349 
    350     new_fstab_recs = (struct fstab_rec *)
    351                      realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
    352 
    353     if (!new_fstab_recs) {
    354         return -1;
    355     }
    356 
    357     /* A new entry was added, so initialize it */
    358      memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
    359      new_fstab_recs[n].mount_point = strdup(mount_point);
    360      new_fstab_recs[n].fs_type = strdup(fs_type);
    361      new_fstab_recs[n].blk_device = strdup(blk_device);
    362      new_fstab_recs[n].length = 0;
    363 
    364      /* Update the fstab struct */
    365      fstab->recs = new_fstab_recs;
    366      fstab->num_entries++;
    367 
    368      return 0;
    369 }
    370 
    371 /*
    372  * Returns the 1st matching fstab_rec that follows the start_rec.
    373  * start_rec is the result of a previous search or NULL.
    374  */
    375 struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
    376 {
    377     int i;
    378     if (!fstab) {
    379         return NULL;
    380     }
    381 
    382     if (start_rec) {
    383         for (i = 0; i < fstab->num_entries; i++) {
    384             if (&fstab->recs[i] == start_rec) {
    385                 i++;
    386                 break;
    387             }
    388         }
    389     } else {
    390         i = 0;
    391     }
    392     for (; i < fstab->num_entries; i++) {
    393         int len = strlen(fstab->recs[i].mount_point);
    394         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
    395             (path[len] == '\0' || path[len] == '/')) {
    396             return &fstab->recs[i];
    397         }
    398     }
    399     return NULL;
    400 }
    401 
    402 /*
    403  * Returns the 1st matching mount point.
    404  * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
    405  * and give the fstab_rec from the previous search.
    406  */
    407 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
    408 {
    409     return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
    410 }
    411 
    412 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
    413 {
    414     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
    415 }
    416 
    417 int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
    418 {
    419     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
    420 }
    421 
    422 int fs_mgr_is_verified(struct fstab_rec *fstab)
    423 {
    424     return fstab->fs_mgr_flags & MF_VERIFY;
    425 }
    426 
    427 int fs_mgr_is_encryptable(struct fstab_rec *fstab)
    428 {
    429     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
    430 }
    431 
    432 int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
    433 {
    434     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
    435 }
    436 
    437 int fs_mgr_is_formattable(struct fstab_rec *fstab)
    438 {
    439     return fstab->fs_mgr_flags & (MF_FORMATTABLE);
    440 }
    441