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.46 2024/11/04 18:36:16 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 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