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
This commit is contained in:
parent
a48551fac2
commit
9fe175f914
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=215570
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/vtoc.h>
|
#include <sys/vtoc.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.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(struct ggeom *, int, void *, ssize_t);
|
||||||
static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
|
static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
|
||||||
static void gpart_print_error(const char *);
|
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)[] = {
|
struct g_command PUBSYM(class_commands)[] = {
|
||||||
{ "add", 0, gpart_issue, {
|
{ "add", 0, gpart_issue, {
|
||||||
@ -97,6 +100,11 @@ struct g_command PUBSYM(class_commands)[] = {
|
|||||||
G_OPT_SENTINEL },
|
G_OPT_SENTINEL },
|
||||||
"[-b start] [-s size] -t type [-i index] [-l label] [-f flags] geom"
|
"[-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, {
|
{ "bootcode", 0, gpart_bootcode, {
|
||||||
{ 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
|
{ 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
|
||||||
{ 'p', GPART_PARAM_PARTCODE, 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 },
|
G_OPT_SENTINEL },
|
||||||
"[-s size] -i index [-f flags] geom"
|
"[-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, {
|
{ "recover", 0, gpart_issue, {
|
||||||
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
|
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
|
||||||
G_OPT_SENTINEL },
|
G_OPT_SENTINEL },
|
||||||
@ -654,6 +668,295 @@ gpart_show(struct gctl_req *req, unsigned int fl __unused)
|
|||||||
geom_deletetree(&mesh);
|
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 *
|
static void *
|
||||||
gpart_bootfile_read(const char *bootfile, ssize_t *size)
|
gpart_bootfile_read(const char *bootfile, ssize_t *size)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd October 25, 2010
|
.Dd November 20, 2010
|
||||||
.Dt GPART 8
|
.Dt GPART 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -91,6 +91,11 @@ utility:
|
|||||||
.Op Fl l Ar label
|
.Op Fl l Ar label
|
||||||
.Op Fl f Ar flags
|
.Op Fl f Ar flags
|
||||||
.Ar geom
|
.Ar geom
|
||||||
|
.\" ==== BACKUP ====
|
||||||
|
.Nm
|
||||||
|
.Cm backup
|
||||||
|
.Op Fl l
|
||||||
|
.Ar geom
|
||||||
.\" ==== BOOTCODE ====
|
.\" ==== BOOTCODE ====
|
||||||
.Nm
|
.Nm
|
||||||
.Cm bootcode
|
.Cm bootcode
|
||||||
@ -141,6 +146,13 @@ utility:
|
|||||||
.Op Fl s Ar size
|
.Op Fl s Ar size
|
||||||
.Op Fl f Ar flags
|
.Op Fl f Ar flags
|
||||||
.Ar geom
|
.Ar geom
|
||||||
|
.\" ==== RESTORE ====
|
||||||
|
.Nm
|
||||||
|
.Cm restore
|
||||||
|
.Op Fl F
|
||||||
|
.Op Fl f Ar flags
|
||||||
|
.Ar provider
|
||||||
|
.Op Ar ...
|
||||||
.\" ==== SET ====
|
.\" ==== SET ====
|
||||||
.Nm
|
.Nm
|
||||||
.Cm set
|
.Cm set
|
||||||
@ -208,6 +220,17 @@ See the section entitled
|
|||||||
below for a discussion
|
below for a discussion
|
||||||
about its use.
|
about its use.
|
||||||
.El
|
.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 ====
|
.\" ==== BOOTCODE ====
|
||||||
.It Cm bootcode
|
.It Cm bootcode
|
||||||
Embed bootstrap code into the partitioning scheme's metadata on the
|
Embed bootstrap code into the partitioning scheme's metadata on the
|
||||||
@ -401,6 +424,28 @@ See the section entitled
|
|||||||
below for a discussion
|
below for a discussion
|
||||||
about its use.
|
about its use.
|
||||||
.El
|
.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 ====
|
.\" ==== SET ====
|
||||||
.It Cm set
|
.It Cm set
|
||||||
Set the named attribute on the partition entry.
|
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
|
.Bd -literal -offset indent
|
||||||
/sbin/gpart bootcode -p /boot/boot1 da0
|
/sbin/gpart bootcode -p /boot/boot1 da0
|
||||||
.Ed
|
.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
|
.Sh SEE ALSO
|
||||||
.Xr dd 1 ,
|
.Xr dd 1 ,
|
||||||
.Xr geom 4 ,
|
.Xr geom 4 ,
|
||||||
|
Loading…
Reference in New Issue
Block a user