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