Module Name:    src
Committed By:   jnemeth
Date:           Sat Sep 20 22:11:27 UTC 2014

Modified Files:
        src/sbin/gpt: restore.c

Log Message:
Initial cut of gpt restore.  This functions correctly in testing,
but isn't all that pretty.  It has minimal error testing and may
leak memory.  It also only works with empty disks.  If passed "-F"
flag, it will blank the disk for you.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 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/restore.c
diff -u src/sbin/gpt/restore.c:1.1 src/sbin/gpt/restore.c:1.2
--- src/sbin/gpt/restore.c:1.1	Sun Aug 10 18:27:15 2014
+++ src/sbin/gpt/restore.c	Sat Sep 20 22:11:27 2014
@@ -29,11 +29,12 @@
 __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 $");
+__RCSID("$NetBSD: restore.c,v 1.2 2014/09/20 22:11:27 jnemeth Exp $");
 #endif
 
 #include <sys/types.h>
 #include <sys/bootblock.h>
+#include <sys/disklabel_gpt.h>
 
 #include <err.h>
 #include <stddef.h>
@@ -41,12 +42,12 @@ __RCSID("$NetBSD: restore.c,v 1.1 2014/0
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <prop/proplib.h>
 
 #include "map.h"
 #include "gpt.h"
 
 static int force;
-static int primary_only;
 
 const char restoremsg[] = "restore [-F] device ...";
 
@@ -59,25 +60,40 @@ usage_restore(void)
 	exit(1);
 }
 
+#define PROP_ERR(x)     if (!(x)) {             \
+                warn("proplib failure");        \
+                return;                         \
+        }
+
 static void
 restore(int fd)
 {
-	uuid_t uuid;
-	off_t blocks, last;
-	map_t *gpt, *tpg;
-	map_t *tbl, *lbt;
+	uuid_t gpt_guid, uuid;
+	off_t firstdata, last, lastdata, gpe_start, gpe_end;
 	map_t *map;
 	struct mbr *mbr;
 	struct gpt_hdr *hdr;
-	struct gpt_ent *ent;
+	struct gpt_ent ent;
 	unsigned int i;
+	prop_dictionary_t props, gpt_dict, mbr_dict, type_dict;
+	prop_object_iterator_t propiter;
+	prop_data_t propdata;
+	prop_array_t mbr_array, gpt_array;
+	prop_number_t propnum;
+	prop_string_t propstr;
+	int entries, gpt_size, rc;
+	const char *s;
+	void *secbuf;
+	uint32_t status;
 
 	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;
+		if (!force) {
+			warnx("%s: error: device contains a GPT", device_name);
+			return;
+		}
 	}
 	map = map_find(MAP_TYPE_MBR);
 	if (map != NULL) {
@@ -90,126 +106,241 @@ restore(int fd)
 		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);
+	props = prop_dictionary_internalize_from_file("/dev/stdin");
+	PROP_ERR(props);
+
+	propnum = prop_dictionary_get(props, "sector_size");
+	PROP_ERR(propnum);
+	if (!prop_number_equals_integer(propnum, secsz)) {
+		warnx("%s: error: sector size does not match backup",
+		    device_name);
+		prop_object_release(props);
 		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);
+	gpt_dict = prop_dictionary_get(props, "GPT_HDR");
+	PROP_ERR(gpt_dict);
+
+	propnum = prop_dictionary_get(gpt_dict, "revision");
+	PROP_ERR(propnum);
+	if (!prop_number_equals_unsigned_integer(propnum, 0x10000)) {
+		warnx("backup is not revision 1.0");
+		prop_object_release(gpt_dict);
+		prop_object_release(props);
 		return;
 	}
 
-	if (map->map_size < blocks)
-		blocks = map->map_size;
-	if (blocks == 1LL) {
-		warnx("%s: error: no room for the GPT table", device_name);
+	propnum = prop_dictionary_get(gpt_dict, "entries");
+	PROP_ERR(propnum);
+	entries = prop_number_integer_value(propnum);
+	propstr = prop_dictionary_get(gpt_dict, "guid");
+	PROP_ERR(propstr);
+	s = prop_string_cstring_nocopy(propstr);
+	uuid_from_string(s, &uuid, &status);
+	if (status != uuid_s_ok) {
+		warnx("%s: not able to convert to an UUID\n", s);
 		return;
 	}
+	le_uuid_enc(&gpt_guid, &uuid);
 
-	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)
+	gpt_size = entries * sizeof(struct gpt_ent) / secsz;
+	firstdata = gpt_size + 2;		/* PMBR and GPT header */
+	lastdata = last - gpt_size - 1;		/* alt. GPT table and header */
+
+	type_dict = prop_dictionary_get(props, "GPT_TBL");
+	PROP_ERR(type_dict);
+	gpt_array = prop_dictionary_get(type_dict, "gpt_array");
+	PROP_ERR(gpt_array);
+	propiter = prop_array_iterator(gpt_array);
+	PROP_ERR(propiter);
+	while ((gpt_dict = prop_object_iterator_next(propiter)) != NULL) {
+		propstr = prop_dictionary_get(gpt_dict, "type");
+		PROP_ERR(propstr);
+		s = prop_string_cstring_nocopy(propstr);
+		uuid_from_string(s, &uuid, &status);
+		if (status != uuid_s_ok) {
+			warnx("%s: not able to convert to an UUID\n", s);
+			return;
+		}
+		rc = uuid_is_nil(&uuid, &status);
+		if (status != uuid_s_ok) {
+			warnx("%s: not able to convert to an UUID\n", s);
+			return;
+		}
+		if (rc == 1)
+			continue;
+		propnum = prop_dictionary_get(gpt_dict, "start");
+		PROP_ERR(propnum);
+		gpe_start = prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(gpt_dict, "end");
+		PROP_ERR(propnum);
+		gpe_end = prop_number_unsigned_integer_value(propnum);
+		if (gpe_start < firstdata || gpe_end > lastdata) {
+			warnx("%s: error: backup GPT doesn't fit", device_name);
+			return;
+		}
+	}
+	prop_object_iterator_release(propiter);
+
+	secbuf = calloc(gpt_size + 1, secsz);	/* GPT TABLE + GPT HEADER */
+	if (secbuf == NULL) {
+		warnx("not enough memory to create a sector buffer");
 		return;
+	}
+	lseek(fd, 0LL, SEEK_SET);
+	for (i = 0; i < firstdata; i++)
+		write(fd, secbuf, secsz);
+	lseek(fd, (lastdata + 1) * secsz, SEEK_SET);
+	for (i = lastdata + 1; i <= last; i++)
+		write(fd, secbuf, secsz);
+
+	mbr = (struct mbr *)secbuf;
+	type_dict = prop_dictionary_get(props, "MBR");
+	PROP_ERR(type_dict);
+	propdata = prop_dictionary_get(type_dict, "code");
+	PROP_ERR(propdata);
+	memcpy(mbr->mbr_code, prop_data_data_nocopy(propdata),
+	    sizeof(mbr->mbr_code));
+	mbr_array = prop_dictionary_get(type_dict, "mbr_array");
+	PROP_ERR(mbr_array);
+	propiter = prop_array_iterator(mbr_array);
+	PROP_ERR(propiter);
+	while ((mbr_dict = prop_object_iterator_next(propiter)) != NULL) {
+		propnum = prop_dictionary_get(mbr_dict, "index");
+		PROP_ERR(propnum);
+		i = prop_number_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "flag");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_flag =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "start_head");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_shd =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "start_sector");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_ssect =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "start_cylinder");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_scyl =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "type");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_typ =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "end_head");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_ehd =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "end_sector");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_esect =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "end_cylinder");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_ecyl =
+		    prop_number_unsigned_integer_value(propnum);
+		propnum = prop_dictionary_get(mbr_dict, "lba_start_low");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_start_lo =
+		    htole16(prop_number_unsigned_integer_value(propnum));
+		propnum = prop_dictionary_get(mbr_dict, "lba_start_high");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_start_hi =
+		    htole16(prop_number_unsigned_integer_value(propnum));
+		propnum = prop_dictionary_get(mbr_dict, "lba_size_low");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_size_lo =
+		    htole16(prop_number_unsigned_integer_value(propnum));
+		propnum = prop_dictionary_get(mbr_dict, "lba_size_high");
+		PROP_ERR(propnum);
+		mbr->mbr_part[i].part_size_hi =
+		    htole16(prop_number_unsigned_integer_value(propnum));
+	}
+	prop_object_iterator_release(propiter);
+	mbr->mbr_sig = htole16(MBR_SIG);
+	lseek(fd, 0LL, SEEK_SET);
+	write(fd, mbr, secsz);
+	
+	propiter = prop_array_iterator(gpt_array);
+	PROP_ERR(propiter);
+	while ((gpt_dict = prop_object_iterator_next(propiter)) != NULL) {
+		memset(&ent, 0, sizeof(ent));
+		propstr = prop_dictionary_get(gpt_dict, "type");
+		PROP_ERR(propstr);
+		s = prop_string_cstring_nocopy(propstr);
+		uuid_from_string(s, &uuid, &status);
+		if (status != uuid_s_ok) {
+			warnx("%s: not able to convert to an UUID\n", s);
+			return;
+		}
+		le_uuid_enc(&ent.ent_type, &uuid);
+		propstr = prop_dictionary_get(gpt_dict, "guid");
+		PROP_ERR(propstr);
+		s = prop_string_cstring_nocopy(propstr);
+		uuid_from_string(s, &uuid, &status);
+		if (status != uuid_s_ok) {
+			warnx("%s: not able to convert to an UUID\n", s);
+			return;
+		}
+		le_uuid_enc(&ent.ent_guid, &uuid);
+		propnum = prop_dictionary_get(gpt_dict, "start");
+		PROP_ERR(propnum);
+		ent.ent_lba_start =
+		    htole64(prop_number_unsigned_integer_value(propnum));
+		propnum = prop_dictionary_get(gpt_dict, "end");
+		PROP_ERR(propnum);
+		ent.ent_lba_end =
+		    htole64(prop_number_unsigned_integer_value(propnum));
+		propnum = prop_dictionary_get(gpt_dict, "attributes");
+		PROP_ERR(propnum);
+		ent.ent_attr =
+		    htole64(prop_number_unsigned_integer_value(propnum));
+		propstr = prop_dictionary_get(gpt_dict, "name");
+		if (propstr != NULL) {
+			s = prop_string_cstring_nocopy(propstr);
+			utf8_to_utf16((const uint8_t *)s, ent.ent_name, 36);
+		}
+		propnum = prop_dictionary_get(gpt_dict, "index");
+		PROP_ERR(propnum);
+		i = prop_number_integer_value(propnum);
+		memcpy((char *)secbuf + secsz + ((i - 1) * sizeof(ent)), &ent,
+		    sizeof(ent));
+	}
+	prop_object_iterator_release(propiter);
+	lseek(fd, 2 * secsz, SEEK_SET);
+	write(fd, (char *)secbuf + 1 * secsz, gpt_size * secsz);
+	lseek(fd, (lastdata + 1) * secsz, SEEK_SET);
+	write(fd, (char *)secbuf + 1 * secsz, gpt_size * secsz);
 
-	hdr = gpt->map_data;
+	memset(secbuf, 0, secsz);
+	hdr = (struct gpt_hdr *)secbuf;
 	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_size = htole32(GPT_HDR_SIZE);
+	hdr->hdr_lba_self = htole64(GPT_HDR_BLKNO);
 	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_lba_start = htole64(firstdata);
+	hdr->hdr_lba_end = htole64(lastdata);
+	memcpy(hdr->hdr_guid, &gpt_guid, sizeof(hdr->hdr_guid));
+	hdr->hdr_lba_table = htole64(2);
+	hdr->hdr_entries = htole32(entries);
 	hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
+	hdr->hdr_crc_table =
+	    htole32(crc32((char *)secbuf + 1 * secsz, gpt_size * secsz));
+	hdr->hdr_crc_self = htole32(crc32(hdr, GPT_HDR_SIZE));
+	lseek(fd, 1 * secsz, SEEK_SET);
+	write(fd, hdr, secsz);
+	hdr->hdr_lba_self = htole64(last);
+	hdr->hdr_lba_alt = htole64(GPT_HDR_BLKNO);
+	hdr->hdr_lba_table = htole64(lastdata + 1);
+	hdr->hdr_crc_self = 0;
+	hdr->hdr_crc_self = htole32(crc32(hdr, GPT_HDR_SIZE));
+	lseek(fd, last * secsz, SEEK_SET);
+	write(fd, hdr, secsz);
 
-	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);
-	}
+	return;
 }
 
 int

Reply via email to