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