process_config解析fstab文件

来源:互联网 发布:phpstorm php配置 编辑:程序博客网 时间:2024/05/22 22:06

  正如Linux的/etc/fstab文件,Android的开机挂载位置在特定的fstab文件中决定。vold的main函数会调用process_config对其进行解析,本例中的fstab文件为板子根目录下的fstab.rk30board文件。

fstab.rk30board

# Android fstab file.#<src>                                          <mnt_point>         <type>    <mnt_flags and options>                       <fs_mgr_flags># The filesystem that contains the filesystem checker binary (typically /system) cannot# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK/dev/block/platform/fe330000.sdhci/by-name/system         /system             ext4      ro,noatime,nodiratime,noauto_da_alloc                                  wait,resize# use this line below instead to enable verity#/dev/block/platform/fe330000.sdhci/by-name/system         /system             ext4      ro,noatime,nodiratime,noauto_da_alloc                                  wait,check,verify/dev/block/platform/fe330000.sdhci/by-name/cache          /cache              ext4      noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard                wait,check/dev/block/platform/fe330000.sdhci/by-name/metadata       /metadata           ext4      noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard                wait,check/dev/block/platform/fe330000.sdhci/by-name/userdata       /data               f2fs      noatime,nodiratime,nosuid,nodev,discard,inline_xattr                   wait,check,notrim,encryptable=/metadata/key_file#data for f2fs nobarrier#/dev/block/platform/fe330000.sdhci/by-name/userdata       /data               f2fs      noatime,nodiratime,nosuid,nodev,discard,inline_xattr,nobarrier   wait,check,notrim,encryptable=/metadata/key_file#data for ext4#/dev/block/platform/fe330000.sdhci/by-name/userdata       /data               ext4      noatime,nodiratime,nosuid,nodev,noauto_da_alloc,discard,errors=panic   wait,check,encryptable=/metadata/key_file# sdcard/devices/platform/fe320000.dwmmc/mmc_host*                auto  auto    defaults        voldmanaged=sdcard1:auto,encryptable=userdata# for usb2.0/devices/platform/*.usb*            auto vfat defaults      voldmanaged=usb:auto# for usb3.0/devices/platform/usb@*/*.dwc3*     auto vfat defaults      voldmanaged=usb:auto /dev/block/zram0                                none                swap      defaults                                              zramsize=533413200

  DefaultFstabPath函数返回上述的fstab文件的路径。fs_mgr_read_fstab是解析的主要函数解析结果保存在结构体struct fstab中。先进入fs_mgr_read_fstab看看。

/system/vold/main.cpp

static int process_config(VolumeManager *vm) {    std::string path(android::vold::DefaultFstabPath());    fstab = fs_mgr_read_fstab(path.c_str());    if (!fstab) {        PLOG(ERROR) << "Failed to open default fstab " << path;        return -1;    }    /* Loop through entries looking for ones that vold manages */    bool has_adoptable = false;    for (int i = 0; i < fstab->num_entries; i++) {        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {            if (fs_mgr_is_nonremovable(&fstab->recs[i])) {                LOG(WARNING) << "nonremovable no longer supported; ignoring volume";                continue;            }            std::string sysPattern(fstab->recs[i].blk_device);            std::string nickname(fstab->recs[i].label);            int flags = 0;            if (fs_mgr_is_encryptable(&fstab->recs[i])) {                flags |= android::vold::Disk::Flags::kAdoptable;                has_adoptable = true;            }            if (fs_mgr_is_noemulatedsd(&fstab->recs[i])                    || property_get_bool("vold.debug.default_primary", false)) {                flags |= android::vold::Disk::Flags::kDefaultPrimary;            }            vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(                    new VolumeManager::DiskSource(sysPattern, nickname, flags)));        }    }    property_set("vold.has_adoptable", has_adoptable ? "1" : "0");    return 0;}

  entries的值表示fstab文件中真正的挂载信息行的数量。得到entries的值后便开始初始化struct fstab结构体。struct fstab的num_entries成员初始化为entries的值,fstab_filename初始化为fstab文件路径表示的字符串,recs初始化为元素数量为num_entries的struct fstab_rec数组的指针。
  接下来遍历每一个挂载信息行,逐一初始化对应的struct fstab_rec元素。正如fstab文件所示,< src>,< mnt_point>,< type>,< mnt_flags and options>,< fs_mgr_flags>标签的内容分别用来初始化struct fstab_rec的成员变量。blk_device,mount_point,fs_type的初始化比较简单,只是直接的字符串拷贝。flags和fs_mgr_flags成员需要经过parse_flags函数处理对应标签内容后才能决定。

/system/core/fs_mgr/include/fs_mgr.h

struct fstab {    int num_entries;    struct fstab_rec *recs;    char *fstab_filename;};

/system/core/fs_mgr/include/fs_mgr.h

struct fstab_rec {    char *blk_device;    char *mount_point;    char *fs_type;    unsigned long flags;    char *fs_options;    int fs_mgr_flags;    char *key_loc;    char *verity_loc;    long long length;    char *label;    int partnum;    int swap_prio;    unsigned int zram_size;};

  看看parse_flags函数。考虑到不同的struct fstab_rec成员的初始化需要对parse_flags传入不同的参数实现。下面分情况讨论:
  先说下flags,fs_options成员的初始化。对于< mnt_flags and options>标签项每一个以逗号为分隔的name,在mount_flags这个struct flag_list结构体数组会有对应的flag值,若没有,说明这个name是文件系统特有的。对于非文件系统特有的name,parse_flags函数会将这些name对应的flags值进行或运算返回。对于文件系统特有的name,处理方法是将它们拷贝到入参fs_options中,以逗号隔开。parse_flags函数返回到fs_mgr_read_fstab函数后,parse_flags函数的返回值用来初始化struct fstab_rec的flags成员,保存在tmp_fs_options的文件系统特有选项用来初始化fs_options成员。
  再来说说剩余的其他struct fstab_rec成员的初始化。这次解析的是< fs_mgr_flags>标签项,根据name查找的依据是fs_mgr_flags的struct flag_list结构体数组。跟上段的相同,一方面,< fs_mgr_flags>标签项的的所有逗号分隔的name是用来设置flags的,另一方面,有一些name是用来初始化入参flag_vals的,具体方法见code。parse_flags函数返回到fs_mgr_read_fstab函数后,返回的flags值用来初始化struct fstab_rec的fs_mgr_flags成员。剩下的成员由入参flag_vals的对应值初始化。

/system/core/fs_mgr/fs_mgr_fstab.c

struct flag_list {    const char *name;    unsigned flag;};static struct flag_list mount_flags[] = {    { "noatime",    MS_NOATIME },    { "noexec",     MS_NOEXEC },    { "nosuid",     MS_NOSUID },    { "nodev",      MS_NODEV },    { "nodiratime", MS_NODIRATIME },    { "ro",         MS_RDONLY },    { "rw",         0 },    { "remount",    MS_REMOUNT },    { "bind",       MS_BIND },    { "rec",        MS_REC },    { "unbindable", MS_UNBINDABLE },    { "private",    MS_PRIVATE },    { "slave",      MS_SLAVE },    { "shared",     MS_SHARED },    { "defaults",   0 },    { 0,            0 },};static struct flag_list fs_mgr_flags[] = {    { "wait",        MF_WAIT },    { "check",       MF_CHECK },    { "encryptable=",MF_CRYPT },    { "forceencrypt=",MF_FORCECRYPT },    { "fileencryption",MF_FILEENCRYPTION },    { "nonremovable",MF_NONREMOVABLE },    { "voldmanaged=",MF_VOLDMANAGED},    { "length=",     MF_LENGTH },    { "recoveryonly",MF_RECOVERYONLY },    { "swapprio=",   MF_SWAPPRIO },    { "zramsize=",   MF_ZRAMSIZE },    { "verify",      MF_VERIFY },    { "noemulatedsd", MF_NOEMULATEDSD },    { "notrim",       MF_NOTRIM },    { "formattable", MF_FORMATTABLE },    { "defaults",    0 },    { 0,             0 },};

/system/core/fs_mgr/fs_mgr_fstab.c

static int parse_flags(char *flags, struct flag_list *fl,                       struct fs_mgr_flag_values *flag_vals,                       char *fs_options, int fs_options_len){    int f = 0;    int i;    char *p;    char *savep;    /* initialize flag values.  If we find a relevant flag, we'll     * update the value */    if (flag_vals) {        memset(flag_vals, 0, sizeof(*flag_vals));        flag_vals->partnum = -1;        flag_vals->swap_prio = -1; /* negative means it wasn't specified. */    }    /* initialize fs_options to the null string */    if (fs_options && (fs_options_len > 0)) {        fs_options[0] = '\0';    }    p = strtok_r(flags, ",", &savep);    while (p) {        /* Look for the flag "p" in the flag list "fl"         * If not found, the loop exits with fl[i].name being null.         */        for (i = 0; fl[i].name; i++) {            if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {                f |= fl[i].flag;                if ((fl[i].flag == MF_CRYPT) && flag_vals) {                    /* The encryptable flag is followed by an = and the                     * location of the keys.  Get it and return it.                     */                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);                } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {                    /* If the verify flag is followed by an = and the                     * location for the verity state,  get it and return it.                     */                    char *start = strchr(p, '=');                    if (start) {                        flag_vals->verity_loc = strdup(start + 1);                    }                } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {                    /* The forceencrypt flag is followed by an = and the                     * location of the keys.  Get it and return it.                     */                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);                } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {                    /* The length flag is followed by an = and the                     * size of the partition.  Get it and return it.                     */                    flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);                } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {                    /* The voldmanaged flag is followed by an = and the                     * label, a colon and the partition number or the                     * word "auto", e.g.                     *   voldmanaged=sdcard:3                     * Get and return them.                     */                    char *label_start;                    char *label_end;                    char *part_start;                    label_start = strchr(p, '=') + 1;                    label_end = strchr(p, ':');                    if (label_end) {                        flag_vals->label = strndup(label_start,                                                   (int) (label_end - label_start));                        part_start = strchr(p, ':') + 1;                        if (!strcmp(part_start, "auto")) {                            flag_vals->partnum = -1;                        } else {                            flag_vals->partnum = strtol(part_start, NULL, 0);                        }                    } else {                        ERROR("Warning: voldmanaged= flag malformed\n");                    }                } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {                    flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);                } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {                    int is_percent = !!strrchr(p, '%');                    unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);                    if (is_percent)                        flag_vals->zram_size = calculate_zram_size(val);                    else                        flag_vals->zram_size = val;                }                break;            }        }        if (!fl[i].name) {            if (fs_options) {                /* It's not a known flag, so it must be a filesystem specific                 * option.  Add it to fs_options if it was passed in.                 */                strlcat(fs_options, p, fs_options_len);                strlcat(fs_options, ",", fs_options_len);            } else {                /* fs_options was not passed in, so if the flag is unknown                 * it's an error.                 */                ERROR("Warning: unknown flag %s\n", p);            }        }        p = strtok_r(NULL, ",", &savep);    }    if (fs_options && fs_options[0]) {        /* remove the last trailing comma from the list of options */        fs_options[strlen(fs_options) - 1] = '\0';    }    return f;}

/system/core/fs_mgr/fs_mgr_fstab.c

struct fstab *fs_mgr_read_fstab(const char *fstab_path){    FILE *fstab_file;    int cnt, entries;    ssize_t len;    size_t alloc_len = 0;    char *line = NULL;    const char *delim = " \t";    char *save_ptr, *p;    struct fstab *fstab = NULL;    struct fs_mgr_flag_values flag_vals;#define FS_OPTIONS_LEN 1024    char tmp_fs_options[FS_OPTIONS_LEN];    fstab_file = fopen(fstab_path, "r");    if (!fstab_file) {        ERROR("Cannot open file %s\n", fstab_path);        return 0;    }    entries = 0;    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {        /* if the last character is a newline, shorten the string by 1 byte */        if (line[len - 1] == '\n') {            line[len - 1] = '\0';        }        /* Skip any leading whitespace */        p = line;        while (isspace(*p)) {            p++;        }        /* ignore comments or empty lines */        if (*p == '#' || *p == '\0')            continue;        entries++;    }    if (!entries) {        ERROR("No entries found in fstab\n");        goto err;    }    /* Allocate and init the fstab structure */    fstab = calloc(1, sizeof(struct fstab));    fstab->num_entries = entries;    fstab->fstab_filename = strdup(fstab_path);    fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));    fseek(fstab_file, 0, SEEK_SET);    cnt = 0;    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {        /* if the last character is a newline, shorten the string by 1 byte */        if (line[len - 1] == '\n') {            line[len - 1] = '\0';        }        /* Skip any leading whitespace */        p = line;        while (isspace(*p)) {            p++;        }        /* ignore comments or empty lines */        if (*p == '#' || *p == '\0')            continue;        /* If a non-comment entry is greater than the size we allocated, give an         * error and quit.  This can happen in the unlikely case the file changes         * between the two reads.         */        if (cnt >= entries) {            ERROR("Tried to process more entries than counted\n");            break;        }        if (!(p = strtok_r(line, delim, &save_ptr))) {            ERROR("Error parsing mount source\n");            goto err;        }        fstab->recs[cnt].blk_device = strdup(p);        if (!(p = strtok_r(NULL, delim, &save_ptr))) {            ERROR("Error parsing mount_point\n");            goto err;        }        fstab->recs[cnt].mount_point = strdup(p);        if (!(p = strtok_r(NULL, delim, &save_ptr))) {            ERROR("Error parsing fs_type\n");            goto err;        }        fstab->recs[cnt].fs_type = strdup(p);        if (!(p = strtok_r(NULL, delim, &save_ptr))) {            ERROR("Error parsing mount_flags\n");            goto err;        }        tmp_fs_options[0] = '\0';        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,                                       tmp_fs_options, FS_OPTIONS_LEN);        /* fs_options are optional */        if (tmp_fs_options[0]) {            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);        } else {            fstab->recs[cnt].fs_options = NULL;        }        if (!(p = strtok_r(NULL, delim, &save_ptr))) {            ERROR("Error parsing fs_mgr_options\n");            goto err;        }        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,                                                    &flag_vals, NULL, 0);        fstab->recs[cnt].key_loc = flag_vals.key_loc;        fstab->recs[cnt].verity_loc = flag_vals.verity_loc;        fstab->recs[cnt].length = flag_vals.part_length;        fstab->recs[cnt].label = flag_vals.label;        fstab->recs[cnt].partnum = flag_vals.partnum;        fstab->recs[cnt].swap_prio = flag_vals.swap_prio;        fstab->recs[cnt].zram_size = flag_vals.zram_size;        cnt++;    }    fclose(fstab_file);    free(line);    return fstab;err:    fclose(fstab_file);    free(line);    if (fstab)        fs_mgr_free_fstab(fstab);    return NULL;}

  回到process_config函数,现在已经得到一个表示挂载情况的struct fstab,接着处理由vold控制的挂载点(带有”voldmanaged=”标志)。根据挂载设备路径,label值(即”voldmanaged”后面’=’和’:’之间的字符串),flag值(由code逻辑得到)构建一个DiskSource对象,并push其指针到VolumeManager的mDiskSources中。vold会从这些DiskSource对象接收kernel传来的uevent事件。

原创粉丝点击