summaryrefslogtreecommitdiffstats
path: root/sbin/geom
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2009-06-08 02:13:24 +0000
committermarcel <marcel@FreeBSD.org>2009-06-08 02:13:24 +0000
commit87bc9febc24f4075ea6e618177947dbcd8c0a353 (patch)
tree88fcba8b177a0e176f8883f3eda2d9523342adc8 /sbin/geom
parent40420f94ac24ed40d16c174a5fcecda87179a6c6 (diff)
downloadFreeBSD-src-87bc9febc24f4075ea6e618177947dbcd8c0a353.zip
FreeBSD-src-87bc9febc24f4075ea6e618177947dbcd8c0a353.tar.gz
Make the size (-s) and start (-b) parameters of the add verb optional.
The missing parameter(s) are automatically filled-in.
Diffstat (limited to 'sbin/geom')
-rw-r--r--sbin/geom/class/part/geom_part.c128
1 files changed, 126 insertions, 2 deletions
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 51c890c..84dfe58 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
uint32_t PUBSYM(lib_version) = G_LIB_VERSION;
uint32_t PUBSYM(version) = 0;
+static char autofill[] = "*";
static char optional[] = "";
static char flags[] = "C";
@@ -68,8 +69,8 @@ static void gpart_show(struct gctl_req *, unsigned int);
struct g_command PUBSYM(class_commands)[] = {
{ "add", 0, gpart_issue, {
- { 'b', "start", NULL, G_TYPE_ASCLBA },
- { 's', "size", NULL, G_TYPE_ASCLBA },
+ { 'b', "start", autofill, G_TYPE_ASCLBA },
+ { 's', "size", autofill, G_TYPE_ASCLBA },
{ 't', "type", NULL, G_TYPE_STRING },
{ 'i', index_param, optional, G_TYPE_ASCNUM },
{ 'l', "label", optional, G_TYPE_STRING },
@@ -240,6 +241,121 @@ fmtattrib(struct gprovider *pp)
return (buf);
}
+static int
+gpart_autofill(struct gctl_req *req)
+{
+ struct gmesh mesh;
+ 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;
+ const char *s;
+ char *val;
+ int error, has_size, has_start;
+
+ s = gctl_get_ascii(req, "verb");
+ 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);
+ cp = find_class(&mesh, gctl_get_ascii(req, "class"));
+ gp = find_geom(cp, gctl_get_ascii(req, "geom"));
+ first = atoll(find_geomcfg(gp, "first"));
+ last = atoll(find_geomcfg(gp, "last"));
+ 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;
+ } else
+ lba = atoll(s);
+
+ if (first < lba) {
+ /* Free space [first, lba> */
+ len = lba - first;
+ if (has_size) {
+ if (len >= size && len - size < grade) {
+ start = first;
+ grade = len - size;
+ }
+ } else if (has_start) {
+ if (start >= first && start < lba) {
+ size = lba - start;
+ grade = start - first;
+ }
+ } else {
+ if (grade == ~0ULL || len > size) {
+ start = first;
+ size = len;
+ grade = 0;
+ }
+ }
+ }
+
+ s = find_provcfg(pp, "end");
+ if (s == NULL) {
+ s = find_provcfg(pp, "length");
+ first = lba + atoll(s) / pp->lg_sectorsize;
+ } else
+ first = atoll(s) + 1;
+ }
+ if (first <= last) {
+ /* Free space [first-last] */
+ len = last - first + 1;
+ if (has_size) {
+ if (len >= size && len - size < grade) {
+ start = first;
+ grade = len - size;
+ }
+ } else if (has_start) {
+ if (start >= first && start <= last) {
+ size = last - start + 1;
+ grade = start - first;
+ }
+ } else {
+ if (grade == ~0ULL || len > size) {
+ start = first;
+ size = len;
+ grade = 0;
+ }
+ }
+ }
+
+ if (grade == ~0ULL)
+ return (ENOSPC);
+
+ if (!has_size) {
+ asprintf(&val, "%jd", size);
+ if (val == NULL)
+ return (ENOMEM);
+ gctl_change_param(req, "size", -1, val);
+ }
+ if (!has_start) {
+ asprintf(&val, "%jd", start);
+ if (val == NULL)
+ return (ENOMEM);
+ gctl_change_param(req, "start", -1, val);
+ }
+ return (0);
+}
+
static void
gpart_show_geom(struct ggeom *gp, const char *element)
{
@@ -531,6 +647,14 @@ gpart_issue(struct gctl_req *req, unsigned int fl __unused)
const char *errstr;
int error, status;
+ /* autofill parameters (if applicable). */
+ error = gpart_autofill(req);
+ if (error) {
+ warnc(error, "autofill");
+ status = EXIT_FAILURE;
+ goto done;
+ }
+
bzero(buf, sizeof(buf));
gctl_rw_param(req, "output", sizeof(buf), buf);
errstr = gctl_issue(req);
OpenPOWER on IntegriCloud