[PATCH] geli: command to set the boot flag
Matthias Lederhofer
matled at gmx.net
Sun Sep 10 10:36:52 PDT 2006
I did not find any way to set the boot flag other than init. Here is
a patch adding a new command setboot which shows the current value
when only a provider is passed or sets it to the value specified on
the command line.
Probably this should have another name and/or another way to pass the
parameters, I can also change this if someone tells me how this should
be done.
---
geom_eli.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/geom_eli.c b/geom_eli.c
index 07026fc..f90e974 100644
--- a/geom_eli.c
+++ b/geom_eli.c
@@ -71,6 +71,7 @@ static void eli_backup(struct gctl_req *
static void eli_restore(struct gctl_req *req);
static void eli_clear(struct gctl_req *req);
static void eli_dump(struct gctl_req *req);
+static void eli_setboot(struct gctl_req *req);
/*
* Available commands:
@@ -191,6 +192,9 @@ struct g_command class_commands[] = {
{ "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
"[-v] prov ..."
},
+ { "setboot", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS,
+ "[-v] prov [value]"
+ },
G_CMD_SENTINEL
};
@@ -251,6 +255,8 @@ eli_main(struct gctl_req *req, unsigned
eli_dump(req);
else if (strcmp(name, "clear") == 0)
eli_clear(req);
+ else if (strcmp(name, "setboot") == 0)
+ eli_setboot(req);
else
gctl_error(req, "Unknown command: %s.", name);
}
@@ -1129,3 +1135,106 @@ eli_dump(struct gctl_req *req)
printf("\n");
}
}
+
+static void
+eli_setboot(struct gctl_req *req)
+{
+ struct g_eli_metadata md;
+ const char *prov;
+ unsigned secsize;
+ unsigned char *sector;
+ off_t mediasize;
+ int nargs, provfd, value;
+
+ value = -1;
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs == 2) {
+ const char *arg = gctl_get_ascii(req, "arg1");
+ if (!strcmp(arg, "0")) {
+ value = 0;
+ } else if (!strcmp(arg, "1")) {
+ value = 1;
+ } else {
+ gctl_error(req, "Invalid argument for the new value.");
+ return;
+ }
+ } else if (nargs != 1) {
+ gctl_error(req, "Invalid number of arguments.");
+ return;
+ }
+ prov = gctl_get_ascii(req, "arg0");
+
+ provfd = -1;
+ sector = NULL;
+ secsize = 0;
+
+ provfd = open(prov, (value == -1) ? O_RDONLY : O_RDWR);
+ if (provfd == -1 && errno == ENOENT && prov[0] != '/') {
+ char devprov[MAXPATHLEN];
+
+ snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov);
+ provfd = open(devprov, (value == -1) ? O_RDONLY : O_RDWR);
+ }
+ if (provfd == -1) {
+ gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno));
+ return;
+ }
+
+ mediasize = g_get_mediasize(prov);
+ secsize = g_get_sectorsize(prov);
+ if (mediasize == 0 || secsize == 0) {
+ gctl_error(req, "Cannot get informations about %s: %s.", prov,
+ strerror(errno));
+ return;
+ }
+
+ sector = malloc(secsize);
+ if (sector == NULL) {
+ gctl_error(req, "Cannot allocate memory.");
+ return;
+ }
+
+ /* Read metadata from the provider. */
+ if (pread(provfd, sector, secsize, mediasize - secsize) !=
+ (ssize_t)secsize) {
+ gctl_error(req, "Cannot read metadata: %s.", strerror(errno));
+ goto out;
+ }
+ /* Check if this is geli provider. */
+ if (eli_metadata_decode(sector, &md) != 0) {
+ gctl_error(req, "MD5 hash mismatch: not a geli provider?");
+ goto out;
+ }
+ /* Show current value. */
+ if (value == -1) {
+ printf("boot flag: %d\n", !!(md.md_flags & G_ELI_FLAG_BOOT));
+ goto out;
+ }
+ /* Don't actually rewrite the metadata, nothing to change. */
+ if ((value && (md.md_flags & G_ELI_FLAG_BOOT)) ||
+ (!value && !(md.md_flags & G_ELI_FLAG_BOOT))) {
+ printf("boot flag: %d -> %d\n",
+ !!(md.md_flags & G_ELI_FLAG_BOOT),
+ !!(md.md_flags & G_ELI_FLAG_BOOT));
+ goto out;
+ }
+ /* Toggle bootflag. */
+ printf("boot flag: %d -> %d\n",
+ !!(md.md_flags & G_ELI_FLAG_BOOT),
+ !(md.md_flags & G_ELI_FLAG_BOOT));
+ md.md_flags ^= G_ELI_FLAG_BOOT;
+ eli_metadata_encode(&md, sector);
+ /* Write metadata to the provider. */
+ if (pwrite(provfd, sector, secsize, mediasize - secsize) !=
+ (ssize_t)secsize) {
+ gctl_error(req, "Cannot write metadata: %s.", strerror(errno));
+ goto out;
+ }
+out:
+ if (provfd > 0)
+ close(provfd);
+ if (sector != NULL) {
+ bzero(sector, secsize);
+ free(sector);
+ }
+}
--
1.4.1
More information about the freebsd-geom
mailing list