Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 Sep 2006 19:36:43 +0200
From:      Matthias Lederhofer <matled@gmx.net>
To:        freebsd-geom@freebsd.org
Subject:   [PATCH] geli: command to set the boot flag
Message-ID:  <20060910173643.GA22815@moooo.ath.cx>

next in thread | raw e-mail | index | archive | help
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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060910173643.GA22815>