blob: e80567c340a7f11afe3dc4b864bf6403e6ca3892 [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
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080052static void HeaderDetails(GptHeader *header, GptEntry *entries,
53 const char *indent, int raw) {
Jay Srinivasana0581432012-01-26 21:50:05 -080054 int i;
55
56 printf("%sSig: ", indent);
57 if (!raw) {
58 printf("[");
59 for (i = 0; i < sizeof(header->signature); ++i)
60 printf("%c", header->signature[i]);
61 printf("]");
62 } else {
63 char buf[BUFFER_SIZE(sizeof(header->signature))];
64 RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
65 printf("%s", buf);
66 }
67 printf("\n");
68
69 printf("%sRev: 0x%08x\n", indent, header->revision);
70 printf("%sSize: %d\n", indent, header->size);
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080071 printf("%sHeader CRC: 0x%08x %s\n", indent, header->header_crc32,
72 (HeaderCrc(header) != header->header_crc32) ? "(INVALID)" : "");
Jay Srinivasana0581432012-01-26 21:50:05 -080073 printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
74 printf("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_lba);
75 printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
76 printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
77
78 { /* For disk guid */
79 char buf[GUID_STRLEN];
80 GuidToStr(&header->disk_uuid, buf, GUID_STRLEN);
81 printf("%sDisk UUID: %s\n", indent, buf);
82 }
83
84 printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
85 printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
86 printf("%sSize of entry: %d\n", indent, header->size_of_entry);
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +080087 printf("%sEntries CRC: 0x%08x %s\n", indent, header->entries_crc32,
88 header->entries_crc32 !=
89 Crc32((const uint8_t *)entries,header->size_of_entry *
90 header->number_of_entries)
91 ? "INVALID" : ""
92 );
Jay Srinivasana0581432012-01-26 21:50:05 -080093}
94
95void EntryDetails(GptEntry *entry, uint32_t index, int raw) {
96 char contents[256]; // scratch buffer for formatting output
97 uint8_t label[GPT_PARTNAME_LEN];
98
99 if (!raw) {
100 char type[GUID_STRLEN], unique[GUID_STRLEN];
101
102 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
103 label, sizeof(label));
104 require(snprintf(contents, sizeof(contents),
105 "Label: \"%s\"", label) < sizeof(contents));
106 printf(PARTITION_FMT, (int)entry->starting_lba,
107 (int)(entry->ending_lba - entry->starting_lba + 1),
108 index+1, contents);
109 if (CGPT_OK == ResolveType(&entry->type, type)) {
110 printf(PARTITION_MORE, "Type: ", type);
111 } else {
112 GuidToStr(&entry->type, type, GUID_STRLEN);
113 printf(PARTITION_MORE, "Type: ", type);
114 }
115 GuidToStr(&entry->unique, unique, GUID_STRLEN);
116 printf(PARTITION_MORE, "UUID: ", unique);
117 if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
118 int tries = (entry->attrs.fields.gpt_att &
119 CGPT_ATTRIBUTE_TRIES_MASK) >>
120 CGPT_ATTRIBUTE_TRIES_OFFSET;
121 int successful = (entry->attrs.fields.gpt_att &
122 CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
123 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
124 int priority = (entry->attrs.fields.gpt_att &
125 CGPT_ATTRIBUTE_PRIORITY_MASK) >>
126 CGPT_ATTRIBUTE_PRIORITY_OFFSET;
127 require(snprintf(contents, sizeof(contents),
128 "priority=%d tries=%d successful=%d",
129 priority, tries, successful) < sizeof(contents));
130 printf(PARTITION_MORE, "Attr: ", contents);
131 }
132 } else {
133 char type[GUID_STRLEN], unique[GUID_STRLEN];
134
135 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
136 label, sizeof(label));
137 require(snprintf(contents, sizeof(contents),
138 "Label: \"%s\"", label) < sizeof(contents));
139 printf(PARTITION_FMT, (int)entry->starting_lba,
140 (int)(entry->ending_lba - entry->starting_lba + 1),
141 index+1, contents);
142 GuidToStr(&entry->type, type, GUID_STRLEN);
143 printf(PARTITION_MORE, "Type: ", type);
144 GuidToStr(&entry->unique, unique, GUID_STRLEN);
145 printf(PARTITION_MORE, "UUID: ", unique);
146 require(snprintf(contents, sizeof(contents),
147 "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents));
148 printf(PARTITION_MORE, "Attr: ", contents);
149 }
150}
151
152
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700153void EntriesDetails(struct drive *drive, const int secondary, int raw) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800154 uint32_t i;
155
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700156 for (i = 0; i < GetNumberOfEntries(drive); ++i) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800157 GptEntry *entry;
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700158 entry = GetEntry(&drive->gpt, secondary, i);
Jay Srinivasana0581432012-01-26 21:50:05 -0800159
Bill Richardson3f806a22013-03-20 15:02:34 -0700160 if (GuidIsZero(&entry->type))
Jay Srinivasana0581432012-01-26 21:50:05 -0800161 continue;
162
163 EntryDetails(entry, i, raw);
164 }
165}
166
Bill Richardson3f806a22013-03-20 15:02:34 -0700167int CgptGetNumNonEmptyPartitions(CgptShowParams *params) {
Jay Srinivasan250549d2012-02-16 17:40:45 -0800168 struct drive drive;
169 int gpt_retval;
170 int retval;
171
172 if (params == NULL)
173 return CGPT_FAILED;
174
Bill Richardson23429d32012-04-30 11:33:13 -0700175 if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY))
Jay Srinivasan250549d2012-02-16 17:40:45 -0800176 return CGPT_FAILED;
177
178 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
179 Error("GptSanityCheck() returned %d: %s\n",
180 gpt_retval, GptError(gpt_retval));
181 retval = CGPT_FAILED;
182 goto done;
183 }
184
185 params->num_partitions = 0;
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700186 int numEntries = GetNumberOfEntries(&drive);
Jay Srinivasan250549d2012-02-16 17:40:45 -0800187 int i;
188 for(i = 0; i < numEntries; i++) {
189 GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i);
Bill Richardson3f806a22013-03-20 15:02:34 -0700190 if (GuidIsZero(&entry->type))
Jay Srinivasan250549d2012-02-16 17:40:45 -0800191 continue;
192
193 params->num_partitions++;
194 }
195
196 retval = CGPT_OK;
197
198done:
199 DriveClose(&drive, 0);
200 return retval;
201}
202
Bill Richardson3f806a22013-03-20 15:02:34 -0700203int CgptShow(CgptShowParams *params) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800204 struct drive drive;
205 int gpt_retval;
206
207 if (params == NULL)
208 return CGPT_FAILED;
209
Bill Richardson23429d32012-04-30 11:33:13 -0700210 if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY))
Jay Srinivasana0581432012-01-26 21:50:05 -0800211 return CGPT_FAILED;
212
213 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
214 Error("GptSanityCheck() returned %d: %s\n",
215 gpt_retval, GptError(gpt_retval));
216 return CGPT_FAILED;
217 }
218
219 if (params->partition) { // show single partition
220
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700221 if (params->partition > GetNumberOfEntries(&drive)) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800222 Error("invalid partition number: %d\n", params->partition);
223 return CGPT_FAILED;
224 }
225
226 uint32_t index = params->partition - 1;
227 GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index);
228 char buf[256]; // scratch buffer for string conversion
229
230 if (params->single_item) {
231 switch(params->single_item) {
232 case 'b':
233 printf("%" PRId64 "\n", entry->starting_lba);
234 break;
Mike Frysinger98624d32013-05-03 18:05:16 -0400235 case 's': {
236 uint64_t size = 0;
237 // If these aren't actually defined, don't show anything
238 if (entry->ending_lba || entry->starting_lba)
239 size = entry->ending_lba - entry->starting_lba + 1;
240 printf("%" PRId64 "\n", size);
Jay Srinivasana0581432012-01-26 21:50:05 -0800241 break;
Mike Frysinger98624d32013-05-03 18:05:16 -0400242 }
Jay Srinivasana0581432012-01-26 21:50:05 -0800243 case 't':
244 GuidToStr(&entry->type, buf, sizeof(buf));
245 printf("%s\n", buf);
246 break;
247 case 'u':
248 GuidToStr(&entry->unique, buf, sizeof(buf));
249 printf("%s\n", buf);
250 break;
251 case 'l':
252 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
253 (uint8_t *)buf, sizeof(buf));
254 printf("%s\n", buf);
255 break;
256 case 'S':
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700257 printf("%d\n", GetSuccessful(&drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800258 break;
259 case 'T':
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700260 printf("%d\n", GetTries(&drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800261 break;
262 case 'P':
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700263 printf("%d\n", GetPriority(&drive, ANY_VALID, index));
Jay Srinivasana0581432012-01-26 21:50:05 -0800264 break;
265 case 'A':
266 printf("0x%x\n", entry->attrs.fields.gpt_att);
267 break;
268 }
269 } else {
270 printf(TITLE_FMT, "start", "size", "part", "contents");
271 EntryDetails(entry, index, params->numeric);
272 }
273
274 } else if (params->quick) { // show all partitions, quickly
275 uint32_t i;
276 GptEntry *entry;
277 char type[GUID_STRLEN];
278
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700279 for (i = 0; i < GetNumberOfEntries(&drive); ++i) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800280 entry = GetEntry(&drive.gpt, ANY_VALID, i);
281
Bill Richardson3f806a22013-03-20 15:02:34 -0700282 if (GuidIsZero(&entry->type))
Jay Srinivasana0581432012-01-26 21:50:05 -0800283 continue;
284
285 if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) {
286 } else {
287 GuidToStr(&entry->type, type, GUID_STRLEN);
288 }
289 printf(PARTITION_FMT, (int)entry->starting_lba,
290 (int)(entry->ending_lba - entry->starting_lba + 1),
291 i+1, type);
292 }
293 } else { // show all partitions
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800294 GptEntry *entries;
295
Jay Srinivasana0581432012-01-26 21:50:05 -0800296 if (CGPT_OK != ReadPMBR(&drive)) {
297 Error("Unable to read PMBR\n");
298 return CGPT_FAILED;
299 }
300
301 printf(TITLE_FMT, "start", "size", "part", "contents");
302 char buf[256]; // buffer for formatted PMBR content
303 PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small
304 printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
305
306 if (drive.gpt.valid_headers & MASK_PRIMARY) {
307 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
308 (int)GPT_HEADER_SECTOR, "", "Pri GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800309 } else {
310 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
311 (int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
312 }
313
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800314 if (params->debug ||
315 ((drive.gpt.valid_headers & MASK_PRIMARY) && params->verbose)) {
316 GptHeader *header;
317 char indent[64];
318
319 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
320 header = (GptHeader*)drive.gpt.primary_header;
321 entries = (GptEntry*)drive.gpt.primary_entries;
322 HeaderDetails(header, entries, indent, params->numeric);
323 }
324
Jay Srinivasana0581432012-01-26 21:50:05 -0800325 printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
326 (int)GPT_ENTRIES_SECTORS,
327 drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
328 "Pri GPT table");
329
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800330 if (params->debug ||
331 (drive.gpt.valid_entries & MASK_PRIMARY))
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700332 EntriesDetails(&drive, PRIMARY, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800333
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800334 /****************************** Secondary *************************/
Jay Srinivasana0581432012-01-26 21:50:05 -0800335 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
336 GPT_ENTRIES_SECTORS),
337 (int)GPT_ENTRIES_SECTORS,
338 drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
339 "Sec GPT table");
340 /* We show secondary table details if any of following is true.
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800341 * 1. in debug mode.
342 * 2. only secondary is valid.
343 * 3. secondary is not identical to promary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800344 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800345 if (params->debug ||
346 ((drive.gpt.valid_entries & MASK_SECONDARY) &&
347 (!(drive.gpt.valid_entries & MASK_PRIMARY) ||
348 memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
349 TOTAL_ENTRIES_SIZE)))) {
Albert Chaulkfa6b35c2013-03-26 13:43:02 -0700350 EntriesDetails(&drive, SECONDARY, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800351 }
352
353 if (drive.gpt.valid_headers & MASK_SECONDARY)
354 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
355 (int)GPT_HEADER_SECTOR, "", "Sec GPT header");
356 else
357 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
358 (int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
359 /* We show secondary header if any of following is true:
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800360 * 1. in debug mode.
361 * 2. only secondary is valid.
362 * 3. secondary is not synonymous to primary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800363 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800364 if (params->debug ||
365 ((drive.gpt.valid_headers & MASK_SECONDARY) &&
366 (!(drive.gpt.valid_headers & MASK_PRIMARY) ||
367 !IsSynonymous((GptHeader*)drive.gpt.primary_header,
368 (GptHeader*)drive.gpt.secondary_header)) &&
369 params->verbose)) {
370 GptHeader *header;
371 char indent[64];
Jay Srinivasana0581432012-01-26 21:50:05 -0800372
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800373 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
374 header = (GptHeader*)drive.gpt.secondary_header;
375 entries = (GptEntry*)drive.gpt.secondary_entries;
376 HeaderDetails(header, entries, indent, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800377 }
378 }
379
Jay Srinivasan250549d2012-02-16 17:40:45 -0800380 CheckValid(&drive);
381 DriveClose(&drive, 0);
Jay Srinivasana0581432012-01-26 21:50:05 -0800382
383 return CGPT_OK;
384}