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.50 2026/03/28 20:43:34 palle Exp $");
     37 #endif
     38 
     39 #include <sys/bootblock.h>
     40 #include <sys/types.h>
     41 #if defined(HAVE_SYS_ENDIAN_H) || ! defined(HAVE_NBTOOL_CONFIG_H)
     42 #include <sys/endian.h>
     43 #endif
     44 
     45 #include <err.h>
     46 #include <locale.h>
     47 #include <stddef.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 #include <vis.h>
     53 
     54 #ifndef HAVE_NBTOOL_CONFIG_H
     55 #include <sys/ioctl.h>
     56 #endif
     57 
     58 #include "map.h"
     59 #include "gpt.h"
     60 #include "gpt_private.h"
     61 
     62 static int cmd_show(gpt_t, int, char *[]);
     63 
     64 static const char *showhelp[] = {
     65 	"[-AagHhlux] [-b start_block] [-i index] [ -W width ]",
     66 };
     67 
     68 #define SHOW_UUID	0x0001
     69 #define SHOW_GUID	0x0002
     70 #define SHOW_LABEL	0x0004
     71 #define SHOW_ALL	0x0008
     72 #define SHOW_HEX	0x0010
     73 #define SHOW_HUMAN	0x0020
     74 #define SHOW_DECIMAL	0x0040
     75 #define SHOW_APPROX	0x0080
     76 #define SHOW_PARSABLE	0x0100
     77 
     78 #define SHOW_NOSHOW	0x10000
     79 
     80 const struct gpt_cmd c_show = {
     81 	"show",
     82 	cmd_show,
     83 	showhelp, __arraycount(showhelp),
     84 	GPT_READONLY,
     85 };
     86 
     87 #define usage() gpt_usage(NULL, &c_show)
     88 
     89 static unsigned int out_width;
     90 
     91 static const char *
     92 get_mbr_sig(char *b, size_t blen, const uint8_t *bp)
     93 {
     94 	gpt_uuid_t uuid;
     95 
     96 	/*
     97 	 * MBR partitions have a 4 byte signature in the MBR.  Table
     98 	 * 10.54 of UEFI Spec 2.10 Errata A states how this is to be
     99 	 * formatted as a GUID.
    100 	 *
    101 	 * XXX: I thought I had seen more on this elsewhere, but I
    102 	 * can't seem to find it now.  In particular, the endianness
    103 	 * of this quanity is not clear in the above.
    104 	 *
    105 	 * XXX: The location and size of the MBR signature should be
    106 	 * in 'struct mbr,' e.g.:
    107 	 *
    108 	 * struct mbr {
    109 	 *	uint8_t		mbr_code[440];
    110 	 *	uint32_t	mbr_disc_sig;
    111 	 *	uint16_t	mbr_unknown;
    112 	 *	struct mbr_part	mbr_part[4];
    113 	 *	uint16_t	mbr_sig;
    114 	 * };
    115 	 *
    116 	 * For now, we just hardcode it.  Ugh!
    117 	 */
    118 	memset(uuid, 0, sizeof(uuid));
    119 	memcpy(uuid, bp + 440, 4);
    120 	gpt_uuid_snprintf(b, blen, "%d", uuid);
    121 	return b;
    122 }
    123 
    124 static const char *
    125 get_gpt_hdr_guid(char *b, size_t blen, struct gpt_hdr *hdr)
    126 {
    127 	gpt_uuid_snprintf(b, blen, "%d", hdr->hdr_guid);
    128 	return b;
    129 }
    130 
    131 static char *
    132 parsable_label(gpt_t gpt, struct gpt_ent *ent)
    133 {
    134 	char *res;
    135 	char *ol;
    136 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    137 
    138 	if (ent->ent_name[0] == 0)
    139 		return NULL;
    140 
    141 	utf16_to_utf8(ent->ent_name,
    142 	    __arraycount(ent->ent_name), utfbuf,
    143 	    __arraycount(utfbuf));
    144 
    145 	ol = setlocale(LC_CTYPE, "en_GB.UTF-8");
    146 	stravis(&res, (char *)utfbuf, VIS_CSTYLE|VIS_OCTAL|VIS_TAB|VIS_NL);
    147 	if (ol)
    148 		setlocale(LC_CTYPE, ol);
    149 
    150 	return res;
    151 }
    152 
    153 static int
    154 print_part_type(gpt_t gpt, int map_type, int flags, void *map_data,
    155     off_t map_start)
    156 {
    157 	off_t start;
    158 	map_t p;
    159 	struct mbr *mbr;
    160 	struct gpt_ent *ent;
    161 	unsigned int i;
    162 	char buf[128], *b = buf;
    163 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    164 	int len = 0;
    165 
    166 	switch (map_type) {
    167 	case MAP_TYPE_UNUSED:
    168 		len += printf("Unused");
    169 		break;
    170 	case MAP_TYPE_MBR:
    171 		if (map_start != 0)
    172 			len += printf("Extended ");
    173 		len += printf("MBR");
    174 		if (map_start == 0 && flags & SHOW_GUID)
    175 			len += printf(" - %s",
    176 			    get_mbr_sig(buf, sizeof(buf), map_data));
    177 		break;
    178 	case MAP_TYPE_PRI_GPT_HDR:
    179 		len += printf("Pri GPT header");
    180 		if (flags & SHOW_GUID)
    181 			len += printf(" - %s",
    182 			    get_gpt_hdr_guid(buf, sizeof(buf), map_data));
    183 		break;
    184 	case MAP_TYPE_SEC_GPT_HDR:
    185 		len += printf("Sec GPT header");
    186 		if (flags & SHOW_GUID)
    187 			len += printf(" - %s",
    188 			    get_gpt_hdr_guid(buf, sizeof(buf), map_data));
    189 		break;
    190 	case MAP_TYPE_PRI_GPT_TBL:
    191 		len += printf("Pri GPT table");
    192 		break;
    193 	case MAP_TYPE_SEC_GPT_TBL:
    194 		len += printf("Sec GPT table");
    195 		break;
    196 	case MAP_TYPE_MBR_PART:
    197 		p = map_data;
    198 		if (p->map_start != 0)
    199 			len += printf("Extended ");
    200 		len += printf("MBR part ");
    201 		mbr = p->map_data;
    202 		for (i = 0; i < 4; i++) {
    203 			start = le16toh(mbr->mbr_part[i].part_start_hi);
    204 			start = (start << 16) +
    205 			    le16toh(mbr->mbr_part[i].part_start_lo);
    206 			if (map_start == p->map_start + start)
    207 				break;
    208 		}
    209 		if (i == 4) {
    210 			/* wasn't there */
    211 			len += printf("[partition not found?]");
    212 		} else {
    213 			len += printf("%d%s", mbr->mbr_part[i].part_typ,
    214 			    mbr->mbr_part[i].part_flag == 0x80 ?
    215 			    " (active)" : "");
    216 		}
    217 		break;
    218 	case MAP_TYPE_GPT_PART:
    219 		len += printf("GPT part ");
    220 		ent = map_data;
    221 		if (flags & SHOW_LABEL && ent->ent_name[0] != 0) {
    222 			if (flags & SHOW_PARSABLE)
    223 				b = parsable_label(gpt, ent);
    224 			else {
    225 				utf16_to_utf8(ent->ent_name,
    226 				    __arraycount(ent->ent_name), utfbuf,
    227 				    __arraycount(utfbuf));
    228 				b = (char *)utfbuf;
    229 			}
    230 		} else if (flags & SHOW_GUID) {
    231 			gpt_uuid_snprintf(buf, sizeof(buf), "%d",
    232 			    ent->ent_guid);
    233 		} else if (flags & SHOW_UUID) {
    234 			gpt_uuid_snprintf(buf, sizeof(buf), "%d",
    235 			    ent->ent_type);
    236 		} else {
    237 			gpt_uuid_snprintf(buf, sizeof(buf), "%l",
    238 			    ent->ent_type);
    239 		}
    240 		if (b != NULL)
    241 			len += printf("- %s", b);
    242 		if (b != buf && b != (char *)utfbuf)
    243 			free(b);
    244 		break;
    245 	case MAP_TYPE_PMBR:
    246 		len += printf("PMBR");
    247 		mbr = map_data;
    248 		if (mbr->mbr_part[0].part_typ == MBR_PTYPE_PMBR &&
    249 		    mbr->mbr_part[0].part_flag == 0x80)
    250 			    len += printf(" (active)");
    251 		break;
    252 	default:
    253 		len += printf("Unknown %#x", map_type);
    254 		break;
    255 	}
    256 	return len;
    257 }
    258 
    259 static char *
    260 cvt_size(gpt_t gpt, uintmax_t sz, int xshow, char *b, unsigned int bs)
    261 {
    262 	char *p;
    263 	const char *u;
    264 	uintmax_t num;
    265 	int plus = 0;
    266 
    267 #define SFMT (xshow & SHOW_HEX) ?    "%jx" :    "%ju"
    268 #define FMT  (xshow & SHOW_HEX) ? "  %*jx" : "  %*ju"
    269 
    270 	if (bs >= INT_MAX)
    271 		bs = INT_MAX / 2;
    272 
    273 	num = sz * gpt->secsz;
    274 
    275 	if (num == 0 || (xshow & SHOW_HUMAN) == 0) {
    276  bale:
    277 		if (snprintf(b, bs, SFMT, sz) <= (int)bs)
    278 			return b;
    279 		if (!(xshow & SHOW_NOSHOW))
    280 			printf(FMT, gpt->lbawidth, sz);
    281 		return NULL;
    282 	}
    283 
    284 	sz = num;	/* so if we bale after this we get bytes, not sectors */
    285 
    286 #ifdef HN_AUTOSCALE
    287 	if (xshow & SHOW_APPROX) {
    288 		int flags = HN_NOSPACE|HN_B|HN_DECIMAL;
    289 
    290 		if (xshow & SHOW_DECIMAL)
    291 			flags |= HN_DIVISOR_1000;
    292 
    293 		if (humanize_number(b, (bs > 6 ? 5 : bs), (int64_t)num,
    294 		    "", HN_AUTOSCALE, flags) < 0)
    295 			goto bale;
    296 		return b;
    297 	}
    298 #endif
    299 
    300 	u = "BKMGTPE";
    301 	p = b + bs - 1;
    302 	*p = '\0';
    303 
    304 		ssize_t n = 0;
    305 	while (num != 0 && *u != '\0') {
    306 		char unitbuf[32];
    307 		uintmax_t val;
    308 
    309 		if (xshow & SHOW_DECIMAL)
    310 			val = num % 1000;
    311 		else
    312 			val = num & 0x3FF;
    313 
    314 		if (u[1] == '\0' || val != 0) {
    315 			n = snprintf(unitbuf, sizeof unitbuf, SFMT,
    316 				u[1] == '\0' ? num : val);
    317 			if (n < 0)
    318 				goto bale;
    319 			if (b + n + plus >= p)
    320 				break;
    321 			p -= n + 1 + plus;
    322 			(void)strcpy(p, unitbuf);
    323 			p[n++] = *u;
    324 			if (plus)
    325 				p[n] = ' '; /* or '_' or '+' */
    326 			plus = 1;
    327 		}
    328 
    329 		if (xshow & SHOW_DECIMAL)
    330 			num /= 1000;
    331 		else
    332 			num >>= 10;
    333 		u++;
    334 	}
    335 	if (*u != '\0' && num != 0)
    336 		goto bale;
    337 
    338 	return p;
    339 }
    340 
    341 static int
    342 show(gpt_t gpt, int xshow)
    343 {
    344 	map_t m;
    345 	char *p;
    346 	unsigned int w1 = (unsigned int)gpt->lbawidth + 2;
    347 	unsigned int w2;
    348 	char szbuf[64];
    349 
    350 	if ((size_t)w1 > sizeof szbuf - 2)
    351 		w1 = sizeof szbuf - 2;
    352 	w2 = w1;
    353 
    354 	if (xshow & SHOW_HUMAN) {
    355 		if (xshow & SHOW_APPROX) {
    356 			if (w1 > 8)
    357 				w2 = w1 = 7;
    358 		} else {
    359 			w1 = w2 = 0;
    360 			m = map_first(gpt);
    361 			while (m != NULL) {
    362 				size_t l;
    363 
    364 				p = cvt_size(gpt, (uintmax_t)m->map_start,
    365 				    xshow | SHOW_NOSHOW, szbuf, sizeof szbuf);
    366 				if (p != NULL && (l = strlen(p)) > (size_t)w1)
    367 					w1 = (unsigned int)l;
    368 				p = cvt_size(gpt, (uintmax_t)m->map_size,
    369 				    xshow | SHOW_NOSHOW, szbuf, sizeof szbuf);
    370 				if (p != NULL && (l = strlen(p)) > (size_t) w2)
    371 					w2 = (unsigned int)l;
    372 
    373 				m = m->map_next;
    374 			}
    375 		}
    376 	}
    377 	w2 += 2;	/* space between columns */
    378 
    379 	if ((size_t)w1 >= sizeof szbuf)
    380 		w1 = (unsigned int)sizeof szbuf - 1;
    381 	if ((size_t)w2 >= sizeof szbuf)
    382 		w2 = (unsigned int)sizeof szbuf - 1;
    383 
    384 	if (!(xshow & SHOW_PARSABLE)) {
    385 		if (w1 < 5 /* strlen("start")) */)
    386 			w1 = 5;
    387 		if (w2 < 4 /* strlen("size")) */)
    388 			w2 = 4;
    389 		printf("%*s", w1, "start");
    390 		printf("%*s", w2, "size");
    391 		printf("  index  contents\n");
    392 	}
    393 
    394 	m = map_first(gpt);
    395 	if (xshow & SHOW_PARSABLE) {
    396 		while (m != NULL) {
    397 			printf("%ju %ju %u ", (uintmax_t)m->map_start,
    398 			    (uintmax_t)m->map_size, m->map_index);
    399 			print_part_type(gpt, m->map_type, xshow, m->map_data,
    400 			    m->map_start);
    401 			putchar('\n');
    402 			m = m->map_next;
    403 		}
    404 		return 0;
    405 	}
    406 
    407 	while (m != NULL) {
    408 		p = cvt_size(gpt, (uintmax_t)m->map_start, xshow, szbuf, w1+1);
    409 		if (p != NULL)
    410 			printf("%*s", w1, p);
    411 
    412 		p = cvt_size(gpt, (uintmax_t)m->map_size, xshow, szbuf, w2+1);
    413 		if (p != NULL)
    414 			printf("%*s", w2, p);
    415 
    416 		putchar(' ');
    417 		putchar(' ');
    418 		if (m->map_index > 0)
    419 			printf("%5d", m->map_index);
    420 		else
    421 			printf("     ");
    422 		putchar(' ');
    423 		putchar(' ');
    424 		print_part_type(gpt, m->map_type, xshow, m->map_data,
    425 		    m->map_start);
    426 		putchar('\n');
    427 		m = m->map_next;
    428 	}
    429 	return 0;
    430 }
    431 
    432 static void
    433 gpt_show_sec_num(const char *label, int64_t secsize, off_t num, int xshow,
    434     gpt_t gpt)
    435 {
    436 	char *p = NULL;
    437 	char size_string[64];
    438 #ifdef HN_AUTOSCALE
    439 	char human_num[5];
    440 #endif
    441 
    442 	if (xshow & SHOW_HUMAN
    443 #ifdef HN_AUTOSCALE
    444 	    && !(xshow & SHOW_APPROX)
    445 #endif
    446 					) {
    447 		p = cvt_size(gpt, (uintmax_t)num, xshow,
    448 		    size_string, sizeof size_string);
    449 	}
    450 #ifdef HN_AUTOSCALE
    451 	if (p == NULL && humanize_number(p = human_num, sizeof(human_num),
    452 	    (int64_t)num*secsize,
    453 	    "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0)
    454 		human_num[0] = '\0';
    455 #endif
    456 	printf("%s: %" PRIu64, label, (uint64_t)num);
    457 	if (p != NULL && p[0] != '\0')
    458 		printf(" (%s)", p);
    459 	printf("\n");
    460 }
    461 
    462 
    463 static int
    464 show_parsable(gpt_t gpt, map_t m, struct gpt_ent *ent, int xshow)
    465 {
    466 	char s1[128], s2[128], *p;
    467 
    468 	printf("Index: %u\n", m->map_index);
    469 	printf("Start: %ju\n", (uintmax_t)m->map_start);
    470 	printf("Size: %ju\n", (uintmax_t)m->map_size);
    471 
    472 	if (gpt->verbose)
    473 		printf("Map_Type: %d\n", m->map_type);
    474 
    475 	if (m->map_type != MAP_TYPE_GPT_PART) {
    476 		printf("Purpose: ");
    477 		print_part_type(gpt, m->map_type, 0, m->map_data,
    478 		    m->map_start);
    479 		putchar('\n');
    480 		if (m->map_type == MAP_TYPE_PRI_GPT_HDR ||
    481 		    m->map_type == MAP_TYPE_SEC_GPT_HDR) {
    482 			get_gpt_hdr_guid(s1, sizeof(s1), m->map_data);
    483 			printf("GUID: %s\n", s1);
    484 		}
    485 		return 0;
    486 	}
    487 
    488 	gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_guid);
    489 	printf("GUID: %s\n", s2);
    490 
    491 	gpt_uuid_snprintf(s1, sizeof(s1), "%s", ent->ent_type);
    492 	gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_type);
    493 	printf("TypeID: %s\n", s2);
    494 	if (strcmp(s1, s2) != 0)
    495 		printf("Type: %s\n", s1);
    496 	gpt_uuid_snprintf(s1, sizeof(s1), "%l", ent->ent_type);
    497 	if (strcmp(s1, s2) != 0)
    498 		printf("Long_Type: %s\n", s1);
    499 
    500 
    501 	if (ent->ent_attr != 0) {
    502 		char buf[1024];
    503 
    504 		printf("Attributes: %s\n",
    505 		    gpt_attr_list(buf, sizeof(buf), ent->ent_attr));
    506 	}
    507 
    508 	p = parsable_label(gpt, ent);
    509 	if (p != NULL) {
    510 		printf("Label: %s\n", p );
    511 		free(p);
    512 	}
    513 
    514 	return 0;
    515 }
    516 
    517 static int
    518 show_one(gpt_t gpt, unsigned int entry, int xshow)
    519 {
    520 	map_t m;
    521 	struct gpt_ent *ent;
    522 	char s1[128], s2[128];
    523 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    524 
    525 	for (m = map_first(gpt); m != NULL; m = m->map_next)
    526 		if (entry == m->map_index)
    527 			break;
    528 	if (m == NULL) {
    529 		gpt_warnx(gpt, "Could not find index %d", entry);
    530 		return -1;
    531 	}
    532 	ent = m->map_data;
    533 
    534 	if (xshow & SHOW_PARSABLE)
    535 		return show_parsable(gpt, m, ent, xshow);
    536 
    537 	printf("Details for index %d:\n", entry);
    538 	gpt_show_sec_num("Start", gpt->secsz, m->map_start, xshow, gpt);
    539 	gpt_show_sec_num("Size", gpt->secsz, m->map_size, xshow, gpt);
    540 
    541 	gpt_uuid_snprintf(s1, sizeof(s1), "%s", ent->ent_type);
    542 	gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_type);
    543 	if (strcmp(s1, s2) == 0)
    544 		strlcpy(s1, "unknown", sizeof(s1));
    545 	printf("Type: %s (%s)\n", s1, s2);
    546 
    547 	gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_guid);
    548 	printf("GUID: %s\n", s2);
    549 
    550 	utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name), utfbuf,
    551 	    __arraycount(utfbuf));
    552 	printf("Label: %s\n", (char *)utfbuf);
    553 
    554 	printf("Attributes: ");
    555 	if (ent->ent_attr == 0) {
    556 		printf("None\n");
    557 	} else  {
    558 		char buf[1024];
    559 		printf("%s\n", gpt_attr_list(buf, sizeof(buf), ent->ent_attr));
    560 	}
    561 
    562 	return 0;
    563 }
    564 
    565 static int
    566 show_all(gpt_t gpt, int xshow)
    567 {
    568 	map_t m;
    569 	struct gpt_ent *ent;
    570 	char s1[128], s2[128];
    571 	char human_num[8];
    572 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    573 	unsigned int width;
    574 	char *p;
    575 
    576 	m = map_first(gpt);
    577 
    578 	if (xshow & SHOW_PARSABLE) {
    579 		while (m != NULL) {
    580 			ent = m->map_data;
    581 			show_parsable(gpt, m, ent, xshow);
    582 			putchar('\n');
    583 			m = m->map_next;
    584 		}
    585 		return 0;
    586 	}
    587 
    588 	printf("  %*s", gpt->lbawidth, "start");
    589 	printf("  %*s", gpt->lbawidth, "size");
    590 	printf("  index  contents\n");
    591 
    592 	width = 2 * ((unsigned)gpt->lbawidth + 2) + 7;
    593 
    594 	while (m != NULL) {
    595 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_start);
    596 		printf(FMT, gpt->lbawidth, (uintmax_t)m->map_size);
    597 		putchar(' ');
    598 		putchar(' ');
    599 		if (m->map_index > 0) {
    600 			printf("%5d  ", m->map_index);
    601 			print_part_type(gpt, m->map_type, 0, m->map_data,
    602 			    m->map_start);
    603 			putchar('\n');
    604 
    605 			ent = m->map_data;
    606 
    607 			gpt_uuid_snprintf(s1, sizeof(s1), "%s", ent->ent_type);
    608 			gpt_uuid_snprintf(s2, sizeof(s2), "%d", ent->ent_type);
    609 			if (strcmp(s1, s2) == 0)
    610 				strlcpy(s1, "unknown", sizeof(s1));
    611 			printf("%*s  Type: %s\n", width, "", s1);
    612 			if (m->map_type == MAP_TYPE_MBR_PART) {
    613 				static uint8_t unused_uuid[sizeof(gpt_uuid_t)];
    614 				/*
    615 				 * MBR part partitions don't have
    616 				 * GUIDs, so don't create a bogus one!
    617 				 *
    618 				 * We could get the TypeID from the
    619 				 * partition type (the one byte OSType
    620 				 * field in the partition structure),
    621 				 * perhaps borrowing info from fdisk.
    622 				 * However, some OSTypes have multiple
    623 				 * OSes assigned to them and many may
    624 				 * not have official UUIDs.
    625 				 *
    626 				 * Should we even print anything for
    627 				 * these, in particular the GUID?
    628 				 */
    629 				gpt_uuid_snprintf(s2, sizeof(s2), "%d",
    630 				    unused_uuid);
    631 
    632 				printf("%*s  TypeID: %s\n", width, "", s2);
    633 				printf("%*s  GUID: %s\n", width, "", s2);
    634 			} else {
    635 				printf("%*s  TypeID: %s\n", width, "", s2);
    636 				gpt_uuid_snprintf(s2, sizeof(s2), "%d",
    637 				    ent->ent_guid);
    638 				printf("%*s  GUID: %s\n", width, "", s2);
    639 			}
    640 
    641 			printf("%*s  Size: ", width, "");
    642 			human_num[0] = '\0';
    643 #ifdef HN_AUTOSCALE
    644 			if (humanize_number(human_num, sizeof(human_num),
    645 			    (int64_t)(m->map_size * gpt->secsz),
    646 			    "", HN_AUTOSCALE, (xshow & SHOW_DECIMAL) ?
    647 			    HN_DIVISOR_1000|HN_B : HN_B) >= 0)
    648 				printf("%s ", human_num);
    649 #endif
    650 			printf("%s%ju%s", human_num[0] ? "(" : "",
    651 			    (intmax_t)m->map_size * gpt->secsz,
    652 			    human_num[0] ? ")" : "");
    653 
    654 			if (xshow & SHOW_HUMAN) {
    655 				p = cvt_size(gpt, (uintmax_t)m->map_size, xshow,
    656 				    s1, sizeof s1);
    657 				if (p)
    658 					printf(" = %s", p);
    659 			}
    660 			putchar('\n');
    661 
    662 			utf16_to_utf8(ent->ent_name,
    663 			    __arraycount(ent->ent_name), utfbuf,
    664 			    __arraycount(utfbuf));
    665 			printf("%*s  Label: %s\n", width, "", (char *)utfbuf);
    666 
    667 			printf("%*s  Attributes: ", width, "");
    668 			if (ent->ent_attr == 0) {
    669 				printf("None\n");
    670 			} else  {
    671 				char buf[1024];
    672 
    673 				printf("%s\n", gpt_attr_list(buf, sizeof(buf),
    674 				    ent->ent_attr));
    675 			}
    676 		} else {
    677 			unsigned int pr = (unsigned)printf("       ");
    678 			pr += (unsigned)print_part_type(gpt, m->map_type, 0,
    679 			    m->map_data, m->map_start);
    680 			if (xshow & SHOW_HUMAN) {
    681 				int bw = 4;
    682 
    683 				p = cvt_size(gpt, (uintmax_t)m->map_size,
    684 					xshow | SHOW_NOSHOW, s1, sizeof s1);
    685 
    686 				if (p != NULL) {
    687 					unsigned int w = (unsigned)strlen(p);
    688 
    689 					if (w < 4)
    690 						w = 4;
    691 
    692 					if (width + pr + w + 4 < out_width) {
    693 						w = out_width - 1 -
    694 						    width - pr - w;
    695 					} else
    696 						bw = 1, w = 2;
    697 
    698 					printf("%*s[ %*s ]", w, "", bw, p);
    699 				}
    700 			}
    701 			putchar('\n');
    702 
    703 			switch (m->map_type) {
    704 			case MAP_TYPE_PRI_GPT_HDR:
    705 			case MAP_TYPE_SEC_GPT_HDR:
    706 				printf("%*s  GUID: %s\n", width, "",
    707 				    get_gpt_hdr_guid(s1, sizeof(s1),
    708 				    m->map_data));
    709 				break;
    710 			case MAP_TYPE_MBR:
    711 				printf("%*s  GUID: %s\n", width, "",
    712 				    get_mbr_sig(s1, sizeof(s1), m->map_data));
    713 				break;
    714 			default:
    715 				break;
    716 			}
    717 		}
    718 		m = m->map_next;
    719 	}
    720 	return 0;
    721 }
    722 
    723 static unsigned int
    724 get_terminal_width(void)
    725 {
    726 	unsigned int w;
    727 	char *p;
    728 	int err;
    729 #ifndef HAVE_NBTOOL_CONFIG_H
    730 	struct winsize wsz;
    731 #endif
    732 
    733 	if ((p = getenv("COLUMNS")) != NULL) {
    734 		w = (unsigned int)strtou(p, NULL, 10, 0, 3000, &err);
    735 		if (err == 0)
    736 			return w;
    737 	}
    738 #ifndef HAVE_NBTOOL_CONFIG_H
    739 	if (ioctl(fileno(stdout), TIOCGWINSZ, &wsz) == 0)
    740 		return wsz.ws_col;
    741 #endif
    742 	return 0;
    743 }
    744 
    745 static int
    746 cmd_show(gpt_t gpt, int argc, char *argv[])
    747 {
    748 	int ch;
    749 	int xshow = 0;
    750 	int wide = 0;
    751 	unsigned int entry = 0;
    752 	off_t start = 0;
    753 	map_t m;
    754 
    755 	out_width = 0;
    756 
    757 	while ((ch = getopt(argc, argv, "gi:b:luaxAhHpW:w")) != -1) {
    758 		switch(ch) {
    759 		case 'a':
    760 			xshow |= SHOW_ALL;
    761 			break;
    762 		case 'g':
    763 			xshow |= SHOW_GUID;
    764 			break;
    765 		case 'i':
    766 			if (gpt_uint_get(gpt, &entry) == -1)
    767 				return usage();
    768 			break;
    769 		case 'b':
    770 			if (gpt_human_get(gpt, &start) == -1)
    771 				return usage();
    772 			break;
    773 		case 'l':
    774 			xshow |= SHOW_LABEL;
    775 			break;
    776 		case 'u':
    777 			xshow |= SHOW_UUID;
    778 			break;
    779 		case 'x':
    780 			xshow |= SHOW_HEX;
    781 			break;
    782 		case 'A':
    783 			xshow |= SHOW_HUMAN | SHOW_APPROX;
    784 			break;
    785 		case 'h':
    786 			xshow |= SHOW_HUMAN;
    787 			break;
    788 		case 'H':
    789 			xshow |= SHOW_HUMAN | SHOW_DECIMAL;
    790 			break;
    791 		case 'p':
    792 			xshow |= SHOW_PARSABLE;
    793 			break;
    794 		case 'W':
    795 			if (gpt_uint_get(gpt, &out_width) < 0)
    796 				usage();
    797 			break;
    798 		case 'w':
    799 			if (wide < 10)	/* avoid overflow! */
    800 				wide++;
    801 			break;
    802 		default:
    803 			return usage();
    804 		}
    805 	}
    806 
    807 	if (out_width == 0) {
    808 		out_width = get_terminal_width();
    809 		if (out_width == 0) {
    810 			switch (wide) {
    811 			case  0: out_width = 80;  break;
    812 			case  1: out_width = 120; break;
    813 			case  2: out_width = 200; break;
    814 			default: out_width = 320; break;
    815 			}
    816 		}
    817 	}
    818 
    819 	/* This restriction is important to keep the output syntax constant */
    820 	if (xshow & SHOW_PARSABLE)
    821 		xshow &= ~(SHOW_HUMAN | SHOW_APPROX | SHOW_DECIMAL | SHOW_HEX);
    822 
    823 	/* This one is just a preventative measure for human sanity */
    824 	if (xshow & SHOW_HUMAN)
    825 		xshow &= ~SHOW_HEX;
    826 
    827 	if (argc != optind)
    828 		return usage();
    829 
    830 	if ((map_find(gpt, MAP_TYPE_PRI_GPT_HDR) == NULL) &&
    831 	    ! (gpt->flags & GPT_QUIET) )
    832 		printf("GPT not found, displaying data from MBR.\n\n");
    833 
    834 	if (xshow & SHOW_ALL)
    835 		return show_all(gpt, xshow);
    836 
    837 	if (start > 0) {
    838 		for (m = map_first(gpt); m != NULL; m = m->map_next) {
    839 			if (m->map_type != MAP_TYPE_GPT_PART ||
    840 			    m->map_index < 1)
    841 				continue;
    842 			if (start != m->map_start)
    843 				continue;
    844 			entry = m->map_index;
    845 			break;
    846 		}
    847 	}
    848 
    849 	return entry > 0 ? show_one(gpt, entry, xshow) : show(gpt, xshow);
    850 }
    851