blob: cb5e2759299db8068177145115532ff51f882784 [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
153void EntriesDetails(GptData *gpt, const int secondary, int raw) {
154 uint32_t i;
155
156 for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
157 GptEntry *entry;
158 entry = GetEntry(gpt, secondary, i);
159
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;
186 int numEntries = GetNumberOfEntries(&drive.gpt);
187 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
221 if (params->partition > GetNumberOfEntries(&drive.gpt)) {
222 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;
235 case 's':
236 printf("%" PRId64 "\n", entry->ending_lba - entry->starting_lba + 1);
237 break;
238 case 't':
239 GuidToStr(&entry->type, buf, sizeof(buf));
240 printf("%s\n", buf);
241 break;
242 case 'u':
243 GuidToStr(&entry->unique, buf, sizeof(buf));
244 printf("%s\n", buf);
245 break;
246 case 'l':
247 UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
248 (uint8_t *)buf, sizeof(buf));
249 printf("%s\n", buf);
250 break;
251 case 'S':
252 printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index));
253 break;
254 case 'T':
255 printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index));
256 break;
257 case 'P':
258 printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index));
259 break;
260 case 'A':
261 printf("0x%x\n", entry->attrs.fields.gpt_att);
262 break;
263 }
264 } else {
265 printf(TITLE_FMT, "start", "size", "part", "contents");
266 EntryDetails(entry, index, params->numeric);
267 }
268
269 } else if (params->quick) { // show all partitions, quickly
270 uint32_t i;
271 GptEntry *entry;
272 char type[GUID_STRLEN];
273
274 for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
275 entry = GetEntry(&drive.gpt, ANY_VALID, i);
276
Bill Richardson3f806a22013-03-20 15:02:34 -0700277 if (GuidIsZero(&entry->type))
Jay Srinivasana0581432012-01-26 21:50:05 -0800278 continue;
279
280 if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) {
281 } else {
282 GuidToStr(&entry->type, type, GUID_STRLEN);
283 }
284 printf(PARTITION_FMT, (int)entry->starting_lba,
285 (int)(entry->ending_lba - entry->starting_lba + 1),
286 i+1, type);
287 }
288 } else { // show all partitions
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800289 GptEntry *entries;
290
Jay Srinivasana0581432012-01-26 21:50:05 -0800291 if (CGPT_OK != ReadPMBR(&drive)) {
292 Error("Unable to read PMBR\n");
293 return CGPT_FAILED;
294 }
295
296 printf(TITLE_FMT, "start", "size", "part", "contents");
297 char buf[256]; // buffer for formatted PMBR content
298 PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small
299 printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
300
301 if (drive.gpt.valid_headers & MASK_PRIMARY) {
302 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
303 (int)GPT_HEADER_SECTOR, "", "Pri GPT header");
Jay Srinivasana0581432012-01-26 21:50:05 -0800304 } else {
305 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
306 (int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
307 }
308
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800309 if (params->debug ||
310 ((drive.gpt.valid_headers & MASK_PRIMARY) && params->verbose)) {
311 GptHeader *header;
312 char indent[64];
313
314 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
315 header = (GptHeader*)drive.gpt.primary_header;
316 entries = (GptEntry*)drive.gpt.primary_entries;
317 HeaderDetails(header, entries, indent, params->numeric);
318 }
319
Jay Srinivasana0581432012-01-26 21:50:05 -0800320 printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
321 (int)GPT_ENTRIES_SECTORS,
322 drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
323 "Pri GPT table");
324
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800325 if (params->debug ||
326 (drive.gpt.valid_entries & MASK_PRIMARY))
Jay Srinivasana0581432012-01-26 21:50:05 -0800327 EntriesDetails(&drive.gpt, PRIMARY, params->numeric);
328
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800329 /****************************** Secondary *************************/
Jay Srinivasana0581432012-01-26 21:50:05 -0800330 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
331 GPT_ENTRIES_SECTORS),
332 (int)GPT_ENTRIES_SECTORS,
333 drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
334 "Sec GPT table");
335 /* We show secondary table details if any of following is true.
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800336 * 1. in debug mode.
337 * 2. only secondary is valid.
338 * 3. secondary is not identical to promary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800339 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800340 if (params->debug ||
341 ((drive.gpt.valid_entries & MASK_SECONDARY) &&
342 (!(drive.gpt.valid_entries & MASK_PRIMARY) ||
343 memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
344 TOTAL_ENTRIES_SIZE)))) {
Jay Srinivasana0581432012-01-26 21:50:05 -0800345 EntriesDetails(&drive.gpt, SECONDARY, params->numeric);
346 }
347
348 if (drive.gpt.valid_headers & MASK_SECONDARY)
349 printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
350 (int)GPT_HEADER_SECTOR, "", "Sec GPT header");
351 else
352 printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
353 (int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
354 /* We show secondary header if any of following is true:
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800355 * 1. in debug mode.
356 * 2. only secondary is valid.
357 * 3. secondary is not synonymous to primary.
Jay Srinivasana0581432012-01-26 21:50:05 -0800358 */
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800359 if (params->debug ||
360 ((drive.gpt.valid_headers & MASK_SECONDARY) &&
361 (!(drive.gpt.valid_headers & MASK_PRIMARY) ||
362 !IsSynonymous((GptHeader*)drive.gpt.primary_header,
363 (GptHeader*)drive.gpt.secondary_header)) &&
364 params->verbose)) {
365 GptHeader *header;
366 char indent[64];
Jay Srinivasana0581432012-01-26 21:50:05 -0800367
Louis Yung-Chieh Lo455b1192012-06-26 14:48:39 +0800368 require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
369 header = (GptHeader*)drive.gpt.secondary_header;
370 entries = (GptEntry*)drive.gpt.secondary_entries;
371 HeaderDetails(header, entries, indent, params->numeric);
Jay Srinivasana0581432012-01-26 21:50:05 -0800372 }
373 }
374
Jay Srinivasan250549d2012-02-16 17:40:45 -0800375 CheckValid(&drive);
376 DriveClose(&drive, 0);
Jay Srinivasana0581432012-01-26 21:50:05 -0800377
378 return CGPT_OK;
379}