summaryrefslogtreecommitdiffstats
path: root/sbin/geom/class/part
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2010-11-20 16:03:53 +0000
committerae <ae@FreeBSD.org>2010-11-20 16:03:53 +0000
commitea55525b9335db160427b7f09e0302fbf4be03c2 (patch)
tree044bf9fc4283e1e5c432db0a0bcc76f4ce813917 /sbin/geom/class/part
parent951f9264d71bae0844b8dccfc545b07625c09cee (diff)
downloadFreeBSD-src-ea55525b9335db160427b7f09e0302fbf4be03c2.zip
FreeBSD-src-ea55525b9335db160427b7f09e0302fbf4be03c2.tar.gz
Add to gpart(8) an ability to backup partition table and
restore it from given backup. Discussed with: geom@ Approved by: kib (mentor) MFC after: 1 week
Diffstat (limited to 'sbin/geom/class/part')
-rw-r--r--sbin/geom/class/part/geom_part.c303
-rw-r--r--sbin/geom/class/part/gpart.869
2 files changed, 371 insertions, 1 deletions
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 15bfa0b..55a95e5 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#include <sys/vtoc.h>
#include <assert.h>
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -85,6 +86,8 @@ static int gpart_show_hasopt(struct gctl_req *, const char *, const char *);
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);
struct g_command PUBSYM(class_commands)[] = {
{ "add", 0, gpart_issue, {
@@ -97,6 +100,11 @@ struct g_command PUBSYM(class_commands)[] = {
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 +173,12 @@ struct g_command PUBSYM(class_commands)[] = {
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] provider [...]"
+ },
{ "recover", 0, gpart_issue, {
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
G_OPT_SENTINEL },
@@ -654,6 +668,295 @@ gpart_show(struct gctl_req *req, unsigned int fl __unused)
geom_deletetree(&mesh);
}
+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") != 1)
+ errx(EXIT_FAILURE, "Invalid number of arguments.");
+ error = geom_gettree(&mesh);
+ if (error != 0)
+ errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+ s = gctl_get_ascii(req, "class");
+ if (s == NULL)
+ abort();
+ classp = find_class(&mesh, s);
+ if (classp == NULL) {
+ geom_deletetree(&mesh);
+ errx(EXIT_FAILURE, "Class %s not found.", s);
+ }
+ s = gctl_get_ascii(req, "arg0");
+ if (s == NULL)
+ abort();
+ labels = gctl_get_int(req, "backup_labels");
+ gp = find_geom(classp, s);
+ if (gp == NULL)
+ errx(EXIT_FAILURE, "No such geom: %s.", s);
+ scheme = find_geomcfg(gp, "scheme");
+ if (scheme == NULL)
+ abort();
+ pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
+ secsz = pp->lg_sectorsize;
+ s = find_geomcfg(gp, "last");
+ wblocks = strlen(s);
+ wtype = 0;
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ s = find_provcfg(pp, "type");
+ i = strlen(s);
+ if (i > wtype)
+ wtype = i;
+ }
+ s = find_geomcfg(gp, "entries");
+ windex = strlen(s);
+ printf("%s %s\n", scheme, s);
+ LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
+ s = find_provcfg(pp, "start");
+ if (s == NULL) {
+ s = find_provcfg(pp, "offset");
+ sector = (off_t)strtoimax(s, NULL, 0) / secsz;
+ } else
+ sector = (off_t)strtoimax(s, NULL, 0);
+
+ s = find_provcfg(pp, "end");
+ if (s == NULL) {
+ s = find_provcfg(pp, "length");
+ length = (off_t)strtoimax(s, NULL, 0) / secsz;
+ } else {
+ end = (off_t)strtoimax(s, NULL, 0);
+ length = end - sector + 1;
+ }
+ s = 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 != NULL)
+ printf(" %s", s);
+ printf(" %s\n", fmtattrib(pp));
+ }
+ geom_deletetree(&mesh);
+}
+
+static int
+skip_line(const char *p)
+{
+
+ while (*p != '\0') {
+ if (*p == '#')
+ return (1);
+ if (isspace(*p) == 0)
+ return (0);
+ p++;
+ }
+ return (1);
+}
+
+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 = gctl_get_int(req, "nargs");
+ if (nargs < 1)
+ errx(EXIT_FAILURE, "Invalid number of arguments.");
+
+ forced = gctl_get_int(req, "force");
+ flags = gctl_get_ascii(req, "flags");
+ s = gctl_get_ascii(req, "class");
+ if (s == NULL)
+ abort();
+ error = geom_gettree(&mesh);
+ if (error != 0)
+ errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+ classp = find_class(&mesh, s);
+ if (classp == NULL) {
+ geom_deletetree(&mesh);
+ errx(EXIT_FAILURE, "Class %s not found.", s);
+ }
+ if (forced) {
+ /* destroy existent partition table before restore */
+ for (i = 0; i < nargs; i++) {
+ s = gctl_get_ascii(req, "arg%d", i);
+ gp = find_geom(classp, s);
+ if (gp != NULL) {
+ r = 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 = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_print_error(errstr);
+ gctl_free(r);
+ goto backout;
+ }
+ gctl_free(r);
+ }
+ }
+ }
+ created = 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 = (char *)line;
+ pline[strlen(line) - 1] = 0;
+ if (skip_line(pline))
+ continue;
+ for (ap = argv;
+ (*ap = strsep(&pline, " \t")) != NULL;)
+ if (**ap != '\0' && ++ap >= &argv[6])
+ break;
+ l = ap - &argv[0];
+ label = pline = NULL;
+ if (l == 2) { /* create table */
+ if (created)
+ errx(EXIT_FAILURE, "Incorrect backup format.");
+ n = atoi(argv[1]);
+ for (i = 0; i < nargs; i++) {
+ s = gctl_get_ascii(req, "arg%d", i);
+ r = gctl_get_handle();
+ n = 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 = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_print_error(errstr);
+ gctl_free(r);
+ goto backout;
+ }
+ gctl_free(r);
+ }
+ created = 1;
+ continue;
+ } else if (l < 4 || created == 0)
+ errx(EXIT_FAILURE, "Incorrect backup format.");
+ else if (l == 5) {
+ if (strchr(argv[4], '[') == NULL)
+ label = argv[4];
+ else
+ pline = argv[4];
+ } else if (l == 6) {
+ label = argv[4];
+ pline = argv[5];
+ }
+ /* Add partitions to each table */
+ for (i = 0; i < nargs; i++) {
+ s = gctl_get_ascii(req, "arg%d", i);
+ r = gctl_get_handle();
+ n = 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 != NULL)
+ gctl_ro_param(r, "label", -1, argv[4]);
+ gctl_ro_param(r, "arg0", -1, s);
+ error = gpart_autofill(r);
+ if (error != 0)
+ errc(EXIT_FAILURE, error, "autofill");
+ errstr = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_print_error(errstr);
+ gctl_free(r);
+ goto backout;
+ }
+ gctl_free(r);
+ }
+ if (pline == NULL || *pline != '[')
+ continue;
+ /* set attributes */
+ pline++;
+ for (ap = argv;
+ (*ap = strsep(&pline, ",]")) != NULL;)
+ if (**ap != '\0' && ++ap >= &argv[6])
+ break;
+ for (i = 0; i < nargs; i++) {
+ l = ap - &argv[0];
+ s = gctl_get_ascii(req, "arg%d", i);
+ while (l > 0) {
+ r = 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 = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\0') {
+ gpart_print_error(errstr);
+ gctl_free(r);
+ goto backout;
+ }
+ gctl_free(r);
+ }
+ }
+ }
+ /* commit changes if needed */
+ if (strchr(flags, 'C') != NULL) {
+ for (i = 0; i < nargs; i++) {
+ s = gctl_get_ascii(req, "arg%d", i);
+ r = 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 = gctl_issue(r);
+ if (errstr != NULL && errstr[0] != '\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 = 0; i < nargs; i++) {
+ s = gctl_get_ascii(req, "arg%d", i);
+ r = 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)
{
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index f01e56a..ef303bf 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 25, 2010
+.Dd November 20, 2010
.Dt GPART 8
.Os
.Sh NAME
@@ -91,6 +91,11 @@ utility:
.Op Fl l Ar label
.Op Fl f Ar flags
.Ar geom
+.\" ==== BACKUP ====
+.Nm
+.Cm backup
+.Op Fl l
+.Ar geom
.\" ==== BOOTCODE ====
.Nm
.Cm bootcode
@@ -141,6 +146,13 @@ utility:
.Op Fl s Ar size
.Op Fl f Ar flags
.Ar geom
+.\" ==== RESTORE ====
+.Nm
+.Cm restore
+.Op Fl F
+.Op Fl f Ar flags
+.Ar provider
+.Op Ar ...
.\" ==== SET ====
.Nm
.Cm set
@@ -208,6 +220,17 @@ See the section entitled
below for a discussion
about its use.
.El
+.\" ==== BACKUP ====
+.It Cm backup
+Dump a partition table to standard output in special format used by
+.Cm restore
+action.
+.Pp
+Additional options include:
+.Bl -tag -width 10n
+.It Fl l
+Dump partition labels for partitioning schemes that support them.
+.El
.\" ==== BOOTCODE ====
.It Cm bootcode
Embed bootstrap code into the partitioning scheme's metadata on the
@@ -401,6 +424,28 @@ See the section entitled
below for a discussion
about its use.
.El
+.\" ==== RESTORE ====
+.It Cm restore
+Restore the partition table from backup previously created by
+.Cm backup
+action and given from standard input. Only partition table
+may be restored. This action does not affect content of partitions.
+This mean that you should copy your data from backup after restoring
+partition table and write bootcode again if it is needed.
+.Pp
+Additional options include:
+.Bl -tag -width 10n
+.It Fl F
+Destroy partition table on the given
+.Ar provider
+before doing restore.
+.It Fl f Ar flags
+Additional operational flags.
+See the section entitled
+.Sx "OPERATIONAL FLAGS"
+below for a discussion
+about its use.
+.El
.\" ==== SET ====
.It Cm set
Set the named attribute on the partition entry.
@@ -770,6 +815,28 @@ After having created all required partitions, embed bootstrap code into them.
.Bd -literal -offset indent
/sbin/gpart bootcode -p /boot/boot1 da0
.Ed
+.Pp
+Create backup of partition table from
+.Pa da0
+.Bd -literal -offset indent
+/sbin/gpart backup -l da0 > da0.backup
+.Ed
+.Pp
+Restore partition table from backup to
+.Pa da0
+.Bd -literal -offset indent
+/sbin/gpart restore da0 < /mnt/da0.backup
+.Ed
+.Pp
+Clone partition table from
+.Pa ada0
+to
+.Pa ada1
+and
+.Pa ada2
+.Bd -literal -offset indent
+/sbin/gpart backup ada0 | /sbin/gpart restore -F ada1 ada2
+.Ed
.Sh SEE ALSO
.Xr dd 1 ,
.Xr geom 4 ,
OpenPOWER on IntegriCloud