cgpt supports dev and add/delete/modify commands.

Review URL: http://codereview.chromium.org/2374001
This commit is contained in:
Louis Yung-Chieh Lo
2010-05-29 18:54:25 +08:00
parent 67660cda7a
commit e6cf857685
11 changed files with 555 additions and 98 deletions

View File

@@ -10,7 +10,8 @@ LIBS += $(FWLIB)
all: cgpt
cgpt: cgpt.o cgpt_attribute.o cgpt_options.o cgpt_repair.o cgpt_show.o $(LIBS)
cgpt: cgpt.o cgpt_add_modify_delete.o cgpt_attribute.o cgpt_dev.o \
cgpt_options.o cgpt_repair.o cgpt_show.o $(LIBS)
$(CC) -o cgpt $(CFLAGS) $^
.c.o: $(INCLUDES)

View File

@@ -38,8 +38,12 @@ struct {
int (*fp)(int argc, char *argv[]);
const char *comment;
} cmds[] = {
{"add", CgptAdm, "Add a partition to drive"},
{"delete", CgptAdm, "Delete a partition on drive"},
{"modify", CgptAdm, "Modify the partition on drive"},
{"attribute", CgptAttribute, "Update GPT attribute bits "
"(for ChromeOS kernel entry only)"},
{"dev", CgptDev, "Developper mode"},
{"repair", CgptRepair, "Repair primary and secondary headers and tables"},
{"show", CgptShow, "Show partition details"},
};
@@ -51,7 +55,7 @@ void Usage(const char *message) {
if (message) printf("%s\n", message);
printf("Usage: %s COMMAND [OPTIONS]\n\n"
"Supported commands:\n\n",
"Supported COMMANDs:\n\n",
progname);
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
@@ -62,11 +66,13 @@ void Usage(const char *message) {
/* GUID conversion functions. Accepted format:
*
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
*
* Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
*/
void StrToGuid(const char *str, Guid *guid) {
int StrToGuid(const char *str, Guid *guid) {
uint32_t time_low, time_mid, time_high_and_version;
sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
if (11 > sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
&time_low,
(unsigned int *)&time_mid,
(unsigned int *)&time_high_and_version,
@@ -77,11 +83,13 @@ void StrToGuid(const char *str, Guid *guid) {
(unsigned int *)&guid->u.Uuid.node[2],
(unsigned int *)&guid->u.Uuid.node[3],
(unsigned int *)&guid->u.Uuid.node[4],
(unsigned int *)&guid->u.Uuid.node[5]);
(unsigned int *)&guid->u.Uuid.node[5])) return CGPT_FAILED;
guid->u.Uuid.time_low = htole32(time_low);
guid->u.Uuid.time_mid = htole16(time_mid);
guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
return CGPT_OK;
}
void GuidToStr(const Guid *guid, char *str) {
@@ -194,6 +202,54 @@ void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
utf16[s16idx++] = 0;
}
struct {
Guid type;
char *name;
char *description;
} supported_types[] = {
{GPT_ENT_TYPE_UNUSED, "unused", "Unused partition"},
{GPT_ENT_TYPE_EFI, "efi", "EFI partition"},
{GPT_ENT_TYPE_CHROMEOS_KERNEL, "croskern", "ChromeOS kernel"},
{GPT_ENT_TYPE_CHROMEOS_ROOTFS, "crosroot", "ChromeOS rootfs"},
{GPT_ENT_TYPE_CHROMEOS_RESERVED, "crosresv", "ChromeOS reserved"},
};
/* Resolves human-readable GPT type.
* Returns CGPT_OK if found.
* Returns CGPT_FAILED if no known type found. */
int ResolveType(const Guid *type, char *buf) {
int i;
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
if (!Memcmp(type, &supported_types[i].type, sizeof(Guid))) {
strcpy(buf, supported_types[i].description);
return CGPT_OK;
}
}
return CGPT_FAILED;
}
int SupportedType(const char *name, Guid *type) {
int i;
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
if (!strcmp(name, supported_types[i].name)) {
Memcpy(type, &supported_types[i].type, sizeof(Guid));
return CGPT_OK;
}
}
return CGPT_FAILED;
}
void PrintTypes(void) {
int i;
printf("\n* For --type option, you can use the following alias, "
"instead of hex values:\n");
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
printf(" %-10s %s\n", supported_types[i].name,
supported_types[i].description);
}
printf("\n");
}
/* Loads sectors from 'fd'.
* *buf is pointed to an allocated memory when returned, and should be
* freed by cgpt_close().
@@ -267,7 +323,7 @@ int CheckValid(const struct drive *drive) {
if ((drive->gpt.valid_headers != MASK_BOTH) ||
(drive->gpt.valid_entries != MASK_BOTH)) {
printf("\n[ERROR] any of GPT header/entries is invalid, "
"please run --repair first\n");
"please run '%s repair' first\n", progname);
return CGPT_FAILED;
}
return CGPT_OK;
@@ -316,9 +372,6 @@ int DriveOpen(const char *drive_path, struct drive *drive) {
goto error_close;
}
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
debug("drive: size:%llu sector_size:%d num_sector:%llu\n",
(long long unsigned int)drive->size, drive->gpt.sector_bytes,
(long long unsigned int)drive->gpt.drive_sectors);
Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
@@ -390,6 +443,7 @@ int main(int argc, char *argv[]) {
int i;
progname = argv[0];
printf("Copyright (c) 2010 The Chromium OS Authors. All rights reserved.\n");
cmd = argv[optind++];
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
if (cmd && !strcmp(cmds[i].name, cmd))

View File

@@ -51,13 +51,15 @@ struct option_details {
* i.e. help, to indicate the option is present. */
int AssignTrue(const char *argument, void *pointer, void *integer);
/* Special validator. Copy string to 'parsed' with max 'valid_range' bytes. */
int CopyString(const char *argument, void *max_len, void *dst);
/* Validator function. Returns 1 if 'argument' is between 'max' and 'min'
* in 'valid_range'. */
struct number_range {
int max;
int min;
};
/* Validator function. Returns 1 if 'argument' is between 'max' and 'min'
* in 'valid_range'. */
int InNumberRange(const char *argument, void *valid_range, void *parsed);
void ShowOptions(const struct option *opts,
@@ -97,7 +99,7 @@ int OpenDriveInLastArgument(const int argc,
* '\0').
*/
#define GUID_STRLEN 37
void StrToGuid(const char *str, Guid *guid);
int StrToGuid(const char *str, Guid *guid);
void GuidToStr(const Guid *guid, char *str);
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
@@ -113,6 +115,11 @@ void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
*/
void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16);
/* Helper functions for supported GPT types. */
int ResolveType(const Guid *type, char *buf);
int SupportedType(const char *name, Guid *type);
void PrintTypes(void);
/* Describes the drive storing the GPT. */
struct drive {
int inited; /* indicated if this structure is valid */
@@ -140,7 +147,9 @@ int CheckValid(const struct drive *drive);
/* Function declarations for commands.
* The return value of these functions is passed to main()'s exit value. */
int CgptAdm(int argc, char *argv[]);
int CgptAttribute(int argc, char *argv[]);
int CgptDev(int argc, char *argv[]);
int CgptRepair(int argc, char *argv[]);
int CgptShow(int argc, char *argv[]);

View File

@@ -0,0 +1,276 @@
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Update GPT attribute bits.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "utility.h"
static struct number_range
range_127_0 = {127, 0};
/* Integers to store parsed argument. */
static int help, partition, begin_lba, size_lba;
static char type[128], unique[128], name[128];
/* The structure for getopt_long(). When you add/delete any line, please refine
* attribute_comments[] and third parameter of getopt_long() too. */
static struct option adm_options[] = {
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
{.name = "partition", .has_arg = required_argument, .flag = 0, .val = 'i'},
#if 0//FIXME
{.name = "bad", .has_arg = required_argument, .flag = 0, .val = 'b'},
{.name = "successful", .has_arg = required_argument, .flag = 0, .val = 's'},
{.name = "tries", .has_arg = required_argument, .flag = 0, .val = 't'},
{.name = "priority", .has_arg = required_argument, .flag = 0, .val = 'p'},
#endif
{.name = "type", .has_arg = required_argument, .flag = 0, .val = 't'},
{.name = "unique", .has_arg = required_argument, .flag = 0, .val = 'u'},
{.name = "begin", .has_arg = required_argument, .flag = 0, .val = 'b'},
{.name = "size", .has_arg = required_argument, .flag = 0, .val = 's'},
{.name = "name", .has_arg = required_argument, .flag = 0, .val = 'n'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
* add/remove any line in attribute_options[]. */
static struct option_details adm_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
/* partition */
{ .comment = "partition number (MUST HAVE)",
.validator = InNumberRange,
.valid_range = &range_127_0,
.parsed = &partition},
#if 0//FIXME
/* bad */
{ .comment = "mark partition bad",
.validator = InNumberRange,
.valid_range = &range_1_0,
.parsed = &bad},
/* successful */
{ .comment = "mark partition successful",
.validator = InNumberRange,
.valid_range = &range_1_0,
.parsed = &successful},
/* tries */
{ .comment = "tries",
.validator = InNumberRange,
.valid_range = &range_15_0,
.parsed = &tries},
/* priority */
{ .comment = "priority to boot",
.validator = InNumberRange,
.valid_range = &range_15_0,
.parsed = &priority},
#endif
/* type */
{ .comment = "Partition Type (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)",
.validator = CopyString,
.valid_range = (void*)sizeof(type),
.parsed = &type},
/* uuid */
{ .comment = "Partition UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)",
.validator = CopyString,
.valid_range = (void*)sizeof(unique),
.parsed = &unique},
/* start */
{ .comment = "starting LBA",
.validator = InNumberRange,
.valid_range = 0,
.parsed = &begin_lba},
/* end */
{ .comment = "ending LBA",
.validator = InNumberRange,
.valid_range = 0,
.parsed = &size_lba},
/* name */
{ .comment = "Partition name",
.validator = CopyString,
.valid_range = (void*)sizeof(name),
.parsed = &name},
{ /* last element, which should be zero. */ }
};
void AdmHelp() {
printf("\nUsage: %s {add|delete|modify} [OPTIONS] device_name\n\n", progname);
ShowOptions(adm_options, adm_options_details, ARRAY_COUNT(adm_options));
PrintTypes();
printf("\n");
}
enum {
ADD,
DELETE,
MODIFY,
} command;
/* Parses all options (and validates them), then opens the drive and sets
* corresponding bits in GPT entry. */
int CgptAdm(int argc, char *argv[]) {
struct drive drive;
char *cmd;
GptEntry *entry;
Guid type_guid, unique_guid;
int dirty = 0;
/* I know this is NOT the perfect place to put code to make options[] and
* details[] are synced. But this is the best place we have right now since C
* preprocessor doesn't know sizeof() for #if directive. */
assert(ARRAY_COUNT(adm_options) ==
ARRAY_COUNT(adm_options_details));
cmd = argv[optind - 1];
if (!strcmp("add", cmd)) command = ADD;
else if (!strcmp("delete", cmd)) command = DELETE;
else if (!strcmp("modify", cmd)) command = MODIFY;
#if 0//FIXME
help = partition = bad = successful = tries = priority =
#endif
help = partition = begin_lba = size_lba = NOT_INITED;
type[0] = '\0';
unique[0] = '\0';
name[0] = '\0';
if (CGPT_OK != HandleOptions(argc, argv,
"hi:t:u:b:s:n:",
ARRAY_COUNT(adm_options),
adm_options,
adm_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
AdmHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
if (CheckValid(&drive) != CGPT_OK) goto error_close;
if (partition == NOT_INITED) {
printf("[ERROR] Please provide partition number with --partition or -i.\n");
goto error_close;
}
entry = GetEntry(&drive.gpt, PRIMARY, partition);
/* check before really doing something. */
switch (command) {
case ADD:
if (NonZeroGuid(&entry->type)) {
printf("[ERROR] partition %d is not free, use '%s modify' instead.\n",
partition, progname);
goto error_close;
}
if (type[0] == '\0') {
printf("* You must give a type with '--type' or '-t'.\n");
PrintTypes();
goto error_close;
}
if (begin_lba == NOT_INITED) {
printf("* You didn't give the begin LBA, use '--begin' to specify.\n");
goto error_close;
}
if (size_lba == NOT_INITED) {
printf("* You didn't give size, use '--size' to specify.\n");
goto error_close;
}
break;
case DELETE:
if (!NonZeroGuid(&entry->type)) {
printf("[ERROR] partition %d is free already.\n", partition);
goto error_close;
}
break;
case MODIFY:
if (!NonZeroGuid(&entry->type)) {
printf("[ERROR] partition %d is free, use '%s add' first.\n",
partition, progname);
goto error_close;
}
break;
}
#if 0 //FIXME
if (bad != NOT_INITED)
SetBad(&drive.gpt, PRIMARY, partition, bad);
if (successful != NOT_INITED)
SetSuccessful(&drive.gpt, PRIMARY, partition, successful);
if (tries != NOT_INITED)
SetTries(&drive.gpt, PRIMARY, partition, tries);
if (priority != NOT_INITED)
SetPriority(&drive.gpt, PRIMARY, partition, priority);
#endif
if (type[0]) {
if (CGPT_OK != SupportedType(type, &type_guid) &&
CGPT_OK != StrToGuid(type, &type_guid)) {
printf("[ERROR] You didn't give a valid type [%s]\n", type);
goto error_close;
}
Memcpy(&entry->type, &type_guid, sizeof(Guid));
++dirty;
}
if (unique[0]) {
if (CGPT_OK != StrToGuid(unique, &unique_guid)) {
printf("[ERROR] You didn't give a valid UUID [%s]\n", unique);
goto error_close;
}
Memcpy(&entry->unique, &unique_guid, sizeof(Guid));
++dirty;
}
if (begin_lba != NOT_INITED) {
entry->starting_lba = begin_lba;
++dirty;
}
if (size_lba != NOT_INITED) {
entry->ending_lba = entry->starting_lba + size_lba - 1;
++dirty;
}
if (name[0]) {
UTF8ToUTF16((uint8_t*)name, entry->name);
++dirty;
}
if (command == DELETE) {
Guid unused = GPT_ENT_TYPE_UNUSED;
Memcpy(&entry->type, &unused, sizeof(Guid));
}
if (dirty) {
uint32_t valid_entries;
valid_entries = drive.gpt.valid_entries;
if ((valid_entries != CheckValidEntries(&drive.gpt)) ||
(valid_entries != CheckOverlappedPartition(&drive.gpt))) {
printf("\n[ERROR] Your change makes GPT invalid (or worse). "
"Please check your arguments.\n\n");
drive.gpt.modified = 0; /* DriveClose() won't update hard drive. */
goto error_close;
}
/* Claims primary is good, then secondary will be overwritten. */
RepairEntries(&drive.gpt, MASK_PRIMARY);
RepairHeader(&drive.gpt, MASK_PRIMARY);
/* Forces headers and entries are modified so that CRC32 will be
* re-calculated and headers and entries will be updated to drive. */
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
UpdateCrc(&drive.gpt);
}
DriveClose(&drive);
return CGPT_OK;
error_close:
DriveClose(&drive);
return CGPT_FAILED;
}

View File

@@ -27,6 +27,7 @@ static struct option attribute_options[] = {
{.name = "successful", .has_arg = required_argument, .flag = 0, .val = 's'},
{.name = "tries", .has_arg = required_argument, .flag = 0, .val = 't'},
{.name = "priority", .has_arg = required_argument, .flag = 0, .val = 'p'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
@@ -63,6 +64,7 @@ static struct option_details attribute_options_details[] = {
.validator = InNumberRange,
.valid_range = &range_15_0,
.parsed = &priority},
{ /* last element, which should be zero. */ }
};
void AttributeHelp() {
@@ -101,8 +103,6 @@ int CgptAttribute(int argc, char *argv[]) {
if (CheckValid(&drive) != CGPT_OK) return CGPT_FAILED;
debug("[OPTION] i:%d b:%d s:%d t:%d p:%d\n", partition, bad, successful, tries, priority); /* FIXME */
/* partition is not specified, search for the first Chromeos kernel. */
if (partition == NOT_INITED) {
int i;

126
utility/cgpt/cgpt_dev.c Normal file
View File

@@ -0,0 +1,126 @@
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Developper mode.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "utility.h"
/* Integers to store parsed argument. */
static int help, primary_header, primary_entries,
secondary_header, secondary_entries;
/* The structure for getopt_long(). When you add/delete any line, please refine
* attribute_comments[] and third parameter of getopt_long() too. */
static struct option dev_options[] = {
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
{.name = "primary-header", .has_arg = no_argument, .flag = 0, .val = 'a'},
{.name = "primary-entries", .has_arg = no_argument, .flag = 0, .val = 'b'},
{.name = "secondary-entries", .has_arg = no_argument, .flag = 0, .val = 'c'},
{.name = "secondary-header", .has_arg = no_argument, .flag = 0, .val = 'd'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
* add/remove any line in attribute_options[]. */
static struct option_details dev_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
/* primary-header */
{ .comment = "damage primary header",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &primary_header},
/* primary-entries */
{ .comment = "damage primary entries",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &primary_entries},
/* secondary-entries */
{ .comment = "damage secondary entries",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &secondary_entries},
/* secondary-header */
{ .comment = "damage secondary header",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &secondary_header},
{ /* last element, which should be zero. */ }
};
void DevHelp() {
printf("\nDeveloper mode.\n\n");
printf("\nUsage: %s dev [OPTIONS] device_name\n\n", progname);
ShowOptions(dev_options, dev_options_details, ARRAY_COUNT(dev_options));
printf("\n");
}
/* Very simple function, you may choose damage one or more of the following
* sections:
*
* Primary GPT header
* Primary GPT table entries
* Secondary GPT table entries
* Secondary GPT header
*/
int CgptDev(int argc, char *argv[]) {
struct drive drive;
/* I know this is NOT the perfect place to put code to make options[] and
* details[] are synced. But this is the best place we have right now since C
* preprocessor doesn't know sizeof() for #if directive. */
assert(ARRAY_COUNT(dev_options) ==
ARRAY_COUNT(dev_options_details));
help = primary_header = primary_entries =
secondary_header = secondary_entries = NOT_INITED;
if (CGPT_OK != HandleOptions(argc, argv,
"h",
ARRAY_COUNT(dev_options),
dev_options,
dev_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
DevHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
#define ANY_PRIME 7
if (primary_header != NOT_INITED) {
printf("* damage Pri Header\n");
drive.gpt.primary_header[0] += ANY_PRIME;
drive.gpt.modified |= GPT_MODIFIED_HEADER1;
}
if (primary_entries != NOT_INITED) {
printf("* damage Pri Table\n");
drive.gpt.primary_entries[0] += ANY_PRIME;
drive.gpt.modified |= GPT_MODIFIED_ENTRIES1;
}
if (secondary_entries != NOT_INITED) {
printf("* damage Sec Table\n");
drive.gpt.secondary_entries[0] += ANY_PRIME;
drive.gpt.modified |= GPT_MODIFIED_ENTRIES2;
}
if (secondary_header != NOT_INITED) {
printf("* damage Sec Header\n");
drive.gpt.secondary_header[0] += ANY_PRIME;
drive.gpt.modified |= GPT_MODIFIED_HEADER2;
}
DriveClose(&drive);
return CGPT_OK;
}

View File

@@ -5,6 +5,7 @@
* Update GPT attribute bits.
*/
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
@@ -16,6 +17,12 @@ int AssignTrue(const char *argument, void *pointer, void *integer) {
return CGPT_OK;
}
/* Special validator. Copy string to 'parsed' with max 'valid_range' bytes. */
int CopyString(const char *argument, void *max_len, void *dst) {
Memcpy(dst, argument, (intptr_t)max_len);
return CGPT_OK;
}
/* Validator function. Returns 1 if 'argument' is between 'max' and 'min'
* in 'valid_range'. */
int InNumberRange(const char *argument, void *valid_range, void *parsed) {
@@ -23,14 +30,13 @@ int InNumberRange(const char *argument, void *valid_range, void *parsed) {
char *endptr;
int number;
assert(valid_range);
number = strtol(argument, &endptr, 10);
if (*endptr) {
printf("[ERROR] argument '%s' is not a number.\n", argument);
return CGPT_FAILED;
}
if (range) {
if (number < range->min) {
printf("[ERROR] argument is too small (min is %d, but you gave: %d).\n",
range->min, number);
@@ -43,6 +49,11 @@ int InNumberRange(const char *argument, void *valid_range, void *parsed) {
if (parsed) *(int*)parsed = number;
return CGPT_OK;
}
} else {
/* no range to check, assign integer. */
if (parsed) *(int*)parsed = number;
return CGPT_OK;
}
}
void ShowOptions(const struct option *opts,
@@ -51,6 +62,7 @@ void ShowOptions(const struct option *opts,
int i;
for (i = 0; i < num; ++i) {
char buf[32];
if (!opts[i].name) break;
snprintf(buf, sizeof(buf), "--%s %s", opts[i].name,
opts[i].has_arg ? "ARG" : "");
printf(" %-20s (-%c) %s\n", buf, opts[i].val, details[i].comment);
@@ -76,6 +88,14 @@ int HandleOptions(const int argc,
break;
} else if (option == 0) {
/* option 'val' has been saved in 'flag'. We do nothing here. */
} else if (option == ':') {
printf("[ERROR] Missing parameter for option.\n");
ShowOptions(options, details, option_count);
return CGPT_FAILED;
} else if (option == '?') {
printf("[ERROR] unknown option name: %s\n", argv[optind - 1]);
ShowOptions(options, details, option_count);
return CGPT_FAILED;
} else {
/* Short option doesn't update 'index'. We search whole array to find out
* the corresponding long option. */

View File

@@ -20,6 +20,7 @@ static int help;
* attribute_comments[] and third parameter of getopt_long() too. */
static struct option repair_options[] = {
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
@@ -30,6 +31,7 @@ static struct option_details repair_options_details[] = {
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
{ /* last element, which should be zero. */ }
};
void RepairHelp() {

View File

@@ -2,7 +2,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Update GPT attribute bits.
* Show GPT details.
*/
#include <getopt.h>
#include <stdio.h>
@@ -20,6 +20,7 @@ static struct option show_options[] = {
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
{.name = "number", .has_arg = no_argument, .flag = 0, .val = 'n'},
{.name = "verbose", .has_arg = no_argument, .flag = 0, .val = 'v'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
@@ -40,6 +41,7 @@ static struct option_details show_options_details[] = {
.validator = AssignTrue,
.valid_range = 0,
.parsed = &verbose},
{ /* last element, which should be zero. */ }
};
void ShowHelp() {
@@ -121,31 +123,6 @@ static void HeaderDetails(GptHeader *header, const char *indent) {
printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
}
/* Resolves human-readable GPT type.
* Returns CGPT_OK if found.
* Returns CGPT_FAILED if no known type found. */
int ResolveType(const Guid *type, char *buf) {
struct {
Guid type;
char *description;
} known[] = {
{GPT_ENT_TYPE_UNUSED, "Unused partition"},
{GPT_ENT_TYPE_EFI, "EFI partition"},
{GPT_ENT_TYPE_CHROMEOS_KERNEL, "ChromeOS kernel"},
{GPT_ENT_TYPE_CHROMEOS_ROOTFS, "ChromeOS rootfs"},
{GPT_ENT_TYPE_CHROMEOS_RESERVED, "ChromeOS reserved"},
};
int i;
for (i = 0; i < ARRAY_COUNT(known); ++i) {
if (!Memcmp(type, &known[i].type, sizeof(Guid))) {
strcpy(buf, known[i].description);
return CGPT_OK;
}
}
return CGPT_FAILED;
}
void EntriesDetails(GptData *gpt, const int secondary) {
int i;
@@ -236,6 +213,7 @@ int CgptShow(int argc, char *argv[]) {
return CGPT_FAILED;
}
OpenDriveInLastArgument(argc, argv, &drive);
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;

View File

@@ -58,7 +58,6 @@ int CheckParameters(GptData *gpt) {
/* Expects header signature should be GPT_HEADER_SIGNATURE. */
uint32_t CheckHeaderSignature(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -69,15 +68,14 @@ uint32_t CheckHeaderSignature(GptData *gpt) {
if (Memcmp(headers[i]->signature,
GPT_HEADER_SIGNATURE,
GPT_HEADER_SIGNATURE_SIZE)) {
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
}
return valid_headers;
return gpt->valid_headers;
}
/* The header revision should be GPT_HEADER_REVISION. */
uint32_t CheckRevision(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -86,15 +84,14 @@ uint32_t CheckRevision(GptData *gpt) {
for (i = PRIMARY; i <= SECONDARY; ++i) {
if (headers[i]->revision != GPT_HEADER_REVISION)
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
return valid_headers;
return gpt->valid_headers;
}
/* A valid header size should be between MIN_SIZE_OF_HEADER and
* MAX_SIZE_OF_HEADER. */
uint32_t CheckSize(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -104,14 +101,13 @@ uint32_t CheckSize(GptData *gpt) {
for (i = PRIMARY; i <= SECONDARY; ++i) {
if ((headers[i]->size < MIN_SIZE_OF_HEADER) ||
(headers[i]->size > MAX_SIZE_OF_HEADER))
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
return valid_headers;
return gpt->valid_headers;
}
/* Reserved and padding fields should be zero. */
uint32_t CheckReservedFields(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -120,32 +116,30 @@ uint32_t CheckReservedFields(GptData *gpt) {
for (i = PRIMARY; i <= SECONDARY; ++i) {
if (headers[i]->reserved || headers[i]->padding)
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
return valid_headers;
return gpt->valid_headers;
}
/* my_lba field points to the header itself.
* So that the my_lba of primary header should be 1 (right after PMBR).
* The my_lba of secondary header should be the last secotr on drive. */
uint32_t CheckMyLba(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
secondary_header = (GptHeader*)gpt->secondary_header;
if (primary_header->my_lba != GPT_PMBR_SECTOR) /* 2nd sector on drive */
INVALIDATE_HEADER(valid_headers, PRIMARY);
INVALIDATE_HEADER(gpt->valid_headers, PRIMARY);
if (secondary_header->my_lba != (gpt->drive_sectors - 1)) /* last sector */
INVALIDATE_HEADER(valid_headers, SECONDARY);
return valid_headers;
INVALIDATE_HEADER(gpt->valid_headers, SECONDARY);
return gpt->valid_headers;
}
/* SizeOfPartitionEntry must be between MIN_SIZE_OF_ENTRY and
* MAX_SIZE_OF_ENTRY, and a multiple of SIZE_OF_ENTRY_MULTIPLE. */
uint32_t CheckSizeOfPartitionEntry(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -157,16 +151,15 @@ uint32_t CheckSizeOfPartitionEntry(GptData *gpt) {
if ((size_of_entry < MIN_SIZE_OF_ENTRY) ||
(size_of_entry > MAX_SIZE_OF_ENTRY) ||
(size_of_entry & (SIZE_OF_ENTRY_MULTIPLE - 1)))
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
return valid_headers;
return gpt->valid_headers;
}
/* number_of_entries must be between MIN_NUMBER_OF_ENTRIES and
* MAX_NUMBER_OF_ENTRIES, and size_of_entry * number_of_entries must be
* equal to TOTAL_ENTRIES_SIZE. */
uint32_t CheckNumberOfEntries(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -178,16 +171,15 @@ uint32_t CheckNumberOfEntries(GptData *gpt) {
if ((number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
(number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
(number_of_entries * headers[i]->size_of_entry != TOTAL_ENTRIES_SIZE))
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
return valid_headers;
return gpt->valid_headers;
}
/* Make sure entries_lba is correct.
* 2 for primary entries
* drive_sectors-1-GPT_ENTRIES_SECTORS for secondary entries. */
uint32_t CheckEntriesLba(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
@@ -196,20 +188,19 @@ uint32_t CheckEntriesLba(GptData *gpt) {
/* We assume the primary partition entry table is located at the sector
* right after primary partition header. */
if (primary_header->entries_lba != (GPT_PMBR_SECTOR + GPT_HEADER_SECTOR))
INVALIDATE_HEADER(valid_headers, PRIMARY);
INVALIDATE_HEADER(gpt->valid_headers, PRIMARY);
/* We assume the secondary partition entry table is the 32 sectors
* right before the secondary partition header. */
if (secondary_header->entries_lba !=
(gpt->drive_sectors - 1 - GPT_ENTRIES_SECTORS))
INVALIDATE_HEADER(valid_headers, SECONDARY);
return valid_headers;
INVALIDATE_HEADER(gpt->valid_headers, SECONDARY);
return gpt->valid_headers;
}
/* FirstUsableLBA must be after the end of the primary GPT table array.
* LastUsableLBA must be before the start of the secondary GPT table array.
* FirstUsableLBA <= LastUsableLBA. */
uint32_t CheckValidUsableLbas(GptData *gpt) {
uint32_t valid_headers = MASK_BOTH;
uint64_t end_of_primary_entries;
uint64_t start_of_secondary_entries;
GptHeader *headers[] = {
@@ -224,20 +215,20 @@ uint32_t CheckValidUsableLbas(GptData *gpt) {
for (i = PRIMARY; i <= SECONDARY; ++i) {
if (headers[i]->first_usable_lba < end_of_primary_entries)
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
if (headers[i]->last_usable_lba >= start_of_secondary_entries)
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
if (headers[i]->first_usable_lba > headers[i]->last_usable_lba)
INVALIDATE_HEADER(valid_headers, i);
INVALIDATE_HEADER(gpt->valid_headers, i);
}
if (headers[PRIMARY]->first_usable_lba - headers[PRIMARY]->entries_lba <
GPT_ENTRIES_SECTORS)
INVALIDATE_HEADER(valid_headers, PRIMARY);
INVALIDATE_HEADER(gpt->valid_headers, PRIMARY);
if (headers[SECONDARY]->last_usable_lba >= headers[SECONDARY]->entries_lba)
INVALIDATE_HEADER(valid_headers, SECONDARY);
INVALIDATE_HEADER(gpt->valid_headers, SECONDARY);
return valid_headers;
return gpt->valid_headers;
}
/* Checks header CRC */
@@ -289,7 +280,7 @@ uint32_t CheckEntriesCrc(GptData *gpt) {
}
/* Returns non-zero if the given GUID is non-zero. */
static int NonZeroGuid(const Guid *guid) {
int NonZeroGuid(const Guid *guid) {
static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
return Memcmp(&zero, guid, sizeof(zero));
}
@@ -376,7 +367,6 @@ int OverlappedEntries(GptEntry *entries, uint32_t number_of_entries) {
/* Checks if any two partitions are overlapped in primary and secondary entries.
*/
uint32_t CheckOverlappedPartition(GptData *gpt) {
uint32_t valid_entries = MASK_BOTH;
GptHeader *headers[] = {
(GptHeader*)gpt->primary_header,
(GptHeader*)gpt->secondary_header,
@@ -395,9 +385,9 @@ uint32_t CheckOverlappedPartition(GptData *gpt) {
for (i = PRIMARY; i <= SECONDARY; ++i) {
if (OverlappedEntries(entries[i], number_of_entries))
INVALIDATE_ENTRIES(valid_entries, i);
INVALIDATE_ENTRIES(gpt->valid_entries, i);
}
return valid_entries;
return gpt->valid_entries;
}
/* Primary entries and secondary entries should be bitwise identical.

View File

@@ -21,6 +21,7 @@ uint32_t CheckEntriesLba(GptData *gpt);
uint32_t CheckValidUsableLbas(GptData *gpt);
uint32_t CheckHeaderCrc(GptData *gpt);
uint32_t CheckEntriesCrc(GptData *gpt);
int NonZeroGuid(const Guid *guid);
uint32_t CheckValidEntries(GptData *gpt);
typedef struct {
uint64_t starting;