blob: 4942251fa06f1bb9ff0cbdf68f6261f268ee955c [file] [log] [blame]
Bill Richardsonf1372d92010-06-11 09:15:55 -07001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cgpt.h"
6
7#define __STDC_FORMAT_MACROS
8#include <getopt.h>
Bill Richardsonc4e92af2010-10-12 07:33:15 -07009#include <inttypes.h>
Bill Richardsonf1372d92010-06-11 09:15:55 -070010#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include "cgptlib_internal.h"
15
16static void Usage(void)
17{
18 printf("\nUsage: %s show [OPTIONS] DRIVE\n\n"
19 "Display the GPT table\n\n"
20 "Options:\n"
21 " -n Numeric output only\n"
22 " -v Verbose output\n"
23 " -q Quick output\n"
24 " -i NUM Show specified partition only - pick one of:\n"
25 " -b beginning sector\n"
26 " -s partition size\n"
27 " -t type guid\n"
28 " -u unique guid\n"
29 " -l label\n"
30 " -S Successful flag\n"
31 " -T Tries flag\n"
32 " -P Priority flag\n"
33 " -A raw 64-bit attribute value\n"
34 "\n", progname);
35}
36
37
38/* Generate output like:
39 *
40 * [AB-CD-EF-01] for group = 1
41 * [ABCD-EF01] for group = 3 (low byte first)
42 *
43 * Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
44 */
45#define BUFFER_SIZE(size) (size *3 - 1 + 3)
46static short Uint8To2Chars(const uint8_t t) {
47 int h = t >> 4;
48 int l = t & 0xf;
49 h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
50 l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
51 return (h << 8) + l;
52}
53static void RawDump(const uint8_t *memory, const int size,
54 char *buf, int group) {
55 int i, outlen = 0;
56 buf[outlen++] = '[';
57 for (i = 0; i < size; ++i) {
58 short c2 = Uint8To2Chars(memory[i]);
59 buf[outlen++] = c2 >> 8;
60 buf[outlen++] = c2 & 0xff;
61 if (i != (size - 1) && ((i + 1) % group) == 0)
62 buf[outlen++] = '-';
63 }
64 buf[outlen++] = ']';
65 buf[outlen++] = '\0';
66}
67
68/* Output formatters */
69
70
71
72#define TITLE_FMT "%10s%10s%8s %s\n"
73#define GPT_FMT "%10d%10d%8s %s\n"
74#define GPT_MORE "%10s%10s%8s ", "", "", ""
75#define PARTITION_FMT "%10d%10d%8d %s\n"
76#define PARTITION_MORE "%10s%10s%8s %s%s\n", "", "", ""
77
78static void HeaderDetails(GptHeader *header, const char *indent, int raw) {
79 int i;
80
81 printf("%sSig: ", indent);
82 if (!raw) {
Bill Richardsonc4e92af2010-10-12 07:33:15 -070083 printf("[");
Bill Richardsonf1372d92010-06-11 09:15:55 -070084 for (i = 0; i < sizeof(header->signature); ++i)
85 printf("%c", header->signature[i]);
86 printf("]");
87 } else {
88 char buf[BUFFER_SIZE(sizeof(header->signature))];
89 RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
90 printf("%s", buf);
91 }
92 printf("\n");
93
94 printf("%sRev: 0x%08x\n", indent, header->revision);
95 printf("%sSize: %d\n", indent, header->size);
96 printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32);
97 printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
Bill Richardson962483c2010-06-15 21:07:18 -070098 printf("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_lba);
Bill Richardsonf1372d92010-06-11 09:15:55 -070099 printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
100 printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
101
102 { /* For disk guid */
103 char buf[GUID_STRLEN];
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700104 GuidToStr(&header->disk_uuid, buf, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700105 printf("%sDisk UUID: %s\n", indent, buf);
106 }
107
108 printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
109 printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
110 printf("%sSize of entry: %d\n", indent, header->size_of_entry);
111 printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
112}
113
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700114void EntryDetails(GptEntry *entry, uint32_t index, int raw) {
115 char contents[256]; // scratch buffer for formatting output
116 uint8_t label[GPT_PARTNAME_LEN];
Bill Richardsonf1372d92010-06-11 09:15:55 -0700117
118 if (!raw) {
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700119 char type[GUID_STRLEN], unique[GUID_STRLEN];
Bill Richardsonf1372d92010-06-11 09:15:55 -0700120
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700121 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
122 label, sizeof(label));
123 require(snprintf(contents, sizeof(contents),
124 "Label: \"%s\"", label) < sizeof(contents));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700125 printf(PARTITION_FMT, (int)entry->starting_lba,
126 (int)(entry->ending_lba - entry->starting_lba + 1),
127 index+1, contents);
128 if (CGPT_OK == ResolveType(&entry->type, type)) {
129 printf(PARTITION_MORE, "Type: ", type);
130 } else {
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700131 GuidToStr(&entry->type, type, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700132 printf(PARTITION_MORE, "Type: ", type);
133 }
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700134 GuidToStr(&entry->unique, unique, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700135 printf(PARTITION_MORE, "UUID: ", unique);
Bill Richardson3430b322010-11-29 14:24:51 -0800136 if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
vbendebf7a45cc2010-06-21 08:44:16 -0700137 int tries = (entry->attrs.fields.gpt_att &
138 CGPT_ATTRIBUTE_TRIES_MASK) >>
139 CGPT_ATTRIBUTE_TRIES_OFFSET;
140 int successful = (entry->attrs.fields.gpt_att &
141 CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
142 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
143 int priority = (entry->attrs.fields.gpt_att &
144 CGPT_ATTRIBUTE_PRIORITY_MASK) >>
145 CGPT_ATTRIBUTE_PRIORITY_OFFSET;
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700146 require(snprintf(contents, sizeof(contents),
147 "priority=%d tries=%d successful=%d",
148 priority, tries, successful) < sizeof(contents));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700149 printf(PARTITION_MORE, "Attr: ", contents);
150 }
151 } else {
152 char type[GUID_STRLEN], unique[GUID_STRLEN];
153
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700154 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
155 label, sizeof(label));
156 require(snprintf(contents, sizeof(contents),
157 "Label: \"%s\"", label) < sizeof(contents));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700158 printf(PARTITION_FMT, (int)entry->starting_lba,
159 (int)(entry->ending_lba - entry->starting_lba + 1),
160 index+1, contents);
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700161 GuidToStr(&entry->type, type, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700162 printf(PARTITION_MORE, "Type: ", type);
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700163 GuidToStr(&entry->unique, unique, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700164 printf(PARTITION_MORE, "UUID: ", unique);
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700165 require(snprintf(contents, sizeof(contents),
166 "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700167 printf(PARTITION_MORE, "Attr: ", contents);
168 }
169}
170
171
172void EntriesDetails(GptData *gpt, const int secondary, int raw) {
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700173 uint32_t i;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700174
175 for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
176 GptEntry *entry;
177 entry = GetEntry(gpt, secondary, i);
178
Bill Richardson3430b322010-11-29 14:24:51 -0800179 if (IsZero(&entry->type))
180 continue;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700181
182 EntryDetails(entry, i, raw);
183 }
184}
185
186int cmd_show(int argc, char *argv[]) {
187 struct drive drive;
188 int numeric = 0;
189 int verbose = 0;
190 int quick = 0;
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700191 uint32_t partition = 0;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700192 int single_item = 0;
193 int gpt_retval;
194
195 int c;
196 int errorcnt = 0;
197 char *e = 0;
198
199 opterr = 0; // quiet, you
200 while ((c=getopt(argc, argv, ":hnvqi:bstulSTPA")) != -1)
201 {
202 switch (c)
203 {
204 case 'n':
205 numeric = 1;
206 break;
207 case 'v':
208 verbose = 1;
209 break;
210 case 'q':
211 quick = 1;
212 break;
213 case 'i':
214 partition = (uint32_t)strtoul(optarg, &e, 0);
215 if (!*optarg || (e && *e))
216 {
217 Error("invalid argument to -%c: \"%s\"\n", c, optarg);
218 errorcnt++;
219 }
220 break;
221 case 'b':
222 case 's':
223 case 't':
224 case 'u':
225 case 'l':
226 case 'S':
227 case 'T':
228 case 'P':
229 case 'A':
230 single_item = c;
231 break;
232
233 case 'h':
234 Usage();
235 return CGPT_OK;
236 case '?':
237 Error("unrecognized option: -%c\n", optopt);
238 errorcnt++;
239 break;
240 case ':':
241 Error("missing argument to -%c\n", optopt);
242 errorcnt++;
243 break;
244 default:
245 errorcnt++;
246 break;
247 }
248 }
249 if (errorcnt)
250 {
251 Usage();
252 return CGPT_FAILED;
253 }
254
255 if (optind >= argc) {
256 Error("missing drive argument\n");
257 Usage();
258 return CGPT_FAILED;
259 }
260
261 if (CGPT_OK != DriveOpen(argv[optind], &drive))
262 return CGPT_FAILED;
263
264 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
265 Error("GptSanityCheck() returned %d: %s\n",
266 gpt_retval, GptError(gpt_retval));
267 return CGPT_FAILED;
268 }
269
270 if (partition) { // show single partition
271
272 if (partition > GetNumberOfEntries(&drive.gpt)) {
273 Error("invalid partition number: %d\n", partition);
274 return CGPT_FAILED;
275 }
276
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700277 uint32_t index = partition - 1;
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800278 GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index);
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700279 char buf[256]; // scratch buffer for string conversion
Bill Richardsonf1372d92010-06-11 09:15:55 -0700280
281 if (single_item) {
282 switch(single_item) {
283 case 'b':
284 printf("%" PRId64 "\n", entry->starting_lba);
285 break;
286 case 's':
287 printf("%" PRId64 "\n", entry->ending_lba - entry->starting_lba + 1);
288 break;
289 case 't':
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700290 GuidToStr(&entry->type, buf, sizeof(buf));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700291 printf("%s\n", buf);
292 break;
293 case 'u':
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700294 GuidToStr(&entry->unique, buf, sizeof(buf));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700295 printf("%s\n", buf);
296 break;
297 case 'l':
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700298 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
299 (uint8_t *)buf, sizeof(buf));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700300 printf("%s\n", buf);
301 break;
302 case 'S':
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800303 printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700304 break;
305 case 'T':
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800306 printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700307 break;
308 case 'P':
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800309 printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700310 break;
311 case 'A':
vbendebf7a45cc2010-06-21 08:44:16 -0700312 printf("0x%x\n", entry->attrs.fields.gpt_att);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700313 break;
314 }
315 } else {
316 printf(TITLE_FMT, "start", "size", "part", "contents");
317 EntryDetails(entry, index, numeric);
318 }
319
320 } else if (quick) { // show all partitions, quickly
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700321 uint32_t i;
Bill Richardsonf1372d92010-06-11 09:15:55 -0700322 GptEntry *entry;
323 char type[GUID_STRLEN];
324
325 for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
Louis Yung-Chieh Lo2b23c022010-11-18 09:53:10 +0800326 entry = GetEntry(&drive.gpt, ANY_VALID, i);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700327
328 if (IsZero(&entry->type))
329 continue;
330
331 if (!numeric && CGPT_OK == ResolveType(&entry->type, type)) {
332 } else {
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700333 GuidToStr(&entry->type, type, GUID_STRLEN);
Bill Richardsonf1372d92010-06-11 09:15:55 -0700334 }
335 printf(PARTITION_FMT, (int)entry->starting_lba,
336 (int)(entry->ending_lba - entry->starting_lba + 1),
337 i+1, type);
338 }
339
340 } else { // show all partitions
341
342 if (CGPT_OK != ReadPMBR(&drive)) {
343 Error("Unable to read PMBR\n");
344 return CGPT_FAILED;
345 }
346
347 printf(TITLE_FMT, "start", "size", "part", "contents");
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700348 char buf[256]; // buffer for formatted PMBR content
349 PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small
Bill Richardsonf1372d92010-06-11 09:15:55 -0700350 printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
351
352 if (drive.gpt.valid_headers & MASK_PRIMARY) {
353 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
354 (int)GPT_HEADER_SECTOR, "", "Pri GPT header");
355 if (verbose) {
356 GptHeader *header;
357 char indent[64];
358
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700359 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700360 header = (GptHeader*)drive.gpt.primary_header;
361 HeaderDetails(header, indent, numeric);
362 }
363 } else {
364 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
365 (int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
366 }
367
368 printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
369 (int)GPT_ENTRIES_SECTORS,
370 drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
371 "Pri GPT table");
372
373 if (drive.gpt.valid_entries & MASK_PRIMARY)
374 EntriesDetails(&drive.gpt, PRIMARY, numeric);
375
376 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
377 GPT_ENTRIES_SECTORS),
378 (int)GPT_ENTRIES_SECTORS,
379 drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
380 "Sec GPT table");
381 /* We show secondary table details if any of following is true.
382 * 1. only secondary is valid.
383 * 2. secondary is not identical to promary.
384 */
385 if ((drive.gpt.valid_entries & MASK_SECONDARY) &&
386 (!(drive.gpt.valid_entries & MASK_PRIMARY) ||
387 memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
388 TOTAL_ENTRIES_SIZE))) {
389 EntriesDetails(&drive.gpt, SECONDARY, numeric);
390 }
391
392 if (drive.gpt.valid_headers & MASK_SECONDARY)
393 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
394 (int)GPT_HEADER_SECTOR, "", "Sec GPT header");
395 else
396 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
397 (int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
398 /* We show secondary header if any of following is true:
399 * 1. only secondary is valid.
400 * 2. secondary is not synonymous to primary.
401 */
402 if ((drive.gpt.valid_headers & MASK_SECONDARY) &&
403 (!(drive.gpt.valid_headers & MASK_PRIMARY) ||
404 !IsSynonymous((GptHeader*)drive.gpt.primary_header,
405 (GptHeader*)drive.gpt.secondary_header))) {
406 if (verbose) {
407 GptHeader *header;
408 char indent[64];
409
Bill Richardsonc4e92af2010-10-12 07:33:15 -0700410 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
Bill Richardsonf1372d92010-06-11 09:15:55 -0700411 header = (GptHeader*)drive.gpt.secondary_header;
412 HeaderDetails(header, indent, numeric);
413 }
414 }
415 }
416
417 (void) CheckValid(&drive);
418 (void) DriveClose(&drive, 0);
419
420 return CGPT_OK;
421}