On Thu, Dec 28, 2017 at 1:40 PM, zhangyi (F) <yi.zhang@xxxxxxxxxx> wrote: > Encapsulate separate underlying directories options to use -o option as > for mount, see mount(8). > > Old Usage: > fsck.overlay [-l lowerdir] [-u upperdir] [-w workdir] > > New Usage: > fsck.overlay [-o lowerdir=<lowers>,upperdir=<upper>,workdir=<work>] > > Example: > fsck.overlay -o lowerdir=lower,upperdir=upper,workdir=work > or > fsck.overlay -o lowerdir=lower -o upperdir=upper -o workdir=work > > Signed-off-by: zhangyi (F) <yi.zhang@xxxxxxxxxx> Looks ok. Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > README.md | 11 ++-- > check.c | 4 +- > fsck.c | 78 +++++++++++++-------------- > mount.c | 182 +++++++++++++++++++++++++++++++++++--------------------------- > mount.h | 12 ++++- > 5 files changed, 157 insertions(+), 130 deletions(-) > > diff --git a/README.md b/README.md > index 458a815..a8d0b1c 100644 > --- a/README.md > +++ b/README.md > @@ -44,13 +44,11 @@ Usage > > 2. Run fsck.overlay program: > Usage: > - fsck.overlay [-l lowerdir] [-u upperdir] [-w workdir] [-pnyvhV] > + fsck.overlay [-o lowerdir=<lowers>,upperdir=<upper>,workdir=<work>] [-pnyvhV] > > Options: > - -l, --lowerdir=LOWERDIR specify lower directories of overlayfs, > - multiple lower use ':' as separator. > - -u, --upperdir=UPPERDIR specify upper directory of overlayfs > - -w, --workdir=WORKDIR specify work directory of overlayfs > + -o, specify underlying directories of overlayfs: > + multiple lower directories use ':' as separator > -p, automatic repair (no questions) > -n, make no changes to the filesystem > -y, assume "yes" to all questions > @@ -58,6 +56,9 @@ Usage > -h, --help display this usage of overlayfs > -V, --version display version information > > + Example: > + fsck.overlay -o lowerdir=lower,upperdir=upper,workdir=work > + > 3. Exit value: > 0 No errors > 1 Filesystem errors corrected > diff --git a/check.c b/check.c > index efa180f..0b5d49b 100644 > --- a/check.c > +++ b/check.c > @@ -58,8 +58,8 @@ struct ovl_redirect_entry { > #define WHITEOUT_MOD 0 > > extern char **lowerdir; > -extern char upperdir[]; > -extern char workdir[]; > +extern char *upperdir; > +extern char *workdir; > extern int lower_num; > extern int flags; > extern int status; > diff --git a/fsck.c b/fsck.c > index 44211f7..5d34378 100644 > --- a/fsck.c > +++ b/fsck.c > @@ -38,15 +38,16 @@ > > char *program_name; > > +char *lowerdirs = NULL; > char **lowerdir = NULL; > -char upperdir[PATH_MAX] = {0}; > -char workdir[PATH_MAX] = {0}; > +char *upperdir = NULL; > +char *workdir = NULL; > int lower_num = 0; > int flags = 0; /* user input option flags */ > int status = 0; /* fsck scan status */ > > -/* Cleanup lower directories buf */ > -static void ovl_clean_lowerdirs(void) > +/* Cleanup underlying directories buffer */ > +static void ovl_clean_dirs(void) > { > int i; > > @@ -57,17 +58,19 @@ static void ovl_clean_lowerdirs(void) > free(lowerdir); > lowerdir = NULL; > lower_num = 0; > + free(upperdir); > + upperdir = NULL; > + free(workdir); > + workdir = NULL; > } > > static void usage(void) > { > - print_info(_("Usage:\n\t%s [-l lowerdir] [-u upperdir] [-w workdir] " > + print_info(_("Usage:\n\t%s [-o lowerdir=<lowers>,upperdir=<upper>,workdir=<work>] " > "[-pnyvhV]\n\n"), program_name); > print_info(_("Options:\n" > - "-l, --lowerdir=LOWERDIR specify lower directories of overlayfs,\n" > - " multiple lower use ':' as separator\n" > - "-u, --upperdir=UPPERDIR specify upper directory of overlayfs\n" > - "-w, --workdir=WORKDIR specify work directory of overlayfs\n" > + "-o, specify underlying directories of overlayfs:\n" > + " multiple lower directories use ':' as separator\n" > "-p, automatic repair (no questions)\n" > "-n, make no changes to the filesystem\n" > "-y, assume \"yes\" to all questions\n" > @@ -79,46 +82,25 @@ static void usage(void) > > static void parse_options(int argc, char *argv[]) > { > - char *lowertemp; > + struct ovl_config config = {0}; > + char *ovl_opts = NULL; > int c; > int ret = 0; > - bool show_usage = false; > bool opt_conflict = false; > > struct option long_options[] = { > - {"lowerdir", required_argument, NULL, 'l'}, > - {"upperdir", required_argument, NULL, 'u'}, > - {"workdir", required_argument, NULL, 'w'}, > {"verbose", no_argument, NULL, 'v'}, > {"version", no_argument, NULL, 'V'}, > {"help", no_argument, NULL, 'h'}, > {NULL, 0, NULL, 0} > }; > > - while ((c = getopt_long(argc, argv, "l:u:w:apnyvVh", long_options, NULL)) != -1) { > + while ((c = getopt_long(argc, argv, "o:apnyvVh", long_options, NULL)) != -1) { > switch (c) { > - case 'l': > - lowertemp = strdup(optarg); > - ret = ovl_resolve_lowerdirs(lowertemp, &lowerdir, &lower_num); > - free(lowertemp); > - break; > - case 'u': > - if (realpath(optarg, upperdir)) { > - print_debug(_("Upperdir:%s\n"), upperdir); > - flags |= FL_UPPER; > - } else { > - print_err(_("Failed to resolve upperdir:%s\n"), optarg); > - ret = -1; > - } > - break; > - case 'w': > - if (realpath(optarg, workdir)) { > - print_debug(_("Workdir:%s\n"), workdir); > - flags |= FL_WORK; > - } else { > - print_err(_("Failed to resolve workdir:%s\n"), optarg); > - ret = -1; > - } > + case 'o': > + ovl_opts = sstrdup(optarg); > + ovl_parse_opt(ovl_opts, &config); > + free(ovl_opts); > break; > case 'a': > case 'p': > @@ -155,23 +137,35 @@ static void parse_options(int argc, char *argv[]) > goto err_out; > } > > + /* Resolve and get each underlying directory of overlay filesystem */ > + ovl_get_dirs(&config, &lowerdir, &lower_num, &upperdir, &workdir); > + if (upperdir) > + flags |= FL_UPPER; > + if (workdir) > + flags |= FL_WORK; > + > if (!lower_num || (!(flags & FL_UPPER) && lower_num == 1)) { > print_info(_("Please specify correct lowerdirs and upperdir!\n\n")); > - show_usage = true; > + goto err_out; > + } > + > + if ((flags & FL_UPPER) && !(flags & FL_WORK)) { > + print_info(_("Please specify correct workdir!\n\n")); > goto err_out; > } > > if (opt_conflict) { > print_info(_("Only one of the options -p/-a, -n or -y can be specified!\n\n")); > - show_usage = true; > goto err_out; > } > > + ovl_free_opt(&config); > return; > > err_out: > - if (show_usage) > - usage(); > + ovl_free_opt(&config); > + ovl_clean_dirs(); > + usage(); > exit(1); > } > > @@ -212,7 +206,7 @@ int main(int argc, char *argv[]) > > out: > fsck_status_check(&exit_value); > - ovl_clean_lowerdirs(); > + ovl_clean_dirs(); > > if (err) > exit_value |= FSCK_ERROR; > diff --git a/mount.c b/mount.c > index fba51e9..908cee0 100644 > --- a/mount.c > +++ b/mount.c > @@ -38,19 +38,18 @@ > #include "mount.h" > > struct ovl_mnt_entry { > - char *lowers; > char **lowerdir; > int lowernum; > - char upperdir[PATH_MAX]; > - char workdir[PATH_MAX]; > + char *upperdir; > + char *workdir; > }; > > /* Mount buf allocate a time */ > #define ALLOC_NUM 16 > > extern char **lowerdir; > -extern char upperdir[]; > -extern char workdir[]; > +extern char *upperdir; > +extern char *workdir; > extern int lower_num; > > /* > @@ -78,9 +77,10 @@ static unsigned int ovl_split_lowerdirs(char *lower) > } > > /* Resolve each lower directories and check the validity */ > -int ovl_resolve_lowerdirs(char *loweropt, char ***lowerdir, > - int *lowernum) > +static int ovl_resolve_lowerdirs(char *loweropt, char ***lowerdir, > + int *lowernum) > { > + char temp[PATH_MAX] = {0}; > int num; > char **dirs; > char *p; > @@ -97,12 +97,12 @@ int ovl_resolve_lowerdirs(char *loweropt, char ***lowerdir, > > p = loweropt; > for (i = 0; i < num; i++) { > - dirs[i] = smalloc(PATH_MAX); > - if (!realpath(p, dirs[i])) { > + if (!realpath(p, temp)) { > print_err(_("Failed to resolve lowerdir:%s:%s\n"), > p, strerror(errno)); > goto err; > } > + dirs[i] = sstrdup(temp); > print_debug(_("Lowerdir %u:%s\n"), i, dirs[i]); > p = strchr(p, '\0') + 1; > } > @@ -115,6 +115,7 @@ err: > for (i--; i >= 0; i--) > free(dirs[i]); > free(dirs); > + *lowerdir = NULL; > *lowernum = 0; > return -1; > } > @@ -146,79 +147,99 @@ static char *ovl_next_opt(char **s) > return sbegin; > } > > +static inline char *ovl_match_dump(const char *opt, const char *type) > +{ > + int len = strlen(opt) - strlen(type) + 1; > + > + return sstrndup(opt+strlen(type), len); > +} > + > /* > - * Split and parse opt to each directories. > - * > - * Note: FIXME: We cannot distinguish mounted directories if overlayfs was > - * mounted use relative path, so there may have misjudgment. > + * Resolve and get each underlying directory of overlay filesystem > + */ > +int ovl_get_dirs(struct ovl_config *config, char ***lowerdir, > + int *lowernum, char **upperdir, char **workdir) > +{ > + char temp[PATH_MAX] = {0}; > + > + /* Resolve upperdir */ > + if (!realpath(config->upperdir, temp)) { > + print_err(_("Faile to resolve upperdir:%s:%s\n"), > + config->upperdir, strerror(errno)); > + goto err_out; > + } > + *upperdir = sstrdup(temp); > + print_debug(_("Upperdir: %s\n"), *upperdir); > + > + /* Resolve workdir */ > + if (!realpath(config->workdir, temp)) { > + print_err(_("Faile to resolve workdir:%s:%s\n"), > + config->workdir, strerror(errno)); > + goto err_work; > + } > + *workdir = sstrdup(temp); > + print_debug(_("Workdir: %s\n"), *workdir); > + > + /* Resolve lowerdir */ > + if (ovl_resolve_lowerdirs(config->lowerdir, lowerdir, lowernum)) > + goto err_lower; > + > + return 0; > + > +err_lower: > + free(*workdir); > + *workdir = NULL; > +err_work: > + free(*upperdir); > + *upperdir = NULL; > +err_out: > + return -1; > +} > + > +void ovl_free_opt(struct ovl_config *config) > +{ > + free(config->upperdir); > + config->upperdir = NULL; > + free(config->lowerdir); > + config->lowerdir = NULL; > + free(config->workdir); > + config->workdir = NULL; > +} > + > +/* > + * Split and parse opt to each underlying directories. > */ > -static int ovl_parse_opt(char *opt, struct ovl_mnt_entry *entry) > +void ovl_parse_opt(char *opt, struct ovl_config *config) > { > - char tmp[PATH_MAX] = {0}; > char *p; > - int len; > - int ret; > - int i; > > while ((p = ovl_next_opt(&opt)) != NULL) { > if (!*p) > continue; > > if (!strncmp(p, OPT_UPPERDIR, strlen(OPT_UPPERDIR))) { > - len = strlen(p) - strlen(OPT_UPPERDIR) + 1; > - strncpy(tmp, p+strlen(OPT_UPPERDIR), len); > - > - if (!realpath(tmp, entry->upperdir)) { > - print_err(_("Faile to resolve path:%s:%s\n"), > - tmp, strerror(errno)); > - ret = -1; > - goto errout; > - } > + free(config->upperdir); > + config->upperdir = ovl_match_dump(p, OPT_UPPERDIR); > } else if (!strncmp(p, OPT_LOWERDIR, strlen(OPT_LOWERDIR))) { > - len = strlen(p) - strlen(OPT_LOWERDIR) + 1; > - entry->lowers = smalloc(len); > - strncpy(entry->lowers, p+strlen(OPT_LOWERDIR), len); > - > - if ((ret = ovl_resolve_lowerdirs(entry->lowers, > - &entry->lowerdir, &entry->lowernum))) > - goto errout; > - > + free(config->lowerdir); > + config->lowerdir = ovl_match_dump(p, OPT_LOWERDIR); > } else if (!strncmp(p, OPT_WORKDIR, strlen(OPT_WORKDIR))) { > - len = strlen(p) - strlen(OPT_WORKDIR) + 1; > - strncpy(tmp, p+strlen(OPT_WORKDIR), len); > - > - if (!realpath(tmp, entry->workdir)) { > - print_err(_("Faile to resolve path:%s:%s\n"), > - tmp, strerror(errno)); > - ret = -1; > - goto errout; > - } > + free(config->workdir); > + config->workdir = ovl_match_dump(p, OPT_WORKDIR); > } > } > - > -errout: > - if (entry->lowernum) { > - for (i = 0; i < entry->lowernum; i++) > - free(entry->lowerdir[i]); > - free(entry->lowerdir); > - entry->lowerdir = NULL; > - entry->lowernum = 0; > - } > - free(entry->lowers); > - entry->lowers = NULL; > - > - return ret; > } > > /* Scan current mounted overlayfs and get used underlying directories */ > static int ovl_scan_mount_init(struct ovl_mnt_entry **ovl_mnt_entries, > int *ovl_mnt_count) > { > - struct ovl_mnt_entry *mnt_entries; > - struct mntent *mnt; > + struct ovl_mnt_entry *entries = NULL; > + struct mntent *mnt = NULL; > + struct ovl_config config = {0}; > FILE *fp; > char *opt; > - int allocated, num = 0; > + int allocated, i = 0; > > fp = setmntent(MOUNT_TAB, "r"); > if (!fp) { > @@ -227,32 +248,32 @@ static int ovl_scan_mount_init(struct ovl_mnt_entry **ovl_mnt_entries, > return -1; > } > > - allocated = ALLOC_NUM; > - mnt_entries = smalloc(sizeof(struct ovl_mnt_entry) * allocated); > + allocated = sizeof(struct ovl_mnt_entry) * ALLOC_NUM; > + entries = smalloc(allocated); > > while ((mnt = getmntent(fp))) { > - if (!strcmp(mnt->mnt_type, OVERLAY_NAME) || > - !strcmp(mnt->mnt_type, OVERLAY_NAME_OLD)) { > + if (strcmp(mnt->mnt_type, OVERLAY_NAME)) > + continue; > > - opt = sstrdup(mnt->mnt_opts); > - if (ovl_parse_opt(opt, &mnt_entries[num])) { > - free(opt); > - continue; > - } > + opt = sstrdup(mnt->mnt_opts); > + ovl_parse_opt(opt, &config); > > - num++; > - if (num % ALLOC_NUM == 0) { > - allocated += ALLOC_NUM; > - mnt_entries = srealloc(mnt_entries, > - sizeof(struct ovl_mnt_entry) * allocated); > + if (!ovl_get_dirs(&config, > + &entries[i].lowerdir, &entries[i].lowernum, > + &entries[i].upperdir, &entries[i].workdir)) { > + i++; > + if (i % ALLOC_NUM == 0) { > + allocated += sizeof(struct ovl_mnt_entry) * ALLOC_NUM; > + entries = srealloc(entries, allocated); > } > - > - free(opt); > } > + > + ovl_free_opt(&config); > + free(opt); > } > > - *ovl_mnt_entries = mnt_entries; > - *ovl_mnt_count = num; > + *ovl_mnt_entries = entries; > + *ovl_mnt_count = i; > > endmntent(fp); > return 0; > @@ -267,7 +288,8 @@ static void ovl_scan_mount_exit(struct ovl_mnt_entry *ovl_mnt_entries, > for (j = 0; j < ovl_mnt_entries[i].lowernum; j++) > free(ovl_mnt_entries[i].lowerdir[j]); > free(ovl_mnt_entries[i].lowerdir); > - free(ovl_mnt_entries[i].lowers); > + free(ovl_mnt_entries[i].upperdir); > + free(ovl_mnt_entries[i].workdir); > } > free(ovl_mnt_entries); > } > @@ -279,6 +301,8 @@ static void ovl_scan_mount_exit(struct ovl_mnt_entry *ovl_mnt_entries, > * > * Note: fsck may modify lower layers, so even match only one directory > * is triggered as mounted. > + * FIXME: We cannot distinguish mounted directories if overlayfs was > + * mounted use relative path, so there may have misjudgment. > */ > int ovl_check_mount(bool *mounted) > { > diff --git a/mount.h b/mount.h > index 7eed0d0..2cf5e6a 100644 > --- a/mount.h > +++ b/mount.h > @@ -19,8 +19,16 @@ > #ifndef OVL_MOUNT_H > #define OVL_MOUNT_H > > -int ovl_resolve_lowerdirs(char *loweropt, char ***lowerdir, > - int *lowernum); > +struct ovl_config { > + char *lowerdir; > + char *upperdir; > + char *workdir; > +}; > + > +void ovl_parse_opt(char *opt, struct ovl_config *config); > +void ovl_free_opt(struct ovl_config *config); > +int ovl_get_dirs(struct ovl_config *config, char ***lowerdir, > + int *lowernum, char **upperdir, char **workdir); > int ovl_check_mount(bool *mounted); > > #endif /* OVL_MOUNT_H */ > -- > 2.9.5 > -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html