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)
This commit is contained in:
Marcel Moolenaar 2002-12-02 01:42:03 +00:00
parent 8e7ea1fc7d
commit 2a944ecdef
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=107482
5 changed files with 153 additions and 55 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;