show.c revision 1.46 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.45 mlelstv __RCSID("$NetBSD: show.c,v 1.46 2024/11/04 18:36:16 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.25 christos 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