From d754678fa99b6881e9023055f8e6a42faf83b7ce Mon Sep 17 00:00:00 2001 From: marcel Date: Sun, 7 Jun 2009 20:12:14 +0000 Subject: Allow humanized numbers for LBAs, as well as partition indices for gpart(8). LBAs in particular are ugly. The ganularity is a sector, but users expect byte granularity when specifying the size or offset with a SI unit. Handle LBAs specially to deal with this. --- sbin/geom/class/part/geom_part.c | 18 +++--- sbin/geom/core/geom.c | 117 +++++++++++++++++++++++++++++++++++---- sbin/geom/core/geom.h | 6 +- 3 files changed, 120 insertions(+), 21 deletions(-) (limited to 'sbin') diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index 357db3f..51c890c 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -68,10 +68,10 @@ static void gpart_show(struct gctl_req *, unsigned int); struct g_command PUBSYM(class_commands)[] = { { "add", 0, gpart_issue, { - { 'b', "start", NULL, G_TYPE_STRING }, - { 's', "size", NULL, G_TYPE_STRING }, + { 'b', "start", NULL, G_TYPE_ASCLBA }, + { 's', "size", NULL, G_TYPE_ASCLBA }, { 't', "type", NULL, G_TYPE_STRING }, - { 'i', index_param, optional, G_TYPE_STRING }, + { 'i', index_param, optional, G_TYPE_ASCNUM }, { 'l', "label", optional, G_TYPE_STRING }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, @@ -80,7 +80,7 @@ struct g_command PUBSYM(class_commands)[] = { { "bootcode", 0, gpart_bootcode, { { 'b', bootcode_param, optional, G_TYPE_STRING }, { 'p', partcode_param, optional, G_TYPE_STRING }, - { 'i', index_param, optional, G_TYPE_STRING }, + { 'i', index_param, optional, G_TYPE_ASCNUM }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, "geom", NULL @@ -88,13 +88,13 @@ struct g_command PUBSYM(class_commands)[] = { { "commit", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, { "create", 0, gpart_issue, { { 's', "scheme", NULL, G_TYPE_STRING }, - { 'n', "entries", optional, G_TYPE_STRING }, + { 'n', "entries", optional, G_TYPE_ASCNUM }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, "provider", NULL }, { "delete", 0, gpart_issue, { - { 'i', index_param, NULL, G_TYPE_STRING }, + { 'i', index_param, NULL, G_TYPE_ASCNUM }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, "geom", NULL @@ -104,7 +104,7 @@ struct g_command PUBSYM(class_commands)[] = { G_OPT_SENTINEL }, "geom", NULL }, { "modify", 0, gpart_issue, { - { 'i', index_param, NULL, G_TYPE_STRING }, + { 'i', index_param, NULL, G_TYPE_ASCNUM }, { 'l', "label", optional, G_TYPE_STRING }, { 't', "type", optional, G_TYPE_STRING }, { 'f', "flags", flags, G_TYPE_STRING }, @@ -113,7 +113,7 @@ struct g_command PUBSYM(class_commands)[] = { }, { "set", 0, gpart_issue, { { 'a', "attrib", NULL, G_TYPE_STRING }, - { 'i', index_param, NULL, G_TYPE_STRING }, + { 'i', index_param, NULL, G_TYPE_ASCNUM }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, "geom", NULL @@ -127,7 +127,7 @@ struct g_command PUBSYM(class_commands)[] = { { "undo", 0, gpart_issue, G_NULL_OPTS, "geom", NULL }, { "unset", 0, gpart_issue, { { 'a', "attrib", NULL, G_TYPE_STRING }, - { 'i', index_param, NULL, G_TYPE_STRING }, + { 'i', index_param, NULL, G_TYPE_ASCNUM }, { 'f', "flags", flags, G_TYPE_STRING }, G_OPT_SENTINEL }, "geom", NULL diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c index f7656dc..8949b73 100644 --- a/sbin/geom/core/geom.c +++ b/sbin/geom/core/geom.c @@ -226,20 +226,117 @@ find_option(struct g_command *cmd, char ch) static void set_option(struct gctl_req *req, struct g_option *opt, const char *val) { + char *s; + intmax_t number; - if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { - intmax_t number; - + if (G_OPT_TYPE(opt) == G_TYPE_NUMBER || + G_OPT_TYPE(opt) == G_TYPE_ASCNUM) { if (expand_number(val, &number) == -1) { err(EXIT_FAILURE, "Invalid value for '%c' argument.", opt->go_char); } - opt->go_val = malloc(sizeof(intmax_t)); + if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) + opt->go_val = malloc(sizeof(intmax_t)); + else { + asprintf(&s, "%jd", number); + opt->go_val = s; + } if (opt->go_val == NULL) errx(EXIT_FAILURE, "No memory."); - *(intmax_t *)opt->go_val = number; + if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { + *(intmax_t *)opt->go_val = number; + gctl_ro_param(req, opt->go_name, sizeof(intmax_t), + opt->go_val); + } else + gctl_ro_param(req, opt->go_name, -1, opt->go_val); + } else if (G_OPT_TYPE(opt) == G_TYPE_ASCLBA) { + /* + * LBAs are ugly. The argument is a sector. The size of a + * sector is context specific (i.e. determined by the media), + * which we don't know here. But when users enter a value + * with a SI unit, they really mean the byte-size or byte- + * offset and not the size or offset in sectors. + * So how can we map the byte-oriented value into a sector- + * oriented value if we don't know the sector size in bytes? + * The approach taken here is: + * o Sectors are 512 bytes in size. Mostly the case anyway. + * o When no SI unit is specified the value is in sectors. + * o With an SI unit the value is in bytes. + * o The 'b' suffix forces byte interpretation and the 's' + * suffix forces sector interpretation. + * + * Thus: + * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. + * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. + * + * "This seemed like a good idea at the time" + */ + intmax_t mult, unit; - gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val); + number = strtoimax(val, &s, 0); + if (s == val) + errc(EXIT_FAILURE, EINVAL, "argument '%c'", + opt->go_char); + mult = 1; + unit = 512; /* sector */ + if (*s == '\0') + goto done; + switch (*s) { + case 'e': case 'E': + mult *= 1024; + /*FALLTHROUGH*/ + case 'p': case 'P': + mult *= 1024; + /*FALLTHROUGH*/ + case 't': case 'T': + mult *= 1024; + /*FALLTHROUGH*/ + case 'g': case 'G': + mult *= 1024; + /*FALLTHROUGH*/ + case 'm': case 'M': + mult *= 1024; + /*FALLTHROUGH*/ + case 'k': case 'K': + mult *= 1024; + break; + default: + goto sfx; + } + unit = 1; /* bytes */ + s++; + if (*s == '\0') + goto done; +sfx: + switch (*s) { + case 's': case 'S': + unit = 512; /* sector */ + break; + case 'b': case 'B': + unit = 1; /* bytes */ + break; + default: + errc(EXIT_FAILURE, EINVAL, "argument '%c': suffix '%c'", + opt->go_char, *s); + } + s++; + if (*s != '\0') + errx(EXIT_FAILURE, "argument '%c': junk at end (%s)", + opt->go_char, s); +done: + if (mult * unit < mult || number * mult * unit < number) + errc(EXIT_FAILURE, ERANGE, "argument '%c'", + opt->go_char); + number *= mult * unit; + if (number % 512) + errx(EXIT_FAILURE, "argument '%c': " + "not a valid block address", opt->go_char); + number /= 512; + asprintf(&s, "%jd", number); + if (s == NULL) + err(EXIT_FAILURE, NULL); + opt->go_val = s; + gctl_ro_param(req, opt->go_name, -1, s); } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) { gctl_ro_param(req, opt->go_name, -1, val); } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) { @@ -247,9 +344,7 @@ set_option(struct gctl_req *req, struct g_option *opt, const char *val) if (opt->go_val == NULL) errx(EXIT_FAILURE, "No memory."); *(int *)opt->go_val = *val - '0'; - - gctl_ro_param(req, opt->go_name, sizeof(int), - opt->go_val); + gctl_ro_param(req, opt->go_name, sizeof(int), opt->go_val); } else { assert(!"Invalid type"); } @@ -333,7 +428,9 @@ parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc, if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val); - } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) { + } else if (G_OPT_TYPE(opt) == G_TYPE_STRING || + G_OPT_TYPE(opt) == G_TYPE_ASCNUM || + G_OPT_TYPE(opt) == G_TYPE_ASCLBA) { if (cmd->gc_argname == NULL || opt->go_val == NULL || *(char *)opt->go_val != '\0') diff --git a/sbin/geom/core/geom.h b/sbin/geom/core/geom.h index e79e855..5c25311 100644 --- a/sbin/geom/core/geom.h +++ b/sbin/geom/core/geom.h @@ -28,7 +28,7 @@ #ifndef _GEOM_H_ #define _GEOM_H_ -#define G_LIB_VERSION 3 +#define G_LIB_VERSION 4 #define G_FLAG_NONE 0x0000 #define G_FLAG_VERBOSE 0x0001 @@ -38,7 +38,9 @@ #define G_TYPE_BOOL 0x01 #define G_TYPE_STRING 0x02 #define G_TYPE_NUMBER 0x03 -#define G_TYPE_MASK 0x03 +#define G_TYPE_ASCNUM 0x04 +#define G_TYPE_ASCLBA 0x05 +#define G_TYPE_MASK 0x0f #define G_TYPE_DONE 0x10 #define G_OPT_MAX 16 -- cgit v1.1