mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-20 15:43:16 +00:00
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:
parent
59458baf2b
commit
3022de951b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179629
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user