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 => 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 => 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 => 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 => 34 204733 md0 GPT (100M) 34 256 1 freebsd-boot (128K) 290 204477 2 freebsd-zfs (100M) => 34 204733 md1 GPT (100M) 34 256 1 freebsd-boot (128K) 290 204477 2 freebsd-zfs (100M) => 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 => 9 204786 md0 MBR (100M) 9 204786 1 freebsd [active] (100M) => 9 204786 md1 MBR (100M) 9 204786 1 freebsd [active] (100M) -- WBR, Andrey V. Elsukov
Index: head/sbin/geom/class/part/geom_part.c =================================================================== --- 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); struct g_command PUBSYM(class_commands)[] = { { "add", 0, gpart_issue, { @@ -97,6 +99,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 +172,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] 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); } +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 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; + for (ap = argv, l = 0; + (*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, l = 0; + (*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) {
signature.asc
Description: OpenPGP digital signature