summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2009-06-07 20:12:14 +0000
committermarcel <marcel@FreeBSD.org>2009-06-07 20:12:14 +0000
commitd754678fa99b6881e9023055f8e6a42faf83b7ce (patch)
tree581940518784791b6b6563f39d6be682ffed19b5 /sbin
parent2d149b09c57b22367f7e05e3efaf23f0cb328621 (diff)
downloadFreeBSD-src-d754678fa99b6881e9023055f8e6a42faf83b7ce.zip
FreeBSD-src-d754678fa99b6881e9023055f8e6a42faf83b7ce.tar.gz
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.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/geom/class/part/geom_part.c18
-rw-r--r--sbin/geom/core/geom.c117
-rw-r--r--sbin/geom/core/geom.h6
3 files changed, 120 insertions, 21 deletions
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
OpenPOWER on IntegriCloud