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>