Enhance the bootcode command to also allow bootcode to be written

to a partition. This avoids that users need to use dd(1) to install
boot code (as is needed for VTOC8 and booting GPT on PCs).
This commit is contained in:
Marcel Moolenaar 2008-06-06 23:58:29 +00:00
parent 59458baf2b
commit 3022de951b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179629

View File

@ -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);
}
}