diff --git a/sbin/gpt/create.c b/sbin/gpt/create.c index ec2b12185b34..e9ac8cedb127 100644 --- a/sbin/gpt/create.c +++ b/sbin/gpt/create.c @@ -58,6 +58,7 @@ create(int fd) 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; @@ -67,6 +68,40 @@ create(int fd) warnx("%s: error: device already contains a GPT", device_name); return; } + if (map_find(MAP_TYPE_MBR) != NULL) { + warnx("%s: error: device contains a MBR", device_name); + return; + } + + /* + * 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 = MBR_SIG; + mbr->mbr_part[0].part_shd = 0xff; + mbr->mbr_part[0].part_ssect = 0xff; + mbr->mbr_part[0].part_scyl = 0xff; + mbr->mbr_part[0].part_typ = 0xee; + mbr->mbr_part[0].part_ehd = 0xff; + mbr->mbr_part[0].part_esect = 0xff; + mbr->mbr_part[0].part_ecyl = 0xff; + mbr->mbr_part[0].part_start_lo = 1; + if (mediasz > 0xffffffff) { + mbr->mbr_part[0].part_size_lo = 0xffff; + mbr->mbr_part[0].part_size_hi = 0xffff; + } else { + mbr->mbr_part[0].part_size_lo = mediasz & 0xffff; + mbr->mbr_part[0].part_size_hi = mediasz >> 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); diff --git a/sbin/gpt/gpt.c b/sbin/gpt/gpt.c index 28b28b26fb98..6ab98d1ed3fc 100644 --- a/sbin/gpt/gpt.c +++ b/sbin/gpt/gpt.c @@ -161,6 +161,90 @@ gpt_write(int fd, map_t *map) return (-1); } +static int +gpt_mbr(int fd, off_t lba) +{ + struct mbr *mbr; + map_t *m, *p; + off_t size, start; + unsigned int i, pmbr; + + mbr = gpt_read(fd, lba, 1); + if (mbr == NULL) + return (-1); + + if (mbr->mbr_sig != MBR_SIG) { + if (verbose) + warnx("%s: MBR not found at sector %llu", device_name, + (long long)lba); + free(mbr); + return (0); + } + + /* + * Differentiate between a regular MBR and a PMBR. This is more + * convenient in general. A PMBR is one with a single partition + * of type 0xee. + */ + pmbr = 0; + for (i = 0; i < 4; i++) { + if (mbr->mbr_part[i].part_typ == 0) + continue; + if (mbr->mbr_part[i].part_typ == 0xee) + pmbr++; + else + break; + } + if (pmbr && i == 4 && lba == 0) { + if (pmbr != 1) + warnx("%s: Suspicious PMBR at sector %llu", + device_name, (long long)lba); + else if (verbose > 1) + warnx("%s: PMBR at sector %llu", device_name, + (long long)lba); + p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr); + return ((p == NULL) ? -1 : 0); + } + if (pmbr) + warnx("%s: Suspicious MBR at sector %llu", device_name, + (long long)lba); + else if (verbose > 1) + warnx("%s: MBR at sector %llu", device_name, (long long)lba); + + p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr); + if (p == NULL) + return (-1); + for (i = 0; i < 4; i++) { + if (mbr->mbr_part[i].part_typ == 0 || + mbr->mbr_part[i].part_typ == 0xee) + continue; + start = mbr->mbr_part[i].part_start_hi; + start = (start << 16) + mbr->mbr_part[i].part_start_lo; + size = mbr->mbr_part[i].part_size_hi; + size = (size << 16) + mbr->mbr_part[i].part_size_lo; + if (start == 0 && size == 0) { + warnx("%s: Malformed MBR at sector %llu", device_name, + (long long)lba); + continue; + } + /* start is relative to the offset of the MBR itself. */ + start += lba; + if (verbose > 2) + warnx("%s: MBR part: type=%d, start=%llu, size=%llu", + device_name, mbr->mbr_part[i].part_typ, + (long long)start, (long long)size); + if (mbr->mbr_part[i].part_typ != 15) { + m = map_add(start, size, MAP_TYPE_MBR_PART, p); + if (m == NULL) + return (-1); + } else { + if (gpt_mbr(fd, start) == -1) + return (-1); + } + } + return (0); +} + static int gpt_gpt(int fd, off_t lba) { @@ -252,10 +336,6 @@ int gpt_open(const char *dev) { struct stat sb; - struct mbr *mbr; - map_t *m; - uint32_t size, start; - unsigned int i; int fd; if (!stat(dev, &sb)) { @@ -306,46 +386,8 @@ gpt_open(const char *dev) map_init(mediasz / secsz); - /* - * MBR - */ - mbr = gpt_read(fd, 0LL, 1); - if (mbr == NULL) + if (gpt_mbr(fd, 0LL) == -1) goto close; - - if (mbr->mbr_sig == MBR_SIG) { - if (verbose > 1) - warnx("%s: MBR at sector 0", device_name); - m = map_add(0LL, 1LL, MAP_TYPE_MBR, mbr); - if (m == NULL) - goto close; - for (i = 0; i < 4; i++) { - start = mbr->mbr_part[i].part_start_hi; - start = (start << 16) + mbr->mbr_part[i].part_start_lo; - size = mbr->mbr_part[i].part_size_hi; - size = (size << 16) + mbr->mbr_part[i].part_size_lo; - if (start == 0 && size == 0) - continue; - if (verbose > 2) - warnx("%s: MBR partition: type=%d, start=%llu, size=%llu", - device_name, mbr->mbr_part[i].part_typ, - (long long)start, (long long)size); - if (mbr->mbr_part[i].part_typ == 0xee) - continue; - m = map_add(start, size, MAP_TYPE_MBR_PART, - mbr->mbr_part + i); - if (m == NULL) - goto close; - } - } else { - if (verbose) - warnx("%s: MBR not found", device_name); - free(mbr); - } - - /* - * GPT - */ if (gpt_gpt(fd, 1LL) == -1) goto close; if (gpt_gpt(fd, mediasz / secsz - 1LL) == -1) diff --git a/sbin/gpt/map.h b/sbin/gpt/map.h index 4bdc94a72e04..34ea0a65397e 100644 --- a/sbin/gpt/map.h +++ b/sbin/gpt/map.h @@ -43,6 +43,7 @@ typedef struct map { #define MAP_TYPE_PRI_GPT_TBL 5 #define MAP_TYPE_SEC_GPT_TBL 6 #define MAP_TYPE_GPT_PART 7 +#define MAP_TYPE_PMBR 8 void *map_data; } map_t; diff --git a/sbin/gpt/migrate.c b/sbin/gpt/migrate.c index eca172d0f8fd..f0affa90761f 100644 --- a/sbin/gpt/migrate.c +++ b/sbin/gpt/migrate.c @@ -92,6 +92,8 @@ migrate_disklabel(int fd, off_t start, struct gpt_ent *ent) break; } default: + warnx("%s: warning: unknown FreeBSD partition (%d)", + device_name, dl->d_partitions[i].p_fstype); continue; } @@ -120,9 +122,8 @@ migrate(int fd) last = mediasz / secsz - 1LL; map = map_find(MAP_TYPE_MBR); - if (map == NULL || map_find(MAP_TYPE_MBR_PART) == NULL) { - warnx("%s: error: no partitions to convert", - device_name); + if (map == NULL || map->map_start != 0) { + warnx("%s: error: no partitions to convert", device_name); return; } @@ -212,6 +213,8 @@ migrate(int fd) size = (size << 16) + mbr->mbr_part[i].part_size_lo; switch (mbr->mbr_part[i].part_typ) { + case 0: + continue; case 165: { /* FreeBSD */ if (slice) { uuid_t freebsd = GPT_ENT_TYPE_FREEBSD; @@ -235,7 +238,9 @@ migrate(int fd) break; } default: - continue; + warnx("%s: error: unknown partition type (%d)", + device_name, mbr->mbr_part[i].part_typ); + return; } } ent = tbl->map_data; diff --git a/sbin/gpt/show.c b/sbin/gpt/show.c index 27fc11369215..3e9ebc83ceda 100644 --- a/sbin/gpt/show.c +++ b/sbin/gpt/show.c @@ -52,11 +52,12 @@ usage_show(void) static void show(int fd __unused) { - off_t end; - map_t *m; - struct mbr_part *part; + off_t start, end; + map_t *m, *p; + struct mbr *mbr; struct gpt_ent *ent; char *s; + unsigned int i; printf(" %*s", lbawidth, "start"); printf(" %*s", lbawidth, "end"); @@ -73,6 +74,8 @@ show(int fd __unused) putchar(' '); putchar(' '); switch (m->map_type) { case MAP_TYPE_MBR: + if (m->map_start != 0) + printf("Extended "); printf("MBR"); break; case MAP_TYPE_PRI_GPT_HDR: @@ -88,17 +91,29 @@ show(int fd __unused) printf("Sec GPT table"); break; case MAP_TYPE_MBR_PART: - printf("MBR partition: "); - part = m->map_data; - printf("type=%d", part->part_typ); + p = m->map_data; + if (p->map_start != 0) + printf("Extended "); + printf("MBR part "); + mbr = p->map_data; + for (i = 0; i < 4; i++) { + start = mbr->mbr_part[i].part_start_hi << 16; + start += mbr->mbr_part[i].part_start_lo; + if (m->map_start == p->map_start + start) + break; + } + printf("%d", mbr->mbr_part[i].part_typ); break; case MAP_TYPE_GPT_PART: - printf("GPT partition: "); + printf("GPT part "); ent = m->map_data; uuid_to_string(&ent->ent_type, &s, NULL); - printf("type=%s", s); + printf("%s", s); free(s); break; + case MAP_TYPE_PMBR: + printf("PMBR"); + break; } putchar('\n'); m = m->map_next;