summaryrefslogtreecommitdiffstats
path: root/sbin/gpt/gpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/gpt/gpt.c')
-rw-r--r--sbin/gpt/gpt.c128
1 files changed, 85 insertions, 43 deletions
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)
OpenPOWER on IntegriCloud