Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Nov 2010 21:48:26 +0300
From:      "Andrey V. Elsukov" <bu7cher@yandex.ru>
To:        freebsd-geom@freebsd.org
Cc:        Marcel Moolenaar <marcel@freebsd.org>, Pawel Jakub Dawidek <pjd@FreeBSD.org>, Andriy Gapon <avg@freebsd.org>
Subject:   [RFC][patch] backup/restore partition table with gpart(8)
Message-ID:  <4CE6C67A.2020904@yandex.ru>

next in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enig9F551532C9939F52D7371402
Content-Type: multipart/mixed; boundary="------------050905090402080807000203"

This is a multi-part message in MIME format.
--------------050905090402080807000203
Content-Type: text/plain; charset=KOI8-R
Content-Transfer-Encoding: quoted-printable

Hi,

So, first working patch is attached.
Two new sub-commands added to gpart(8):
	gpart backup [-l] geom
	gpart restore [-F] [-f flags] geom [...]

"backup" command does dump partition table in simple text format
to standard output. With -l specified it does dump with partition's
labels. The format is simple, e.g:
# gpart show ada0
=3D>        34  1250263661  ada0  GPT  (596G)
          34         256     1  freebsd-boot  (128K)
         290     8388608     2  freebsd-swap  (4.0G)
     8388898  1241874797     3  freebsd-zfs  (592G)

# gpart show -l ada0
=3D>        34  1250263661  ada0  GPT  (596G)
          34         256     1  boot00  (128K)
         290     8388608     2  swap00  (4.0G)
     8388898  1241874797     3  zfs00  (592G)

# gpart backup ada0
GPT 128
1   freebsd-boot         34        256
2   freebsd-swap        290    8388608
3    freebsd-zfs    8388898 1241874797
# gpart backup -l ada0
GPT 128
1   freebsd-boot         34        256 boot00
2   freebsd-swap        290    8388608 swap00
3    freebsd-zfs    8388898 1241874797 zfs00

First line - partition scheme name and number of entries.
Next lines - partition table entries in the following format:
<index> <type> <start> <size> [label] [attributes]

Last two fields are optional.

"restore" command reads these commands from standard input.
With -F option it destroys partition table on specified geoms before
doing restore.

gpart does try to done all commands with auto-commit disabled. And
it does rollback when error occurs. If all commands successfully done
it calls "commit".

Small example:
# mdconfig -s 100m
md0
# mdconfig -s 100m
md1
# mdconfig -s 100m
md2
# gpart create -s gpt md0
md0 created
# gpart add -t freebsd-boot -s 128k md0
md0p1 added
# gpart add -t freebsd-zfs md0
md0p2 added
# gpart show md0
=3D>    34  204733  md0  GPT  (100M)
      34     256    1  freebsd-boot  (128K)
     290  204477    2  freebsd-zfs  (100M)

# gpart backup md0 | gpart restore md1 md2
# gpart show md0 md1 md2
=3D>    34  204733  md0  GPT  (100M)
      34     256    1  freebsd-boot  (128K)
     290  204477    2  freebsd-zfs  (100M)

=3D>    34  204733  md1  GPT  (100M)
      34     256    1  freebsd-boot  (128K)
     290  204477    2  freebsd-zfs  (100M)

=3D>    34  204733  md2  GPT  (100M)
      34     256    1  freebsd-boot  (128K)
     290  204477    2  freebsd-zfs  (100M)

# gpart restore -F md0 md1
mbr 4
1 freebsd * * [active]
^D
# gpart show md0 md1
=3D>     9  204786  md0  MBR  (100M)
       9  204786    1  freebsd  [active]  (100M)

=3D>     9  204786  md1  MBR  (100M)
       9  204786    1  freebsd  [active]  (100M)

--=20
WBR, Andrey V. Elsukov

--------------050905090402080807000203
Content-Type: text/plain;
 name="gpart_backup_restore.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="gpart_backup_restore.diff"

Index: head/sbin/geom/class/part/geom_part.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- head/sbin/geom/class/part/geom_part.c	(revision 215454)
+++ head/sbin/geom/class/part/geom_part.c	(working copy)
@@ -85,6 +85,8 @@ static int gpart_show_hasopt(struct gctl_req *, co
 static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t);
 static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
 static void gpart_print_error(const char *);
+static void gpart_backup(struct gctl_req *, unsigned int);
+static void gpart_restore(struct gctl_req *, unsigned int);
=20
 struct g_command PUBSYM(class_commands)[] =3D {
 	{ "add", 0, gpart_issue, {
@@ -97,6 +99,11 @@ struct g_command PUBSYM(class_commands)[] =3D {
 		G_OPT_SENTINEL },
 	    "[-b start] [-s size] -t type [-i index] [-l label] [-f flags] geom=
"
 	},
+	{ "backup", 0, gpart_backup, {
+		{ 'l', "backup_labels", NULL, G_TYPE_BOOL},
+		G_OPT_SENTINEL },
+	    "[-l] geom"
+	},
 	{ "bootcode", 0, gpart_bootcode, {
 		{ 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
 		{ 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
@@ -165,6 +172,12 @@ struct g_command PUBSYM(class_commands)[] =3D {
 		G_OPT_SENTINEL },
 	    "[-s size] -i index [-f flags] geom"
 	},
+	{ "restore", 0, gpart_restore, {
+		{ 'F', "force", NULL, G_TYPE_BOOL },
+		{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
+		G_OPT_SENTINEL },
+	    "[-F] [-f flags] geom ..."
+	},
 	{ "recover", 0, gpart_issue, {
 		{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
 		G_OPT_SENTINEL },
@@ -654,6 +667,279 @@ gpart_show(struct gctl_req *req, unsigned int fl _
 	geom_deletetree(&mesh);
 }
=20
+static void
+gpart_backup(struct gctl_req *req, unsigned int fl __unused)
+{
+	struct gmesh mesh;
+	struct gclass *classp;
+	struct gprovider *pp;
+	struct ggeom *gp;
+	const char *s, *scheme;
+	off_t sector, end;
+	off_t length, secsz;
+	int error, labels, i, windex, wblocks, wtype;
+
+	if (gctl_get_int(req, "nargs") !=3D 1)
+		errx(EXIT_FAILURE, "Invalid number of arguments.");
+	error =3D geom_gettree(&mesh);
+	if (error !=3D 0)
+		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+	s =3D gctl_get_ascii(req, "class");
+	if (s =3D=3D NULL)
+		abort();
+	classp =3D find_class(&mesh, s);
+	if (classp =3D=3D NULL) {
+		geom_deletetree(&mesh);
+		errx(EXIT_FAILURE, "Class %s not found.", s);
+	}
+	s =3D gctl_get_ascii(req, "arg0");
+	if (s =3D=3D NULL)
+		abort();
+	labels =3D gctl_get_int(req, "backup_labels");
+	gp =3D find_geom(classp, s);
+	if (gp =3D=3D NULL)
+		errx(EXIT_FAILURE, "No such geom: %s.", s);
+	scheme =3D find_geomcfg(gp, "scheme");
+	if (scheme =3D=3D NULL)
+		abort();
+	pp =3D LIST_FIRST(&gp->lg_consumer)->lg_provider;
+	secsz =3D pp->lg_sectorsize;
+	s =3D find_geomcfg(gp, "last");
+	wblocks =3D strlen(s);
+	wtype =3D 0;
+	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+		s =3D find_provcfg(pp, "type");
+		i =3D strlen(s);
+		if (i > wtype)
+			wtype =3D i;
+	}
+	s =3D find_geomcfg(gp, "entries");
+	windex =3D strlen(s);
+	printf("%s %s\n", scheme, s);
+	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+		s =3D find_provcfg(pp, "start");
+		if (s =3D=3D NULL) {
+			s =3D find_provcfg(pp, "offset");
+			sector =3D (off_t)strtoimax(s, NULL, 0) / secsz;
+		} else
+			sector =3D (off_t)strtoimax(s, NULL, 0);
+
+		s =3D find_provcfg(pp, "end");
+		if (s =3D=3D NULL) {
+			s =3D find_provcfg(pp, "length");
+			length =3D (off_t)strtoimax(s, NULL, 0) / secsz;
+		} else {
+			end =3D (off_t)strtoimax(s, NULL, 0);
+			length =3D end - sector + 1;
+		}
+		s =3D find_provcfg(pp, "label");
+		printf("%-*s %*s %*jd %*jd",
+		    windex, find_provcfg(pp, "index"),
+		    wtype, find_provcfg(pp, "type"),
+		    wblocks, (intmax_t)sector,
+		    wblocks, (intmax_t)length);
+		if (labels && s !=3D NULL)
+			printf(" %s", s);
+		printf(" %s\n", fmtattrib(pp));
+	}
+	geom_deletetree(&mesh);
+}
+
+static void
+gpart_restore(struct gctl_req *req, unsigned int fl __unused)
+{
+	struct gmesh mesh;
+	struct gclass *classp;
+	struct gctl_req *r;
+	struct ggeom *gp;
+	const char *s, *flags, *errstr, *label;
+	char **ap, *argv[6], line[BUFSIZ], *pline;
+	int error, forced, i, l, nargs, created;
+	intmax_t n;
+
+	nargs =3D gctl_get_int(req, "nargs");
+	if (nargs < 1)
+		errx(EXIT_FAILURE, "Invalid number of arguments.");
+
+	forced =3D gctl_get_int(req, "force");
+	flags =3D gctl_get_ascii(req, "flags");
+	s =3D gctl_get_ascii(req, "class");
+	if (s =3D=3D NULL)
+		abort();
+	error =3D geom_gettree(&mesh);
+	if (error !=3D 0)
+		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+	classp =3D find_class(&mesh, s);
+	if (classp =3D=3D NULL) {
+		geom_deletetree(&mesh);
+		errx(EXIT_FAILURE, "Class %s not found.", s);
+	}
+	if (forced) {
+		/* destroy existent partition table before restore */
+		for (i =3D 0; i < nargs; i++) {
+			s =3D gctl_get_ascii(req, "arg%d", i);
+			gp =3D find_geom(classp, s);
+			if (gp !=3D NULL) {
+				r =3D gctl_get_handle();
+				gctl_ro_param(r, "class", -1,
+				    classp->lg_name);
+				gctl_ro_param(r, "verb", -1, "destroy");
+				gctl_ro_param(r, "flags", -1, "restore");
+				gctl_ro_param(r, "force", sizeof(forced),
+				    &forced);
+				gctl_ro_param(r, "arg0", -1, s);
+				errstr =3D gctl_issue(r);
+				if (errstr !=3D NULL && errstr[0] !=3D '\0') {
+					gpart_print_error(errstr);
+					gctl_free(r);
+					goto backout;
+				}
+				gctl_free(r);
+			}
+		}
+	}
+	created =3D 0;
+	while (fgets(line, sizeof(line) - 1, stdin)) {
+		/* Format of backup entries:
+		 * <scheme name> <number of entries>
+		 * <index> <type> <start> <size> [label] ['['attrib[,attrib]']']
+		 */
+		pline =3D (char *)line;
+		pline[strlen(line) - 1] =3D 0;
+		for (ap =3D argv, l =3D 0;
+		    (*ap =3D strsep(&pline, " \t")) !=3D NULL;)
+			if (**ap !=3D '\0' && ++ap >=3D &argv[6])
+				break;
+		l =3D ap - &argv[0];
+		label =3D pline =3D NULL;
+		if (l =3D=3D 2) { /* create table */
+			if (created)
+				errx(EXIT_FAILURE, "Incorrect backup format.");
+			n =3D atoi(argv[1]);
+			for (i =3D 0; i < nargs; i++) {
+				s =3D gctl_get_ascii(req, "arg%d", i);
+				r =3D gctl_get_handle();
+				n =3D strtoimax(argv[1], NULL, 0);
+				gctl_ro_param(r, "class", -1,
+				    classp->lg_name);
+				gctl_ro_param(r, "verb", -1, "create");
+				gctl_ro_param(r, "scheme", -1, argv[0]);
+				gctl_ro_param(r, "entries", sizeof(n), &n);
+				gctl_ro_param(r, "flags", -1, "restore");
+				gctl_ro_param(r, "arg0", -1, s);
+				errstr =3D gctl_issue(r);
+				if (errstr !=3D NULL && errstr[0] !=3D '\0') {
+					gpart_print_error(errstr);
+					gctl_free(r);
+					goto backout;
+				}
+				gctl_free(r);
+			}
+			created =3D 1;
+			continue;
+		} else if (l < 4 || created =3D=3D 0)
+			errx(EXIT_FAILURE, "Incorrect backup format.");
+		else if (l =3D=3D 5) {
+			if (strchr(argv[4], '[') =3D=3D NULL)
+				label =3D argv[4];
+			else
+				pline =3D argv[4];
+		} else if (l =3D=3D 6) {
+			label =3D argv[4];
+			pline =3D argv[5];
+		}
+		/* Add partitions to each table */
+		for (i =3D 0; i < nargs; i++) {
+			s =3D gctl_get_ascii(req, "arg%d", i);
+			r =3D gctl_get_handle();
+			n =3D strtoimax(argv[0], NULL, 0);
+			gctl_ro_param(r, "class", -1, classp->lg_name);
+			gctl_ro_param(r, "verb", -1, "add");
+			gctl_ro_param(r, "flags", -1, "restore");
+			gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n);
+			gctl_ro_param(r, "type", -1, argv[1]);
+			gctl_ro_param(r, "start", -1, argv[2]);
+			gctl_ro_param(r, "size", -1, argv[3]);
+			if (label !=3D NULL)
+				gctl_ro_param(r, "label", -1, argv[4]);
+			gctl_ro_param(r, "arg0", -1, s);
+			error =3D gpart_autofill(r);
+			if (error !=3D 0)
+				errc(EXIT_FAILURE, error, "autofill");
+			errstr =3D gctl_issue(r);
+			if (errstr !=3D NULL && errstr[0] !=3D '\0') {
+				gpart_print_error(errstr);
+				gctl_free(r);
+				goto backout;
+			}
+			gctl_free(r);
+		}
+		if (pline =3D=3D NULL || *pline !=3D '[')
+			continue;
+		/* set attributes */
+		pline++;
+		for (ap =3D argv, l =3D 0;
+		    (*ap =3D strsep(&pline, ",]")) !=3D NULL;)
+			if (**ap !=3D '\0' && ++ap >=3D &argv[6])
+				break;
+		for (i =3D 0; i < nargs; i++) {
+			l =3D ap - &argv[0];
+			s =3D gctl_get_ascii(req, "arg%d", i);
+			while (l > 0) {
+				r =3D gctl_get_handle();
+				gctl_ro_param(r, "class", -1, classp->lg_name);
+				gctl_ro_param(r, "verb", -1, "set");
+				gctl_ro_param(r, "flags", -1, "restore");
+				gctl_ro_param(r, GPART_PARAM_INDEX,
+				    sizeof(n), &n);
+				gctl_ro_param(r, "attrib", -1, argv[--l]);
+				gctl_ro_param(r, "arg0", -1, s);
+				errstr =3D gctl_issue(r);
+				if (errstr !=3D NULL && errstr[0] !=3D '\0') {
+					gpart_print_error(errstr);
+					gctl_free(r);
+					goto backout;
+				}
+				gctl_free(r);
+			}
+		}
+	}
+	/* commit changes if needed */
+	if (strchr(flags, 'C') !=3D NULL) {
+		for (i =3D 0; i < nargs; i++) {
+			s =3D gctl_get_ascii(req, "arg%d", i);
+			r =3D gctl_get_handle();
+			gctl_ro_param(r, "class", -1, classp->lg_name);
+			gctl_ro_param(r, "verb", -1, "commit");
+			gctl_ro_param(r, "arg0", -1, s);
+			errstr =3D gctl_issue(r);
+			if (errstr !=3D NULL && errstr[0] !=3D '\0') {
+				gpart_print_error(errstr);
+				gctl_free(r);
+				goto backout;
+			}
+			gctl_free(r);
+		}
+	}
+	gctl_free(req);
+	geom_deletetree(&mesh);
+	exit(EXIT_SUCCESS);
+
+backout:
+	for (i =3D 0; i < nargs; i++) {
+		s =3D gctl_get_ascii(req, "arg%d", i);
+		r =3D gctl_get_handle();
+		gctl_ro_param(r, "class", -1, classp->lg_name);
+		gctl_ro_param(r, "verb", -1, "undo");
+		gctl_ro_param(r, "arg0", -1, s);
+		gctl_issue(r);
+		gctl_free(r);
+	}
+	gctl_free(req);
+	geom_deletetree(&mesh);
+	exit(EXIT_FAILURE);
+}
+
 static void *
 gpart_bootfile_read(const char *bootfile, ssize_t *size)
 {

--------------050905090402080807000203--

--------------enig9F551532C9939F52D7371402
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.16 (FreeBSD)

iQEcBAEBAgAGBQJM5saBAAoJEAHF6gQQyKF6f34H/3hd9poaKD7p5SfL0A+AdkGt
Qw0hYnHyhxdGL4eBeaqUWZrbl2p2ZtpQ5ITbEcTXW5D/hauHPD7PIYTMipsmfUUU
RSc2zMPmMKlHiskDv39Ea7cJhUf/5uPBsg1I8vqed73dohU3sl5wboRVhjhso849
uy9HnBSv8/MG/ZMqFwuiCN/VLvOz26Il9tCtp8jAVDRzmCBv11f/5xnZV94Gh6qp
RR1C4OV7oJ3xDffBMo6gvUPhCPklV0WRvPoRq6Xr+ZCOO1GlXuUGPYLwN+PCYyvR
RXS02fTjy+uT6N/58IjILIDA39fMk1i/lu5WU+pE3f3ssrzwBR6/ztCU/P3N1Yw=
=2nYz
-----END PGP SIGNATURE-----

--------------enig9F551532C9939F52D7371402--



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