From owner-freebsd-geom@FreeBSD.ORG Sun Sep 10 17:36:52 2006 Return-Path: X-Original-To: freebsd-geom@freebsd.org Delivered-To: freebsd-geom@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4D6CA16A47E for ; Sun, 10 Sep 2006 17:36:52 +0000 (UTC) (envelope-from matled@gmx.net) Received: from moooo.ath.cx (moooo.ath.cx [85.116.203.178]) by mx1.FreeBSD.org (Postfix) with ESMTP id BAB1D43D70 for ; Sun, 10 Sep 2006 17:36:45 +0000 (GMT) (envelope-from matled@gmx.net) Date: Sun, 10 Sep 2006 19:36:43 +0200 From: Matthias Lederhofer To: freebsd-geom@freebsd.org Message-ID: <20060910173643.GA22815@moooo.ath.cx> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Subject: [PATCH] geli: command to set the boot flag X-BeenThere: freebsd-geom@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: GEOM-specific discussions and implementations List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Sep 2006 17:36:52 -0000 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