Module Name:    src
Committed By:   jnemeth
Date:           Sun Jun 12 12:48:33 UTC 2016

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

Log Message:
- fix setting of hdr_lba_alt which was broken in revision 1.10 on 2015/12/2
- switch to using gpt_last
- PR/51230 -- recreate the PMBR if it was lost


To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/sbin/gpt/recover.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/recover.c
diff -u src/sbin/gpt/recover.c:1.15 src/sbin/gpt/recover.c:1.16
--- src/sbin/gpt/recover.c:1.15	Fri Dec  4 16:46:24 2015
+++ src/sbin/gpt/recover.c	Sun Jun 12 12:48:32 2016
@@ -33,7 +33,7 @@
 __FBSDID("$FreeBSD: src/sbin/gpt/recover.c,v 1.8 2005/08/31 01:47:19 marcel Exp $");
 #endif
 #ifdef __RCSID
-__RCSID("$NetBSD: recover.c,v 1.15 2015/12/04 16:46:24 christos Exp $");
+__RCSID("$NetBSD: recover.c,v 1.16 2016/06/12 12:48:32 jnemeth Exp $");
 #endif
 
 #include <sys/types.h>
@@ -68,7 +68,7 @@ static int
 recover_gpt_hdr(gpt_t gpt, int type, off_t last)
 {
 	const char *name, *origname;
-	map_t *dgpt, dtbl, sgpt, stbl;
+	map_t *dgpt, dtbl, sgpt, stbl __unused;
 	struct gpt_hdr *hdr;
 
 	if (gpt_add_hdr(gpt, type, last) == -1)
@@ -99,7 +99,7 @@ recover_gpt_hdr(gpt_t gpt, int type, off
 	memcpy((*dgpt)->map_data, sgpt->map_data, gpt->secsz);
 	hdr = (*dgpt)->map_data;
 	hdr->hdr_lba_self = htole64((uint64_t)(*dgpt)->map_start);
-	hdr->hdr_lba_alt = htole64((uint64_t)stbl->map_start);
+	hdr->hdr_lba_alt = htole64((uint64_t)sgpt->map_start);
 	hdr->hdr_lba_table = htole64((uint64_t)dtbl->map_start);
 	hdr->hdr_crc_self = 0;
 	hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
@@ -151,7 +151,9 @@ recover_gpt_tbl(gpt_t gpt, int type, off
 static int
 recover(gpt_t gpt, int recoverable)
 {
-	uint64_t last;
+	off_t last = gpt_last(gpt);
+	map_t map;
+	struct mbr *mbr;
 
 	if (map_find(gpt, MAP_TYPE_MBR) != NULL) {
 		gpt_warnx(gpt, "Device contains an MBR");
@@ -174,10 +176,9 @@ recover(gpt_t gpt, int recoverable)
 		return -1;
 	}
 
-	last = (uint64_t)(gpt->mediasz / gpt->secsz - 1LL);
-
 	if (gpt->gpt != NULL &&
-	    ((struct gpt_hdr *)(gpt->gpt->map_data))->hdr_lba_alt != last) {
+	    ((struct gpt_hdr *)(gpt->gpt->map_data))->hdr_lba_alt !=
+	    (uint64_t)last) {
 		gpt_warnx(gpt, "Media size has changed, please use "
 		   "'%s resizedisk'", getprogname());
 		return -1;
@@ -185,7 +186,7 @@ recover(gpt_t gpt, int recoverable)
 
 	if (gpt->tbl != NULL && gpt->lbt == NULL) {
 		if (recover_gpt_tbl(gpt, MAP_TYPE_SEC_GPT_TBL,
-		    (off_t)last - gpt->tbl->map_size) == -1)
+		    last - gpt->tbl->map_size) == -1)
 			return -1;
 	} else if (gpt->tbl == NULL && gpt->lbt != NULL) {
 		if (recover_gpt_tbl(gpt, MAP_TYPE_PRI_GPT_TBL, 2LL) == -1)
@@ -193,13 +194,38 @@ recover(gpt_t gpt, int recoverable)
 	}
 
 	if (gpt->gpt != NULL && gpt->tpg == NULL) {
-		if (recover_gpt_hdr(gpt, MAP_TYPE_SEC_GPT_HDR,
-		    (off_t)last) == -1)
+		if (recover_gpt_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1)
 			return -1;
 	} else if (gpt->gpt == NULL && gpt->tpg != NULL) {
 		if (recover_gpt_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1LL) == -1)
 			return -1;
 	}
+
+	/*
+	 * Create PMBR if it doesn't already exist.
+	 */
+	if (map_find(gpt, MAP_TYPE_PMBR) == NULL) {
+		if (map_free(gpt, 0LL, 1LL) == 0) {
+			gpt_warnx(gpt, "No room for the PMBR");
+			return -1;
+		}
+		mbr = gpt_read(gpt, 0LL, 1);
+		if (mbr == NULL) {
+			gpt_warnx(gpt, "Error reading MBR");
+			return -1;
+		}
+		memset(mbr, 0, sizeof(*mbr));
+		mbr->mbr_sig = htole16(MBR_SIG);
+		gpt_create_pmbr_part(mbr->mbr_part, last, 0);
+
+		map = map_add(gpt, 0LL, 1LL, MAP_TYPE_PMBR, mbr, 1);
+		if (gpt_write(gpt, map) == -1) {
+			gpt_warn(gpt, "Can't write PMBR");
+			return -1;
+		}
+		gpt_msg(gpt,
+		    "Recreated PMBR (you may need to rerun 'gpt biosboot'");
+	}
 	return 0;
 }
 

Reply via email to