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
This commit is contained in:
Ed Maste 2017-03-15 13:34:51 +00:00
parent ce9f323727
commit 776c68249b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315304
5 changed files with 338 additions and 215 deletions

View File

@ -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 *val, const char *fieldtitle, int length,
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;
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);
rv = 0;
} else {
cd9660_eltorito_add_boot_option(diskStructure, var,
val);
}
} else {
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
rv = set_option(cd9660_options, var, val);
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 = 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;
}
/*

View File

@ -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

View File

@ -144,7 +144,6 @@ static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *,
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;
}

View File

@ -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 *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 <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);
}

View File

@ -103,12 +103,38 @@ typedef struct _fsnode {
#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
#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 *); \