summaryrefslogtreecommitdiffstats
path: root/sbin/gpt
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2002-12-02 01:42:03 +0000
committermarcel <marcel@FreeBSD.org>2002-12-02 01:42:03 +0000
commit4abeaed33de9450b5e4900151806d6b8329b4958 (patch)
treef64f1e9698713b9f0a3d0bedc5af4f9a905e7278 /sbin/gpt
parentd5387889cf085aef87f5ad40da8b3971385e2a1e (diff)
downloadFreeBSD-src-4abeaed33de9450b5e4900151806d6b8329b4958.zip
FreeBSD-src-4abeaed33de9450b5e4900151806d6b8329b4958.tar.gz
o Newer EFI implementations require that a GPT is preceeded by
a PMBR. Make sure the create command creates a PMBR as well (if not already present). o When parsing the MBR, explicitly check for a PMBR and create a PMBR map node if one is found. o When parsing the MBR, recurse to handle extended partitions. This allows us to flatten nested MBRs when migrating to a GPT. o Have the migrate command bail out if it encounters a partition it doesn't know how to migrate. This avoids data loss. o Change the output of the show command so that the UUIDs of the GPT partitions fit on the same line. o Show when partitions are extended partitions and add the PMBR type. Approved by: re (blanket)
Diffstat (limited to 'sbin/gpt')
-rw-r--r--sbin/gpt/create.c35
-rw-r--r--sbin/gpt/gpt.c128
-rw-r--r--sbin/gpt/map.h1
-rw-r--r--sbin/gpt/migrate.c13
-rw-r--r--sbin/gpt/show.c31
5 files changed, 153 insertions, 55 deletions
diff --git a/sbin/gpt/create.c b/sbin/gpt/create.c
index ec2b121..e9ac8ce 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 28b28b2..6ab98d1 100644
--- a/sbin/gpt/gpt.c
+++ b/sbin/gpt/gpt.c
@@ -162,6 +162,90 @@ gpt_write(int fd, map_t *map)
}
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)
{
off_t size;
@@ -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 4bdc94a..34ea0a6 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 eca172d..f0affa9 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 27fc113..3e9ebc8 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;
OpenPOWER on IntegriCloud