summaryrefslogtreecommitdiffstats
path: root/sbin/geom
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/geom')
-rw-r--r--sbin/geom/class/part/geom_part.c204
-rw-r--r--sbin/geom/core/geom.c91
-rw-r--r--sbin/geom/core/geom.h1
-rw-r--r--sbin/geom/misc/subr.c90
-rw-r--r--sbin/geom/misc/subr.h1
5 files changed, 210 insertions, 177 deletions
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index a72155b..cc1145e 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$");
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
@@ -60,6 +62,9 @@ static char autofill[] = "*";
static char optional[] = "";
static char flags[] = "C";
+static char sstart[32];
+static char ssize[32];
+
static const char const bootcode_param[] = "bootcode";
static const char const index_param[] = "index";
static const char const partcode_param[] = "partcode";
@@ -68,8 +73,7 @@ static struct gclass *find_class(struct gmesh *, const char *);
static struct ggeom * find_geom(struct gclass *, const char *);
static const char *find_geomcfg(struct ggeom *, const char *);
static const char *find_provcfg(struct gprovider *, const char *);
-static struct gprovider *find_provider(struct ggeom *,
- unsigned long long);
+static struct gprovider *find_provider(struct ggeom *, off_t);
static const char *fmtsize(int64_t);
static int gpart_autofill(struct gctl_req *);
static int gpart_autofill_resize(struct gctl_req *);
@@ -84,8 +88,8 @@ static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
struct g_command PUBSYM(class_commands)[] = {
{ "add", 0, gpart_issue, {
- { 'b', "start", autofill, G_TYPE_ASCLBA },
- { 's', "size", autofill, G_TYPE_ASCLBA },
+ { 'b', "start", autofill, G_TYPE_STRING },
+ { 's', "size", autofill, G_TYPE_STRING },
{ 't', "type", NULL, G_TYPE_STRING },
{ 'i', index_param, optional, G_TYPE_ASCNUM },
{ 'l', "label", optional, G_TYPE_STRING },
@@ -149,7 +153,7 @@ struct g_command PUBSYM(class_commands)[] = {
"geom", NULL
},
{ "resize", 0, gpart_issue, {
- { 's', "size", autofill, G_TYPE_ASCLBA },
+ { 's', "size", autofill, G_TYPE_STRING },
{ 'i', index_param, NULL, G_TYPE_ASCNUM },
{ 'f', "flags", flags, G_TYPE_STRING },
G_OPT_SENTINEL },
@@ -207,11 +211,11 @@ find_provcfg(struct gprovider *pp, const char *cfg)
}
static struct gprovider *
-find_provider(struct ggeom *gp, unsigned long long minsector)
+find_provider(struct ggeom *gp, off_t minsector)
{
struct gprovider *pp, *bestpp;
const char *s;
- unsigned long long sector, bestsector;
+ off_t sector, bestsector;
bestpp = NULL;
bestsector = 0;
@@ -219,9 +223,10 @@ find_provider(struct ggeom *gp, unsigned long long minsector)
s = find_provcfg(pp, "start");
if (s == NULL) {
s = find_provcfg(pp, "offset");
- sector = atoll(s) / pp->lg_sectorsize;
+ sector =
+ (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- sector = atoll(s);
+ sector = (off_t)strtoimax(s, NULL, 0);
if (sector < minsector)
continue;
@@ -271,18 +276,12 @@ gpart_autofill_resize(struct gctl_req *req)
struct gclass *cp;
struct ggeom *gp;
struct gprovider *pp;
- unsigned long long last, size, start, new_size;
- unsigned long long lba, new_lba;
+ off_t last, size, start, new_size;
+ off_t lba, new_lba;
const char *s;
char *val;
int error, idx;
- s = gctl_get_ascii(req, "size");
- if (*s == '*')
- new_size = (unsigned long long)atoll(s);
- else
- return (0);
-
s = gctl_get_ascii(req, index_param);
idx = strtol(s, &val, 10);
if (idx < 1 || *s == '\0' || *val != '\0')
@@ -303,8 +302,22 @@ gpart_autofill_resize(struct gctl_req *req)
gp = find_geom(cp, s);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
- last = atoll(find_geomcfg(gp, "last"));
+ pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
+ if (pp == NULL)
+ errx(EXIT_FAILURE, "Provider for geom %s not found.", s);
+
+ s = gctl_get_ascii(req, "size");
+ if (*s == '*')
+ new_size = 0;
+ else {
+ error = g_parse_lba(s, pp->lg_sectorsize, &new_size);
+ if (error)
+ errc(EXIT_FAILURE, error, "Invalid size param");
+ /* no autofill necessary. */
+ goto done;
+ }
+ last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0);
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
s = find_provcfg(pp, "index");
if (s == NULL)
@@ -318,18 +331,21 @@ gpart_autofill_resize(struct gctl_req *req)
s = find_provcfg(pp, "start");
if (s == NULL) {
s = find_provcfg(pp, "offset");
- start = atoll(s) / pp->lg_sectorsize;
+ start = (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- start = atoll(s);
+ start = (off_t)strtoimax(s, NULL, 0);
s = find_provcfg(pp, "end");
if (s == NULL) {
s = find_provcfg(pp, "length");
- lba = start + atoll(s) / pp->lg_sectorsize;
+ lba = start +
+ (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- lba = atoll(s) + 1;
+ lba = (off_t)strtoimax(s, NULL, 0) + 1;
- if (lba > last)
+ if (lba > last) {
+ geom_deletetree(&mesh);
return (ENOSPC);
+ }
size = lba - start;
pp = find_provider(gp, lba);
if (pp == NULL)
@@ -338,22 +354,25 @@ gpart_autofill_resize(struct gctl_req *req)
s = find_provcfg(pp, "start");
if (s == NULL) {
s = find_provcfg(pp, "offset");
- new_lba = atoll(s) / pp->lg_sectorsize;
+ new_lba =
+ (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- new_lba = atoll(s);
- /* Is there any free space between current and
+ new_lba = (off_t)strtoimax(s, NULL, 0);
+ /*
+ * Is there any free space between current and
* next providers?
*/
if (new_lba > lba)
new_size = new_lba - start;
- else
+ else {
+ geom_deletetree(&mesh);
return (ENOSPC);
+ }
}
- asprintf(&val, "%llu", new_size);
- if (val == NULL)
- return (ENOMEM);
- gctl_change_param(req, "size", -1, val);
-
+done:
+ snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size);
+ gctl_change_param(req, "size", -1, ssize);
+ geom_deletetree(&mesh);
return (0);
}
@@ -364,11 +383,11 @@ gpart_autofill(struct gctl_req *req)
struct gclass *cp;
struct ggeom *gp;
struct gprovider *pp;
- unsigned long long first, last;
- unsigned long long size, start;
- unsigned long long lba, len, grade;
+ off_t first, last;
+ off_t size, start;
+ off_t lba, len;
+ uintmax_t grade;
const char *s;
- char *val;
int error, has_size, has_start;
s = gctl_get_ascii(req, "verb");
@@ -377,18 +396,6 @@ gpart_autofill(struct gctl_req *req)
if (strcmp(s, "add") != 0)
return (0);
- s = gctl_get_ascii(req, "size");
- has_size = (*s == '*') ? 0 : 1;
- size = (has_size) ? (unsigned long long)atoll(s) : 0ULL;
-
- s = gctl_get_ascii(req, "start");
- has_start = (*s == '*') ? 0 : 1;
- start = (has_start) ? (unsigned long long)atoll(s) : ~0ULL;
-
- /* No autofill necessary. */
- if (has_size && has_start)
- return (0);
-
error = geom_gettree(&mesh);
if (error)
return (error);
@@ -404,22 +411,49 @@ gpart_autofill(struct gctl_req *req)
gp = find_geom(cp, s);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
- first = atoll(find_geomcfg(gp, "first"));
- last = atoll(find_geomcfg(gp, "last"));
+ pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
+ if (pp == NULL)
+ errx(EXIT_FAILURE, "Provider for geom %s not found.", s);
+
+ s = gctl_get_ascii(req, "size");
+ has_size = (*s == '*') ? 0 : 1;
+ size = 0;
+ if (has_size) {
+ error = g_parse_lba(s, pp->lg_sectorsize, &size);
+ if (error)
+ errc(EXIT_FAILURE, error, "Invalid size param");
+ }
+
+ s = gctl_get_ascii(req, "start");
+ has_start = (*s == '*') ? 0 : 1;
+ start = 0ULL;
+ if (has_start) {
+ error = g_parse_lba(s, pp->lg_sectorsize, &start);
+ if (error)
+ errc(EXIT_FAILURE, error, "Invalid start param");
+ }
+
+ /* No autofill necessary. */
+ if (has_size && has_start)
+ goto done;
+
+ first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0);
+ last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0);
grade = ~0ULL;
while ((pp = find_provider(gp, first)) != NULL) {
s = find_provcfg(pp, "start");
if (s == NULL) {
s = find_provcfg(pp, "offset");
- lba = atoll(s) / pp->lg_sectorsize;
+ lba = (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- lba = atoll(s);
+ lba = (off_t)strtoimax(s, NULL, 0);
if (first < lba) {
/* Free space [first, lba> */
len = lba - first;
if (has_size) {
- if (len >= size && len - size < grade) {
+ if (len >= size &&
+ (uintmax_t)(len - size) < grade) {
start = first;
grade = len - size;
}
@@ -440,15 +474,17 @@ gpart_autofill(struct gctl_req *req)
s = find_provcfg(pp, "end");
if (s == NULL) {
s = find_provcfg(pp, "length");
- first = lba + atoll(s) / pp->lg_sectorsize;
+ first = lba +
+ (off_t)strtoimax(s, NULL, 0) / pp->lg_sectorsize;
} else
- first = atoll(s) + 1;
+ first = (off_t)strtoimax(s, NULL, 0) + 1;
}
if (first <= last) {
/* Free space [first-last] */
len = last - first + 1;
if (has_size) {
- if (len >= size && len - size < grade) {
+ if (len >= size &&
+ (uintmax_t)(len - size) < grade) {
start = first;
grade = len - size;
}
@@ -466,21 +502,17 @@ gpart_autofill(struct gctl_req *req)
}
}
- if (grade == ~0ULL)
+ if (grade == ~0ULL) {
+ geom_deletetree(&mesh);
return (ENOSPC);
-
- if (!has_size) {
- asprintf(&val, "%llu", size);
- if (val == NULL)
- return (ENOMEM);
- gctl_change_param(req, "size", -1, val);
- }
- if (!has_start) {
- asprintf(&val, "%llu", start);
- if (val == NULL)
- return (ENOMEM);
- gctl_change_param(req, "start", -1, val);
}
+
+done:
+ snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size);
+ gctl_change_param(req, "size", -1, ssize);
+ snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start);
+ gctl_change_param(req, "start", -1, sstart);
+ geom_deletetree(&mesh);
return (0);
}
@@ -489,21 +521,21 @@ gpart_show_geom(struct ggeom *gp, const char *element)
{
struct gprovider *pp;
const char *s, *scheme;
- unsigned long long first, last, sector, end;
- unsigned long long length, secsz;
+ off_t first, last, sector, end;
+ off_t length, secsz;
int idx, wblocks, wname;
scheme = find_geomcfg(gp, "scheme");
s = find_geomcfg(gp, "first");
- first = atoll(s);
+ first = (off_t)strtoimax(s, NULL, 0);
s = find_geomcfg(gp, "last");
- last = atoll(s);
+ last = (off_t)strtoimax(s, NULL, 0);
wblocks = strlen(s);
wname = strlen(gp->lg_name);
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
secsz = pp->lg_sectorsize;
- printf("=>%*llu %*llu %*s %s (%s)\n",
- wblocks, first, wblocks, (last - first + 1),
+ printf("=>%*jd %*jd %*s %s (%s)\n",
+ wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1),
wname, gp->lg_name,
scheme, fmtsize(pp->lg_mediasize));
@@ -511,37 +543,37 @@ gpart_show_geom(struct ggeom *gp, const char *element)
s = find_provcfg(pp, "start");
if (s == NULL) {
s = find_provcfg(pp, "offset");
- sector = atoll(s) / secsz;
+ sector = (off_t)strtoimax(s, NULL, 0) / secsz;
} else
- sector = atoll(s);
+ sector = (off_t)strtoimax(s, NULL, 0);
s = find_provcfg(pp, "end");
if (s == NULL) {
s = find_provcfg(pp, "length");
- length = atoll(s) / secsz;
+ length = (off_t)strtoimax(s, NULL, 0) / secsz;
end = sector + length - 1;
} else {
- end = atoll(s);
+ end = (off_t)strtoimax(s, NULL, 0);
length = end - sector + 1;
}
s = find_provcfg(pp, "index");
idx = atoi(s);
if (first < sector) {
- printf(" %*llu %*llu %*s - free - (%s)\n",
- wblocks, first, wblocks, sector - first,
- wname, "",
+ printf(" %*jd %*jd %*s - free - (%s)\n",
+ wblocks, (intmax_t)first, wblocks,
+ (intmax_t)(sector - first), wname, "",
fmtsize((sector - first) * secsz));
}
- printf(" %*llu %*llu %*d %s %s (%s)\n",
- wblocks, sector, wblocks, length,
+ printf(" %*jd %*jd %*d %s %s (%s)\n",
+ wblocks, (intmax_t)sector, wblocks, (intmax_t)length,
wname, idx, find_provcfg(pp, element),
fmtattrib(pp), fmtsize(pp->lg_mediasize));
first = end + 1;
}
if (first <= last) {
length = last - first + 1;
- printf(" %*llu %*llu %*s - free - (%s)\n",
- wblocks, first, wblocks, length,
+ printf(" %*jd %*jd %*s - free - (%s)\n",
+ wblocks, (intmax_t)first, wblocks, (intmax_t)length,
wname, "",
fmtsize(length * secsz));
}
diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c
index 66f2a8f..49ebdc5 100644
--- a/sbin/geom/core/geom.c
+++ b/sbin/geom/core/geom.c
@@ -259,94 +259,6 @@ set_option(struct gctl_req *req, struct g_option *opt, const char *val)
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;
-
- 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) {
@@ -439,8 +351,7 @@ parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
gctl_ro_param(req, opt->go_name,
sizeof(intmax_t), opt->go_val);
} else if (G_OPT_TYPE(opt) == G_TYPE_STRING ||
- G_OPT_TYPE(opt) == G_TYPE_ASCNUM ||
- G_OPT_TYPE(opt) == G_TYPE_ASCLBA) {
+ G_OPT_TYPE(opt) == G_TYPE_ASCNUM) {
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 5c25311..424695b 100644
--- a/sbin/geom/core/geom.h
+++ b/sbin/geom/core/geom.h
@@ -39,7 +39,6 @@
#define G_TYPE_STRING 0x02
#define G_TYPE_NUMBER 0x03
#define G_TYPE_ASCNUM 0x04
-#define G_TYPE_ASCLBA 0x05
#define G_TYPE_MASK 0x0f
#define G_TYPE_DONE 0x10
diff --git a/sbin/geom/misc/subr.c b/sbin/geom/misc/subr.c
index e71ec74..7a4786f 100644
--- a/sbin/geom/misc/subr.c
+++ b/sbin/geom/misc/subr.c
@@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$");
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
@@ -107,6 +109,94 @@ bitcount32(uint32_t x)
return (x);
}
+/*
+ * The size of a sector is context specific (i.e. determined by the
+ * media). 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. We should map the byte-oriented value into a sector-oriented
+ * value when we already know the sector size in bytes. At this time
+ * we can use g_parse_lba() function. It converts user specified
+ * value into sectors with following conditions:
+ * o Sectors size taken as argument from caller.
+ * 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.
+ *
+ */
+int
+g_parse_lba(const char *lbastr, unsigned sectorsize, off_t *sectors)
+{
+ off_t number, mult, unit;
+ char *s;
+
+ assert(lbastr != NULL);
+ assert(sectorsize > 0);
+ assert(sectors != NULL);
+
+ number = (off_t)strtoimax(lbastr, &s, 0);
+ if (s == lbastr)
+ return (EINVAL);
+
+ mult = 1;
+ unit = sectorsize;
+ 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 = sectorsize; /* sector */
+ break;
+ case 'b': case 'B':
+ unit = 1; /* bytes */
+ break;
+ default:
+ return (EINVAL);
+ }
+ s++;
+ if (*s != '\0')
+ return (EINVAL);
+done:
+ if (mult * unit < mult || number * mult * unit < number)
+ return (ERANGE);
+ number *= mult * unit;
+ if (number % sectorsize)
+ return (EINVAL);
+ number /= sectorsize;
+ *sectors = number;
+ return (0);
+}
+
off_t
g_get_mediasize(const char *name)
{
diff --git a/sbin/geom/misc/subr.h b/sbin/geom/misc/subr.h
index c3242a3..2b43bdb 100644
--- a/sbin/geom/misc/subr.h
+++ b/sbin/geom/misc/subr.h
@@ -32,6 +32,7 @@
unsigned g_lcm(unsigned a, unsigned b);
uint32_t bitcount32(uint32_t x);
+int g_parse_lba(const char *lbastr, unsigned sectorsize, off_t *sectors);
off_t g_get_mediasize(const char *name);
unsigned g_get_sectorsize(const char *name);
OpenPOWER on IntegriCloud