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 <dirent.h>
     19 #include <errno.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/mount.h>
     24 #include <unistd.h>
     25 
     26 #include <android-base/file.h>
     27 #include <android-base/stringprintf.h>
     28 #include <android-base/strings.h>
     29 
     30 #include "fs_mgr_priv.h"
     31 
     32 struct fs_mgr_flag_values {
     33     char *key_loc;
     34     char *verity_loc;
     35     long long part_length;
     36     char *label;
     37     int partnum;
     38     int swap_prio;
     39     int max_comp_streams;
     40     unsigned int zram_size;
     41     uint64_t reserved_size;
     42     unsigned int file_contents_mode;
     43     unsigned int file_names_mode;
     44     unsigned int erase_blk_size;
     45     unsigned int logical_blk_size;
     46 };
     47 
     48 struct flag_list {
     49     const char *name;
     50     unsigned int flag;
     51 };
     52 
     53 static struct flag_list mount_flags[] = {
     54     { "noatime",    MS_NOATIME },
     55     { "noexec",     MS_NOEXEC },
     56     { "nosuid",     MS_NOSUID },
     57     { "nodev",      MS_NODEV },
     58     { "nodiratime", MS_NODIRATIME },
     59     { "ro",         MS_RDONLY },
     60     { "rw",         0 },
     61     { "remount",    MS_REMOUNT },
     62     { "bind",       MS_BIND },
     63     { "rec",        MS_REC },
     64     { "unbindable", MS_UNBINDABLE },
     65     { "private",    MS_PRIVATE },
     66     { "slave",      MS_SLAVE },
     67     { "shared",     MS_SHARED },
     68     { "defaults",   0 },
     69     { 0,            0 },
     70 };
     71 
     72 static struct flag_list fs_mgr_flags[] = {
     73     { "wait",               MF_WAIT },
     74     { "check",              MF_CHECK },
     75     { "encryptable=",       MF_CRYPT },
     76     { "forceencrypt=",      MF_FORCECRYPT },
     77     { "fileencryption=",    MF_FILEENCRYPTION },
     78     { "forcefdeorfbe=",     MF_FORCEFDEORFBE },
     79     { "nonremovable",       MF_NONREMOVABLE },
     80     { "voldmanaged=",       MF_VOLDMANAGED},
     81     { "length=",            MF_LENGTH },
     82     { "recoveryonly",       MF_RECOVERYONLY },
     83     { "swapprio=",          MF_SWAPPRIO },
     84     { "zramsize=",          MF_ZRAMSIZE },
     85     { "max_comp_streams=",  MF_MAX_COMP_STREAMS },
     86     { "verifyatboot",       MF_VERIFYATBOOT },
     87     { "verify",             MF_VERIFY },
     88     { "avb",                MF_AVB },
     89     { "noemulatedsd",       MF_NOEMULATEDSD },
     90     { "notrim",             MF_NOTRIM },
     91     { "formattable",        MF_FORMATTABLE },
     92     { "slotselect",         MF_SLOTSELECT },
     93     { "nofail",             MF_NOFAIL },
     94     { "latemount",          MF_LATEMOUNT },
     95     { "reservedsize=",      MF_RESERVEDSIZE },
     96     { "quota",              MF_QUOTA },
     97     { "eraseblk=",          MF_ERASEBLKSIZE },
     98     { "logicalblk=",        MF_LOGICALBLKSIZE },
     99     { "defaults",           0 },
    100     { 0,                    0 },
    101 };
    102 
    103 #define EM_AES_256_XTS  1
    104 #define EM_ICE          2
    105 #define EM_AES_256_CTS  3
    106 #define EM_AES_256_HEH  4
    107 
    108 static const struct flag_list file_contents_encryption_modes[] = {
    109     {"aes-256-xts", EM_AES_256_XTS},
    110     {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
    111     {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
    112     {0, 0},
    113 };
    114 
    115 static const struct flag_list file_names_encryption_modes[] = {
    116     {"aes-256-cts", EM_AES_256_CTS},
    117     {"aes-256-heh", EM_AES_256_HEH},
    118     {0, 0},
    119 };
    120 
    121 static unsigned int encryption_mode_to_flag(const struct flag_list *list,
    122                                             const char *mode, const char *type)
    123 {
    124     const struct flag_list *j;
    125 
    126     for (j = list; j->name; ++j) {
    127         if (!strcmp(mode, j->name)) {
    128             return j->flag;
    129         }
    130     }
    131     LERROR << "Unknown " << type << " encryption mode: " << mode;
    132     return 0;
    133 }
    134 
    135 static const char *flag_to_encryption_mode(const struct flag_list *list,
    136                                            unsigned int flag)
    137 {
    138     const struct flag_list *j;
    139 
    140     for (j = list; j->name; ++j) {
    141         if (flag == j->flag) {
    142             return j->name;
    143         }
    144     }
    145     return nullptr;
    146 }
    147 
    148 static uint64_t calculate_zram_size(unsigned int percentage)
    149 {
    150     uint64_t total;
    151 
    152     total  = sysconf(_SC_PHYS_PAGES);
    153     total *= percentage;
    154     total /= 100;
    155 
    156     total *= sysconf(_SC_PAGESIZE);
    157 
    158     return total;
    159 }
    160 
    161 static uint64_t parse_size(const char *arg)
    162 {
    163     char *endptr;
    164     uint64_t size = strtoull(arg, &endptr, 10);
    165     if (*endptr == 'k' || *endptr == 'K')
    166         size *= 1024LL;
    167     else if (*endptr == 'm' || *endptr == 'M')
    168         size *= 1024LL * 1024LL;
    169     else if (*endptr == 'g' || *endptr == 'G')
    170         size *= 1024LL * 1024LL * 1024LL;
    171 
    172     return size;
    173 }
    174 
    175 /* fills 'dt_value' with the underlying device tree value string without
    176  * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
    177  * otherwise.
    178  */
    179 static bool read_dt_file(const std::string& file_name, std::string* dt_value)
    180 {
    181     if (android::base::ReadFileToString(file_name, dt_value)) {
    182         if (!dt_value->empty()) {
    183             // trim the trailing '\0' out, otherwise the comparison
    184             // will produce false-negatives.
    185             dt_value->resize(dt_value->size() - 1);
    186             return true;
    187         }
    188     }
    189 
    190     return false;
    191 }
    192 
    193 static int parse_flags(char *flags, struct flag_list *fl,
    194                        struct fs_mgr_flag_values *flag_vals,
    195                        char *fs_options, int fs_options_len)
    196 {
    197     int f = 0;
    198     int i;
    199     char *p;
    200     char *savep;
    201 
    202     /* initialize flag values.  If we find a relevant flag, we'll
    203      * update the value */
    204     if (flag_vals) {
    205         memset(flag_vals, 0, sizeof(*flag_vals));
    206         flag_vals->partnum = -1;
    207         flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
    208     }
    209 
    210     /* initialize fs_options to the null string */
    211     if (fs_options && (fs_options_len > 0)) {
    212         fs_options[0] = '\0';
    213     }
    214 
    215     p = strtok_r(flags, ",", &savep);
    216     while (p) {
    217         /* Look for the flag "p" in the flag list "fl"
    218          * If not found, the loop exits with fl[i].name being null.
    219          */
    220         for (i = 0; fl[i].name; i++) {
    221             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
    222                 f |= fl[i].flag;
    223                 if ((fl[i].flag == MF_CRYPT) && flag_vals) {
    224                     /* The encryptable flag is followed by an = and the
    225                      * location of the keys.  Get it and return it.
    226                      */
    227                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
    228                 } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
    229                     /* If the verify flag is followed by an = and the
    230                      * location for the verity state,  get it and return it.
    231                      */
    232                     char *start = strchr(p, '=');
    233                     if (start) {
    234                         flag_vals->verity_loc = strdup(start + 1);
    235                     }
    236                 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
    237                     /* The forceencrypt flag is followed by an = and the
    238                      * location of the keys.  Get it and return it.
    239                      */
    240                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
    241                 } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
    242                     /* The forcefdeorfbe flag is followed by an = and the
    243                      * location of the keys.  Get it and return it.
    244                      */
    245                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
    246                     flag_vals->file_contents_mode = EM_AES_256_XTS;
    247                     flag_vals->file_names_mode = EM_AES_256_CTS;
    248                 } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
    249                     /* The fileencryption flag is followed by an = and
    250                      * the mode of contents encryption, then optionally a
    251                      * : and the mode of filenames encryption (defaults
    252                      * to aes-256-cts).  Get it and return it.
    253                      */
    254                     char *mode = strchr(p, '=') + 1;
    255                     char *colon = strchr(mode, ':');
    256                     if (colon) {
    257                         *colon = '\0';
    258                     }
    259                     flag_vals->file_contents_mode =
    260                         encryption_mode_to_flag(file_contents_encryption_modes,
    261                                                 mode, "file contents");
    262                     if (colon) {
    263                         flag_vals->file_names_mode =
    264                             encryption_mode_to_flag(file_names_encryption_modes,
    265                                                     colon + 1, "file names");
    266                     } else {
    267                         flag_vals->file_names_mode = EM_AES_256_CTS;
    268                     }
    269                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
    270                     /* The length flag is followed by an = and the
    271                      * size of the partition.  Get it and return it.
    272                      */
    273                     flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
    274                 } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
    275                     /* The voldmanaged flag is followed by an = and the
    276                      * label, a colon and the partition number or the
    277                      * word "auto", e.g.
    278                      *   voldmanaged=sdcard:3
    279                      * Get and return them.
    280                      */
    281                     char *label_start;
    282                     char *label_end;
    283                     char *part_start;
    284 
    285                     label_start = strchr(p, '=') + 1;
    286                     label_end = strchr(p, ':');
    287                     if (label_end) {
    288                         flag_vals->label = strndup(label_start,
    289                                                    (int) (label_end - label_start));
    290                         part_start = strchr(p, ':') + 1;
    291                         if (!strcmp(part_start, "auto")) {
    292                             flag_vals->partnum = -1;
    293                         } else {
    294                             flag_vals->partnum = strtol(part_start, NULL, 0);
    295                         }
    296                     } else {
    297                         LERROR << "Warning: voldmanaged= flag malformed";
    298                     }
    299                 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
    300                     flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
    301                 } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
    302                     flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
    303                 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
    304                     int is_percent = !!strrchr(p, '%');
    305                     unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
    306                     if (is_percent)
    307                         flag_vals->zram_size = calculate_zram_size(val);
    308                     else
    309                         flag_vals->zram_size = val;
    310                 } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
    311                     /* The reserved flag is followed by an = and the
    312                      * reserved size of the partition.  Get it and return it.
    313                      */
    314                     flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
    315                 } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
    316                     /* The erase block size flag is followed by an = and the flash
    317                      * erase block size. Get it, check that it is a power of 2 and
    318                      * at least 4096, and return it.
    319                      */
    320                     unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
    321                     if (val >= 4096 && (val & (val - 1)) == 0)
    322                         flag_vals->erase_blk_size = val;
    323                 } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
    324                     /* The logical block size flag is followed by an = and the flash
    325                      * logical block size. Get it, check that it is a power of 2 and
    326                      * at least 4096, and return it.
    327                      */
    328                     unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
    329                     if (val >= 4096 && (val & (val - 1)) == 0)
    330                         flag_vals->logical_blk_size = val;
    331                 }
    332                 break;
    333             }
    334         }
    335 
    336         if (!fl[i].name) {
    337             if (fs_options) {
    338                 /* It's not a known flag, so it must be a filesystem specific
    339                  * option.  Add it to fs_options if it was passed in.
    340                  */
    341                 strlcat(fs_options, p, fs_options_len);
    342                 strlcat(fs_options, ",", fs_options_len);
    343             } else {
    344                 /* fs_options was not passed in, so if the flag is unknown
    345                  * it's an error.
    346                  */
    347                 LERROR << "Warning: unknown flag " << p;
    348             }
    349         }
    350         p = strtok_r(NULL, ",", &savep);
    351     }
    352 
    353     if (fs_options && fs_options[0]) {
    354         /* remove the last trailing comma from the list of options */
    355         fs_options[strlen(fs_options) - 1] = '\0';
    356     }
    357 
    358     return f;
    359 }
    360 
    361 static bool is_dt_fstab_compatible() {
    362     std::string dt_value;
    363     std::string file_name = kAndroidDtDir + "/fstab/compatible";
    364     if (read_dt_file(file_name, &dt_value)) {
    365         if (dt_value == "android,fstab") {
    366             return true;
    367         }
    368     }
    369 
    370     return false;
    371 }
    372 
    373 static std::string read_fstab_from_dt() {
    374     std::string fstab;
    375     if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
    376         return fstab;
    377     }
    378 
    379     std::string fstabdir_name = kAndroidDtDir + "/fstab";
    380     std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
    381     if (!fstabdir) return fstab;
    382 
    383     dirent* dp;
    384     while ((dp = readdir(fstabdir.get())) != NULL) {
    385         // skip over name and compatible
    386         if (dp->d_type != DT_DIR) {
    387             continue;
    388         }
    389 
    390         // skip if its not 'vendor', 'odm' or 'system'
    391         if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
    392             strcmp(dp->d_name, "vendor")) {
    393             continue;
    394         }
    395 
    396         // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
    397         std::vector<std::string> fstab_entry;
    398         std::string file_name;
    399         std::string value;
    400         // skip a partition entry if the status property is present and not set to ok
    401         file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
    402         if (read_dt_file(file_name, &value)) {
    403             if (value != "okay" && value != "ok") {
    404                 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
    405                 continue;
    406             }
    407         }
    408 
    409         file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
    410         if (!read_dt_file(file_name, &value)) {
    411             LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
    412             fstab.clear();
    413             break;
    414         }
    415         fstab_entry.push_back(value);
    416         fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
    417 
    418         file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
    419         if (!read_dt_file(file_name, &value)) {
    420             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
    421             fstab.clear();
    422             break;
    423         }
    424         fstab_entry.push_back(value);
    425 
    426         file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
    427         if (!read_dt_file(file_name, &value)) {
    428             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
    429             fstab.clear();
    430             break;
    431         }
    432         fstab_entry.push_back(value);
    433 
    434         file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
    435         if (!read_dt_file(file_name, &value)) {
    436             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
    437             fstab.clear();
    438             break;
    439         }
    440         fstab_entry.push_back(value);
    441 
    442         fstab += android::base::Join(fstab_entry, " ");
    443         fstab += '\n';
    444     }
    445 
    446     return fstab;
    447 }
    448 
    449 bool is_dt_compatible() {
    450     std::string file_name = kAndroidDtDir + "/compatible";
    451     std::string dt_value;
    452     if (read_dt_file(file_name, &dt_value)) {
    453         if (dt_value == "android,firmware") {
    454             return true;
    455         }
    456     }
    457 
    458     return false;
    459 }
    460 
    461 static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
    462 {
    463     int cnt, entries;
    464     ssize_t len;
    465     size_t alloc_len = 0;
    466     char *line = NULL;
    467     const char *delim = " \t";
    468     char *save_ptr, *p;
    469     struct fstab *fstab = NULL;
    470     struct fs_mgr_flag_values flag_vals;
    471 #define FS_OPTIONS_LEN 1024
    472     char tmp_fs_options[FS_OPTIONS_LEN];
    473 
    474     entries = 0;
    475     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
    476         /* if the last character is a newline, shorten the string by 1 byte */
    477         if (line[len - 1] == '\n') {
    478             line[len - 1] = '\0';
    479         }
    480         /* Skip any leading whitespace */
    481         p = line;
    482         while (isspace(*p)) {
    483             p++;
    484         }
    485         /* ignore comments or empty lines */
    486         if (*p == '#' || *p == '\0')
    487             continue;
    488         entries++;
    489     }
    490 
    491     if (!entries) {
    492         LERROR << "No entries found in fstab";
    493         goto err;
    494     }
    495 
    496     /* Allocate and init the fstab structure */
    497     fstab = static_cast<struct fstab *>(calloc(1, sizeof(struct fstab)));
    498     fstab->num_entries = entries;
    499     fstab->recs = static_cast<struct fstab_rec *>(
    500         calloc(fstab->num_entries, sizeof(struct fstab_rec)));
    501 
    502     fseek(fstab_file, 0, SEEK_SET);
    503 
    504     cnt = 0;
    505     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
    506         /* if the last character is a newline, shorten the string by 1 byte */
    507         if (line[len - 1] == '\n') {
    508             line[len - 1] = '\0';
    509         }
    510 
    511         /* Skip any leading whitespace */
    512         p = line;
    513         while (isspace(*p)) {
    514             p++;
    515         }
    516         /* ignore comments or empty lines */
    517         if (*p == '#' || *p == '\0')
    518             continue;
    519 
    520         /* If a non-comment entry is greater than the size we allocated, give an
    521          * error and quit.  This can happen in the unlikely case the file changes
    522          * between the two reads.
    523          */
    524         if (cnt >= entries) {
    525             LERROR << "Tried to process more entries than counted";
    526             break;
    527         }
    528 
    529         if (!(p = strtok_r(line, delim, &save_ptr))) {
    530             LERROR << "Error parsing mount source";
    531             goto err;
    532         }
    533         fstab->recs[cnt].blk_device = strdup(p);
    534 
    535         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    536             LERROR << "Error parsing mount_point";
    537             goto err;
    538         }
    539         fstab->recs[cnt].mount_point = strdup(p);
    540 
    541         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    542             LERROR << "Error parsing fs_type";
    543             goto err;
    544         }
    545         fstab->recs[cnt].fs_type = strdup(p);
    546 
    547         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    548             LERROR << "Error parsing mount_flags";
    549             goto err;
    550         }
    551         tmp_fs_options[0] = '\0';
    552         fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
    553                                        tmp_fs_options, FS_OPTIONS_LEN);
    554 
    555         /* fs_options are optional */
    556         if (tmp_fs_options[0]) {
    557             fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
    558         } else {
    559             fstab->recs[cnt].fs_options = NULL;
    560         }
    561 
    562         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
    563             LERROR << "Error parsing fs_mgr_options";
    564             goto err;
    565         }
    566         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
    567                                                     &flag_vals, NULL, 0);
    568         fstab->recs[cnt].key_loc = flag_vals.key_loc;
    569         fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
    570         fstab->recs[cnt].length = flag_vals.part_length;
    571         fstab->recs[cnt].label = flag_vals.label;
    572         fstab->recs[cnt].partnum = flag_vals.partnum;
    573         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
    574         fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
    575         fstab->recs[cnt].zram_size = flag_vals.zram_size;
    576         fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
    577         fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
    578         fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
    579         fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
    580         fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
    581         cnt++;
    582     }
    583     /* If an A/B partition, modify block device to be the real block device */
    584     if (!fs_mgr_update_for_slotselect(fstab)) {
    585         LERROR << "Error updating for slotselect";
    586         goto err;
    587     }
    588     free(line);
    589     return fstab;
    590 
    591 err:
    592     free(line);
    593     if (fstab)
    594         fs_mgr_free_fstab(fstab);
    595     return NULL;
    596 }
    597 
    598 /* merges fstab entries from both a and b, then returns the merged result.
    599  * note that the caller should only manage the return pointer without
    600  * doing further memory management for the two inputs, i.e. only need to
    601  * frees up memory of the return value without touching a and b. */
    602 static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
    603 {
    604     if (!a) return b;
    605     if (!b) return a;
    606 
    607     int total_entries = a->num_entries + b->num_entries;
    608     a->recs = static_cast<struct fstab_rec *>(realloc(
    609         a->recs, total_entries * (sizeof(struct fstab_rec))));
    610     if (!a->recs) {
    611         LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
    612         // If realloc() fails the original block is left untouched;
    613         // it is not freed or moved. So we have to free both a and b here.
    614         fs_mgr_free_fstab(a);
    615         fs_mgr_free_fstab(b);
    616         return nullptr;
    617     }
    618 
    619     for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
    620         // copy the pointer directly *without* malloc and memcpy
    621         a->recs[i] = b->recs[j];
    622     }
    623 
    624     // Frees up b, but don't free b->recs[X] to make sure they are
    625     // accessible through a->recs[X].
    626     free(b->fstab_filename);
    627     free(b);
    628 
    629     a->num_entries = total_entries;
    630     return a;
    631 }
    632 
    633 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
    634 {
    635     FILE *fstab_file;
    636     struct fstab *fstab;
    637 
    638     fstab_file = fopen(fstab_path, "r");
    639     if (!fstab_file) {
    640         PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
    641         return nullptr;
    642     }
    643 
    644     fstab = fs_mgr_read_fstab_file(fstab_file);
    645     if (fstab) {
    646         fstab->fstab_filename = strdup(fstab_path);
    647     } else {
    648         LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
    649     }
    650 
    651     fclose(fstab_file);
    652     return fstab;
    653 }
    654 
    655 /* Returns fstab entries parsed from the device tree if they
    656  * exist
    657  */
    658 struct fstab *fs_mgr_read_fstab_dt()
    659 {
    660     std::string fstab_buf = read_fstab_from_dt();
    661     if (fstab_buf.empty()) {
    662         LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
    663         return nullptr;
    664     }
    665 
    666     std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
    667         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
    668                  fstab_buf.length(), "r"), fclose);
    669     if (!fstab_file) {
    670         PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
    671         return nullptr;
    672     }
    673 
    674     struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
    675     if (!fstab) {
    676         LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
    677                << std::endl << fstab_buf;
    678     }
    679 
    680     return fstab;
    681 }
    682 
    683 /*
    684  * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
    685  * or /. loads the first one found and also combines fstab entries passed
    686  * in from device tree.
    687  */
    688 struct fstab *fs_mgr_read_fstab_default()
    689 {
    690     std::string hw;
    691     std::string default_fstab;
    692 
    693     // Use different fstab paths for normal boot and recovery boot, respectively
    694     if (access("/sbin/recovery", F_OK) == 0) {
    695         default_fstab = "/etc/recovery.fstab";
    696     } else if (fs_mgr_get_boot_config("hardware", &hw)) {  // normal boot
    697         for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
    698             default_fstab = prefix + hw;
    699             if (access(default_fstab.c_str(), F_OK) == 0) break;
    700         }
    701     } else {
    702         LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
    703     }
    704 
    705     // combines fstab entries passed in from device tree with
    706     // the ones found from default_fstab file
    707     struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
    708     struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
    709 
    710     return in_place_merge(fstab_dt, fstab);
    711 }
    712 
    713 void fs_mgr_free_fstab(struct fstab *fstab)
    714 {
    715     int i;
    716 
    717     if (!fstab) {
    718         return;
    719     }
    720 
    721     for (i = 0; i < fstab->num_entries; i++) {
    722         /* Free the pointers return by strdup(3) */
    723         free(fstab->recs[i].blk_device);
    724         free(fstab->recs[i].mount_point);
    725         free(fstab->recs[i].fs_type);
    726         free(fstab->recs[i].fs_options);
    727         free(fstab->recs[i].key_loc);
    728         free(fstab->recs[i].label);
    729     }
    730 
    731     /* Free the fstab_recs array created by calloc(3) */
    732     free(fstab->recs);
    733 
    734     /* Free the fstab filename */
    735     free(fstab->fstab_filename);
    736 
    737     /* Free fstab */
    738     free(fstab);
    739 }
    740 
    741 /* Add an entry to the fstab, and return 0 on success or -1 on error */
    742 int fs_mgr_add_entry(struct fstab *fstab,
    743                      const char *mount_point, const char *fs_type,
    744                      const char *blk_device)
    745 {
    746     struct fstab_rec *new_fstab_recs;
    747     int n = fstab->num_entries;
    748 
    749     new_fstab_recs = (struct fstab_rec *)
    750                      realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
    751 
    752     if (!new_fstab_recs) {
    753         return -1;
    754     }
    755 
    756     /* A new entry was added, so initialize it */
    757      memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
    758      new_fstab_recs[n].mount_point = strdup(mount_point);
    759      new_fstab_recs[n].fs_type = strdup(fs_type);
    760      new_fstab_recs[n].blk_device = strdup(blk_device);
    761      new_fstab_recs[n].length = 0;
    762 
    763      /* Update the fstab struct */
    764      fstab->recs = new_fstab_recs;
    765      fstab->num_entries++;
    766 
    767      return 0;
    768 }
    769 
    770 /*
    771  * Returns the 1st matching fstab_rec that follows the start_rec.
    772  * start_rec is the result of a previous search or NULL.
    773  */
    774 struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
    775 {
    776     int i;
    777     if (!fstab) {
    778         return NULL;
    779     }
    780 
    781     if (start_rec) {
    782         for (i = 0; i < fstab->num_entries; i++) {
    783             if (&fstab->recs[i] == start_rec) {
    784                 i++;
    785                 break;
    786             }
    787         }
    788     } else {
    789         i = 0;
    790     }
    791     for (; i < fstab->num_entries; i++) {
    792         int len = strlen(fstab->recs[i].mount_point);
    793         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
    794             (path[len] == '\0' || path[len] == '/')) {
    795             return &fstab->recs[i];
    796         }
    797     }
    798     return NULL;
    799 }
    800 
    801 /*
    802  * Returns the 1st matching mount point.
    803  * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
    804  * and give the fstab_rec from the previous search.
    805  */
    806 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
    807 {
    808     return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
    809 }
    810 
    811 int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
    812 {
    813     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
    814 }
    815 
    816 int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
    817 {
    818     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
    819 }
    820 
    821 int fs_mgr_is_verified(const struct fstab_rec *fstab)
    822 {
    823     return fstab->fs_mgr_flags & MF_VERIFY;
    824 }
    825 
    826 int fs_mgr_is_avb(const struct fstab_rec *fstab)
    827 {
    828     return fstab->fs_mgr_flags & MF_AVB;
    829 }
    830 
    831 int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
    832 {
    833     return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
    834 }
    835 
    836 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
    837 {
    838     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
    839 }
    840 
    841 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
    842 {
    843     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
    844 }
    845 
    846 void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
    847                                       const char **contents_mode_ret,
    848                                       const char **filenames_mode_ret)
    849 {
    850     *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
    851                                                  fstab->file_contents_mode);
    852     *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
    853                                                   fstab->file_names_mode);
    854 }
    855 
    856 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
    857 {
    858     return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
    859 }
    860 
    861 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
    862 {
    863     return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
    864 }
    865 
    866 int fs_mgr_is_notrim(struct fstab_rec *fstab)
    867 {
    868     return fstab->fs_mgr_flags & MF_NOTRIM;
    869 }
    870 
    871 int fs_mgr_is_formattable(struct fstab_rec *fstab)
    872 {
    873     return fstab->fs_mgr_flags & (MF_FORMATTABLE);
    874 }
    875 
    876 int fs_mgr_is_slotselect(struct fstab_rec *fstab)
    877 {
    878     return fstab->fs_mgr_flags & MF_SLOTSELECT;
    879 }
    880 
    881 int fs_mgr_is_nofail(struct fstab_rec *fstab)
    882 {
    883     return fstab->fs_mgr_flags & MF_NOFAIL;
    884 }
    885 
    886 int fs_mgr_is_latemount(struct fstab_rec *fstab)
    887 {
    888     return fstab->fs_mgr_flags & MF_LATEMOUNT;
    889 }
    890 
    891 int fs_mgr_is_quota(struct fstab_rec *fstab)
    892 {
    893     return fstab->fs_mgr_flags & MF_QUOTA;
    894 }
    895