aboutsummaryrefslogtreecommitdiff
path: root/sbin/gconcat
diff options
context:
space:
mode:
authorPawel Jakub Dawidek <pjd@FreeBSD.org>2004-02-19 16:02:08 +0000
committerPawel Jakub Dawidek <pjd@FreeBSD.org>2004-02-19 16:02:08 +0000
commitcc3ba4277b446f67f1d9f12bf732941b7bec94a4 (patch)
tree26eb1135d1ff416892671d7e163d48bdf5cbd088 /sbin/gconcat
parentb909c84bf2ef895044a6fcc3f5fb85666c257d2b (diff)
downloadsrc-cc3ba4277b446f67f1d9f12bf732941b7bec94a4.tar.gz
src-cc3ba4277b446f67f1d9f12bf732941b7bec94a4.zip
Add control utility for disk concatenation (GEOM_CONCAT class).
Reviewed by: phk, scottl Approved by: scottl (mentor)
Notes
Notes: svn path=/head/; revision=126010
Diffstat (limited to 'sbin/gconcat')
-rw-r--r--sbin/gconcat/Makefile11
-rw-r--r--sbin/gconcat/gconcat.c525
2 files changed, 536 insertions, 0 deletions
diff --git a/sbin/gconcat/Makefile b/sbin/gconcat/Makefile
new file mode 100644
index 000000000000..d2d5d7d5a075
--- /dev/null
+++ b/sbin/gconcat/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+PROG= gconcat
+#MAN= gconcat.8
+NOMAN= not_yet
+DPADD= ${LIBGEOM}
+LDADD= -lgeom
+WARNS?= 6
+CFLAGS+=-I${.CURDIR}/../../sys
+
+.include <bsd.prog.mk>
diff --git a/sbin/gconcat/gconcat.c b/sbin/gconcat/gconcat.c
new file mode 100644
index 000000000000..0b1644bbfe2c
--- /dev/null
+++ b/sbin/gconcat/gconcat.c
@@ -0,0 +1,525 @@
+/*-
+ * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <sys/disk.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <assert.h>
+#include <libgeom.h>
+#include <geom/concat/g_concat.h>
+
+
+enum {
+ UNSET,
+ CREATE,
+ DESTROY,
+ LABEL,
+ CLEAR,
+ LIST
+} action = UNSET;
+
+static const char *comm;
+static int force = 0;
+static int verbose = 0;
+
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s create [-v] name dev1 dev2 [dev3 [...]]\n"
+ " %s destroy [-fv] name\n"
+ " %s label [-v] name dev1 dev2 [dev3 [...]]\n"
+ " %s clear [-v] dev1 dev2 [dev3 [...]]\n"
+ " %s list\n",
+ comm, comm, comm, comm, comm);
+ exit(EXIT_FAILURE);
+}
+
+static void
+load_module(void)
+{
+
+ if (modfind("g_concat") < 0) {
+ /* Not present in kernel, try loading it. */
+ if (kldload("geom_concat") < 0 || modfind("g_concat") < 0) {
+ if (errno != EEXIST) {
+ errx(EXIT_FAILURE,
+ "geom_concat module not available!");
+ }
+ }
+ }
+}
+
+/*
+ * Remove ".concat" suffix if exists.
+ */
+static void
+cut_suffix(char *name)
+{
+
+ for (; *name != '\0'; name++) {
+ if (strcmp(name, ".concat") == 0) {
+ *name = '\0';
+ return;
+ }
+ }
+}
+
+/*
+ * Add ".concat" suffix if not exists.
+ */
+static char *
+add_suffix(char *name)
+{
+ char *newname, *s;
+ size_t size;
+
+ for (s = name; *s != '\0'; s++) {
+ if (strcmp(s, ".concat") == 0) {
+ newname = strdup(name);
+ if (newname == NULL)
+ errx(EXIT_FAILURE, "no memory");
+ return (newname);
+ }
+ }
+ /* 8 == strlen(".concat") + 1 */
+ size = strlen(name) + 8;
+ newname = malloc(size);
+ if (newname == NULL)
+ errx(EXIT_FAILURE, "no memory");
+ snprintf(newname, size, "%s.concat", name);
+
+ return (newname);
+}
+
+static struct gctl_req *
+init_gctl(const char *name, const char *verb)
+{
+ struct gctl_req *grq;
+
+ grq = gctl_get_handle();
+ gctl_ro_param(grq, "verb", -1, verb);
+ gctl_ro_param(grq, "class", -1, G_CONCAT_CLASS_NAME);
+ if (name != NULL)
+ gctl_ro_param(grq, "geom", -1, name);
+
+ return (grq);
+}
+
+static void
+concat_create(int argc, char *argv[])
+{
+ struct g_concat_metadata md;
+ struct gctl_req *grq;
+ const char *errstr;
+ char buf[256], *s;
+ unsigned i;
+
+ if (argc < 2)
+ usage();
+
+ cut_suffix(argv[0]);
+ strlcpy(md.md_name, argv[0], sizeof(md.md_name));
+ md.md_id = arc4random();
+
+ argc--;
+ argv++;
+
+ load_module();
+
+ if (verbose)
+ printf("Creating device %s:", md.md_name);
+
+ md.md_all = argc;
+ grq = init_gctl(NULL, "create device");
+ gctl_ro_param(grq, "metadata", sizeof(md), &md);
+ for (i = 0; i < (unsigned)argc; i++) {
+ snprintf(buf, sizeof(buf), "disk%u", i);
+ s = argv[i];
+ if (strncmp(s, _PATH_DEV, strlen(_PATH_DEV)) == 0)
+ s += strlen(_PATH_DEV);
+ if (verbose)
+ printf(" %s", s);
+ gctl_ro_param(grq, buf, -1, s);
+ }
+ if (verbose)
+ printf(".\n");
+ errstr = gctl_issue(grq);
+ if (errstr == NULL) {
+ gctl_free(grq);
+ if (verbose)
+ printf("Done.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ fprintf(stderr, "%s\n", errstr);
+ gctl_free(grq);
+ exit(EXIT_FAILURE);
+}
+
+static void
+concat_destroy(int argc, char *argv[])
+{
+ struct gctl_req *grq;
+ const char *errstr;
+ char *name;
+
+ if (argc != 1)
+ usage();
+
+ name = add_suffix(argv[0]);
+
+ if (verbose)
+ printf("Destroying device %s.\n", name);
+
+ grq = init_gctl(name, "destroy device");
+ gctl_ro_param(grq, "force", sizeof(force), &force);
+ errstr = gctl_issue(grq);
+ free(name);
+ if (errstr == NULL) {
+ gctl_free(grq);
+ if (verbose)
+ printf("Done.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ fprintf(stderr, "%s\n", errstr);
+ gctl_free(grq);
+ exit(EXIT_FAILURE);
+}
+
+static void
+concat_label(int argc, char *argv[])
+{
+ struct g_concat_metadata md;
+ unsigned sectorsize;
+ off_t mediasize;
+ u_char *sector;
+ int fd, i, status;
+
+ if (argc < 2)
+ usage();
+
+ load_module();
+
+ strlcpy(md.md_magic, G_CONCAT_MAGIC, sizeof(md.md_magic));
+ md.md_version = G_CONCAT_VERSION;
+ strlcpy(md.md_name, argv[0], sizeof(md.md_name));
+ md.md_id = arc4random();
+
+ argc--;
+ argv++;
+ status = EXIT_SUCCESS;
+
+ md.md_all = argc;
+ for (i = 0; i < argc; i++) {
+ fd = open(argv[i], O_WRONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Can't open %s: %s.\n", argv[i],
+ strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ fprintf(stderr, "Can't get media size for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
+ fprintf(stderr, "Can't get sector size for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ assert(sectorsize >= sizeof(md));
+ sector = malloc(sectorsize);
+ if (sector == NULL) {
+ fprintf(stderr, "Can't allocate memory for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ md.md_no = i;
+ concat_metadata_encode(&md, sector);
+ if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ fprintf(stderr, "Problems with storing metadata on %s: "
+ "%s.\n", argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ free(sector);
+ continue;
+ }
+ free(sector);
+ close(fd);
+ if (verbose)
+ printf("Metadata value stored on %s.\n", argv[i]);
+ }
+
+ exit(status);
+}
+
+static void
+concat_clear(int argc, char *argv[])
+{
+ struct g_concat_metadata md;
+ unsigned sectorsize;
+ off_t mediasize;
+ u_char *sector;
+ int fd, i, status;
+
+ if (argc < 1)
+ usage();
+
+ status = EXIT_SUCCESS;
+
+ md.md_all = argc;
+ for (i = 0; i < argc; i++) {
+ fd = open(argv[i], O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "Can't open %s: %s.\n", argv[i],
+ strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
+ fprintf(stderr, "Can't get media size for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
+ fprintf(stderr, "Can't get sector size for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ assert(sectorsize >= sizeof(md));
+ sector = malloc(sectorsize);
+ if (sector == NULL) {
+ fprintf(stderr, "Can't allocate memory for %s: %s.\n",
+ argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ continue;
+ }
+ if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ fprintf(stderr, "Problems with reading metadata from "
+ "%s: %s.\n", argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ free(sector);
+ continue;
+ }
+ concat_metadata_decode(sector, &md);
+ if (strcmp(md.md_magic, G_CONCAT_MAGIC) != 0) {
+ fprintf(stderr, "Cannot find metadata to clear on "
+ "%s.\n", argv[i]);
+ status = EXIT_FAILURE;
+ free(sector);
+ continue;
+ }
+ bzero(sector, sectorsize);
+ if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
+ (ssize_t)sectorsize) {
+ fprintf(stderr, "Problems with clearing metadata on "
+ "%s: %s.\n", argv[i], strerror(errno));
+ status = EXIT_FAILURE;
+ free(sector);
+ continue;
+ }
+ free(sector);
+ close(fd);
+ if (verbose)
+ printf("Metadata cleared on %s.\n", argv[i]);
+ }
+
+ exit(status);
+}
+
+static struct gclass *
+find_class(struct gmesh *mesh, const char *name)
+{
+ struct gclass *class;
+
+ LIST_FOREACH(class, &mesh->class, class) {
+ if (strcmp(class->name, name) == 0)
+ return (class);
+ }
+
+ return (NULL);
+}
+
+static const char *
+get_conf(struct ggeom *gp, const char *name)
+{
+ struct gconfig *conf;
+
+ LIST_FOREACH(conf, &gp->config, config) {
+ if (strcmp(conf->name, name) == 0)
+ return (conf->val);
+ }
+
+ return (NULL);
+}
+
+static void
+show_config(struct ggeom *gp)
+{
+ struct gprovider *pp;
+ struct gconsumer *cp;
+
+ pp = LIST_FIRST(&gp->provider);
+ if (pp == NULL)
+ return;
+
+ printf(" NAME: %s\n", pp->name);
+ printf(" id: %s\n", get_conf(gp, "id"));
+ printf(" type: %s\n", get_conf(gp, "type"));
+ printf(" mediasize: %jd\n", pp->mediasize);
+ printf("sectorsize: %u\n", pp->sectorsize);
+ printf(" mode: %s\n", pp->mode);
+ printf(" providers:");
+ LIST_FOREACH(cp, &gp->consumer, consumer) {
+ printf(" %s", cp->provider->name);
+ }
+ printf("\n");
+}
+
+static void
+concat_list(void)
+{
+ struct gmesh mesh;
+ struct gclass *class;
+ struct ggeom *gp;
+ int error;
+
+ error = geom_gettree(&mesh);
+ if (error != 0)
+ exit(EXIT_FAILURE);
+
+ class = find_class(&mesh, G_CONCAT_CLASS_NAME);
+ if (class == NULL) {
+ geom_deletetree(&mesh);
+ exit(EXIT_SUCCESS);
+ }
+
+ LIST_FOREACH(gp, &class->geom, geom) {
+ show_config(gp);
+ }
+
+ geom_deletetree(&mesh);
+ exit(EXIT_SUCCESS);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ comm = basename(argv[0]);
+
+ if (argc < 2)
+ usage();
+
+ if (strcasecmp(argv[1], "create") == 0)
+ action = CREATE;
+ else if (strcasecmp(argv[1], "destroy") == 0)
+ action = DESTROY;
+ else if (strcasecmp(argv[1], "label") == 0)
+ action = LABEL;
+ else if (strcasecmp(argv[1], "clear") == 0)
+ action = CLEAR;
+ else if (strcasecmp(argv[1], "list") == 0)
+ action = LIST;
+ else
+ usage();
+ argv++;
+ argc--;
+
+ while ((ch = getopt(argc, argv, "fv")) != -1) {
+ switch (ch) {
+ case 'f':
+ if (action != DESTROY)
+ usage();
+ force = 1;
+ break;
+ case 'v':
+ /* -v options is only not permited while listing */
+ if (action == LIST)
+ usage();
+ verbose = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (action) {
+ case CREATE:
+ concat_create(argc, argv);
+ /* NOTREACHED */
+ break;
+ case DESTROY:
+ concat_destroy(argc, argv);
+ /* NOTREACHED */
+ break;
+ case LABEL:
+ concat_label(argc, argv);
+ /* NOTREACHED */
+ break;
+ case CLEAR:
+ concat_clear(argc, argv);
+ /* NOTREACHED */
+ break;
+ case LIST:
+ concat_list();
+ /* NOTREACHED */
+ break;
+ case UNSET:
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ exit(EXIT_SUCCESS);
+}