blob: 143b5fa14a067fc4397b0072d21d1a17fd411174 [file] [log] [blame]
Jay Srinivasana0581432012-01-26 21:50:05 -08001// Copyright (c) 2012 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
Jay Srinivasana0581432012-01-26 21:50:05 -08005#define __STDC_FORMAT_MACROS
6
7#include <string.h>
8
Bill Richardson0c3ba242013-03-29 11:09:30 -07009#include "cgpt.h"
Jay Srinivasana0581432012-01-26 21:50:05 -080010#include "cgptlib_internal.h"
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080011#include "crc32.h"
Bill Richardson0c3ba242013-03-29 11:09:30 -070012#include "vboot_host.h"
Jay Srinivasana0581432012-01-26 21:50:05 -080013
Jay Srinivasana0581432012-01-26 21:50:05 -080014/* Generate output like:
15 *
16 * [AB-CD-EF-01] for group = 1
17 * [ABCD-EF01] for group = 3 (low byte first)
18 *
19 * Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
20 */
21#define BUFFER_SIZE(size) (size *3 - 1 + 3)
22static short Uint8To2Chars(const uint8_t t) {
23 int h = t >> 4;
24 int l = t & 0xf;
25 h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
26 l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
27 return (h << 8) + l;
28}
29
30static void RawDump(const uint8_t *memory, const int size,
31 char *buf, int group) {
32 int i, outlen = 0;
33 buf[outlen++] = '[';
34 for (i = 0; i < size; ++i) {
35 short c2 = Uint8To2Chars(memory[i]);
36 buf[outlen++] = c2 >> 8;
37 buf[outlen++] = c2 & 0xff;
38 if (i != (size - 1) && ((i + 1) % group) == 0)
39 buf[outlen++] = '-';
40 }
41 buf[outlen++] = ']';
42 buf[outlen++] = '\0';
43}
44
45/* Output formatters */
Shawn Nematbakhsh82bb8022012-07-30 15:05:59 -070046#define TITLE_FMT "%12s%12s%8s %s\n"
47#define GPT_FMT "%12d%12d%8s %s\n"
48#define GPT_MORE "%12s%12s%8s ", "", "", ""
49#define PARTITION_FMT "%12d%12d%8d %s\n"
50#define PARTITION_MORE "%12s%12s%8s %s%s\n", "", "", ""
Jay Srinivasana0581432012-01-26 21:50:05 -080051
Albert Chaulk1c568bc2013-04-02 14:35:39 -070052void PrintSignature(const char *indent, const char *sig, size_t n, int raw) {
53 size_t i;
Jay Srinivasana0581432012-01-26 21:50:05 -080054 printf("%sSig: ", indent);
55 if (!raw) {
56 printf("[");
Albert Chaulk1c568bc2013-04-02 14:35:39 -070057 for (i = 0; i < n; ++i)
58 printf("%c", sig[i]);
Jay Srinivasana0581432012-01-26 21:50:05 -080059 printf("]");
60 } else {
Albert Chaulk1c568bc2013-04-02 14:35:39 -070061 char *buf = malloc(BUFFER_SIZE(n));
62 RawDump((uint8_t *)sig, n, buf, 1);
Jay Srinivasana0581432012-01-26 21:50:05 -080063 printf("%s", buf);
Albert Chaulk1c568bc2013-04-02 14:35:39 -070064 free(buf);
Jay Srinivasana0581432012-01-26 21:50:05 -080065 }
66 printf("\n");
Albert Chaulk1c568bc2013-04-02 14:35:39 -070067}
68
Albert Chaulk1c568bc2013-04-02 14:35:39 -070069static void HeaderDetails(GptHeader *header, GptEntry *entries,
70 const char *indent, int raw) {
71 PrintSignature(indent, header->signature, sizeof(header->signature), raw);
Jay Srinivasana0581432012-01-26 21:50:05 -080072
73 printf("%sRev: 0x%08x\n", indent, header->revision);
74 printf("%sSize: %d\n", indent, header->size);
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080075 printf("%sHeader CRC: 0x%08x %s\n", indent, header->header_crc32,
76 (HeaderCrc(header) != header->header_crc32) ? "(INVALID)" : "");
Jay Srinivasana0581432012-01-26 21:50:05 -080077 printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
78 printf("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_lba);
79 printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
80 printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
81
82 { /* For disk guid */
83 char buf[GUID_STRLEN];
84 GuidToStr(&header->disk_uuid, buf, GUID_STRLEN);
85 printf("%sDisk UUID: %s\n", indent, buf);
86 }
87
88 printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
89 printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
90 printf("%sSize of entry: %d\n", indent, header->size_of_entry);
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080091 printf("%sEntries CRC: 0x%08x %s\n", indent, header->entries_crc32,
92 header->entries_crc32 !=
93 Crc32((const uint8_t *)entries,header->size_of_entry *
94 header->number_of_entries)
95 ? "INVALID" : ""
96 );
Jay Srinivasana0581432012-01-26 21:50:05 -080097}
98
99void EntryDetails(GptEntry *entry, uint32_t index, int raw) {
100 char contents[256]; // scratch buffer for formatting output
101 uint8_t label[GPT_PARTNAME_LEN];
Albert Chaulk32fd6de2013-07-25 11:32:57 -0700102 char type[GUID_STRLEN], unique[GUID_STRLEN];
103
104 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
105 label, sizeof(label));
106 require(snprintf(contents, sizeof(contents),
107 "Label: \"%s\"", label) < sizeof(contents));
108 printf(PARTITION_FMT, (int)entry->starting_lba,
109 (int)(entry->ending_lba - entry->starting_lba + 1),
110 index+1, contents);
111
112 if (!raw && CGPT_OK == ResolveType(&entry->type, type)) {
113 printf(PARTITION_MORE, "Type: ", type);
114 } else {
115 GuidToStr(&entry->type, type, GUID_STRLEN);
116 printf(PARTITION_MORE, "Type: ", type);
117 }
118 GuidToStr(&entry->unique, unique, GUID_STRLEN);
119 printf(PARTITION_MORE, "UUID: ", unique);
Jay Srinivasana0581432012-01-26 21:50:05 -0800120
121 if (!raw) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800122 if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
123 int tries = (entry->attrs.fields.gpt_att &
124 CGPT_ATTRIBUTE_TRIES_MASK) >>
125 CGPT_ATTRIBUTE_TRIES_OFFSET;
126 int successful = (entry->attrs.fields.gpt_att &
127 CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
128 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
129 int priority = (entry->attrs.fields.gpt_att &
130 CGPT_ATTRIBUTE_PRIORITY_MASK) >>
131 CGPT_ATTRIBUTE_PRIORITY_OFFSET;
132 require(snprintf(contents, sizeof(contents),
133 "priority=%d tries=%d successful=%d",
134 priority, tries, successful) < sizeof(contents));
135 printf(PARTITION_MORE, "Attr: ", contents);
136 }
137 } else {
Jay Srinivasana0581432012-01-26 21:50:05 -0800138 require(snprintf(contents, sizeof(contents),
139 "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents));
140 printf(PARTITION_MORE, "Attr: ", contents);
141 }
142}
143
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700144void EntriesDetails(struct drive *drive, const int secondary, int raw) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800145 uint32_t i;
146
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700147 for (i = 0; i < GetNumberOfEntries(drive); ++i) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800148 GptEntry *entry;
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700149 entry = GetEntry(&drive->gpt, secondary, i);
Jay Srinivasana0581432012-01-26 21:50:05 -0800150
Bill Richardson3f806a22013-03-20 15:02:34 -0700151 if (GuidIsZero(&entry->type))
Jay Srinivasana0581432012-01-26 21:50:05 -0800152 continue;
153
154 EntryDetails(entry, i, raw);
155 }
156}
157
Bill Richardson18e03702014-06-23 17:48:33 -0700158static int GptShow(struct drive *drive, CgptShowParams *params) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800159 int gpt_retval;
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700160 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800161 Error("GptSanityCheck() returned %d: %s\n",
162 gpt_retval, GptError(gpt_retval));
163 return CGPT_FAILED;
164 }
165
166 if (params->partition) { // show single partition
167
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700168 if (params->partition > GetNumberOfEntries(drive)) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800169 Error("invalid partition number: %d\n", params->partition);
170 return CGPT_FAILED;
171 }
172
173 uint32_t index = params->partition - 1;
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700174 GptEntry *entry = GetEntry(&drive->gpt, ANY_VALID, index);
Jay Srinivasana0581432012-01-26 21:50:05 -0800175 char buf[256]; // scratch buffer for string conversion
176
177 if (params->single_item) {
178 switch(params->single_item) {
179 case 'b':
180 printf("%" PRId64 "\n", entry->starting_lba);
181 break;
Mike Frysinger98624d32013-05-03 18:05:16 -0400182 case 's': {
183 uint64_t size = 0;
184 // If these aren't actually defined, don't show anything
185 if (entry->ending_lba || entry->starting_lba)
186 size = entry->ending_lba - entry->starting_lba + 1;
187 printf("%" PRId64 "\n", size);
Jay Srinivasana0581432012-01-26 21:50:05 -0800188 break;
Mike Frysinger98624d32013-05-03 18:05:16 -0400189 }
Jay Srinivasana0581432012-01-26 21:50:05 -0800190 case 't':
191 GuidToStr(&entry->type, buf, sizeof(buf));
192 printf("%s\n", buf);
193 break;
194 case 'u':
195 GuidToStr(&entry->unique, buf, sizeof(buf));
196 printf("%s\n", buf);
197 break;
198 case 'l':
199 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
200 (uint8_t *)buf, sizeof(buf));
201 printf("%s\n", buf);
202 break;
203 case 'S':
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700204 printf("%d\n", GetSuccessful(drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800205 break;
206 case 'T':
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700207 printf("%d\n", GetTries(drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800208 break;
209 case 'P':
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700210 printf("%d\n", GetPriority(drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800211 break;
212 case 'A':
213 printf("0x%x\n", entry->attrs.fields.gpt_att);
214 break;
215 }
216 } else {
217 printf(TITLE_FMT, "start", "size", "part", "contents");
218 EntryDetails(entry, index, params->numeric);
219 }
220
221 } else if (params->quick) { // show all partitions, quickly
222 uint32_t i;
223 GptEntry *entry;
224 char type[GUID_STRLEN];
225
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700226 for (i = 0; i < GetNumberOfEntries(drive); ++i) {
227 entry = GetEntry(&drive->gpt, ANY_VALID, i);
Jay Srinivasana0581432012-01-26 21:50:05 -0800228
Bill Richardson3f806a22013-03-20 15:02:34 -0700229 if (GuidIsZero(&entry->type))
Jay Srinivasana0581432012-01-26 21:50:05 -0800230 continue;
231
232 if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) {
233 } else {
234 GuidToStr(&entry->type, type, GUID_STRLEN);
235 }
236 printf(PARTITION_FMT, (int)entry->starting_lba,
237 (int)(entry->ending_lba - entry->starting_lba + 1),
238 i+1, type);
239 }
240 } else { // show all partitions
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800241 GptEntry *entries;
242
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700243 if (CGPT_OK != ReadPMBR(drive)) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800244 Error("Unable to read PMBR\n");
245 return CGPT_FAILED;
246 }
247
248 printf(TITLE_FMT, "start", "size", "part", "contents");
249 char buf[256]; // buffer for formatted PMBR content
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700250 PMBRToStr(&drive->pmbr, buf, sizeof(buf)); // will exit if buf is too small
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700251 printf(GPT_FMT, 0, GPT_PMBR_SECTORS, "", buf);
Jay Srinivasana0581432012-01-26 21:50:05 -0800252
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700253 if (drive->gpt.valid_headers & MASK_PRIMARY) {
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700254 printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
255 (int)GPT_HEADER_SECTORS, "", "Pri GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800256 } else {
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700257 printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
258 (int)GPT_HEADER_SECTORS, "INVALID", "Pri GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800259 }
260
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800261 if (params->debug ||
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700262 ((drive->gpt.valid_headers & MASK_PRIMARY) && params->verbose)) {
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800263 GptHeader *header;
264 char indent[64];
265
266 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700267 header = (GptHeader*)drive->gpt.primary_header;
268 entries = (GptEntry*)drive->gpt.primary_entries;
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800269 HeaderDetails(header, entries, indent, params->numeric);
270 }
271
Nam T. Nguyena2d72f72014-08-22 15:01:38 -0700272 GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
273 printf(GPT_FMT, (int)primary_header->entries_lba,
Nam T. Nguyen32004012014-12-12 09:38:35 -0800274 (int)CalculateEntriesSectors(primary_header),
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700275 drive->gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
Jay Srinivasana0581432012-01-26 21:50:05 -0800276 "Pri GPT table");
277
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800278 if (params->debug ||
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700279 (drive->gpt.valid_entries & MASK_PRIMARY))
280 EntriesDetails(drive, PRIMARY, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800281
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800282 /****************************** Secondary *************************/
Nam T. Nguyena2d72f72014-08-22 15:01:38 -0700283 GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
284 printf(GPT_FMT, (int)secondary_header->entries_lba,
Nam T. Nguyen32004012014-12-12 09:38:35 -0800285 (int)CalculateEntriesSectors(secondary_header),
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700286 drive->gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
Jay Srinivasana0581432012-01-26 21:50:05 -0800287 "Sec GPT table");
288 /* We show secondary table details if any of following is true.
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800289 * 1. in debug mode.
290 * 2. only secondary is valid.
291 * 3. secondary is not identical to promary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800292 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800293 if (params->debug ||
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700294 ((drive->gpt.valid_entries & MASK_SECONDARY) &&
295 (!(drive->gpt.valid_entries & MASK_PRIMARY) ||
296 memcmp(drive->gpt.primary_entries, drive->gpt.secondary_entries,
Nam T. Nguyen32004012014-12-12 09:38:35 -0800297 secondary_header->number_of_entries *
298 secondary_header->size_of_entry)))) {
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700299 EntriesDetails(drive, SECONDARY, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800300 }
301
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700302 if (drive->gpt.valid_headers & MASK_SECONDARY)
Nam T. Nguyen6ee52d92014-10-24 13:20:39 -0700303 printf(GPT_FMT, (int)(drive->gpt.gpt_drive_sectors - GPT_HEADER_SECTORS),
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700304 (int)GPT_HEADER_SECTORS, "", "Sec GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800305 else
Nam T. Nguyen88458d92014-08-28 10:58:47 -0700306 printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
307 (int)GPT_HEADER_SECTORS, "INVALID", "Sec GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800308 /* We show secondary header if any of following is true:
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800309 * 1. in debug mode.
310 * 2. only secondary is valid.
311 * 3. secondary is not synonymous to primary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800312 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800313 if (params->debug ||
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700314 ((drive->gpt.valid_headers & MASK_SECONDARY) &&
315 (!(drive->gpt.valid_headers & MASK_PRIMARY) ||
316 !IsSynonymous((GptHeader*)drive->gpt.primary_header,
317 (GptHeader*)drive->gpt.secondary_header)) &&
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800318 params->verbose)) {
319 GptHeader *header;
320 char indent[64];
Jay Srinivasana0581432012-01-26 21:50:05 -0800321
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800322 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700323 header = (GptHeader*)drive->gpt.secondary_header;
324 entries = (GptEntry*)drive->gpt.secondary_entries;
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800325 HeaderDetails(header, entries, indent, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800326 }
327 }
328
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700329 CheckValid(drive);
Jay Srinivasana0581432012-01-26 21:50:05 -0800330
331 return CGPT_OK;
332}
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700333
334int CgptShow(CgptShowParams *params) {
335 struct drive drive;
336
337 if (params == NULL)
338 return CGPT_FAILED;
339
Nam T. Nguyenab899592014-11-13 19:30:46 -0800340 if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY,
341 params->drive_size))
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700342 return CGPT_FAILED;
343
Nam T. Nguyen8577b532014-11-25 13:26:53 -0800344 if (GptShow(&drive, params))
345 return CGPT_FAILED;
Albert Chaulk1c568bc2013-04-02 14:35:39 -0700346
347 DriveClose(&drive, 0);
348 return CGPT_OK;
349}