#include <sys/param.h>
#include <err.h>
#include <libutil.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "gpt.h"
static bool show_guid = false;
static bool show_label = false;
static bool show_uuid = false;
static void
usage_show(void)
{
fprintf(stderr, "usage: %s [-glu] device ...\n", getprogname());
exit(1);
}
static const char *
friendly(uuid_t *t)
{
static char *save_name1 = NULL;
static char *save_name2 = NULL;
if (show_uuid)
goto unfriendly;
uuid_addr_lookup(t, &save_name1, NULL);
if (save_name1)
return (save_name1);
unfriendly:
if (save_name2) {
free(save_name2);
save_name2 = NULL;
}
uuid_to_string(t, &save_name2, NULL);
return (save_name2);
}
static void
show(int fd __unused)
{
uuid_t type, guid;
off_t start;
map_t *m, *p;
struct mbr *mbr;
struct gpt_ent *ent;
size_t i, j;
char *s, humansz[sizeof("99.9GB")], lwbuf[32];
char utfbuf[NELEM(ent->ent_name) * 3 + 1];
const char *name;
int lbawidth;
lbawidth = sprintf(lwbuf, "%ju", (uintmax_t)(mediasz / secsz));
if (lbawidth < 5)
lbawidth = 5;
humanize_number(humansz, sizeof(humansz), (int64_t)mediasz, "B",
HN_AUTOSCALE, HN_FRACTIONAL | HN_NOSPACE);
printf("Disk %s: %s (%ju %u-byte sectors)\n",
device_name, humansz, (uintmax_t)(mediasz / secsz), secsz);
printf(" %*s", lbawidth, "Start");
printf(" %*s", lbawidth, "Sectors");
printf(" %*s", (int)(sizeof(humansz) - 1), "Size");
printf(" Index Contents\n");
for (m = map_first(); m != NULL; m = m->map_next) {
printf(" %*ju", lbawidth, (uintmax_t)m->map_start);
printf(" %*ju", lbawidth, (uintmax_t)m->map_size);
humanize_number(humansz, sizeof(humansz),
(int64_t)(m->map_size * secsz), "B",
HN_AUTOSCALE, HN_FRACTIONAL | HN_NOSPACE);
printf(" %*s", (int)(sizeof(humansz) - 1), humansz);
putchar(' ');
putchar(' ');
if (m->map_index != MAP_NOENTRY)
printf("%5d", m->map_index);
else
printf(" -");
putchar(' ');
putchar(' ');
switch (m->map_type) {
case MAP_TYPE_UNUSED:
printf("Unused");
break;
case MAP_TYPE_MBR:
if (m->map_start != 0)
printf("Extended ");
printf("MBR");
break;
case MAP_TYPE_GPT_PRI_HDR:
printf("Primary GPT header");
break;
case MAP_TYPE_GPT_SEC_HDR:
printf("Secondary GPT header");
break;
case MAP_TYPE_GPT_PRI_TBL:
printf("Primary GPT table");
break;
case MAP_TYPE_GPT_SEC_TBL:
printf("Secondary GPT table");
break;
case MAP_TYPE_MBR_PART:
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 = le32toh(mbr->mbr_part[i].dp_start);
if (m->map_start == p->map_start + start)
break;
}
if (i == 4) {
printf("[partition not found?]");
} else {
name = NULL;
for (j = 0; j < NELEM(dos_ptypes); j++) {
if (dos_ptypes[j].type ==
mbr->mbr_part[i].dp_typ) {
name = dos_ptypes[j].name;
break;
}
}
if (name != NULL)
printf("- %s", name);
else
printf("- %d", mbr->mbr_part[i].dp_typ);
if (mbr->mbr_part[i].dp_flag == 0x80)
printf(" (active)");
}
break;
case MAP_TYPE_GPT_PART:
printf("GPT part ");
ent = m->map_data;
if (show_label) {
utf16_to_utf8(ent->ent_name,
NELEM(ent->ent_name),
utfbuf, sizeof(utfbuf));
printf("- \"%s\"", utfbuf);
} else if (show_guid) {
s = NULL;
uuid_dec_le(&ent->ent_uuid, &guid);
uuid_to_string(&guid, &s, NULL);
printf("- %s", s);
free(s);
s = NULL;
} else {
uuid_dec_le(&ent->ent_type, &type);
printf("- %s", friendly(&type));
}
break;
case MAP_TYPE_PMBR:
printf("PMBR");
mbr = m->map_data;
if (mbr->mbr_part[0].dp_typ == DOSPTYP_PMBR &&
mbr->mbr_part[0].dp_flag == 0x80)
printf(" (active)");
break;
default:
printf("Unknown %#x", m->map_type);
break;
}
putchar('\n');
}
}
int
cmd_show(int argc, char *argv[])
{
int ch, fd;
while ((ch = getopt(argc, argv, "ghlu")) != -1) {
switch(ch) {
case 'g':
show_guid = true;
break;
case 'l':
show_label = true;
break;
case 'u':
show_uuid = true;
break;
case 'h':
default:
usage_show();
}
}
if (argc == optind)
usage_show();
while (optind < argc) {
fd = gpt_open(argv[optind++]);
if (fd == -1) {
warn("unable to open device '%s'", device_name);
} else {
show(fd);
gpt_close(fd);
}
if (optind != argc)
putchar('\n');
}
return (0);
}