Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jul 2010 08:48:45 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r210322 - in stable/8/sbin/geom: class/part core misc
Message-ID:  <201007210848.o6L8mjVZ065832@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Wed Jul 21 08:48:45 2010
New Revision: 210322
URL: http://svn.freebsd.org/changeset/base/210322

Log:
  MFC r209388:
    Remove G_TYPE_ASCLBA type and replace it with G_TYPE_STRING in gpart.
    Move code that converts params from humanized numbers to sectors count
    to subr.c and adjust comment.
    Add post-processing for "size" and "start offset" params in gpart,
    now they are properly converted to sectors count with known sector size
    that can be greater that 512 bytes.
    Also replace "unsigned long long" type to "off_t" for unify code since
    it used for medium size in libgeom(3) and DIOCGMEDIASIZE ioctl.
  
    PR:		bin/146277
  
  MFC r209392:
    Check for overflow before it occurs. Also add check for
    negative numbers.
  
    Suggested by:	ache
  
  Approved by:	mav (mentor)

Modified:
  stable/8/sbin/geom/class/part/geom_part.c
  stable/8/sbin/geom/core/geom.c
  stable/8/sbin/geom/core/geom.h
  stable/8/sbin/geom/misc/subr.c
  stable/8/sbin/geom/misc/subr.h
Directory Properties:
  stable/8/sbin/geom/   (props changed)
  stable/8/sbin/geom/class/part/   (props changed)
  stable/8/sbin/geom/class/stripe/   (props changed)

Modified: stable/8/sbin/geom/class/part/geom_part.c
==============================================================================
--- stable/8/sbin/geom/class/part/geom_part.c	Wed Jul 21 08:43:48 2010	(r210321)
+++ stable/8/sbin/geom/class/part/geom_part.c	Wed Jul 21 08:48:45 2010	(r210322)
@@ -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 
 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 void gpart_bootcode(struct gctl_req *, unsigned int);
@@ -83,8 +87,8 @@ static void gpart_write_partcode_vtoc8(s
 
 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 },
@@ -148,7 +152,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 },
@@ -206,11 +210,11 @@ find_provcfg(struct gprovider *pp, const
 }
 
 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;
@@ -218,9 +222,10 @@ find_provider(struct ggeom *gp, unsigned
 		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;
@@ -270,18 +275,12 @@ gpart_autofill_resize(struct gctl_req *r
 	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')
@@ -302,8 +301,22 @@ gpart_autofill_resize(struct gctl_req *r
 	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)
@@ -317,18 +330,21 @@ gpart_autofill_resize(struct gctl_req *r
 	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)
@@ -337,22 +353,25 @@ gpart_autofill_resize(struct gctl_req *r
 		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);
 }
 
@@ -363,11 +382,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");
@@ -376,18 +395,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);
@@ -403,22 +410,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;
 				}
@@ -439,15 +473,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;
 			}
@@ -465,21 +501,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);
 }
 
@@ -488,21 +520,21 @@ gpart_show_geom(struct ggeom *gp, const 
 {
 	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));
 
@@ -510,37 +542,37 @@ gpart_show_geom(struct ggeom *gp, const 
 		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));
 	}

Modified: stable/8/sbin/geom/core/geom.c
==============================================================================
--- stable/8/sbin/geom/core/geom.c	Wed Jul 21 08:43:48 2010	(r210321)
+++ stable/8/sbin/geom/core/geom.c	Wed Jul 21 08:48:45 2010	(r210322)
@@ -249,94 +249,6 @@ set_option(struct gctl_req *req, struct 
 			    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) {
@@ -429,8 +341,7 @@ parse_arguments(struct g_command *cmd, s
 					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')

Modified: stable/8/sbin/geom/core/geom.h
==============================================================================
--- stable/8/sbin/geom/core/geom.h	Wed Jul 21 08:43:48 2010	(r210321)
+++ stable/8/sbin/geom/core/geom.h	Wed Jul 21 08:48:45 2010	(r210322)
@@ -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
 

Modified: stable/8/sbin/geom/misc/subr.c
==============================================================================
--- stable/8/sbin/geom/misc/subr.c	Wed Jul 21 08:43:48 2010	(r210321)
+++ stable/8/sbin/geom/misc/subr.c	Wed Jul 21 08:48:45 2010	(r210322)
@@ -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 || number < 0)
+		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 ((OFF_MAX / unit) < mult || (OFF_MAX / 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)
 {

Modified: stable/8/sbin/geom/misc/subr.h
==============================================================================
--- stable/8/sbin/geom/misc/subr.h	Wed Jul 21 08:43:48 2010	(r210321)
+++ stable/8/sbin/geom/misc/subr.h	Wed Jul 21 08:48:45 2010	(r210322)
@@ -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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007210848.o6L8mjVZ065832>