From owner-svn-src-all@freebsd.org Wed Apr 25 01:20:26 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 90FF7FB9A08; Wed, 25 Apr 2018 01:20:26 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 458CD744DF; Wed, 25 Apr 2018 01:20:26 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 3B97F22634; Wed, 25 Apr 2018 01:20:26 +0000 (UTC) (envelope-from benno@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w3P1KQPW074611; Wed, 25 Apr 2018 01:20:26 GMT (envelope-from benno@FreeBSD.org) Received: (from benno@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w3P1KPrR074606; Wed, 25 Apr 2018 01:20:25 GMT (envelope-from benno@FreeBSD.org) Message-Id: <201804250120.w3P1KPrR074606@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: benno set sender to benno@FreeBSD.org using -f From: Benno Rice Date: Wed, 25 Apr 2018 01:20:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r332978 - stable/11/usr.sbin/makefs X-SVN-Group: stable-11 X-SVN-Commit-Author: benno X-SVN-Commit-Paths: stable/11/usr.sbin/makefs X-SVN-Commit-Revision: 332978 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 25 Apr 2018 01:20:26 -0000 Author: benno Date: Wed Apr 25 01:20:25 2018 New Revision: 332978 URL: https://svnweb.freebsd.org/changeset/base/332978 Log: MFC r315304 makefs: sync option parsing with NetBSD - add support for parsing different types; not just int - homogenize option parsing - fix single letter parsing - remove duplicated code NetBSD revisions: cd9660.c 1.36 1.37 1.38 1.41 1.42 1.43 ffs.c 1.50 1.51 1.52 1.53 1.56 1.57 makefs.c 1.36 1.37 1.38 1.39 1.40 1.42 1.43 1.44 1.46 makefs.h 1.28 1.29 1.31 1.32 Sponsored by: iXsystems, Inc. Modified: stable/11/usr.sbin/makefs/cd9660.c stable/11/usr.sbin/makefs/cd9660.h stable/11/usr.sbin/makefs/ffs.c stable/11/usr.sbin/makefs/makefs.c stable/11/usr.sbin/makefs/makefs.h Directory Properties: stable/11/ (props changed) Modified: stable/11/usr.sbin/makefs/cd9660.c ============================================================================== --- stable/11/usr.sbin/makefs/cd9660.c Wed Apr 25 01:12:40 2018 (r332977) +++ stable/11/usr.sbin/makefs/cd9660.c Wed Apr 25 01:20:25 2018 (r332978) @@ -257,7 +257,70 @@ cd9660_prep_opts(fsinfo_t *fsopts) if ((diskStructure = calloc(1, sizeof(*diskStructure))) == NULL) err(EXIT_FAILURE, "%s: calloc", __func__); +#define OPT_STR(letter, name, desc) \ + { letter, name, NULL, OPT_STRBUF, 0, 0, desc } + +#define OPT_NUM(letter, name, field, min, max, desc) \ + { letter, name, &diskStructure->field, \ + sizeof(diskStructure->field) == 8 ? OPT_INT64 : \ + (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \ + (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \ + min, max, desc } + +#define OPT_BOOL(letter, name, field, desc) \ + OPT_NUM(letter, name, field, 0, 1, desc) + + const option_t cd9660_options[] = { + OPT_NUM('l', "isolevel", isoLevel, + 1, 2, "ISO Level"), + OPT_NUM('v', "verbose", verbose_level, + 0, 2, "Turns on verbose output"), + + OPT_BOOL('h', "help", displayHelp, + "Show help message"), + OPT_BOOL('S', "follow-symlinks", follow_sym_links, + "Resolve symlinks in pathnames"), + OPT_BOOL('R', "rockridge", rock_ridge_enabled, + "Enable Rock-Ridge extensions"), + OPT_BOOL('C', "chrp-boot", chrp_boot, + "Enable CHRP boot"), + OPT_BOOL('K', "keep-bad-images", keep_bad_images, + "Keep bad images"), + OPT_BOOL('D', "allow-deep-trees", allow_deep_trees, + "Allow trees more than 8 levels"), + OPT_BOOL('a', "allow-max-name", allow_max_name, + "Allow 37 char filenames (unimplemented)"), + OPT_BOOL('i', "allow-illegal-chars", allow_illegal_chars, + "Allow illegal characters in filenames"), + OPT_BOOL('d', "allow-multidot", allow_multidot, + "Allow multiple periods in filenames"), + OPT_BOOL('o', "omit-trailing-period", omit_trailing_period, + "Omit trailing periods in filenames"), + OPT_BOOL('\0', "allow-lowercase", allow_lowercase, + "Allow lowercase characters in filenames"), + OPT_BOOL('\0', "archimedes", archimedes_enabled, + "Enable Archimedes structure"), + OPT_BOOL('\0', "no-trailing-padding", include_padding_areas, + "Include padding areas"), + + OPT_STR('A', "applicationid", "Application Identifier"), + OPT_STR('P', "publisher", "Publisher Identifier"), + OPT_STR('p', "preparer", "Preparer Identifier"), + OPT_STR('L', "label", "Disk Label"), + OPT_STR('V', "volumeid", "Volume Set Identifier"), + OPT_STR('B', "bootimage", "Boot image parameter"), + OPT_STR('G', "generic-bootimage", "Generic boot image param"), + OPT_STR('\0', "bootimagedir", "Boot image directory"), + OPT_STR('\0', "no-emul-boot", "No boot emulation"), + OPT_STR('\0', "no-boot", "No boot support"), + OPT_STR('\0', "hard-disk-boot", "Boot from hard disk"), + OPT_STR('\0', "boot-load-segment", "Boot load segment"), + + { .name = NULL } + }; + fsopts->fs_specific = diskStructure; + fsopts->fs_options = copy_opts(cd9660_options); cd9660_set_defaults(diskStructure); } @@ -266,6 +329,7 @@ void cd9660_cleanup_opts(fsinfo_t *fsopts) { free(fsopts->fs_specific); + free(fsopts->fs_options); } static int @@ -302,144 +366,106 @@ cd9660_arguments_set_string(const char *val, const cha int cd9660_parse_opts(const char *option, fsinfo_t *fsopts) { - char *var, *val; - int rv; + int rv, i; iso9660_disk *diskStructure = fsopts->fs_specific; + option_t *cd9660_options = fsopts->fs_options; + char buf[1024]; + const char *name, *desc; - /* Set up allowed options - integer options ONLY */ - option_t cd9660_options[] = { - { "l", &diskStructure->isoLevel, 1, 2, "ISO Level" }, - { "isolevel", &diskStructure->isoLevel, 1, 2, "ISO Level" }, - { "verbose", &diskStructure->verbose_level, 0, 2, - "Turns on verbose output" }, - { "v", &diskStructure->verbose_level, 0 , 2, - "Turns on verbose output"}, - { .name = NULL } - }; - - /* - * Todo : finish implementing this, and make a function that - * parses them - */ - /* - string_option_t cd9660_string_options[] = { - { "L", "Label", &diskStructure.primaryDescriptor.volume_id, 1, 32, "Disk Label", ISO_STRING_FILTER_DCHARS }, - { NULL } - } - */ - assert(option != NULL); if (debug & DEBUG_FS_PARSE_OPTS) printf("cd9660_parse_opts: got `%s'\n", option); - if ((var = strdup(option)) == NULL) - err(1, "allocating memory for copy of option string"); - rv = 1; + i = set_option(cd9660_options, option, buf, sizeof(buf)); + if (i == -1) + return 0; - val = strchr(var, '='); - if (val != NULL) - *val++ = '\0'; + if (cd9660_options[i].name == NULL) + abort(); - /* First handle options with no parameters */ - if (strcmp(var, "h") == 0) { - diskStructure->displayHelp = 1; - rv = 1; - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "S", "follow-symlinks")) { - /* this is not handled yet */ - diskStructure->follow_sym_links = 1; - rv = 1; - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "L", "label")) { - rv = cd9660_arguments_set_string(val, "Disk Label", 32, 'd', - diskStructure->primaryDescriptor.volume_id); - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "applicationid")) { - rv = cd9660_arguments_set_string(val, "Application Identifier", 128, 'a', - diskStructure->primaryDescriptor.application_id); - } else if(CD9660_IS_COMMAND_ARG_DUAL(var, "P", "publisher")) { - rv = cd9660_arguments_set_string(val, "Publisher Identifier", - 128, 'a', diskStructure->primaryDescriptor.publisher_id); - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "p", "preparer")) { - rv = cd9660_arguments_set_string(val, "Preparer Identifier", - 128, 'a', diskStructure->primaryDescriptor.preparer_id); - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "V", "volumeid")) { - rv = cd9660_arguments_set_string(val, "Volume Set Identifier", - 128, 'a', diskStructure->primaryDescriptor.volume_set_id); + name = cd9660_options[i].name; + desc = cd9660_options[i].desc; + switch (cd9660_options[i].letter) { + case 'h': + case 'S': + rv = 0; /* this is not handled yet */ + break; + case 'L': + rv = cd9660_arguments_set_string(buf, desc, 32, 'd', + diskStructure->primaryDescriptor.volume_id); + break; + case 'A': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.application_id); + break; + case 'P': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.publisher_id); + break; + case 'p': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.preparer_id); + break; + case 'V': + rv = cd9660_arguments_set_string(buf, desc, 128, 'a', + diskStructure->primaryDescriptor.volume_set_id); + break; /* Boot options */ - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "B", "bootimage")) { - if (val == NULL) - warnx("error: The Boot Image parameter requires a valid boot information string"); - else - rv = cd9660_add_boot_disk(diskStructure, val); - } else if (CD9660_IS_COMMAND_ARG(var, "bootimagedir")) { - /* - * XXXfvdl this is unused. - */ - if (val == NULL) - errx(1, "error: The Boot Image Directory parameter" - " requires a directory name\n"); - else { - if ((diskStructure->boot_image_directory = - malloc(strlen(val) + 1)) == NULL) { - CD9660_MEM_ALLOC_ERROR("cd9660_parse_opts"); - exit(1); - } - - /* BIG TODO: Add the max length function here */ - cd9660_arguments_set_string(val, "Boot Image Directory", - 12 , 'd', diskStructure->boot_image_directory); - } - } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "G", "generic-bootimage")) { - if (val == NULL) - warnx("error: The Boot Image parameter requires a valid boot information string"); - else - rv = cd9660_add_generic_bootimage(diskStructure, val); - } else if (CD9660_IS_COMMAND_ARG(var, "no-trailing-padding")) - diskStructure->include_padding_areas = 0; - /* RRIP */ - else if (CD9660_IS_COMMAND_ARG_DUAL(var, "R", "rockridge")) - diskStructure->rock_ridge_enabled = 1; - else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "archimedes")) - diskStructure->archimedes_enabled = 1; - else if (CD9660_IS_COMMAND_ARG(var, "chrp-boot")) - diskStructure->chrp_boot = 1; - else if (CD9660_IS_COMMAND_ARG_DUAL(var, "K", "keep-bad-images")) - diskStructure->keep_bad_images = 1; - else if (CD9660_IS_COMMAND_ARG(var, "allow-deep-trees")) - diskStructure->allow_deep_trees = 1; - else if (CD9660_IS_COMMAND_ARG(var, "allow-max-name")) - diskStructure->allow_max_name = 1; - else if (CD9660_IS_COMMAND_ARG(var, "allow-illegal-chars")) - diskStructure->allow_illegal_chars = 1; - else if (CD9660_IS_COMMAND_ARG(var, "allow-lowercase")) - diskStructure->allow_lowercase = 1; - else if (CD9660_IS_COMMAND_ARG(var,"allow-multidot")) - diskStructure->allow_multidot = 1; - else if (CD9660_IS_COMMAND_ARG(var, "omit-trailing-period")) - diskStructure->omit_trailing_period = 1; - else if (CD9660_IS_COMMAND_ARG(var, "no-emul-boot") || - CD9660_IS_COMMAND_ARG(var, "no-boot") || - CD9660_IS_COMMAND_ARG(var, "hard-disk-boot")) { - cd9660_eltorito_add_boot_option(diskStructure, var, 0); - - /* End of flag variables */ - } else if (CD9660_IS_COMMAND_ARG(var, "boot-load-segment")) { - if (val == NULL) { - warnx("Option `%s' doesn't contain a value", var); + case 'B': + if (buf[0] == '\0') { + warnx("The Boot Image parameter requires a valid boot" + "information string"); rv = 0; - } else { - cd9660_eltorito_add_boot_option(diskStructure, var, - val); - } - } else { - if (val == NULL) { - warnx("Option `%s' doesn't contain a value", var); + } else + rv = cd9660_add_boot_disk(diskStructure, buf); + break; + case 'G': + if (buf[0] == '\0') { + warnx("The Generic Boot Image parameter requires a" + " valid boot information string"); rv = 0; } else - rv = set_option(cd9660_options, var, val); + rv = cd9660_add_generic_bootimage(diskStructure, buf); + break; + default: + if (strcmp(name, "bootimagedir") == 0) { + /* + * XXXfvdl this is unused. + */ + if (buf[0] == '\0') { + warnx("The Boot Image Directory parameter" + " requires a directory name\n"); + rv = 0; + } else { + diskStructure->boot_image_directory = + malloc(strlen(buf) + 1); + if (diskStructure->boot_image_directory == NULL) + err(1, "malloc"); + /* BIG TODO: Add the max length function here */ + rv = cd9660_arguments_set_string(buf, desc, 12, + 'd', diskStructure->boot_image_directory); + } + } else if (strcmp(name, "no-emul-boot") == 0 || + strcmp(name, "no-boot") == 0 || + strcmp(name, "hard-disk-boot") == 0) { + /* RRIP */ + cd9660_eltorito_add_boot_option(diskStructure, name, 0); + rv = 1; + } else if (strcmp(name, "boot-load-segment") == 0) { + if (buf[0] == '\0') { + warnx("Option `%s' doesn't contain a value", + name); + rv = 0; + } else { + cd9660_eltorito_add_boot_option(diskStructure, + name, buf); + rv = 1; + } + } else + rv = 1; } - - free(var); - return (rv); + return rv; } /* Modified: stable/11/usr.sbin/makefs/cd9660.h ============================================================================== --- stable/11/usr.sbin/makefs/cd9660.h Wed Apr 25 01:12:40 2018 (r332977) +++ stable/11/usr.sbin/makefs/cd9660.h Wed Apr 25 01:20:25 2018 (r332978) @@ -122,12 +122,6 @@ typedef struct { #define CD9660_MEM_ALLOC_ERROR(_F) \ err(EXIT_FAILURE, "%s, %s l. %d", _F, __FILE__, __LINE__) -#define CD9660_IS_COMMAND_ARG_DUAL(var,short,long)\ - (strcmp((var),(short)) == 0) || (strcmp((var),(long))==0) - -#define CD9660_IS_COMMAND_ARG(var,arg)\ - (strcmp((var),(arg)) == 0) - #define CD9660_TYPE_FILE 0x01 #define CD9660_TYPE_DIR 0x02 #define CD9660_TYPE_DOT 0x04 Modified: stable/11/usr.sbin/makefs/ffs.c ============================================================================== --- stable/11/usr.sbin/makefs/ffs.c Wed Apr 25 01:12:40 2018 (r332977) +++ stable/11/usr.sbin/makefs/ffs.c Wed Apr 25 01:20:25 2018 (r332978) @@ -144,7 +144,6 @@ static void *ffs_build_dinode2(struct ufs2_dinode *, int sectorsize; /* XXX: for buf.c::getblk() */ - /* publicly visible functions */ void @@ -155,7 +154,33 @@ ffs_prep_opts(fsinfo_t *fsopts) if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL) err(1, "Allocating memory for ffs_options"); - fsopts->fs_specific = ffs_opts; + const option_t ffs_options[] = { + { 'b', "bsize", &ffs_opts->bsize, OPT_INT32, + 1, INT_MAX, "block size" }, + { 'f', "fsize", &ffs_opts->fsize, OPT_INT32, + 1, INT_MAX, "fragment size" }, + { 'd', "density", &ffs_opts->density, OPT_INT32, + 1, INT_MAX, "bytes per inode" }, + { 'm', "minfree", &ffs_opts->minfree, OPT_INT32, + 0, 99, "minfree" }, + { 'M', "maxbpg", &ffs_opts->maxbpg, OPT_INT32, + 1, INT_MAX, "max blocks per file in a cg" }, + { 'a', "avgfilesize", &ffs_opts->avgfilesize, OPT_INT32, + 1, INT_MAX, "expected average file size" }, + { 'n', "avgfpdir", &ffs_opts->avgfpdir, OPT_INT32, + 1, INT_MAX, "expected # of files per directory" }, + { 'x', "extent", &ffs_opts->maxbsize, OPT_INT32, + 1, INT_MAX, "maximum # extent size" }, + { 'g', "maxbpcg", &ffs_opts->maxblkspercg, OPT_INT32, + 1, INT_MAX, "max # of blocks per group" }, + { 'v', "version", &ffs_opts->version, OPT_INT32, + 1, 2, "UFS version" }, + { 'o', "optimization", NULL, OPT_STRBUF, + 0, 0, "Optimization (time|space)" }, + { 'l', "label", ffs_opts->label, OPT_STRARRAY, + 1, sizeof(ffs_opts->label), "UFS label" }, + { .name = NULL } + }; ffs_opts->bsize= -1; ffs_opts->fsize= -1; @@ -168,45 +193,25 @@ ffs_prep_opts(fsinfo_t *fsopts) ffs_opts->avgfilesize= -1; ffs_opts->avgfpdir= -1; ffs_opts->version = 1; + + fsopts->fs_specific = ffs_opts; + fsopts->fs_options = copy_opts(ffs_options); } void ffs_cleanup_opts(fsinfo_t *fsopts) { - if (fsopts->fs_specific) - free(fsopts->fs_specific); + free(fsopts->fs_specific); + free(fsopts->fs_options); } int ffs_parse_opts(const char *option, fsinfo_t *fsopts) { ffs_opt_t *ffs_opts = fsopts->fs_specific; + option_t *ffs_options = fsopts->fs_options; + char buf[1024]; - option_t ffs_options[] = { - { "bsize", &ffs_opts->bsize, 1, INT_MAX, - "block size" }, - { "fsize", &ffs_opts->fsize, 1, INT_MAX, - "fragment size" }, - { "density", &ffs_opts->density, 1, INT_MAX, - "bytes per inode" }, - { "minfree", &ffs_opts->minfree, 0, 99, - "minfree" }, - { "maxbpg", &ffs_opts->maxbpg, 1, INT_MAX, - "max blocks per file in a cg" }, - { "avgfilesize", &ffs_opts->avgfilesize,1, INT_MAX, - "expected average file size" }, - { "avgfpdir", &ffs_opts->avgfpdir, 1, INT_MAX, - "expected # of files per directory" }, - { "extent", &ffs_opts->maxbsize, 1, INT_MAX, - "maximum # extent size" }, - { "maxbpcg", &ffs_opts->maxblkspercg,1, INT_MAX, - "max # of blocks per group" }, - { "version", &ffs_opts->version, 1, 2, - "UFS version" }, - { .name = NULL } - }; - - char *var, *val; int rv; assert(option != NULL); @@ -216,36 +221,28 @@ ffs_parse_opts(const char *option, fsinfo_t *fsopts) if (debug & DEBUG_FS_PARSE_OPTS) printf("ffs_parse_opts: got `%s'\n", option); - if ((var = strdup(option)) == NULL) - err(1, "Allocating memory for copy of option string"); - rv = 0; + rv = set_option(ffs_options, option, buf, sizeof(buf)); + if (rv == -1) + return 0; - if ((val = strchr(var, '=')) == NULL) { - warnx("Option `%s' doesn't contain a value", var); - goto leave_ffs_parse_opts; - } - *val++ = '\0'; + if (ffs_options[rv].name == NULL) + abort(); - if (strcmp(var, "optimization") == 0) { - if (strcmp(val, "time") == 0) { + switch (ffs_options[rv].letter) { + case 'o': + if (strcmp(buf, "time") == 0) { ffs_opts->optimization = FS_OPTTIME; - } else if (strcmp(val, "space") == 0) { + } else if (strcmp(buf, "space") == 0) { ffs_opts->optimization = FS_OPTSPACE; } else { - warnx("Invalid optimization `%s'", val); - goto leave_ffs_parse_opts; + warnx("Invalid optimization `%s'", buf); + return 0; } - rv = 1; - } else if (strcmp(var, "label") == 0) { - strlcpy(ffs_opts->label, val, sizeof(ffs_opts->label)); - rv = 1; - } else - rv = set_option(ffs_options, var, val); - - leave_ffs_parse_opts: - if (var) - free(var); - return (rv); + break; + default: + break; + } + return 1; } Modified: stable/11/usr.sbin/makefs/makefs.c ============================================================================== --- stable/11/usr.sbin/makefs/makefs.c Wed Apr 25 01:12:40 2018 (r332977) +++ stable/11/usr.sbin/makefs/makefs.c Wed Apr 25 01:20:25 2018 (r332978) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "makefs.h" #include "mtree.h" @@ -84,7 +85,7 @@ struct stat stampst; static fstype_t *get_fstype(const char *); static int get_tstamp(const char *, struct stat *); -static void usage(void); +static void usage(fstype_t *, fsinfo_t *); int main(int, char *[]); int @@ -140,7 +141,7 @@ main(int argc, char *argv[]) #endif } else { warnx("Invalid endian `%s'.", optarg); - usage(); + usage(fstype, &fsoptions); } break; @@ -209,7 +210,7 @@ main(int argc, char *argv[]) if (*p == '\0') errx(1, "Empty option"); if (! fstype->parse_options(p, &fsoptions)) - usage(); + usage(fstype, &fsoptions); } break; } @@ -262,7 +263,7 @@ main(int argc, char *argv[]) case '?': default: - usage(); + usage(fstype, &fsoptions); /* NOTREACHED */ } @@ -277,7 +278,7 @@ main(int argc, char *argv[]) argv += optind; if (argc < 2) - usage(); + usage(fstype, &fsoptions); /* -x must be accompanied by -F */ if (fsoptions.onlyspec != 0 && specfile == NULL) @@ -343,21 +344,84 @@ main(int argc, char *argv[]) /* NOTREACHED */ } +int +set_option(const option_t *options, const char *option, char *buf, size_t len) +{ + char *var, *val; + int retval; + assert(option != NULL); + + if ((var = strdup(option)) == NULL) { + err(EXIT_FAILURE, "Allocating memory for copy of option string"); + } + + for (val = var; *val; val++) + if (*val == '=') { + *val++ = '\0'; + break; + } + retval = set_option_var(options, var, val, buf, len); + free(var); + return retval; +} + int -set_option(option_t *options, const char *var, const char *val) +set_option_var(const option_t *options, const char *var, const char *val, + char *buf, size_t len) { - int i; + char *s; + size_t i; +#define NUM(type) \ + if (!*val) { \ + *(type *)options[i].value = 1; \ + break; \ + } \ + *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ + options[i].minimum, options[i].maximum); break + for (i = 0; options[i].name != NULL; i++) { - if (strcmp(options[i].name, var) != 0) + if (var[1] == '\0') { + if (options[i].letter != var[0]) + continue; + } else if (strcmp(options[i].name, var) != 0) continue; - *options[i].value = (int)strsuftoll(options[i].desc, val, - options[i].minimum, options[i].maximum); - return (1); + switch (options[i].type) { + case OPT_BOOL: + *(bool *)options[i].value = 1; + break; + case OPT_STRARRAY: + strlcpy((void *)options[i].value, val, (size_t) + options[i].maximum); + break; + case OPT_STRPTR: + if ((s = strdup(val)) == NULL) + err(1, NULL); + *(char **)options[i].value = s; + break; + case OPT_STRBUF: + if (buf == NULL) + abort(); + strlcpy(buf, val, len); + break; + case OPT_INT64: + NUM(uint64_t); + case OPT_INT32: + NUM(uint32_t); + case OPT_INT16: + NUM(uint16_t); + case OPT_INT8: + NUM(uint8_t); + default: + warnx("Unknown type %d in option %s", options[i].type, + val); + return 0; + } + return i; } warnx("Unknown option `%s'", var); - return (0); + return -1; } @@ -372,6 +436,20 @@ get_fstype(const char *type) return (NULL); } +option_t * +copy_opts(const option_t *o) +{ + size_t i; + void *rv; + + for (i = 0; o[i].name; i++) + continue; + i++; + if ((rv = calloc(i, sizeof(*o))) == NULL) + err(1, "calloc"); + return memcpy(rv, o, i * sizeof(*o)); +} + static int get_tstamp(const char *b, struct stat *st) { @@ -399,17 +477,29 @@ get_tstamp(const char *b, struct stat *st) } static void -usage(void) +usage(fstype_t *fstype, fsinfo_t *fsoptions) { const char *prog; prog = getprogname(); fprintf(stderr, -"usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" +"Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" "\t[-N userdb-dir] [-o fs-options] [-R roundup-size] [-S sector-size]\n" "\t[-s image-size] [-T ] [-t fs-type]\n" "\timage-file directory | manifest [extra-directory ...]\n", prog); + + if (fstype) { + size_t i; + option_t *o = fsoptions->fs_options; + + fprintf(stderr, "\n%s specific options:\n", fstype->type); + for (i = 0; o[i].name != NULL; i++) + fprintf(stderr, "\t%c%c%20.20s\t%s\n", + o[i].letter ? o[i].letter : ' ', + o[i].letter ? ',' : ' ', + o[i].name, o[i].desc); + } exit(1); } Modified: stable/11/usr.sbin/makefs/makefs.h ============================================================================== --- stable/11/usr.sbin/makefs/makefs.h Wed Apr 25 01:12:40 2018 (r332977) +++ stable/11/usr.sbin/makefs/makefs.h Wed Apr 25 01:20:25 2018 (r332978) @@ -106,11 +106,37 @@ typedef struct _fsnode { #define FSNODE_F_OPTIONAL 0x02 /* fsnode is optional */ /* + * option_t - contains option name, description, pointer to location to store + * result, and range checks for the result. Used to simplify fs specific + * option setting + */ +typedef enum { + OPT_STRARRAY, + OPT_STRPTR, + OPT_STRBUF, + OPT_BOOL, + OPT_INT8, + OPT_INT16, + OPT_INT32, + OPT_INT64 +} opttype_t; + +typedef struct { + char letter; /* option letter NUL for none */ + const char *name; /* option name */ + void *value; /* where to stuff the value */ + opttype_t type; /* type of entry */ + long long minimum; /* minimum for value */ + long long maximum; /* maximum for value */ + const char *desc; /* option description */ +} option_t; + +/* * fsinfo_t - contains various settings and parameters pertaining to * the image, including current settings, global options, and fs * specific options */ -typedef struct { +typedef struct makefs_fsinfo { /* current settings */ off_t size; /* total size */ off_t inodes; /* number of inodes */ @@ -135,30 +161,20 @@ typedef struct { int sparse; /* sparse image, don't fill it with zeros */ void *fs_specific; /* File system specific additions. */ + option_t *fs_options; /* File system specific options */ } fsinfo_t; -/* - * option_t - contains option name, description, pointer to location to store - * result, and range checks for the result. Used to simplify fs specific - * option setting - */ -typedef struct { - const char *name; /* option name */ - int *value; /* where to stuff the value */ - int minimum; /* minimum for value */ - int maximum; /* maximum for value */ - const char *desc; /* option description */ -} option_t; - - void apply_specfile(const char *, const char *, fsnode *, int); void dump_fsnodes(fsnode *); const char * inode_type(mode_t); fsnode * read_mtree(const char *, fsnode *); -int set_option(option_t *, const char *, const char *); +int set_option(const option_t *, const char *, char *, size_t); +int set_option_var(const option_t *, const char *, const char *, + char *, size_t); fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *); void free_fsnodes(fsnode *); +option_t * copy_opts(const option_t *); void ffs_prep_opts(fsinfo_t *); int ffs_parse_opts(const char *, fsinfo_t *);