summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/geom/class/part/geom_part.c168
1 files changed, 143 insertions, 25 deletions
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 94e44be..58dbc3c 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -56,6 +56,10 @@ uint32_t PUBSYM(version) = 0;
static char optional[] = "";
static char flags[] = "C";
+static char bootcode_param[] = "bootcode";
+static char index_param[] = "index";
+static char partcode_param[] = "partcode";
+
static void gpart_bootcode(struct gctl_req *, unsigned int);
static void gpart_show(struct gctl_req *, unsigned int);
@@ -64,14 +68,16 @@ struct g_command PUBSYM(class_commands)[] = {
{ 'b', "start", NULL, G_TYPE_STRING },
{ 's', "size", NULL, G_TYPE_STRING },
{ 't', "type", NULL, G_TYPE_STRING },
- { 'i', "index", optional, G_TYPE_STRING },
+ { 'i', index_param, optional, G_TYPE_STRING },
{ 'l', "label", optional, G_TYPE_STRING },
{ 'f', "flags", flags, G_TYPE_STRING },
G_OPT_SENTINEL },
"geom", NULL
},
{ "bootcode", 0, gpart_bootcode, {
- { 'b', "bootcode", NULL, G_TYPE_STRING },
+ { 'b', bootcode_param, optional, G_TYPE_STRING },
+ { 'p', partcode_param, optional, G_TYPE_STRING },
+ { 'i', index_param, optional, G_TYPE_STRING },
{ 'f', "flags", flags, G_TYPE_STRING },
G_OPT_SENTINEL },
"geom", NULL
@@ -85,7 +91,7 @@ struct g_command PUBSYM(class_commands)[] = {
"provider", NULL
},
{ "delete", 0, NULL, {
- { 'i', "index", NULL, G_TYPE_STRING },
+ { 'i', index_param, NULL, G_TYPE_STRING },
{ 'f', "flags", flags, G_TYPE_STRING },
G_OPT_SENTINEL },
"geom", NULL
@@ -95,7 +101,7 @@ struct g_command PUBSYM(class_commands)[] = {
G_OPT_SENTINEL },
"geom", NULL },
{ "modify", 0, NULL, {
- { 'i', "index", NULL, G_TYPE_STRING },
+ { 'i', index_param, NULL, G_TYPE_STRING },
{ 'l', "label", optional, G_TYPE_STRING },
{ 't', "type", optional, G_TYPE_STRING },
{ 'f', "flags", flags, G_TYPE_STRING },
@@ -286,38 +292,150 @@ gpart_show(struct gctl_req *req, unsigned int fl __unused)
geom_deletetree(&mesh);
}
-static void
-gpart_bootcode(struct gctl_req *req, unsigned int fl __unused)
+static void *
+gpart_bootfile_read(const char *bootfile, ssize_t *size)
{
struct stat sb;
- const char *bootfile;
void *code;
- int error, fd, size;
+ int fd;
- bootfile = gctl_get_ascii(req, "bootcode");
- if (bootfile == NULL)
- errx(EXIT_FAILURE, "Missing bootfile argument");
-
- error = stat(bootfile, &sb);
- if (error)
- errx(EXIT_FAILURE, "%s: not found", bootfile);
+ if (stat(bootfile, &sb) == -1)
+ err(EXIT_FAILURE, "%s", bootfile);
if (!S_ISREG(sb.st_mode))
errx(EXIT_FAILURE, "%s: not a regular file", bootfile);
- if (sb.st_size >= 1024*1024)
- errx(EXIT_FAILURE, "%s: file too big", bootfile);
+ if (sb.st_size == 0)
+ errx(EXIT_FAILURE, "%s: empty file", bootfile);
+ if (*size > 0 && sb.st_size >= *size)
+ errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile,
+ *size);
- size = sb.st_size;
+ *size = sb.st_size;
fd = open(bootfile, O_RDONLY);
if (fd == -1)
- errx(EXIT_FAILURE, "%s: unable to open", bootfile);
- code = malloc(size);
+ err(EXIT_FAILURE, "%s", bootfile);
+ code = malloc(*size);
if (code == NULL)
- errx(EXIT_FAILURE, "out of memory");
- if (read(fd, code, size) != size)
- errx(EXIT_FAILURE, "%s: unable to read", bootfile);
+ err(EXIT_FAILURE, NULL);
+ if (read(fd, code, *size) != *size)
+ err(EXIT_FAILURE, "%s", bootfile);
close(fd);
- gctl_change_param(req, "bootcode", size, code);
- gctl_issue(req);
+ return (code);
+}
+
+static void
+gpart_write_partcode(struct gctl_req *req, int idx, void *code, ssize_t size)
+{
+ char dsf[128];
+ struct gmesh mesh;
+ struct gclass *classp;
+ struct ggeom *gp;
+ struct gprovider *pp;
+ const char *s;
+ int error, fd;
+
+ s = gctl_get_ascii(req, "class");
+ if (s == NULL)
+ abort();
+ error = geom_gettree(&mesh);
+ if (error != 0)
+ errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+ classp = find_class(&mesh, s);
+ if (classp == NULL) {
+ geom_deletetree(&mesh);
+ errx(EXIT_FAILURE, "Class %s not found.", s);
+ }
+ s = gctl_get_ascii(req, "geom");
+ gp = find_geom(classp, s);
+ if (gp == NULL)
+ errx(EXIT_FAILURE, "No such geom: %s.", s);
+
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ s = find_provcfg(pp, "index");
+ if (s == NULL)
+ continue;
+ if (atoi(s) == idx)
+ break;
+ }
+
+ if (pp != NULL) {
+ snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name);
+ fd = open(dsf, O_WRONLY);
+ if (fd == -1)
+ err(EXIT_FAILURE, "%s", dsf);
+ if (lseek(fd, size, SEEK_SET) != size)
+ errx(EXIT_FAILURE, "%s: not enough space", dsf);
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ err(EXIT_FAILURE, "%s", dsf);
+ if (write(fd, code, size) != size)
+ err(EXIT_FAILURE, "%s", dsf);
+ close(fd);
+ } else
+ errx(EXIT_FAILURE, "invalid partition index");
+
+ geom_deletetree(&mesh);
+}
+
+static void
+gpart_bootcode(struct gctl_req *req, unsigned int fl __unused)
+{
+ const char *s;
+ char *sp;
+ void *bootcode, *partcode;
+ size_t bootsize, partsize;
+ int error, idx;
+
+ if (gctl_has_param(req, bootcode_param)) {
+ s = gctl_get_ascii(req, bootcode_param);
+ bootsize = 64 * 1024; /* Arbitrary limit. */
+ bootcode = gpart_bootfile_read(s, &bootsize);
+ error = gctl_change_param(req, bootcode_param, bootsize,
+ bootcode);
+ if (error)
+ errc(EXIT_FAILURE, error, "internal error");
+ } else {
+ bootcode = NULL;
+ bootsize = 0;
+ }
+
+ if (gctl_has_param(req, partcode_param)) {
+ s = gctl_get_ascii(req, partcode_param);
+ partsize = bootsize * 1024;
+ partcode = gpart_bootfile_read(s, &partsize);
+ error = gctl_delete_param(req, partcode_param);
+ if (error)
+ errc(EXIT_FAILURE, error, "internal error");
+ } else {
+ partcode = NULL;
+ partsize = 0;
+ }
+
+ if (gctl_has_param(req, index_param)) {
+ if (partcode == NULL)
+ errx(EXIT_FAILURE, "-i is only valid with -p");
+ s = gctl_get_ascii(req, index_param);
+ idx = strtol(s, &sp, 10);
+ if (idx < 1 || *s == '\0' || *sp != '\0')
+ errx(EXIT_FAILURE, "invalid partition index");
+ error = gctl_delete_param(req, index_param);
+ if (error)
+ errc(EXIT_FAILURE, error, "internal error");
+ } else
+ idx = 0;
+
+ if (partcode != NULL) {
+ if (idx == 0)
+ errx(EXIT_FAILURE, "missing -i option");
+ gpart_write_partcode(req, idx, partcode, partsize);
+ } else {
+ if (bootcode == NULL)
+ errx(EXIT_FAILURE, "no -b nor -p");
+ }
+
+ if (bootcode != NULL) {
+ s = gctl_issue(req);
+ if (s != NULL)
+ errx(EXIT_FAILURE, "%s", s);
+ }
}
OpenPOWER on IntegriCloud