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