summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/geom/core/geom.c40
-rw-r--r--sbin/geom/core/geom.h6
2 files changed, 40 insertions, 6 deletions
diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c
index 4a3dcd4..39731e9 100644
--- a/sbin/geom/core/geom.c
+++ b/sbin/geom/core/geom.c
@@ -234,9 +234,31 @@ find_option(struct g_command *cmd, char ch)
static void
set_option(struct gctl_req *req, struct g_option *opt, const char *val)
{
+ const char *optname;
uint64_t number;
void *ptr;
+ if (G_OPT_ISMULTI(opt)) {
+ size_t optnamesize;
+
+ if (G_OPT_NUM(opt) == UCHAR_MAX)
+ errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
+
+ /*
+ * Base option name length plus 3 bytes for option number
+ * (max. 255 options) plus 1 byte for terminating '\0'.
+ */
+ optnamesize = strlen(opt->go_name) + 3 + 1;
+ ptr = malloc(optnamesize);
+ if (ptr == NULL)
+ errx(EXIT_FAILURE, "No memory.");
+ snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
+ G_OPT_NUMINC(opt);
+ optname = ptr;
+ } else {
+ optname = opt->go_name;
+ }
+
if (G_OPT_TYPE(opt) == G_TYPE_NUMBER ||
G_OPT_TYPE(opt) == G_TYPE_ASCNUM) {
if (expand_number(val, &number) == -1) {
@@ -249,27 +271,30 @@ set_option(struct gctl_req *req, struct g_option *opt, const char *val)
errx(EXIT_FAILURE, "No memory.");
*(intmax_t *)ptr = number;
opt->go_val = ptr;
- gctl_ro_param(req, opt->go_name, sizeof(intmax_t),
+ gctl_ro_param(req, optname, sizeof(intmax_t),
opt->go_val);
} else {
asprintf((void *)(&ptr), "%jd", number);
if (ptr == NULL)
errx(EXIT_FAILURE, "No memory.");
opt->go_val = ptr;
- gctl_ro_param(req, opt->go_name, -1, opt->go_val);
+ gctl_ro_param(req, optname, -1, opt->go_val);
}
} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
- gctl_ro_param(req, opt->go_name, -1, val);
+ gctl_ro_param(req, optname, -1, val);
} else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
ptr = malloc(sizeof(int));
if (ptr == NULL)
errx(EXIT_FAILURE, "No memory.");
*(int *)ptr = *val - '0';
opt->go_val = ptr;
- gctl_ro_param(req, opt->go_name, sizeof(int), opt->go_val);
+ gctl_ro_param(req, optname, sizeof(int), opt->go_val);
} else {
assert(!"Invalid type");
}
+
+ if (G_OPT_ISMULTI(opt))
+ free(__DECONST(char *, optname));
}
/*
@@ -294,7 +319,10 @@ parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
if (opt->go_name == NULL)
break;
assert(G_OPT_TYPE(opt) != 0);
- assert((opt->go_type & ~G_TYPE_MASK) == 0);
+ assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
+ /* Multiple bool arguments makes no sense. */
+ assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
+ (opt->go_type & G_TYPE_MULTI) == 0);
strlcatf(opts, sizeof(opts), "%c", opt->go_char);
if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
strlcat(opts, ":", sizeof(opts));
@@ -314,7 +342,7 @@ parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
opt = find_option(cmd, ch);
if (opt == NULL)
usage();
- if (G_OPT_ISDONE(opt)) {
+ if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
warnx("Option '%c' specified twice.", opt->go_char);
usage();
}
diff --git a/sbin/geom/core/geom.h b/sbin/geom/core/geom.h
index 92c97a3..c88005e 100644
--- a/sbin/geom/core/geom.h
+++ b/sbin/geom/core/geom.h
@@ -41,11 +41,17 @@
#define G_TYPE_ASCNUM 0x04
#define G_TYPE_MASK 0x0f
#define G_TYPE_DONE 0x10
+#define G_TYPE_MULTI 0x20
+#define G_TYPE_NUMMASK 0xff00
+#define G_TYPE_NUMSHIFT 8
#define G_OPT_MAX 16
#define G_OPT_DONE(opt) do { (opt)->go_type |= G_TYPE_DONE; } while (0)
#define G_OPT_ISDONE(opt) ((opt)->go_type & G_TYPE_DONE)
+#define G_OPT_ISMULTI(opt) ((opt)->go_type & G_TYPE_MULTI)
#define G_OPT_TYPE(opt) ((opt)->go_type & G_TYPE_MASK)
+#define G_OPT_NUM(opt) (((opt)->go_type & G_TYPE_NUMMASK) >> G_TYPE_NUMSHIFT)
+#define G_OPT_NUMINC(opt) ((opt)->go_type += (1 << G_TYPE_NUMSHIFT))
#define G_OPT_SENTINEL { '\0', NULL, NULL, G_TYPE_NONE }
#define G_NULL_OPTS { G_OPT_SENTINEL }
OpenPOWER on IntegriCloud