Home | History | Annotate | Line # | Download | only in gpt
      1 /*-
      2  * Copyright (c) 2002 Marcel Moolenaar
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #if HAVE_NBTOOL_CONFIG_H
     28 #include "nbtool_config.h"
     29 #endif
     30 
     31 #include <sys/cdefs.h>
     32 #ifdef __FBSDID
     33 __FBSDID("$FreeBSD: src/sbin/gpt/show.c,v 1.14 2006/06/22 22:22:32 marcel Exp $");
     34 #endif
     35 #ifdef __RCSID
     36 __RCSID("$NetBSD: show.c,v 1.47 2025/02/23 20:47:19 christos Exp $");
     37 #endif
     38 
     39 #include <sys/bootblock.h>
     40 #include <sys/types.h>
     41 
     42 #include <err.h>
     43 #include <stddef.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <unistd.h>
     48 
     49 
     50 #include "map.h"
     51 #include "gpt.h"
     52 #include "gpt_private.h"
     53 
     54 static int cmd_show(gpt_t, int, char *[]);
     55 
     56 static const char *showhelp[] = {
     57 	"[-aglux] [-i index]",
     58 };
     59 
     60 #define SHOW_UUID  1
     61 #define SHOW_GUID  2
     62 #define SHOW_LABEL 4
     63 #define SHOW_ALL   8
     64 #define SHOW_HEX   16
     65 
     66 const struct gpt_cmd c_show = {
     67 	"show",
     68 	cmd_show,
     69 	showhelp, __arraycount(showhelp),
     70 	GPT_READONLY,
     71 };
     72 
     73 #define usage() gpt_usage(NULL, &c_show)
     74 
     75 static const char *
     76 get_mbr_sig(char *b, size_t blen, const uint8_t *bp)
     77 {
     78 	gpt_uuid_t uuid;
     79 
     80 	/*
     81 	 * MBR partitions have a 4 byte signature in the MBR.  Table
     82 	 * 10.54 of UEFI Spec 2.10 Errata A states how this is to be
     83 	 * formatted as a GUID.
     84 	 *
     85 	 * XXX: I thought I had seen more on this elsewhere, but I
     86 	 * can't seem to find it now.  In particular, the endianness
     87 	 * of this quanity is not clear in the above.
     88 	 *
     89 	 * XXX: The location and size of the MBR signature should be
     90 	 * in 'struct mbr,' e.g.:
     91 	 *
     92 	 * struct mbr {
     93 	 *	uint8_t		mbr_code[440];
     94 	 *	uint32_t	mbr_disc_sig;
     95 	 *	uint16_t	mbr_unknown;
     96 	 *	struct mbr_part	mbr_part[4];
     97 	 *	uint16_t	mbr_sig;
     98 	 * };
     99 	 *
    100 	 * For now, we just hardcode it.  Ugh!
    101 	 */
    102 	memset(uuid, 0, sizeof(uuid));
    103 	memcpy(uuid, bp + 440, 4);
    104 	gpt_uuid_snprintf(b, blen, "%d", uuid);
    105 	return b;
    106 }
    107 
    108 static const char *
    109 get_gpt_hdr_guid(char *b, size_t blen, struct gpt_hdr *hdr)
    110 {
    111 	gpt_uuid_snprintf(b, blen, "%d", hdr->hdr_guid);
    112 	return b;
    113 }
    114 
    115 static void
    116 print_part_type(int map_type, int flags, void *map_data, off_t map_start)
    117 {
    118 	off_t start;
    119 	map_t p;
    120 	struct mbr *mbr;
    121 	struct gpt_ent *ent;
    122 	unsigned int i;
    123 	char buf[128], *b = buf;
    124 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    125 
    126 	switch (map_type) {
    127 	case MAP_TYPE_UNUSED:
    128 		printf("Unused");
    129 		break;
    130 	case MAP_TYPE_MBR:
    131 		if (map_start != 0)
    132 			printf("Extended ");
    133 		printf("MBR");
    134 		if (map_start == 0 && flags & SHOW_GUID)
    135 			printf(" - %s",
    136 			    get_mbr_sig(buf, sizeof(buf), map_data));
    137 		break;
    138 	case MAP_TYPE_PRI_GPT_HDR:
    139 		printf("Pri GPT header");
    140 		if (flags & SHOW_GUID)
    141 			printf(" - %s",
    142 			    get_gpt_hdr_guid(buf, sizeof(buf), map_data));
    143 		break;
    144 	case MAP_TYPE_SEC_GPT_HDR:
    145 		printf("Sec GPT header");
    146 		if (flags & SHOW_GUID)
    147 			printf(" - %s",
    148 			    get_gpt_hdr_guid(buf, sizeof(buf), map_data));
    149 		break;
    150 	case MAP_TYPE_PRI_GPT_TBL:
    151 		printf("Pri GPT table");
    152 		break;
    153 	case MAP_TYPE_SEC_GPT_TBL:
    154 		printf("Sec GPT table");
    155 		break;
    156 	case MAP_TYPE_MBR_PART:
    157 		p = map_data;
    158 		if (p->map_start != 0)
    159 			printf("Extended ");
    160 		printf("MBR part ");
    161 		mbr = p->map_data;
    162 		for (i = 0; i < 4; i++) {
    163 			start = le16toh(mbr->mbr_part[i].part_start_hi);
    164 			start = (start << 16) +
    165 			    le16toh(mbr->mbr_part[i].part_start_lo);
    166 			if (map_start == p->map_start + start)
    167 				break;
    168 		}
    169 		if (i == 4) {
    170 			/* wasn't there */
    171 			printf("[partition not found?]");
    172 		} else {
    173 			printf("%d%s", mbr->mbr_part[i].part_typ,
    174 			    mbr->mbr_part[i].part_flag == 0x80 ?
    175 			    " (active)" : "");
    176 		}
    177 		break;
    178 	case MAP_TYPE_GPT_PART:
    179 		printf("GPT part ");
    180 		ent = map_data;
    181 		if (flags & SHOW_LABEL) {
    182 			utf16_to_utf8(ent->ent_name,
    183 			    __arraycount(ent->ent_name), utfbuf,
    184 			    __arraycount(utfbuf));
    185 			b = (char *)utfbuf;
    186 		} else if (flags & SHOW_GUID) {
    187 			gpt_uuid_snprintf( buf, sizeof(buf), "%d",
    188 			    ent->ent_guid);
    189 		} else if (flags & SHOW_UUID) {
    190 			gpt_uuid_snprintf(buf, sizeof(buf),
    191 			    "%d", ent->ent_type);
    192 		} else {
    193 			gpt_uuid_snprintf(buf, sizeof(buf), "%ls",
    194 			    ent->ent_type);
    195 		}
    196 		printf("- %s", b);
    197 		break;
    198 	case MAP_TYPE_PMBR:
    199 		printf("PMBR");
    200 		mbr = map_data;
    201 		if (mbr->mbr_part[0].part_typ == MBR_PTYPE_PMBR &&
    202 		    mbr->mbr_part[0].part_flag == 0x80)
    203 			    printf(" (active)");
    204 		break;
    205 	default:
    206 		printf("Unknown %#x", map_type);
    207 		break;
    208 	}
    209 }
    210 
    211 static int
    212 show(gpt_t gpt, int xshow)
    213 {
    214 	map_t m;
    215 
    216 	printf("  %*s", gpt->lbawidth, "start");
    217 	printf("  %*s", gpt->lbawidth, "size");
    218 	printf("  index  contents\n");
    219 
    220 	m = map_first(gpt);
    221 	while (m != NULL) {
    222 #define FMT (xshow & SHOW_HEX) ? "  %*jx" : "  %*ju"
    223 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_start);
    224 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_size);
    225 		putchar(' ');
    226 		putchar(' ');
    227 		if (m->map_index > 0)
    228 			printf("%5d", m->map_index);
    229 		else
    230 			printf("     ");
    231 		putchar(' ');
    232 		putchar(' ');
    233 		print_part_type(m->map_type, xshow, m->map_data, m->map_start);
    234 		putchar('\n');
    235 		m = m->map_next;
    236 	}
    237 	return 0;
    238 }
    239 
    240 static void
    241 gpt_show_sec_num(const char *prompt, int64_t secsize, off_t num)
    242 {
    243 #ifdef HN_AUTOSCALE
    244 	char human_num[5];
    245 	if (humanize_number(human_num, sizeof(human_num),
    246 	    (int64_t)num*secsize,
    247 	    "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0)
    248 		human_num[0] = '\0';
    249 #endif
    250 	printf("%s: %" PRIu64, prompt, (uint64_t)num);
    251 #ifdef HN_AUTOSCALE
    252 	if (human_num[0] != '\0')
    253 		printf(" (%s)", human_num);
    254 #endif
    255 	printf("\n");
    256 }
    257 
    258 static int
    259 show_one(gpt_t gpt, unsigned int entry)
    260 {
    261 	map_t m;
    262 	struct gpt_ent *ent;
    263 	char s1[128], s2[128];
    264 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    265 
    266 	for (m = map_first(gpt); m != NULL; m = m->map_next)
    267 		if (entry == m->map_index)
    268 			break;
    269 	if (m == NULL) {
    270 		gpt_warnx(gpt, "Could not find index %d", entry);
    271 		return -1;
    272 	}
    273 	ent = m->map_data;
    274 
    275 	printf("Details for index %d:\n", entry);
    276 	gpt_show_sec_num("Start", gpt->secsz, m->map_start);
    277 	gpt_show_sec_num("Size", gpt->secsz, m->map_size);
    278 
    279 	gpt_uuid_snprintf(s1, sizeof(s1), "%s", ent->ent_type);
    280 	gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_type);
    281 	if (strcmp(s1, s2) == 0)
    282 		strlcpy(s1, "unknown", sizeof(s1));
    283 	printf("Type: %s (%s)\n", s1, s2);
    284 
    285 	gpt_uuid_snprintf(s2, sizeof(s1), "%d", ent->ent_guid);
    286 	printf("GUID: %s\n", s2);
    287 
    288 	utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name), utfbuf,
    289 	    __arraycount(utfbuf));
    290 	printf("Label: %s\n", (char *)utfbuf);
    291 
    292 	printf("Attributes: ");
    293 	if (ent->ent_attr == 0) {
    294 		printf("None\n");
    295 	} else  {
    296 		char buf[1024];
    297 		printf("%s\n", gpt_attr_list(buf, sizeof(buf), ent->ent_attr));
    298 	}
    299 
    300 	return 0;
    301 }
    302 
    303 static int
    304 show_all(gpt_t gpt, int xshow)
    305 {
    306 	map_t m;
    307 	struct gpt_ent *ent;
    308 	char s1[128], s2[128];
    309 #ifdef HN_AUTOSCALE
    310 	char human_num[8];
    311 #endif
    312 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    313 #define PFX "                                 "
    314 
    315 	printf("  %*s", gpt->lbawidth, "start");
    316 	printf("  %*s", gpt->lbawidth, "size");
    317 	printf("  index  contents\n");
    318 
    319 	m = map_first(gpt);
    320 	while (m != NULL) {
    321 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_start);
    322 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_size);
    323 		putchar(' ');
    324 		putchar(' ');
    325 		if (m->map_index > 0) {
    326 			printf("%5d  ", m->map_index);
    327 			print_part_type(m->map_type, 0, m->map_data,
    328 			    m->map_start);
    329 			putchar('\n');
    330 
    331 			ent = m->map_data;
    332 
    333 			gpt_uuid_snprintf(s1, sizeof(s1), "%s", ent->ent_type);
    334 			gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_type);
    335 			if (strcmp(s1, s2) == 0)
    336 				strlcpy(s1, "unknown", sizeof(s1));
    337 			printf(PFX "Type: %s\n", s1);
    338 			if (m->map_type == MAP_TYPE_MBR_PART) {
    339 				static uint8_t unused_uuid[sizeof(gpt_uuid_t)];
    340 				/*
    341 				 * MBR part partitions don't have
    342 				 * GUIDs, so don't create a bogus one!
    343 				 *
    344 				 * We could get the TypeID from the
    345 				 * partition type (the one byte OSType
    346 				 * field in the partition structure),
    347 				 * perhaps borrowing info from fdisk.
    348 				 * However, some OSTypes have multiple
    349 				 * OSes assigned to them and many may
    350 				 * not have official UUIDs.
    351 				 *
    352 				 * Should we even print anything for
    353 				 * these, in particular the GUID?
    354 				 */
    355 				gpt_uuid_snprintf(s2, sizeof(s2), "%d",
    356 				    unused_uuid);
    357 				printf(PFX "TypeID: %s\n", s2);	/* XXX: show this? */
    358 				printf(PFX "GUID: %s\n", s2);	/* XXX: show this? */
    359 			}
    360 			else {
    361 				printf(PFX "TypeID: %s\n", s2);
    362 				gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_guid);
    363 				printf(PFX "GUID: %s\n", s2);
    364 			}
    365 
    366 			printf(PFX "Size: ");
    367 #ifdef HN_AUTOSCALE
    368 			if (humanize_number(human_num, sizeof(human_num),
    369 			    (int64_t)(m->map_size * gpt->secsz),
    370 			    "", HN_AUTOSCALE, HN_B) < 0) {
    371 #endif
    372 				printf("%ju",
    373 				    (int64_t)(m->map_size * gpt->secsz));
    374 #ifdef HN_AUTOSCALE
    375 			} else {
    376 				printf("%s", human_num);
    377 			}
    378 #endif
    379 			putchar('\n');
    380 
    381 			utf16_to_utf8(ent->ent_name,
    382 			    __arraycount(ent->ent_name), utfbuf,
    383 			    __arraycount(utfbuf));
    384 			printf(PFX "Label: %s\n", (char *)utfbuf);
    385 
    386 			printf(PFX "Attributes: ");
    387 			if (ent->ent_attr == 0) {
    388 				printf("None\n");
    389 			} else  {
    390 				char buf[1024];
    391 
    392 				printf("%s\n", gpt_attr_list(buf, sizeof(buf),
    393 				    ent->ent_attr));
    394 			}
    395 		} else {
    396 			printf("       ");
    397 			print_part_type(m->map_type, 0, m->map_data,
    398 			    m->map_start);
    399 			putchar('\n');
    400 
    401 			switch (m->map_type) {
    402 			case MAP_TYPE_PRI_GPT_HDR:
    403 			case MAP_TYPE_SEC_GPT_HDR:
    404 				printf(PFX "GUID: %s\n",
    405 				    get_gpt_hdr_guid(s1, sizeof(s1),
    406 				    m->map_data));
    407 				break;
    408 			case MAP_TYPE_MBR:
    409 				printf(PFX "GUID: %s\n",
    410 				    get_mbr_sig(s1, sizeof(s1), m->map_data));
    411 				break;
    412 			default:
    413 				break;
    414 			}
    415 		}
    416 		m = m->map_next;
    417 	}
    418 	return 0;
    419 }
    420 
    421 static int
    422 cmd_show(gpt_t gpt, int argc, char *argv[])
    423 {
    424 	int ch;
    425 	int xshow = 0;
    426 	unsigned int entry = 0;
    427 	off_t start = 0;
    428 	map_t m;
    429 
    430 	while ((ch = getopt(argc, argv, "gi:b:luax")) != -1) {
    431 		switch(ch) {
    432 		case 'a':
    433 			xshow |= SHOW_ALL;
    434 			break;
    435 		case 'g':
    436 			xshow |= SHOW_GUID;
    437 			break;
    438 		case 'i':
    439 			if (gpt_uint_get(gpt, &entry) == -1)
    440 				return usage();
    441 			break;
    442 		case 'b':
    443 			if (gpt_human_get(gpt, &start) == -1)
    444 				return usage();
    445 			break;
    446 		case 'l':
    447 			xshow |= SHOW_LABEL;
    448 			break;
    449 		case 'u':
    450 			xshow |= SHOW_UUID;
    451 			break;
    452 		case 'x':
    453 			xshow |= SHOW_HEX;
    454 			break;
    455 		default:
    456 			return usage();
    457 		}
    458 	}
    459 
    460 	if (argc != optind)
    461 		return usage();
    462 
    463 	if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) == NULL)
    464 		printf("GPT not found, displaying data from MBR.\n\n");
    465 
    466 	if (xshow & SHOW_ALL)
    467 		return show_all(gpt, xshow);
    468 
    469 	if (start > 0) {
    470 		for (m = map_first(gpt); m != NULL; m = m->map_next) {
    471 			if (m->map_type != MAP_TYPE_GPT_PART ||
    472 			    m->map_index < 1)
    473 				continue;
    474 			if (start != m->map_start)
    475 				continue;
    476 			entry = m->map_index;
    477 			break;
    478 		}
    479 	}
    480 
    481 	return entry > 0 ? show_one(gpt, entry) : show(gpt, xshow);
    482 }
    483