From d0148d1d0e3aa38270161af616e93efadcf9d38e Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Mon, 8 Jun 2009 02:13:24 +0000 Subject: [PATCH] Make the size (-s) and start (-b) parameters of the add verb optional. The missing parameter(s) are automatically filled-in. --- sbin/geom/class/part/geom_part.c | 128 ++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index 51c890c5b4d2..84dfe58a57c4 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);