Module Name: src Committed By: jnemeth Date: Sun Aug 10 18:27:16 UTC 2014
Modified Files: src/sbin/gpt: Makefile gpt.c gpt.h Added Files: src/sbin/gpt: restore.c Log Message: Add restore subcommand. XXX It does not actually work yet. It is being committed now to make later pullups easier. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sbin/gpt/Makefile cvs rdiff -u -r1.27 -r1.28 src/sbin/gpt/gpt.c cvs rdiff -u -r1.10 -r1.11 src/sbin/gpt/gpt.h cvs rdiff -u -r0 -r1.1 src/sbin/gpt/restore.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sbin/gpt/Makefile diff -u src/sbin/gpt/Makefile:1.7 src/sbin/gpt/Makefile:1.8 --- src/sbin/gpt/Makefile:1.7 Thu Dec 19 06:46:51 2013 +++ src/sbin/gpt/Makefile Sun Aug 10 18:27:15 2014 @@ -1,9 +1,9 @@ -# $NetBSD: Makefile,v 1.7 2013/12/19 06:46:51 jnemeth Exp $ +# $NetBSD: Makefile,v 1.8 2014/08/10 18:27:15 jnemeth Exp $ # $FreeBSD: src/sbin/gpt/Makefile,v 1.7 2005/09/01 02:49:20 marcel Exp $ PROG= gpt SRCS= add.c backup.c biosboot.c create.c destroy.c gpt.c label.c map.c \ - migrate.c recover.c remove.c resize.c set.c show.c unset.c + migrate.c recover.c remove.c resize.c restore.c set.c show.c unset.c MAN= gpt.8 LDADD+= -lprop -lutil Index: src/sbin/gpt/gpt.c diff -u src/sbin/gpt/gpt.c:1.27 src/sbin/gpt/gpt.c:1.28 --- src/sbin/gpt/gpt.c:1.27 Thu Dec 19 06:46:51 2013 +++ src/sbin/gpt/gpt.c Sun Aug 10 18:27:15 2014 @@ -31,7 +31,7 @@ __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $"); #endif #ifdef __RCSID -__RCSID("$NetBSD: gpt.c,v 1.27 2013/12/19 06:46:51 jnemeth Exp $"); +__RCSID("$NetBSD: gpt.c,v 1.28 2014/08/10 18:27:15 jnemeth Exp $"); #endif #include <sys/param.h> @@ -728,6 +728,7 @@ static struct { { cmd_remove, "remove" }, { NULL, "rename" }, { cmd_resize, "resize" }, + { cmd_restore, "restore" }, { cmd_set, "set" }, { cmd_show, "show" }, { cmd_unset, "unset" }, @@ -741,8 +742,8 @@ usage(void) extern const char addmsg1[], addmsg2[], backupmsg[], biosbootmsg[]; extern const char createmsg[], destroymsg[], labelmsg1[], labelmsg2[]; extern const char labelmsg3[], migratemsg[], recovermsg[], removemsg1[]; - extern const char removemsg2[], resizemsg[], setmsg[], showmsg[]; - extern const char unsetmsg[]; + extern const char removemsg2[], resizemsg[], restoremsg[], setmsg[]; + extern const char showmsg[], unsetmsg[]; fprintf(stderr, "usage: %s %s\n" @@ -761,6 +762,7 @@ usage(void) " %s %s\n" " %s %s\n" " %s %s\n" + " %s %s\n" " %s %s\n", getprogname(), addmsg1, getprogname(), addmsg2, @@ -776,6 +778,7 @@ usage(void) getprogname(), removemsg1, getprogname(), removemsg2, getprogname(), resizemsg, + getprogname(), restoremsg, getprogname(), setmsg, getprogname(), showmsg, getprogname(), unsetmsg); Index: src/sbin/gpt/gpt.h diff -u src/sbin/gpt/gpt.h:1.10 src/sbin/gpt/gpt.h:1.11 --- src/sbin/gpt/gpt.h:1.10 Thu Dec 19 06:46:51 2013 +++ src/sbin/gpt/gpt.h Sun Aug 10 18:27:15 2014 @@ -89,6 +89,7 @@ int cmd_migrate(int, char *[]); int cmd_recover(int, char *[]); int cmd_remove(int, char *[]); int cmd_resize(int, char *[]); +int cmd_restore(int, char *[]); int cmd_set(int, char *[]); int cmd_show(int, char *[]); int cmd_unset(int, char *[]); Added files: Index: src/sbin/gpt/restore.c diff -u /dev/null src/sbin/gpt/restore.c:1.1 --- /dev/null Sun Aug 10 18:27:16 2014 +++ src/sbin/gpt/restore.c Sun Aug 10 18:27:15 2014 @@ -0,0 +1,246 @@ +/*- + * Copyright (c) 2002 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/sbin/gpt/create.c,v 1.11 2005/08/31 01:47:19 marcel Exp $"); +#endif +#ifdef __RCSID +__RCSID("$NetBSD: restore.c,v 1.1 2014/08/10 18:27:15 jnemeth Exp $"); +#endif + +#include <sys/types.h> +#include <sys/bootblock.h> + +#include <err.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "map.h" +#include "gpt.h" + +static int force; +static int primary_only; + +const char restoremsg[] = "restore [-F] device ..."; + +__dead static void +usage_restore(void) +{ + + fprintf(stderr, + "usage: %s %s\n", getprogname(), restoremsg); + exit(1); +} + +static void +restore(int fd) +{ + uuid_t uuid; + off_t blocks, last; + map_t *gpt, *tpg; + map_t *tbl, *lbt; + map_t *map; + struct mbr *mbr; + struct gpt_hdr *hdr; + struct gpt_ent *ent; + unsigned int i; + + last = mediasz / secsz - 1LL; + + if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL || + map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) { + warnx("%s: error: device already contains a GPT", device_name); + return; + } + map = map_find(MAP_TYPE_MBR); + if (map != NULL) { + if (!force) { + warnx("%s: error: device contains a MBR", device_name); + return; + } + + /* Nuke the MBR in our internal map. */ + map->map_type = MAP_TYPE_UNUSED; + } + + /* + * Create PMBR. + */ + if (map_find(MAP_TYPE_PMBR) == NULL) { + if (map_free(0LL, 1LL) == 0) { + warnx("%s: error: no room for the PMBR", device_name); + return; + } + mbr = gpt_read(fd, 0LL, 1); + bzero(mbr, sizeof(*mbr)); + mbr->mbr_sig = htole16(MBR_SIG); + mbr->mbr_part[0].part_shd = 0x00; + mbr->mbr_part[0].part_ssect = 0x02; + mbr->mbr_part[0].part_scyl = 0x00; + mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR; + mbr->mbr_part[0].part_ehd = 0xfe; + mbr->mbr_part[0].part_esect = 0xff; + mbr->mbr_part[0].part_ecyl = 0xff; + mbr->mbr_part[0].part_start_lo = htole16(1); + if (last > 0xffffffff) { + mbr->mbr_part[0].part_size_lo = htole16(0xffff); + mbr->mbr_part[0].part_size_hi = htole16(0xffff); + } else { + mbr->mbr_part[0].part_size_lo = htole16(last); + mbr->mbr_part[0].part_size_hi = htole16(last >> 16); + } + map = map_add(0LL, 1LL, MAP_TYPE_PMBR, mbr); + gpt_write(fd, map); + } + + /* Get the amount of free space after the MBR */ + blocks = map_free(1LL, 0LL); + if (blocks == 0LL) { + warnx("%s: error: no room for the GPT header", device_name); + return; + } + + /* Don't create more than parts entries. */ + if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { + blocks = (parts * sizeof(struct gpt_ent)) / secsz; + if ((parts * sizeof(struct gpt_ent)) % secsz) + blocks++; + blocks++; /* Don't forget the header itself */ + } + + /* Never cross the median of the device. */ + if ((blocks + 1LL) > ((last + 1LL) >> 1)) + blocks = ((last + 1LL) >> 1) - 1LL; + + /* + * Get the amount of free space at the end of the device and + * calculate the size for the GPT structures. + */ + map = map_last(); + if (map->map_type != MAP_TYPE_UNUSED) { + warnx("%s: error: no room for the backup header", device_name); + return; + } + + if (map->map_size < blocks) + blocks = map->map_size; + if (blocks == 1LL) { + warnx("%s: error: no room for the GPT table", device_name); + return; + } + + blocks--; /* Number of blocks in the GPT table. */ + gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz)); + tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL, + calloc(blocks, secsz)); + if (gpt == NULL || tbl == NULL) + return; + + hdr = gpt->map_data; + memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); + hdr->hdr_revision = htole32(GPT_HDR_REVISION); + hdr->hdr_size = htole32(GPT_SIZE); + hdr->hdr_lba_self = htole64(gpt->map_start); + hdr->hdr_lba_alt = htole64(last); + hdr->hdr_lba_start = htole64(tbl->map_start + blocks); + hdr->hdr_lba_end = htole64(last - blocks - 1LL); + uuid_create(&uuid, NULL); + le_uuid_enc(hdr->hdr_uuid, &uuid); + hdr->hdr_lba_table = htole64(tbl->map_start); + hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent)); + if (le32toh(hdr->hdr_entries) > parts) + hdr->hdr_entries = htole32(parts); + hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); + + ent = tbl->map_data; + for (i = 0; i < le32toh(hdr->hdr_entries); i++) { + uuid_create(&uuid, NULL); + le_uuid_enc(ent[i].ent_uuid, &uuid); + } + + hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) * + le32toh(hdr->hdr_entsz))); + hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); + + gpt_write(fd, gpt); + gpt_write(fd, tbl); + + /* + * Create backup GPT if the user didn't suppress it. + */ + if (!primary_only) { + tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, + calloc(1, secsz)); + lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL, + tbl->map_data); + memcpy(tpg->map_data, gpt->map_data, secsz); + hdr = tpg->map_data; + hdr->hdr_lba_self = htole64(tpg->map_start); + hdr->hdr_lba_alt = htole64(gpt->map_start); + hdr->hdr_lba_table = htole64(lbt->map_start); + hdr->hdr_crc_self = 0; /* Don't ever forget this! */ + hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); + gpt_write(fd, lbt); + gpt_write(fd, tpg); + } +} + +int +cmd_restore(int argc, char *argv[]) +{ + int ch, fd; + + while ((ch = getopt(argc, argv, "F")) != -1) { + switch(ch) { + case 'F': + force = 1; + break; + default: + usage_restore(); + } + } + + if (argc == optind) + usage_restore(); + + while (optind < argc) { + fd = gpt_open(argv[optind++]); + if (fd == -1) { + warn("unable to open device '%s'", device_name); + continue; + } + + restore(fd); + + gpt_close(fd); + } + + return (0); +}