Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Mar 2017 13:34:52 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r315304 - head/usr.sbin/makefs
Message-ID:  <201703151334.v2FDYqY8057248@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 *);				\



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703151334.v2FDYqY8057248>