Author: emaste
Date: Wed Mar 15 13:34:51 2017
New Revision: 315304
URL: https://svnweb.freebsd.org/changeset/base/315304

Log:
  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
  
  Obtained from:        NetBSD
  Sponsored by: The FreeBSD Foundation

Modified:
  head/usr.sbin/makefs/cd9660.c
  head/usr.sbin/makefs/cd9660.h
  head/usr.sbin/makefs/ffs.c
  head/usr.sbin/makefs/makefs.c
  head/usr.sbin/makefs/makefs.h

Modified: head/usr.sbin/makefs/cd9660.c
==============================================================================
--- head/usr.sbin/makefs/cd9660.c       Wed Mar 15 11:16:26 2017        
(r315303)
+++ head/usr.sbin/makefs/cd9660.c       Wed Mar 15 13:34:51 2017        
(r315304)
@@ -256,7 +256,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);
 }
@@ -265,6 +328,7 @@ void
 cd9660_cleanup_opts(fsinfo_t *fsopts)
 {
        free(fsopts->fs_specific);
+       free(fsopts->fs_options);
 }
 
 static int
@@ -301,144 +365,106 @@ cd9660_arguments_set_string(const char *
 int
 cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
 {
-       char *var, *val;
-       int     rv;
+       int     rv, i;
        iso9660_disk *diskStructure = fsopts->fs_specific;
-
-       /* 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 }
-       }
-       */
+       option_t *cd9660_options = fsopts->fs_options;
+       char buf[1024];
+       const char *name, *desc;
 
        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;
-
-       val = strchr(var, '=');
-       if (val != NULL)
-               *val++ = '\0';
-
-       /* 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);
-       /* 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);
-                       }
+       i = set_option(cd9660_options, option, buf, sizeof(buf));
+       if (i == -1)
+               return 0;
 
-                       /* 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);
+       if (cd9660_options[i].name == NULL)
+               abort();
+
+       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 */
+       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: head/usr.sbin/makefs/cd9660.h
==============================================================================
--- head/usr.sbin/makefs/cd9660.h       Wed Mar 15 11:16:26 2017        
(r315303)
+++ head/usr.sbin/makefs/cd9660.h       Wed Mar 15 13:34:51 2017        
(r315304)
@@ -120,12 +120,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: head/usr.sbin/makefs/ffs.c
==============================================================================
--- head/usr.sbin/makefs/ffs.c  Wed Mar 15 11:16:26 2017        (r315303)
+++ head/usr.sbin/makefs/ffs.c  Wed Mar 15 13:34:51 2017        (r315304)
@@ -144,7 +144,6 @@ static  void        *ffs_build_dinode2(struct u
 
 
 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, fsinf
        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;
-
-       if ((val = strchr(var, '=')) == NULL) {
-               warnx("Option `%s' doesn't contain a value", var);
-               goto leave_ffs_parse_opts;
-       }
-       *val++ = '\0';
-
-       if (strcmp(var, "optimization") == 0) {
-               if (strcmp(val, "time") == 0) {
+       rv = set_option(ffs_options, option, buf, sizeof(buf));
+       if (rv == -1)
+               return 0;
+
+       if (ffs_options[rv].name == NULL)
+               abort();
+
+       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: head/usr.sbin/makefs/makefs.c
==============================================================================
--- head/usr.sbin/makefs/makefs.c       Wed Mar 15 11:16:26 2017        
(r315303)
+++ head/usr.sbin/makefs/makefs.c       Wed Mar 15 13:34:51 2017        
(r315304)
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #include "makefs.h"
 #include "mtree.h"
@@ -82,7 +83,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
@@ -141,7 +142,7 @@ main(int argc, char *argv[])
 #endif
                        } else {
                                warnx("Invalid endian `%s'.", optarg);
-                               usage();
+                               usage(fstype, &fsoptions);
                        }
                        break;
 
@@ -210,7 +211,7 @@ main(int argc, char *argv[])
                                if (*p == '\0')
                                        errx(1, "Empty option");
                                if (! fstype->parse_options(p, &fsoptions))
-                                       usage();
+                                       usage(fstype, &fsoptions);
                        }
                        break;
                }
@@ -263,7 +264,7 @@ main(int argc, char *argv[])
 
                case '?':
                default:
-                       usage();
+                       usage(fstype, &fsoptions);
                        /* NOTREACHED */
 
                }
@@ -278,7 +279,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)
@@ -344,21 +345,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;
 }
 
 
@@ -373,6 +437,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)
 {
@@ -400,17 +478,29 @@ get_tstamp(const char *b, struct stat *s
 }
 
 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 <timestamp/file>] [-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: head/usr.sbin/makefs/makefs.h
==============================================================================
--- head/usr.sbin/makefs/makefs.h       Wed Mar 15 11:16:26 2017        
(r315303)
+++ head/usr.sbin/makefs/makefs.h       Wed Mar 15 13:34:51 2017        
(r315304)
@@ -104,11 +104,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 */
@@ -124,8 +150,8 @@ typedef struct {
        off_t   minsize;        /* minimum size image should be */
        off_t   maxsize;        /* maximum size image can be */
        off_t   freefiles;      /* free file entries to leave */
-       int     freefilepc;     /* free file % */
        off_t   freeblocks;     /* free blocks to leave */
+       int     freefilepc;     /* free file % */
        int     freeblockpc;    /* free block % */
        int     needswap;       /* non-zero if byte swapping needed */
        int     sectorsize;     /* sector size */
@@ -133,30 +159,20 @@ typedef struct {
        off_t   roundup;        /* round image size up to this value */
 
        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 *);
 
 #define DECLARE_FUN(fs)                                                        
\
 void           fs ## _prep_opts(fsinfo_t *);                           \
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to