mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-25 10:45:02 +00:00
cgpt supports dev and add/delete/modify commands.
Review URL: http://codereview.chromium.org/2374001
This commit is contained in:
@@ -10,7 +10,8 @@ LIBS += $(FWLIB)
|
|||||||
|
|
||||||
all: cgpt
|
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) $^
|
$(CC) -o cgpt $(CFLAGS) $^
|
||||||
|
|
||||||
.c.o: $(INCLUDES)
|
.c.o: $(INCLUDES)
|
||||||
|
|||||||
@@ -38,8 +38,12 @@ struct {
|
|||||||
int (*fp)(int argc, char *argv[]);
|
int (*fp)(int argc, char *argv[]);
|
||||||
const char *comment;
|
const char *comment;
|
||||||
} cmds[] = {
|
} 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 "
|
{"attribute", CgptAttribute, "Update GPT attribute bits "
|
||||||
"(for ChromeOS kernel entry only)"},
|
"(for ChromeOS kernel entry only)"},
|
||||||
|
{"dev", CgptDev, "Developper mode"},
|
||||||
{"repair", CgptRepair, "Repair primary and secondary headers and tables"},
|
{"repair", CgptRepair, "Repair primary and secondary headers and tables"},
|
||||||
{"show", CgptShow, "Show partition details"},
|
{"show", CgptShow, "Show partition details"},
|
||||||
};
|
};
|
||||||
@@ -51,7 +55,7 @@ void Usage(const char *message) {
|
|||||||
|
|
||||||
if (message) printf("%s\n", message);
|
if (message) printf("%s\n", message);
|
||||||
printf("Usage: %s COMMAND [OPTIONS]\n\n"
|
printf("Usage: %s COMMAND [OPTIONS]\n\n"
|
||||||
"Supported commands:\n\n",
|
"Supported COMMANDs:\n\n",
|
||||||
progname);
|
progname);
|
||||||
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
||||||
printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
|
printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
|
||||||
@@ -62,26 +66,30 @@ void Usage(const char *message) {
|
|||||||
/* GUID conversion functions. Accepted format:
|
/* GUID conversion functions. Accepted format:
|
||||||
*
|
*
|
||||||
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
|
* "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;
|
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,
|
&time_low,
|
||||||
(unsigned int *)&time_mid,
|
(unsigned int *)&time_mid,
|
||||||
(unsigned int *)&time_high_and_version,
|
(unsigned int *)&time_high_and_version,
|
||||||
(unsigned int *)&guid->u.Uuid.clock_seq_high_and_reserved,
|
(unsigned int *)&guid->u.Uuid.clock_seq_high_and_reserved,
|
||||||
(unsigned int *)&guid->u.Uuid.clock_seq_low,
|
(unsigned int *)&guid->u.Uuid.clock_seq_low,
|
||||||
(unsigned int *)&guid->u.Uuid.node[0],
|
(unsigned int *)&guid->u.Uuid.node[0],
|
||||||
(unsigned int *)&guid->u.Uuid.node[1],
|
(unsigned int *)&guid->u.Uuid.node[1],
|
||||||
(unsigned int *)&guid->u.Uuid.node[2],
|
(unsigned int *)&guid->u.Uuid.node[2],
|
||||||
(unsigned int *)&guid->u.Uuid.node[3],
|
(unsigned int *)&guid->u.Uuid.node[3],
|
||||||
(unsigned int *)&guid->u.Uuid.node[4],
|
(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_low = htole32(time_low);
|
||||||
guid->u.Uuid.time_mid = htole16(time_mid);
|
guid->u.Uuid.time_mid = htole16(time_mid);
|
||||||
guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
|
guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
|
||||||
|
|
||||||
|
return CGPT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuidToStr(const Guid *guid, char *str) {
|
void GuidToStr(const Guid *guid, char *str) {
|
||||||
@@ -194,6 +202,54 @@ void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
|
|||||||
utf16[s16idx++] = 0;
|
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'.
|
/* Loads sectors from 'fd'.
|
||||||
* *buf is pointed to an allocated memory when returned, and should be
|
* *buf is pointed to an allocated memory when returned, and should be
|
||||||
* freed by cgpt_close().
|
* freed by cgpt_close().
|
||||||
@@ -267,7 +323,7 @@ int CheckValid(const struct drive *drive) {
|
|||||||
if ((drive->gpt.valid_headers != MASK_BOTH) ||
|
if ((drive->gpt.valid_headers != MASK_BOTH) ||
|
||||||
(drive->gpt.valid_entries != MASK_BOTH)) {
|
(drive->gpt.valid_entries != MASK_BOTH)) {
|
||||||
printf("\n[ERROR] any of GPT header/entries is invalid, "
|
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_FAILED;
|
||||||
}
|
}
|
||||||
return CGPT_OK;
|
return CGPT_OK;
|
||||||
@@ -316,9 +372,6 @@ int DriveOpen(const char *drive_path, struct drive *drive) {
|
|||||||
goto error_close;
|
goto error_close;
|
||||||
}
|
}
|
||||||
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
|
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,
|
Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR,
|
||||||
drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
|
drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
|
||||||
@@ -390,6 +443,7 @@ int main(int argc, char *argv[]) {
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
printf("Copyright (c) 2010 The Chromium OS Authors. All rights reserved.\n");
|
||||||
cmd = argv[optind++];
|
cmd = argv[optind++];
|
||||||
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
||||||
if (cmd && !strcmp(cmds[i].name, cmd))
|
if (cmd && !strcmp(cmds[i].name, cmd))
|
||||||
|
|||||||
@@ -51,13 +51,15 @@ struct option_details {
|
|||||||
* i.e. help, to indicate the option is present. */
|
* i.e. help, to indicate the option is present. */
|
||||||
int AssignTrue(const char *argument, void *pointer, void *integer);
|
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 {
|
struct number_range {
|
||||||
int max;
|
int max;
|
||||||
int min;
|
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);
|
int InNumberRange(const char *argument, void *valid_range, void *parsed);
|
||||||
|
|
||||||
void ShowOptions(const struct option *opts,
|
void ShowOptions(const struct option *opts,
|
||||||
@@ -97,7 +99,7 @@ int OpenDriveInLastArgument(const int argc,
|
|||||||
* '\0').
|
* '\0').
|
||||||
*/
|
*/
|
||||||
#define GUID_STRLEN 37
|
#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);
|
void GuidToStr(const Guid *guid, char *str);
|
||||||
|
|
||||||
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
|
/* 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);
|
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. */
|
/* Describes the drive storing the GPT. */
|
||||||
struct drive {
|
struct drive {
|
||||||
int inited; /* indicated if this structure is valid */
|
int inited; /* indicated if this structure is valid */
|
||||||
@@ -140,7 +147,9 @@ int CheckValid(const struct drive *drive);
|
|||||||
|
|
||||||
/* Function declarations for commands.
|
/* Function declarations for commands.
|
||||||
* The return value of these functions is passed to main()'s exit value. */
|
* 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 CgptAttribute(int argc, char *argv[]);
|
||||||
|
int CgptDev(int argc, char *argv[]);
|
||||||
int CgptRepair(int argc, char *argv[]);
|
int CgptRepair(int argc, char *argv[]);
|
||||||
int CgptShow(int argc, char *argv[]);
|
int CgptShow(int argc, char *argv[]);
|
||||||
|
|
||||||
|
|||||||
276
utility/cgpt/cgpt_add_modify_delete.c
Normal file
276
utility/cgpt/cgpt_add_modify_delete.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ static struct option attribute_options[] = {
|
|||||||
{.name = "successful", .has_arg = required_argument, .flag = 0, .val = 's'},
|
{.name = "successful", .has_arg = required_argument, .flag = 0, .val = 's'},
|
||||||
{.name = "tries", .has_arg = required_argument, .flag = 0, .val = 't'},
|
{.name = "tries", .has_arg = required_argument, .flag = 0, .val = 't'},
|
||||||
{.name = "priority", .has_arg = required_argument, .flag = 0, .val = 'p'},
|
{.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
|
/* Extra information than struct option, please update this structure if you
|
||||||
@@ -63,6 +64,7 @@ static struct option_details attribute_options_details[] = {
|
|||||||
.validator = InNumberRange,
|
.validator = InNumberRange,
|
||||||
.valid_range = &range_15_0,
|
.valid_range = &range_15_0,
|
||||||
.parsed = &priority},
|
.parsed = &priority},
|
||||||
|
{ /* last element, which should be zero. */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
void AttributeHelp() {
|
void AttributeHelp() {
|
||||||
@@ -101,8 +103,6 @@ int CgptAttribute(int argc, char *argv[]) {
|
|||||||
|
|
||||||
if (CheckValid(&drive) != CGPT_OK) return CGPT_FAILED;
|
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. */
|
/* partition is not specified, search for the first Chromeos kernel. */
|
||||||
if (partition == NOT_INITED) {
|
if (partition == NOT_INITED) {
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
126
utility/cgpt/cgpt_dev.c
Normal file
126
utility/cgpt/cgpt_dev.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
* Update GPT attribute bits.
|
* Update GPT attribute bits.
|
||||||
*/
|
*/
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "cgpt.h"
|
#include "cgpt.h"
|
||||||
@@ -16,6 +17,12 @@ int AssignTrue(const char *argument, void *pointer, void *integer) {
|
|||||||
return CGPT_OK;
|
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'
|
/* Validator function. Returns 1 if 'argument' is between 'max' and 'min'
|
||||||
* in 'valid_range'. */
|
* in 'valid_range'. */
|
||||||
int InNumberRange(const char *argument, void *valid_range, void *parsed) {
|
int InNumberRange(const char *argument, void *valid_range, void *parsed) {
|
||||||
@@ -23,23 +30,27 @@ int InNumberRange(const char *argument, void *valid_range, void *parsed) {
|
|||||||
char *endptr;
|
char *endptr;
|
||||||
int number;
|
int number;
|
||||||
|
|
||||||
assert(valid_range);
|
|
||||||
|
|
||||||
number = strtol(argument, &endptr, 10);
|
number = strtol(argument, &endptr, 10);
|
||||||
if (*endptr) {
|
if (*endptr) {
|
||||||
printf("[ERROR] argument '%s' is not a number.\n", argument);
|
printf("[ERROR] argument '%s' is not a number.\n", argument);
|
||||||
return CGPT_FAILED;
|
return CGPT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (number < range->min) {
|
if (range) {
|
||||||
printf("[ERROR] argument is too small (min is %d, but you gave: %d).\n",
|
if (number < range->min) {
|
||||||
range->min, number);
|
printf("[ERROR] argument is too small (min is %d, but you gave: %d).\n",
|
||||||
return CGPT_FAILED;
|
range->min, number);
|
||||||
} else if (number > range->max) {
|
return CGPT_FAILED;
|
||||||
printf("[ERROR] argument is too large (max is %d, but you gave: %d).\n",
|
} else if (number > range->max) {
|
||||||
range->max, number);
|
printf("[ERROR] argument is too large (max is %d, but you gave: %d).\n",
|
||||||
return CGPT_FAILED;
|
range->max, number);
|
||||||
|
return CGPT_FAILED;
|
||||||
|
} else {
|
||||||
|
if (parsed) *(int*)parsed = number;
|
||||||
|
return CGPT_OK;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* no range to check, assign integer. */
|
||||||
if (parsed) *(int*)parsed = number;
|
if (parsed) *(int*)parsed = number;
|
||||||
return CGPT_OK;
|
return CGPT_OK;
|
||||||
}
|
}
|
||||||
@@ -51,6 +62,7 @@ void ShowOptions(const struct option *opts,
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < num; ++i) {
|
for (i = 0; i < num; ++i) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
if (!opts[i].name) break;
|
||||||
snprintf(buf, sizeof(buf), "--%s %s", opts[i].name,
|
snprintf(buf, sizeof(buf), "--%s %s", opts[i].name,
|
||||||
opts[i].has_arg ? "ARG" : "");
|
opts[i].has_arg ? "ARG" : "");
|
||||||
printf(" %-20s (-%c) %s\n", buf, opts[i].val, details[i].comment);
|
printf(" %-20s (-%c) %s\n", buf, opts[i].val, details[i].comment);
|
||||||
@@ -76,6 +88,14 @@ int HandleOptions(const int argc,
|
|||||||
break;
|
break;
|
||||||
} else if (option == 0) {
|
} else if (option == 0) {
|
||||||
/* option 'val' has been saved in 'flag'. We do nothing here. */
|
/* 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 {
|
} else {
|
||||||
/* Short option doesn't update 'index'. We search whole array to find out
|
/* Short option doesn't update 'index'. We search whole array to find out
|
||||||
* the corresponding long option. */
|
* the corresponding long option. */
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ static int help;
|
|||||||
* attribute_comments[] and third parameter of getopt_long() too. */
|
* attribute_comments[] and third parameter of getopt_long() too. */
|
||||||
static struct option repair_options[] = {
|
static struct option repair_options[] = {
|
||||||
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
|
{.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
|
/* Extra information than struct option, please update this structure if you
|
||||||
@@ -30,6 +31,7 @@ static struct option_details repair_options_details[] = {
|
|||||||
.validator = AssignTrue,
|
.validator = AssignTrue,
|
||||||
.valid_range = 0,
|
.valid_range = 0,
|
||||||
.parsed = &help},
|
.parsed = &help},
|
||||||
|
{ /* last element, which should be zero. */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
void RepairHelp() {
|
void RepairHelp() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Use of this source code is governed by a BSD-style license that can be
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*
|
*
|
||||||
* Update GPT attribute bits.
|
* Show GPT details.
|
||||||
*/
|
*/
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -20,6 +20,7 @@ static struct option show_options[] = {
|
|||||||
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
|
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
|
||||||
{.name = "number", .has_arg = no_argument, .flag = 0, .val = 'n'},
|
{.name = "number", .has_arg = no_argument, .flag = 0, .val = 'n'},
|
||||||
{.name = "verbose", .has_arg = no_argument, .flag = 0, .val = 'v'},
|
{.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
|
/* Extra information than struct option, please update this structure if you
|
||||||
@@ -40,6 +41,7 @@ static struct option_details show_options_details[] = {
|
|||||||
.validator = AssignTrue,
|
.validator = AssignTrue,
|
||||||
.valid_range = 0,
|
.valid_range = 0,
|
||||||
.parsed = &verbose},
|
.parsed = &verbose},
|
||||||
|
{ /* last element, which should be zero. */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
void ShowHelp() {
|
void ShowHelp() {
|
||||||
@@ -121,31 +123,6 @@ static void HeaderDetails(GptHeader *header, const char *indent) {
|
|||||||
printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
|
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) {
|
void EntriesDetails(GptData *gpt, const int secondary) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -236,6 +213,7 @@ int CgptShow(int argc, char *argv[]) {
|
|||||||
return CGPT_FAILED;
|
return CGPT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenDriveInLastArgument(argc, argv, &drive);
|
||||||
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
|
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
|
||||||
return CGPT_FAILED;
|
return CGPT_FAILED;
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ int CheckParameters(GptData *gpt) {
|
|||||||
|
|
||||||
/* Expects header signature should be GPT_HEADER_SIGNATURE. */
|
/* Expects header signature should be GPT_HEADER_SIGNATURE. */
|
||||||
uint32_t CheckHeaderSignature(GptData *gpt) {
|
uint32_t CheckHeaderSignature(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -69,15 +68,14 @@ uint32_t CheckHeaderSignature(GptData *gpt) {
|
|||||||
if (Memcmp(headers[i]->signature,
|
if (Memcmp(headers[i]->signature,
|
||||||
GPT_HEADER_SIGNATURE,
|
GPT_HEADER_SIGNATURE,
|
||||||
GPT_HEADER_SIGNATURE_SIZE)) {
|
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. */
|
/* The header revision should be GPT_HEADER_REVISION. */
|
||||||
uint32_t CheckRevision(GptData *gpt) {
|
uint32_t CheckRevision(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -86,15 +84,14 @@ uint32_t CheckRevision(GptData *gpt) {
|
|||||||
|
|
||||||
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
||||||
if (headers[i]->revision != GPT_HEADER_REVISION)
|
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
|
/* A valid header size should be between MIN_SIZE_OF_HEADER and
|
||||||
* MAX_SIZE_OF_HEADER. */
|
* MAX_SIZE_OF_HEADER. */
|
||||||
uint32_t CheckSize(GptData *gpt) {
|
uint32_t CheckSize(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -104,14 +101,13 @@ uint32_t CheckSize(GptData *gpt) {
|
|||||||
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
||||||
if ((headers[i]->size < MIN_SIZE_OF_HEADER) ||
|
if ((headers[i]->size < MIN_SIZE_OF_HEADER) ||
|
||||||
(headers[i]->size > MAX_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. */
|
/* Reserved and padding fields should be zero. */
|
||||||
uint32_t CheckReservedFields(GptData *gpt) {
|
uint32_t CheckReservedFields(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -120,32 +116,30 @@ uint32_t CheckReservedFields(GptData *gpt) {
|
|||||||
|
|
||||||
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
||||||
if (headers[i]->reserved || headers[i]->padding)
|
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.
|
/* my_lba field points to the header itself.
|
||||||
* So that the my_lba of primary header should be 1 (right after PMBR).
|
* 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. */
|
* The my_lba of secondary header should be the last secotr on drive. */
|
||||||
uint32_t CheckMyLba(GptData *gpt) {
|
uint32_t CheckMyLba(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *primary_header, *secondary_header;
|
GptHeader *primary_header, *secondary_header;
|
||||||
|
|
||||||
primary_header = (GptHeader*)gpt->primary_header;
|
primary_header = (GptHeader*)gpt->primary_header;
|
||||||
secondary_header = (GptHeader*)gpt->secondary_header;
|
secondary_header = (GptHeader*)gpt->secondary_header;
|
||||||
|
|
||||||
if (primary_header->my_lba != GPT_PMBR_SECTOR) /* 2nd sector on drive */
|
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 */
|
if (secondary_header->my_lba != (gpt->drive_sectors - 1)) /* last sector */
|
||||||
INVALIDATE_HEADER(valid_headers, SECONDARY);
|
INVALIDATE_HEADER(gpt->valid_headers, SECONDARY);
|
||||||
return valid_headers;
|
return gpt->valid_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SizeOfPartitionEntry must be between MIN_SIZE_OF_ENTRY and
|
/* SizeOfPartitionEntry must be between MIN_SIZE_OF_ENTRY and
|
||||||
* MAX_SIZE_OF_ENTRY, and a multiple of SIZE_OF_ENTRY_MULTIPLE. */
|
* MAX_SIZE_OF_ENTRY, and a multiple of SIZE_OF_ENTRY_MULTIPLE. */
|
||||||
uint32_t CheckSizeOfPartitionEntry(GptData *gpt) {
|
uint32_t CheckSizeOfPartitionEntry(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -157,16 +151,15 @@ uint32_t CheckSizeOfPartitionEntry(GptData *gpt) {
|
|||||||
if ((size_of_entry < MIN_SIZE_OF_ENTRY) ||
|
if ((size_of_entry < MIN_SIZE_OF_ENTRY) ||
|
||||||
(size_of_entry > MAX_SIZE_OF_ENTRY) ||
|
(size_of_entry > MAX_SIZE_OF_ENTRY) ||
|
||||||
(size_of_entry & (SIZE_OF_ENTRY_MULTIPLE - 1)))
|
(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
|
/* number_of_entries must be between MIN_NUMBER_OF_ENTRIES and
|
||||||
* MAX_NUMBER_OF_ENTRIES, and size_of_entry * number_of_entries must be
|
* MAX_NUMBER_OF_ENTRIES, and size_of_entry * number_of_entries must be
|
||||||
* equal to TOTAL_ENTRIES_SIZE. */
|
* equal to TOTAL_ENTRIES_SIZE. */
|
||||||
uint32_t CheckNumberOfEntries(GptData *gpt) {
|
uint32_t CheckNumberOfEntries(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -178,16 +171,15 @@ uint32_t CheckNumberOfEntries(GptData *gpt) {
|
|||||||
if ((number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
|
if ((number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
|
||||||
(number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
|
(number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
|
||||||
(number_of_entries * headers[i]->size_of_entry != TOTAL_ENTRIES_SIZE))
|
(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.
|
/* Make sure entries_lba is correct.
|
||||||
* 2 for primary entries
|
* 2 for primary entries
|
||||||
* drive_sectors-1-GPT_ENTRIES_SECTORS for secondary entries. */
|
* drive_sectors-1-GPT_ENTRIES_SECTORS for secondary entries. */
|
||||||
uint32_t CheckEntriesLba(GptData *gpt) {
|
uint32_t CheckEntriesLba(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
GptHeader *primary_header, *secondary_header;
|
GptHeader *primary_header, *secondary_header;
|
||||||
|
|
||||||
primary_header = (GptHeader*)gpt->primary_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
|
/* We assume the primary partition entry table is located at the sector
|
||||||
* right after primary partition header. */
|
* right after primary partition header. */
|
||||||
if (primary_header->entries_lba != (GPT_PMBR_SECTOR + GPT_HEADER_SECTOR))
|
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
|
/* We assume the secondary partition entry table is the 32 sectors
|
||||||
* right before the secondary partition header. */
|
* right before the secondary partition header. */
|
||||||
if (secondary_header->entries_lba !=
|
if (secondary_header->entries_lba !=
|
||||||
(gpt->drive_sectors - 1 - GPT_ENTRIES_SECTORS))
|
(gpt->drive_sectors - 1 - GPT_ENTRIES_SECTORS))
|
||||||
INVALIDATE_HEADER(valid_headers, SECONDARY);
|
INVALIDATE_HEADER(gpt->valid_headers, SECONDARY);
|
||||||
return valid_headers;
|
return gpt->valid_headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FirstUsableLBA must be after the end of the primary GPT table array.
|
/* FirstUsableLBA must be after the end of the primary GPT table array.
|
||||||
* LastUsableLBA must be before the start of the secondary GPT table array.
|
* LastUsableLBA must be before the start of the secondary GPT table array.
|
||||||
* FirstUsableLBA <= LastUsableLBA. */
|
* FirstUsableLBA <= LastUsableLBA. */
|
||||||
uint32_t CheckValidUsableLbas(GptData *gpt) {
|
uint32_t CheckValidUsableLbas(GptData *gpt) {
|
||||||
uint32_t valid_headers = MASK_BOTH;
|
|
||||||
uint64_t end_of_primary_entries;
|
uint64_t end_of_primary_entries;
|
||||||
uint64_t start_of_secondary_entries;
|
uint64_t start_of_secondary_entries;
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
@@ -224,20 +215,20 @@ uint32_t CheckValidUsableLbas(GptData *gpt) {
|
|||||||
|
|
||||||
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
||||||
if (headers[i]->first_usable_lba < end_of_primary_entries)
|
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)
|
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)
|
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 <
|
if (headers[PRIMARY]->first_usable_lba - headers[PRIMARY]->entries_lba <
|
||||||
GPT_ENTRIES_SECTORS)
|
GPT_ENTRIES_SECTORS)
|
||||||
INVALIDATE_HEADER(valid_headers, PRIMARY);
|
INVALIDATE_HEADER(gpt->valid_headers, PRIMARY);
|
||||||
if (headers[SECONDARY]->last_usable_lba >= headers[SECONDARY]->entries_lba)
|
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 */
|
/* Checks header CRC */
|
||||||
@@ -289,7 +280,7 @@ uint32_t CheckEntriesCrc(GptData *gpt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns non-zero if the given GUID is non-zero. */
|
/* 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}}}};
|
static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
|
||||||
return Memcmp(&zero, guid, sizeof(zero));
|
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.
|
/* Checks if any two partitions are overlapped in primary and secondary entries.
|
||||||
*/
|
*/
|
||||||
uint32_t CheckOverlappedPartition(GptData *gpt) {
|
uint32_t CheckOverlappedPartition(GptData *gpt) {
|
||||||
uint32_t valid_entries = MASK_BOTH;
|
|
||||||
GptHeader *headers[] = {
|
GptHeader *headers[] = {
|
||||||
(GptHeader*)gpt->primary_header,
|
(GptHeader*)gpt->primary_header,
|
||||||
(GptHeader*)gpt->secondary_header,
|
(GptHeader*)gpt->secondary_header,
|
||||||
@@ -395,9 +385,9 @@ uint32_t CheckOverlappedPartition(GptData *gpt) {
|
|||||||
|
|
||||||
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
for (i = PRIMARY; i <= SECONDARY; ++i) {
|
||||||
if (OverlappedEntries(entries[i], number_of_entries))
|
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.
|
/* Primary entries and secondary entries should be bitwise identical.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ uint32_t CheckEntriesLba(GptData *gpt);
|
|||||||
uint32_t CheckValidUsableLbas(GptData *gpt);
|
uint32_t CheckValidUsableLbas(GptData *gpt);
|
||||||
uint32_t CheckHeaderCrc(GptData *gpt);
|
uint32_t CheckHeaderCrc(GptData *gpt);
|
||||||
uint32_t CheckEntriesCrc(GptData *gpt);
|
uint32_t CheckEntriesCrc(GptData *gpt);
|
||||||
|
int NonZeroGuid(const Guid *guid);
|
||||||
uint32_t CheckValidEntries(GptData *gpt);
|
uint32_t CheckValidEntries(GptData *gpt);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t starting;
|
uint64_t starting;
|
||||||
|
|||||||
Reference in New Issue
Block a user