Nearly complete rewrite of cgpt tool.

This fixes a number of bugs, adds a bunch of commands, and essentially makes
cgpt ready to use as a replacement for gpt. Still to do is to add commands
and options that will let it generated intentionally bad partitions, for use
in testing.

Review URL: http://codereview.chromium.org/2719008
This commit is contained in:
Bill Richardson
2010-06-11 09:15:55 -07:00
parent 6a97b3e2a1
commit f1372d9109
29 changed files with 2216 additions and 2058 deletions

View File

@@ -3,6 +3,7 @@
# found in the LICENSE file.
export CC ?= gcc
export CXX ?= g++
export CFLAGS = -Wall -DNDEBUG -O3 -Werror
export TOP = $(shell pwd)
export FWDIR=$(TOP)/vboot_firmware
@@ -14,7 +15,7 @@ export INCLUDES = \
export FWLIB=$(FWDIR)/vboot_fw.a
export HOSTLIB=$(HOSTDIR)/vboot_host.a
SUBDIRS=vboot_firmware misclibs host vfirmware vkernel utility tests
SUBDIRS=vboot_firmware misclibs host vfirmware vkernel utility cgpt tests
all:
set -e; \
@@ -30,6 +31,7 @@ clean:
install:
$(MAKE) -C utility install
$(MAKE) -C cgpt install
runtests:
$(MAKE) -C tests runtests

45
cgpt/Makefile Normal file
View File

@@ -0,0 +1,45 @@
# 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.
CC ?= gcc
TOP ?= ..
CFLAGS ?= -Wall -DNDEBUG -O3 -Werror
CFLAGS += -static
LDFLAGS += -luuid
FWDIR=$(TOP)/vboot_firmware
INCLUDES = -I$(FWDIR)/lib/cgptlib/include
LIBS = $(FWDIR)/vboot_fw.a
DESTDIR ?= /usr/bin
PROGNAME = cgpt
OBJS= \
cgpt.o \
cmd_show.o \
cmd_repair.o \
cmd_create.o \
cmd_add.o \
cmd_boot.o \
cgpt_common.o
all: $(PROGNAME)
$(PROGNAME): $(OBJS) $(LIBS)
$(CC) -o $(PROGNAME) $(CFLAGS) $^ $(LDFLAGS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
rm -f $(PROGNAME) *.o *~
install: $(PROGNAME)
mkdir -p $(DESTDIR)
cp -f $^ $(DESTDIR)
chmod a+rx $(patsubst %,$(DESTDIR)/%,$^)
.PHONY: all clean install

75
cgpt/cgpt.c Normal file
View File

@@ -0,0 +1,75 @@
/* 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.
*
* Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
* files for more details.
*/
#include "cgpt.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
const char* progname;
const char* command;
struct {
const char *name;
int (*fp)(int argc, char *argv[]);
const char *comment;
} cmds[] = {
{"create", cmd_create, "Create or reset GPT headers and tables"},
{"add", cmd_add, "Add, edit or remove a partition entry"},
{"show", cmd_show, "Show partition table and entries"},
{"repair", cmd_repair, "Repair damaged GPT headers and tables"},
{"boot", cmd_boot, "Edit the PMBR sector for legacy BIOSes"},
};
void Usage(void) {
int i;
printf("Usage: %s COMMAND [OPTIONS] DRIVE\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);
}
printf("\nFor more detailed usage, use %s COMMAND -h\n\n", progname);
}
int main(int argc, char *argv[]) {
int i;
progname = strrchr(argv[0], '/');
if (progname)
progname++;
else
progname = argv[0];
if (argc < 2) {
Usage();
return CGPT_FAILED;
}
// increment optind now, so that getopt skips argv[0] in command function
command = argv[optind++];
// Find the command to invoke.
for (i = 0; command && i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
if (0 == strcmp(cmds[i].name, command)) {
return cmds[i].fp(argc, argv);
}
}
// Couldn't find the command.
Usage();
return CGPT_FAILED;
}

130
cgpt/cgpt.h Normal file
View File

@@ -0,0 +1,130 @@
// 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.
#ifndef VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
#define VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <features.h>
#include <stdint.h>
#include "endian.h"
#include "gpt.h"
#include "cgptlib.h"
// Just for clarity
enum {
CGPT_OK = 0,
CGPT_FAILED,
};
struct legacy_partition {
uint8_t status;
uint8_t f_head;
uint8_t f_sect;
uint8_t f_cyl;
uint8_t type;
uint8_t l_head;
uint8_t l_sect;
uint8_t l_cyl;
uint32_t f_lba;
uint32_t num_sect;
} __attribute__((packed));
// syslinux uses this format:
struct pmbr {
uint8_t bootcode[424];
Guid boot_guid;
uint32_t disk_id;
uint8_t magic[2]; // 0x1d, 0x9a
struct legacy_partition part[4];
uint8_t sig[2]; // 0x55, 0xaa
} __attribute__((packed));
void PMBRToStr(struct pmbr *pmbr, char *str);
// Handle to the drive storing the GPT.
struct drive {
int fd; /* file descriptor */
uint64_t size; /* total size (in bytes) */
GptData gpt;
struct pmbr pmbr;
};
int DriveOpen(const char *drive_path, struct drive *drive);
int DriveClose(struct drive *drive, int update_as_needed);
int CheckValid(const struct drive *drive);
/* GUID conversion functions. Accepted format:
*
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
*
* At least GUID_STRLEN bytes should be reserved in 'str' (included the tailing
* '\0').
*/
#define GUID_STRLEN 37
int StrToGuid(const char *str, Guid *guid);
void GuidToStr(const Guid *guid, char *str);
int IsZero(const Guid *guid);
int ReadPMBR(struct drive *drive);
int WritePMBR(struct drive *drive);
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
* Caller must prepare enough space for UTF8. The rough estimation is:
*
* utf8 length = bytecount(utf16) * 1.5
*/
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
* Caller must prepare enough space for UTF16. The conservative estimation is:
*
* utf16 bytecount = bytecount(utf8) / 3 * 4
*/
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);
void EntryDetails(GptEntry *entry, int index, int raw);
uint32_t GetNumberOfEntries(const GptData *gpt);
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index);
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority);
int GetPriority(GptData *gpt, int secondary, int entry_index);
void SetTries(GptData *gpt, int secondary, int entry_index, int tries);
int GetTries(GptData *gpt, int secondary, int entry_index);
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success);
int GetSuccessful(GptData *gpt, int secondary, int entry_index);
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
void UpdateCrc(GptData *gpt);
int IsSynonymous(const GptHeader* a, const GptHeader* b);
// For usage and error messages.
extern const char* progname;
extern const char* command;
void Error(const char *format, ...);
// Command functions.
int cmd_show(int argc, char *argv[]);
int cmd_repair(int argc, char *argv[]);
int cmd_create(int argc, char *argv[]);
int cmd_add(int argc, char *argv[]);
int cmd_boot(int argc, char *argv[]);
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
const char *GptError(int errnum);
#endif // VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_

726
cgpt/cgpt_common.c Normal file
View File

@@ -0,0 +1,726 @@
/* 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.
*
* Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
* files for more details.
*/
#include "cgpt.h"
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include "cgptlib_internal.h"
#include "crc32.h"
void Error(const char *format, ...) {
va_list ap;
va_start(ap, format);
fprintf(stderr, "ERROR: %s %s: ", progname, command);
vfprintf(stderr, format, ap);
va_end(ap);
}
int CheckValid(const struct drive *drive) {
if ((drive->gpt.valid_headers != MASK_BOTH) ||
(drive->gpt.valid_entries != MASK_BOTH)) {
fprintf(stderr, "\nWARNING: one of the GPT header/entries is invalid, "
"please run '%s repair'\n", progname);
return CGPT_FAILED;
}
return CGPT_OK;
}
/* Loads sectors from 'fd'.
* *buf is pointed to an allocated memory when returned, and should be
* freed by cgpt_close().
*
* fd -- file descriptot.
* buf -- pointer to buffer pointer
* sector -- offset of starting sector (in sectors)
* sector_bytes -- bytes per sector
* sector_count -- number of sectors to load
*
* Returns CGPT_OK for successful. Aborts if any error occurs.
*/
static int Load(const int fd, uint8_t **buf,
const uint64_t sector,
const uint64_t sector_bytes,
const uint64_t sector_count) {
int count; /* byte count to read */
int nread;
assert(buf);
count = sector_bytes * sector_count;
*buf = malloc(count);
assert(*buf);
if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
goto error_free;
nread = read(fd, *buf, count);
if (nread < count)
goto error_free;
return CGPT_OK;
error_free:
free(*buf);
*buf = 0;
return CGPT_FAILED;
}
int ReadPMBR(struct drive *drive) {
if (-1 == lseek(drive->fd, 0, SEEK_SET))
return CGPT_FAILED;
int nread = read(drive->fd, &drive->pmbr, sizeof(struct pmbr));
if (nread != sizeof(struct pmbr))
return CGPT_FAILED;
return CGPT_OK;
}
int WritePMBR(struct drive *drive) {
if (-1 == lseek(drive->fd, 0, SEEK_SET))
return CGPT_FAILED;
int nwrote = write(drive->fd, &drive->pmbr, sizeof(struct pmbr));
if (nwrote != sizeof(struct pmbr))
return CGPT_FAILED;
return CGPT_OK;
}
/* Saves sectors to 'fd'.
*
* fd -- file descriptot.
* buf -- pointer to buffer
* sector -- starting sector offset
* sector_bytes -- bytes per sector
* sector_count -- number of sector to save
*
* Returns CGPT_OK for successful, CGPT_FAILED for failed.
*/
static int Save(const int fd, const uint8_t *buf,
const uint64_t sector,
const uint64_t sector_bytes,
const uint64_t sector_count) {
int count; /* byte count to write */
int nwrote;
assert(buf);
count = sector_bytes * sector_count;
if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
return CGPT_FAILED;
nwrote = write(fd, buf, count);
if (nwrote < count)
return CGPT_FAILED;
return CGPT_OK;
}
// Opens a block device or file, loads raw GPT data from it.
//
// Returns CGPT_FAILED if any error happens.
// Returns CGPT_OK if success and information are stored in 'drive'. */
int DriveOpen(const char *drive_path, struct drive *drive) {
struct stat stat;
assert(drive_path);
assert(drive);
// Clear struct for proper error handling.
memset(drive, 0, sizeof(struct drive));
drive->fd = open(drive_path, O_RDWR | O_LARGEFILE);
if (drive->fd == -1) {
Error("Can't open %s: %s\n", drive_path, strerror(errno));
return CGPT_FAILED;
}
if (fstat(drive->fd, &stat) == -1) {
goto error_close;
}
if ((stat.st_mode & S_IFMT) != S_IFREG) {
if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno));
goto error_close;
}
if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) {
Error("Can't read sector size from %s: %s\n",
drive_path, strerror(errno));
goto error_close;
}
} else {
drive->gpt.sector_bytes = 512; /* bytes */
drive->size = stat.st_size;
}
if (drive->size % drive->gpt.sector_bytes) {
Error("Media size (%llu) is not a multiple of sector size(%d)\n",
(long long unsigned int)drive->size, drive->gpt.sector_bytes);
goto error_close;
}
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
// Read the data.
if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_header,
GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
goto error_close;
}
if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_header,
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
goto error_close;
}
if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_entries,
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
goto error_close;
}
if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_entries,
drive->gpt.drive_sectors - GPT_HEADER_SECTOR
- GPT_ENTRIES_SECTORS,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
goto error_close;
}
// We just load the data. Caller must validate it.
return CGPT_OK;
error_close:
(void) DriveClose(drive, 0);
return CGPT_FAILED;
}
int DriveClose(struct drive *drive, int update_as_needed) {
int errors = 0;
if (update_as_needed) {
if (drive->gpt.modified & GPT_MODIFIED_HEADER1) {
if (CGPT_OK != Save(drive->fd, drive->gpt.primary_header,
GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
errors++;
Error("Cannot write primary header: %s\n", strerror(errno));
}
}
if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
if(CGPT_OK != Save(drive->fd, drive->gpt.secondary_header,
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
errors++;
Error("Cannot write secondary header: %s\n", strerror(errno));
}
}
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) {
if (CGPT_OK != Save(drive->fd, drive->gpt.primary_entries,
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
errors++;
Error("Cannot write primary entries: %s\n", strerror(errno));
}
}
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) {
if (CGPT_OK != Save(drive->fd, drive->gpt.secondary_entries,
drive->gpt.drive_sectors - GPT_HEADER_SECTOR
- GPT_ENTRIES_SECTORS,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
errors++;
Error("Cannot write secondary entries: %s\n", strerror(errno));
}
}
}
close(drive->fd);
if (drive->gpt.primary_header)
free(drive->gpt.primary_header);
drive->gpt.primary_header = 0;
if (drive->gpt.primary_entries)
free(drive->gpt.primary_entries);
drive->gpt.primary_entries = 0;
if (drive->gpt.secondary_header)
free(drive->gpt.secondary_header);
drive->gpt.secondary_header = 0;
if (drive->gpt.secondary_entries)
free(drive->gpt.secondary_entries);
drive->gpt.secondary_entries = 0;
return errors ? CGPT_FAILED : CGPT_OK;
}
/* GUID conversion functions. Accepted format:
*
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
*
* Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
*/
int StrToGuid(const char *str, Guid *guid) {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_high_and_version;
unsigned int chunk[11];
if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
chunk+0,
chunk+1,
chunk+2,
chunk+3,
chunk+4,
chunk+5,
chunk+6,
chunk+7,
chunk+8,
chunk+9,
chunk+10)) {
printf("FAILED\n");
return CGPT_FAILED;
}
time_low = chunk[0] & 0xffffffff;
time_mid = chunk[1] & 0xffff;
time_high_and_version = chunk[2] & 0xffff;
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);
guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff;
guid->u.Uuid.clock_seq_low = chunk[4] & 0xff;
guid->u.Uuid.node[0] = chunk[5] & 0xff;
guid->u.Uuid.node[1] = chunk[6] & 0xff;
guid->u.Uuid.node[2] = chunk[7] & 0xff;
guid->u.Uuid.node[3] = chunk[8] & 0xff;
guid->u.Uuid.node[4] = chunk[9] & 0xff;
guid->u.Uuid.node[5] = chunk[10] & 0xff;
return CGPT_OK;
}
void GuidToStr(const Guid *guid, char *str) {
sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid),
le16toh(guid->u.Uuid.time_high_and_version),
guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low,
guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2],
guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]);
}
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
* Caller must prepare enough space for UTF8. The rough estimation is:
*
* utf8 length = bytecount(utf16) * 1.5
*/
#define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8)
{
size_t s8idx, s16idx, s16len;
uint32_t utfchar;
unsigned int next_utf16;
for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len);
*utf8 = s8idx = s16idx = 0;
while (s16idx < s16len) {
utfchar = le16toh(utf16[s16idx++]);
if ((utfchar & 0xf800) == 0xd800) {
next_utf16 = le16toh(utf16[s16idx]);
if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00)
utfchar = 0xfffd;
else
s16idx++;
}
if (utfchar < 0x80) {
utf8[s8idx++] = utfchar;
} else if (utfchar < 0x800) {
utf8[s8idx++] = 0xc0 | (utfchar >> 6);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
} else if (utfchar < 0x10000) {
utf8[s8idx++] = 0xe0 | (utfchar >> 12);
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
} else if (utfchar < 0x200000) {
utf8[s8idx++] = 0xf0 | (utfchar >> 18);
utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
}
}
utf8[s8idx++] = 0;
}
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
* Caller must prepare enough space for UTF16. The conservative estimation is:
*
* utf16 bytecount = bytecount(utf8) / 3 * 4
*/
void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
{
size_t s16idx, s8idx, s8len;
uint32_t utfchar;
unsigned int c, utfbytes;
for (s8len = 0; utf8[s8len]; ++s8len);
s8idx = s16idx = 0;
utfbytes = 0;
do {
c = utf8[s8idx++];
if ((c & 0xc0) != 0x80) {
/* Initial characters. */
if (utfbytes != 0) {
/* Incomplete encoding. */
utf16[s16idx++] = 0xfffd;
}
if ((c & 0xf8) == 0xf0) {
utfchar = c & 0x07;
utfbytes = 3;
} else if ((c & 0xf0) == 0xe0) {
utfchar = c & 0x0f;
utfbytes = 2;
} else if ((c & 0xe0) == 0xc0) {
utfchar = c & 0x1f;
utfbytes = 1;
} else {
utfchar = c & 0x7f;
utfbytes = 0;
}
} else {
/* Followup characters. */
if (utfbytes > 0) {
utfchar = (utfchar << 6) + (c & 0x3f);
utfbytes--;
} else if (utfbytes == 0)
utfbytes = -1;
utfchar = 0xfffd;
}
if (utfbytes == 0) {
if (utfchar >= 0x10000) {
utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40));
if (s16idx >= SIZEOF_GPTENTRY_NAME) break;
utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff));
} else {
utf16[s16idx++] = htole16(utfchar);
}
}
} while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME);
if (s16idx < SIZEOF_GPTENTRY_NAME)
utf16[s16idx++] = 0;
}
struct {
Guid type;
char *name;
char *description;
} supported_types[] = {
{GPT_ENT_TYPE_CHROMEOS_KERNEL, "kernel", "ChromeOS kernel"},
{GPT_ENT_TYPE_CHROMEOS_ROOTFS, "rootfs", "ChromeOS rootfs"},
{GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"},
{GPT_ENT_TYPE_CHROMEOS_RESERVED, "reserved", "ChromeOS reserved"},
{GPT_ENT_TYPE_EFI, "efi", "EFI System Partition"},
{GPT_ENT_TYPE_UNUSED, "unused", "Unused (nonexistent) partition"},
};
/* 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("The partition type may also be given as one of these aliases:\n\n");
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
printf(" %-10s %s\n", supported_types[i].name,
supported_types[i].description);
}
printf("\n");
}
uint32_t GetNumberOfEntries(const GptData *gpt) {
GptHeader *header = 0;
if (gpt->valid_headers & MASK_PRIMARY)
header = (GptHeader*)gpt->primary_header;
else if (gpt->valid_headers & MASK_SECONDARY)
header = (GptHeader*)gpt->secondary_header;
else
return 0;
return header->number_of_entries;
}
static uint32_t GetSizeOfEntries(const GptData *gpt) {
GptHeader *header = 0;
if (gpt->valid_headers & MASK_PRIMARY)
header = (GptHeader*)gpt->primary_header;
else if (gpt->valid_headers & MASK_SECONDARY)
header = (GptHeader*)gpt->secondary_header;
else
return 0;
return header->number_of_entries;
}
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) {
uint8_t *entries;
int stride = GetSizeOfEntries(gpt);
if (!stride)
return 0;
if (secondary == PRIMARY) {
entries = gpt->primary_entries;
} else {
entries = gpt->secondary_entries;
}
return (GptEntry*)(&entries[stride * entry_index]);
}
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET;
}
int GetPriority(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
}
void SetTries(GptData *gpt, int secondary, int entry_index, int tries) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK;
entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET;
}
int GetTries(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
CGPT_ATTRIBUTE_TRIES_OFFSET;
}
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
}
int GetSuccessful(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
}
#define TOSTRING(A) #A
const char *GptError(int errnum) {
const char *error_string[] = {
TOSTRING(GPT_SUCCESS),
TOSTRING(GPT_ERROR_NO_VALID_KERNEL),
TOSTRING(GPT_ERROR_INVALID_HEADERS),
TOSTRING(GPT_ERROR_INVALID_ENTRIES),
TOSTRING(GPT_ERROR_INVALID_SECTOR_SIZE),
TOSTRING(GPT_ERROR_INVALID_SECTOR_NUMBER),
TOSTRING(GPT_ERROR_INVALID_UPDATE_TYPE)
};
if (errnum < 0 || errnum >= ARRAY_COUNT(error_string))
return "<illegal value>";
return error_string[errnum];
}
/* Update CRC value if necessary. */
void UpdateCrc(GptData *gpt) {
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
secondary_header = (GptHeader*)gpt->secondary_header;
if (gpt->modified & GPT_MODIFIED_ENTRIES1) {
primary_header->entries_crc32 =
Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE);
}
if (gpt->modified & GPT_MODIFIED_ENTRIES2) {
secondary_header->entries_crc32 =
Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
}
if (gpt->modified & GPT_MODIFIED_HEADER1) {
primary_header->header_crc32 = 0;
primary_header->header_crc32 = Crc32(
(const uint8_t *)primary_header, primary_header->size);
}
if (gpt->modified & GPT_MODIFIED_HEADER2) {
secondary_header->header_crc32 = 0;
secondary_header->header_crc32 = Crc32(
(const uint8_t *)secondary_header, secondary_header->size);
}
}
/* Two headers are NOT bitwise identical. For example, my_lba pointers to header
* itself so that my_lba in primary and secondary is definitely different.
* Only the following fields should be identical.
*
* first_usable_lba
* last_usable_lba
* number_of_entries
* size_of_entry
* disk_uuid
*
* If any of above field are not matched, overwrite secondary with primary since
* we always trust primary.
* If any one of header is invalid, copy from another. */
int IsSynonymous(const GptHeader* a, const GptHeader* b) {
if ((a->first_usable_lba == b->first_usable_lba) &&
(a->last_usable_lba == b->last_usable_lba) &&
(a->number_of_entries == b->number_of_entries) &&
(a->size_of_entry == b->size_of_entry) &&
(!memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid))))
return 1;
return 0;
}
/* Primary entries and secondary entries should be bitwise identical.
* If two entries tables are valid, compare them. If not the same,
* overwrites secondary with primary (primary always has higher priority),
* and marks secondary as modified.
* If only one is valid, overwrites invalid one.
* If all are invalid, does nothing.
* This function returns bit masks for GptData.modified field.
* Note that CRC is NOT re-computed in this function.
*/
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) {
if (valid_entries == MASK_BOTH) {
if (memcmp(gpt->primary_entries, gpt->secondary_entries,
TOTAL_ENTRIES_SIZE)) {
memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES2;
}
} else if (valid_entries == MASK_PRIMARY) {
memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES2;
} else if (valid_entries == MASK_SECONDARY) {
memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES1;
}
return 0;
}
/* The above five fields are shared between primary and secondary headers.
* We can recover one header from another through copying those fields. */
void CopySynonymousParts(GptHeader* target, const GptHeader* source) {
target->first_usable_lba = source->first_usable_lba;
target->last_usable_lba = source->last_usable_lba;
target->number_of_entries = source->number_of_entries;
target->size_of_entry = source->size_of_entry;
memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid));
}
/* This function repairs primary and secondary headers if possible.
* If both headers are valid (CRC32 is correct) but
* a) indicate inconsistent usable LBA ranges,
* b) inconsistent partition entry size and number,
* c) inconsistent disk_uuid,
* we will use the primary header to overwrite secondary header.
* If primary is invalid (CRC32 is wrong), then we repair it from secondary.
* If secondary is invalid (CRC32 is wrong), then we repair it from primary.
* This function returns the bitmasks for modified header.
* Note that CRC value is NOT re-computed in this function. UpdateCrc() will
* do it later.
*/
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) {
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
secondary_header = (GptHeader*)gpt->secondary_header;
if (valid_headers == MASK_BOTH) {
if (!IsSynonymous(primary_header, secondary_header)) {
CopySynonymousParts(secondary_header, primary_header);
return GPT_MODIFIED_HEADER2;
}
} else if (valid_headers == MASK_PRIMARY) {
memcpy(secondary_header, primary_header, primary_header->size);
secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */
secondary_header->alternate_lba = primary_header->my_lba;
secondary_header->entries_lba = secondary_header->my_lba -
GPT_ENTRIES_SECTORS;
return GPT_MODIFIED_HEADER2;
} else if (valid_headers == MASK_SECONDARY) {
memcpy(primary_header, secondary_header, secondary_header->size);
primary_header->my_lba = GPT_PMBR_SECTOR; /* the second sector on drive */
primary_header->alternate_lba = secondary_header->my_lba;
primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTOR;
return GPT_MODIFIED_HEADER1;
}
return 0;
}
int IsZero(const Guid *gp) {
return (0 == memcmp(gp, &guid_unused, sizeof(Guid)));
}
void PMBRToStr(struct pmbr *pmbr, char *str) {
char buf[256];
if (IsZero(&pmbr->boot_guid)) {
sprintf(str, "PMBR");
} else {
GuidToStr(&pmbr->boot_guid, buf);
sprintf(str, "PMBR (Boot GUID: %s)", buf);
}
}

276
cgpt/cmd_add.c Normal file
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.
#include "cgpt.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>
#include "cgptlib_internal.h"
static void Usage(void)
{
printf("\nUsage: %s add [OPTIONS] DRIVE\n\n"
"Add, edit, or remove a partition entry.\n\n"
"Options:\n"
" -i NUM Specify partition (default is next available)\n"
" -b NUM Beginning sector\n"
" -s NUM Size in sectors\n"
" -t GUID Partition Type GUID\n"
" -u GUID Partition Unique ID\n"
" -l LABEL Label\n"
" -S NUM set Successful flag (0|1)\n"
" -T NUM set Tries flag (0-15)\n"
" -P NUM set Priority flag (0-15)\n"
" -A NUM set raw 64-bit attribute value\n"
"\n"
"Use the -i option to modify an existing partition.\n"
"The -b, -s, and -t options must be given for new partitions.\n"
"\n", progname);
PrintTypes();
}
int cmd_add(int argc, char *argv[]) {
struct drive drive;
int partition = 0;
uint64_t begin = 0;
uint64_t size = 0;
Guid type_guid;
Guid unique_guid;
char *label = 0;
int successful = 0;
int tries = 0;
int priority = 0;
uint64_t raw_value = 0;
int set_begin = 0;
int set_size = 0;
int set_type = 0;
int set_unique = 0;
int set_successful = 0;
int set_tries = 0;
int set_priority = 0;
int set_raw = 0;
int gpt_retval;
GptEntry *entry;
int index;
int c;
int errorcnt = 0;
char *e = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hi:b:s:t:u:l:S:T:P:A:")) != -1)
{
switch (c)
{
case 'i':
partition = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 'b':
set_begin = 1;
begin = strtoull(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 's':
set_size = 1;
size = strtoull(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 't':
set_type = 1;
if (CGPT_OK != SupportedType(optarg, &type_guid) &&
CGPT_OK != StrToGuid(optarg, &type_guid)) {
Error("invalid argument to -%c: %s\n", c, optarg);
errorcnt++;
}
break;
case 'u':
set_unique = 1;
if (CGPT_OK != StrToGuid(optarg, &unique_guid)) {
Error("invalid argument to -%c: %s\n", c, optarg);
errorcnt++;
}
break;
case 'l':
label = optarg;
break;
case 'S':
set_successful = 1;
successful = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
if (successful < 0 || successful > 1) {
Error("value for -%c must be between 0 and 1", c);
errorcnt++;
}
break;
case 'T':
set_tries = 1;
tries = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
progname, c, optarg);
errorcnt++;
}
if (tries < 0 || tries > 15) {
Error("value for -%c must be between 0 and 15", c);
errorcnt++;
}
break;
case 'P':
set_priority = 1;
priority = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
if (priority < 0 || priority > 15) {
Error("value for -%c must be between 0 and 15", c);
errorcnt++;
}
break;
case 'A':
set_raw = 1;
raw_value = strtoull(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 'h':
Usage();
return CGPT_OK;
case '?':
Error("unrecognized option: -%c\n", optopt);
errorcnt++;
break;
case ':':
Error("missing argument to -%c\n", optopt);
errorcnt++;
break;
default:
errorcnt++;
break;
}
}
if (errorcnt)
{
Usage();
return CGPT_FAILED;
}
if (optind >= argc) {
Error("missing drive argument\n");
return CGPT_FAILED;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
Error("GptSanityCheck() returned %d: %s\n",
gpt_retval, GptError(gpt_retval));
return CGPT_FAILED;
}
int max_part = GetNumberOfEntries(&drive.gpt);
if (partition) {
if (partition > max_part) {
Error("invalid partition number: %d\n", partition);
goto bad;
}
index = partition - 1;
entry = GetEntry(&drive.gpt, PRIMARY, index);
} else {
// find next empty partition
for (index = 0; index < max_part; index++) {
entry = GetEntry(&drive.gpt, PRIMARY, index);
if (IsZero(&entry->type)) {
partition = index + 1;
break;
}
}
if (index >= max_part) {
Error("no unused partitions available\n");
goto bad;
}
}
// New partitions must specify type, begin, and size.
if (IsZero(&entry->type)) {
if (!set_begin || !set_size || !set_type) {
Error("-t, -b, and -s options are required for new partitions\n");
goto bad;
}
if (IsZero(&type_guid)) {
Error("New partitions must have a type other than \"unused\"\n");
goto bad;
}
if (!set_unique)
uuid_generate((uint8_t *)&entry->unique);
}
if (set_begin)
entry->starting_lba = begin;
if (set_size)
entry->ending_lba = begin + size - 1;
if (set_type)
memcpy(&entry->type, &type_guid, sizeof(Guid));
if (set_unique)
memcpy(&entry->unique, &unique_guid, sizeof(Guid));
if (label) {
uint16_t buf[128];
UTF8ToUTF16((uint8_t *)label, buf);
memcpy(entry->name, buf, sizeof(entry->name));
}
if (set_raw) {
entry->attributes = raw_value;
} else {
if (set_successful)
SetSuccessful(&drive.gpt, PRIMARY, index, successful);
if (set_tries)
SetTries(&drive.gpt, PRIMARY, index, tries);
if (set_priority)
SetPriority(&drive.gpt, PRIMARY, index, priority);
}
RepairEntries(&drive.gpt, MASK_PRIMARY);
RepairHeader(&drive.gpt, MASK_PRIMARY);
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
UpdateCrc(&drive.gpt);
// Write it all out
return DriveClose(&drive, 1);
bad:
(void) DriveClose(&drive, 0);
return CGPT_FAILED;
}

167
cgpt/cmd_boot.c Normal file
View File

@@ -0,0 +1,167 @@
// 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.
#include "cgpt.h"
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <uuid/uuid.h>
#include "cgptlib_internal.h"
#include "endian.h"
static void Usage(void)
{
printf("\nUsage: %s boot [OPTIONS] DRIVE\n\n"
"Edit the PMBR sector for legacy BIOSes\n\n"
"Options:\n"
" -i NUM Set bootable partition\n"
" -b FILE Install bootloader code in the PMBR\n"
" -p Create legacy PMBR partition table\n"
"\n"
"With no options, it will just print the PMBR boot guid\n"
"\n", progname);
}
int cmd_boot(int argc, char *argv[]) {
struct drive drive;
int partition = 0;
char *bootfile = 0;
int create_pmbr = 0;
int retval = 1;
int gpt_retval;
int c;
int errorcnt = 0;
char *e = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hi:b:p")) != -1)
{
switch (c)
{
case 'i':
partition = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 'b':
bootfile = optarg;
break;
case 'p':
create_pmbr = 1;
break;
case 'h':
Usage();
return CGPT_OK;
case '?':
Error("unrecognized option: -%c\n", optopt);
errorcnt++;
break;
case ':':
Error("missing argument to -%c\n", optopt);
errorcnt++;
break;
default:
errorcnt++;
break;
}
}
if (errorcnt)
{
Usage();
return CGPT_FAILED;
}
if (optind >= argc) {
Error("missing drive argument\n");
return CGPT_FAILED;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
if (CGPT_OK != ReadPMBR(&drive)) {
Error("Unable to read PMBR\n");
goto done;
}
if (create_pmbr) {
drive.pmbr.magic[0] = 0x1d;
drive.pmbr.magic[1] = 0x9a;
drive.pmbr.sig[0] = 0x55;
drive.pmbr.sig[1] = 0xaa;
memset(&drive.pmbr.part, 0, sizeof(drive.pmbr.part));
drive.pmbr.part[0].f_head = 0x00;
drive.pmbr.part[0].f_sect = 0x02;
drive.pmbr.part[0].f_cyl = 0x00;
drive.pmbr.part[0].type = 0xee;
drive.pmbr.part[0].l_head = 0xff;
drive.pmbr.part[0].l_sect = 0xff;
drive.pmbr.part[0].l_cyl = 0xff;
drive.pmbr.part[0].f_lba = htole32(1);
uint32_t max = 0xffffffff;
if (drive.gpt.drive_sectors < 0xffffffff)
max = drive.gpt.drive_sectors - 1;
drive.pmbr.part[0].num_sect = htole32(max);
}
if (partition) {
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
Error("GptSanityCheck() returned %d: %s\n",
gpt_retval, GptError(gpt_retval));
goto done;
}
if (partition > GetNumberOfEntries(&drive.gpt)) {
Error("invalid partition number: %d\n", partition);
goto done;
}
int index = partition - 1;
GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
memcpy(&drive.pmbr.boot_guid, &entry->unique, sizeof(Guid));
}
if (bootfile) {
int fd = open(bootfile, O_RDONLY);
if (fd < 0) {
Error("Can't read %s: %s\n", bootfile, strerror(errno));
goto done;
}
int n = read(fd, drive.pmbr.bootcode, sizeof(drive.pmbr.bootcode));
if (n < 1) {
Error("problem reading %s: %s\n", bootfile, strerror(errno));
close(fd);
goto done;
}
close(fd);
}
char buf[256];
GuidToStr(&drive.pmbr.boot_guid, buf);
printf("%s\n", buf);
// Write it all out
if (CGPT_OK == WritePMBR(&drive))
retval = 0;
done:
(void) DriveClose(&drive, 1);
return retval;
}

106
cgpt/cmd_create.c Normal file
View File

@@ -0,0 +1,106 @@
// 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.
#include "cgpt.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>
#include "cgptlib_internal.h"
static void Usage(void)
{
printf("\nUsage: %s create [OPTIONS] DRIVE\n\n"
"Create or reset an empty GPT.\n\n"
"Options:\n"
" -z Zero the sectors of the GPT table and entries\n"
"\n", progname);
}
int cmd_create(int argc, char *argv[]) {
struct drive drive;
int zap = 0;
int c;
int errorcnt = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hz")) != -1)
{
switch (c)
{
case 'z':
zap = 1;
break;
case 'h':
Usage();
return CGPT_OK;
case '?':
Error("unrecognized option: -%c\n", optopt);
errorcnt++;
break;
case ':':
Error("missing argument to -%c\n", optopt);
errorcnt++;
break;
default:
errorcnt++;
break;
}
}
if (errorcnt)
{
Usage();
return CGPT_FAILED;
}
if (optind >= argc) {
Usage();
return CGPT_FAILED;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
// Erase the data
memset(drive.gpt.primary_header, 0,
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
memset(drive.gpt.secondary_header, 0,
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
memset(drive.gpt.primary_entries, 0,
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
memset(drive.gpt.secondary_entries, 0,
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
// Initialize a blank set
if (!zap)
{
GptHeader *h = (GptHeader *)drive.gpt.primary_header;
memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
h->revision = GPT_HEADER_REVISION;
h->size = sizeof(GptHeader);
h->my_lba = 1;
h->first_usable_lba = 1 + 1 + GPT_ENTRIES_SECTORS;
h->last_usable_lba = drive.gpt.drive_sectors - 1 - GPT_ENTRIES_SECTORS - 1;
uuid_generate((uint8_t *)&h->disk_uuid);
h->entries_lba = 2;
h->number_of_entries = 128;
h->size_of_entry = sizeof(GptEntry);
// Copy to secondary
RepairHeader(&drive.gpt, MASK_PRIMARY);
UpdateCrc(&drive.gpt);
}
// Write it all out
return DriveClose(&drive, 1);
}

85
cgpt/cmd_repair.c Normal file
View File

@@ -0,0 +1,85 @@
// 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.
#include "cgpt.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cgptlib_internal.h"
static void Usage(void)
{
printf("\nUsage: %s repair [OPTIONS] DRIVE\n\n"
"Repair damaged GPT headers and tables.\n\n"
"Options:\n"
" -v Verbose\n"
"\n", progname);
}
int cmd_repair(int argc, char *argv[]) {
struct drive drive;
int verbose = 0;
int c;
int errorcnt = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hv")) != -1)
{
switch (c)
{
case 'v':
verbose++;
break;
case 'h':
Usage();
return CGPT_OK;
case '?':
Error("unrecognized option: -%c\n", optopt);
errorcnt++;
break;
case ':':
Error("missing argument to -%c\n", optopt);
errorcnt++;
break;
default:
errorcnt++;
break;
}
}
if (errorcnt)
{
Usage();
return CGPT_FAILED;
}
if (optind >= argc) {
Error("missing drive argument\n");
return CGPT_FAILED;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
int gpt_retval = GptSanityCheck(&drive.gpt);
if (verbose)
printf("GptSanityCheck() returned %d: %s\n",
gpt_retval, GptError(gpt_retval));
GptRepair(&drive.gpt);
if (drive.gpt.modified & GPT_MODIFIED_HEADER1)
printf("Primary Header is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1)
printf("Primary Entries is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2)
printf("Secondary Entries is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_HEADER2)
printf("Secondary Header is updated.\n");
return DriveClose(&drive, 1);
}

413
cgpt/cmd_show.c Normal file
View File

@@ -0,0 +1,413 @@
// 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.
#include "cgpt.h"
#define __STDC_FORMAT_MACROS
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cgptlib_internal.h"
static void Usage(void)
{
printf("\nUsage: %s show [OPTIONS] DRIVE\n\n"
"Display the GPT table\n\n"
"Options:\n"
" -n Numeric output only\n"
" -v Verbose output\n"
" -q Quick output\n"
" -i NUM Show specified partition only - pick one of:\n"
" -b beginning sector\n"
" -s partition size\n"
" -t type guid\n"
" -u unique guid\n"
" -l label\n"
" -S Successful flag\n"
" -T Tries flag\n"
" -P Priority flag\n"
" -A raw 64-bit attribute value\n"
"\n", progname);
}
/* Generate output like:
*
* [AB-CD-EF-01] for group = 1
* [ABCD-EF01] for group = 3 (low byte first)
*
* Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
*/
#define BUFFER_SIZE(size) (size *3 - 1 + 3)
static short Uint8To2Chars(const uint8_t t) {
int h = t >> 4;
int l = t & 0xf;
h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
return (h << 8) + l;
}
static void RawDump(const uint8_t *memory, const int size,
char *buf, int group) {
int i, outlen = 0;
buf[outlen++] = '[';
for (i = 0; i < size; ++i) {
short c2 = Uint8To2Chars(memory[i]);
buf[outlen++] = c2 >> 8;
buf[outlen++] = c2 & 0xff;
if (i != (size - 1) && ((i + 1) % group) == 0)
buf[outlen++] = '-';
}
buf[outlen++] = ']';
buf[outlen++] = '\0';
}
/* Output formatters */
#define TITLE_FMT "%10s%10s%8s %s\n"
#define GPT_FMT "%10d%10d%8s %s\n"
#define GPT_MORE "%10s%10s%8s ", "", "", ""
#define PARTITION_FMT "%10d%10d%8d %s\n"
#define PARTITION_MORE "%10s%10s%8s %s%s\n", "", "", ""
static void HeaderDetails(GptHeader *header, const char *indent, int raw) {
int i;
printf("%sSig: ", indent);
if (!raw) {
printf("[");
for (i = 0; i < sizeof(header->signature); ++i)
printf("%c", header->signature[i]);
printf("]");
} else {
char buf[BUFFER_SIZE(sizeof(header->signature))];
RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
printf("%s", buf);
}
printf("\n");
printf("%sRev: 0x%08x\n", indent, header->revision);
printf("%sSize: %d\n", indent, header->size);
printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32);
printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
{ /* For disk guid */
char buf[GUID_STRLEN];
GuidToStr(&header->disk_uuid, buf);
printf("%sDisk UUID: %s\n", indent, buf);
}
printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
printf("%sSize of entry: %d\n", indent, header->size_of_entry);
printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
}
void EntryDetails(GptEntry *entry, int index, int raw) {
char contents[256];
uint8_t label[sizeof(entry->name) * 3 / 2];
if (!raw) {
char type[GUID_STRLEN], unique[GUID_STRLEN];;
UTF16ToUTF8(entry->name, label);
snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
printf(PARTITION_FMT, (int)entry->starting_lba,
(int)(entry->ending_lba - entry->starting_lba + 1),
index+1, contents);
if (CGPT_OK == ResolveType(&entry->type, type)) {
printf(PARTITION_MORE, "Type: ", type);
} else {
GuidToStr(&entry->type, type);
printf(PARTITION_MORE, "Type: ", type);
}
GuidToStr(&entry->unique, unique);
printf(PARTITION_MORE, "UUID: ", unique);
if (!memcmp(&guid_chromeos_kernel, &entry->type, sizeof(Guid))) {
int tries = (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
CGPT_ATTRIBUTE_TRIES_OFFSET;
int successful = (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
int priority = (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
snprintf(contents, sizeof(contents),
"priority=%d tries=%d successful=%d",
priority, tries, successful);
printf(PARTITION_MORE, "Attr: ", contents);
}
} else {
char type[GUID_STRLEN], unique[GUID_STRLEN];
UTF16ToUTF8(entry->name, label);
snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
printf(PARTITION_FMT, (int)entry->starting_lba,
(int)(entry->ending_lba - entry->starting_lba + 1),
index+1, contents);
GuidToStr(&entry->type, type);
printf(PARTITION_MORE, "Type: ", type);
GuidToStr(&entry->unique, unique);
printf(PARTITION_MORE, "UUID: ", unique);
snprintf(contents, sizeof(contents), "[%" PRIx64 "]", entry->attributes);
printf(PARTITION_MORE, "Attr: ", contents);
}
}
void EntriesDetails(GptData *gpt, const int secondary, int raw) {
int i;
for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, i);
if (!memcmp(&guid_unused, &entry->type, sizeof(Guid))) continue;
EntryDetails(entry, i, raw);
}
}
int cmd_show(int argc, char *argv[]) {
struct drive drive;
int numeric = 0;
int verbose = 0;
int quick = 0;
int partition = 0;
int single_item = 0;
int gpt_retval;
int c;
int errorcnt = 0;
char *e = 0;
opterr = 0; // quiet, you
while ((c=getopt(argc, argv, ":hnvqi:bstulSTPA")) != -1)
{
switch (c)
{
case 'n':
numeric = 1;
break;
case 'v':
verbose = 1;
break;
case 'q':
quick = 1;
break;
case 'i':
partition = (uint32_t)strtoul(optarg, &e, 0);
if (!*optarg || (e && *e))
{
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
errorcnt++;
}
break;
case 'b':
case 's':
case 't':
case 'u':
case 'l':
case 'S':
case 'T':
case 'P':
case 'A':
single_item = c;
break;
case 'h':
Usage();
return CGPT_OK;
case '?':
Error("unrecognized option: -%c\n", optopt);
errorcnt++;
break;
case ':':
Error("missing argument to -%c\n", optopt);
errorcnt++;
break;
default:
errorcnt++;
break;
}
}
if (errorcnt)
{
Usage();
return CGPT_FAILED;
}
if (optind >= argc) {
Error("missing drive argument\n");
Usage();
return CGPT_FAILED;
}
if (CGPT_OK != DriveOpen(argv[optind], &drive))
return CGPT_FAILED;
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
Error("GptSanityCheck() returned %d: %s\n",
gpt_retval, GptError(gpt_retval));
return CGPT_FAILED;
}
if (partition) { // show single partition
if (partition > GetNumberOfEntries(&drive.gpt)) {
Error("invalid partition number: %d\n", partition);
return CGPT_FAILED;
}
int index = partition - 1;
GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
char buf[256];
if (single_item) {
switch(single_item) {
case 'b':
printf("%" PRId64 "\n", entry->starting_lba);
break;
case 's':
printf("%" PRId64 "\n", entry->ending_lba - entry->starting_lba + 1);
break;
case 't':
GuidToStr(&entry->type, buf);
printf("%s\n", buf);
break;
case 'u':
GuidToStr(&entry->unique, buf);
printf("%s\n", buf);
break;
case 'l':
UTF16ToUTF8(entry->name, (uint8_t *)buf);
printf("%s\n", buf);
break;
case 'S':
printf("%d\n", GetSuccessful(&drive.gpt, PRIMARY, index));
break;
case 'T':
printf("%d\n", GetTries(&drive.gpt, PRIMARY, index));
break;
case 'P':
printf("%d\n", GetPriority(&drive.gpt, PRIMARY, index));
break;
case 'A':
printf("0x%" PRIx64 "\n", entry->attributes);
break;
}
} else {
printf(TITLE_FMT, "start", "size", "part", "contents");
EntryDetails(entry, index, numeric);
}
} else if (quick) { // show all partitions, quickly
int i;
GptEntry *entry;
char type[GUID_STRLEN];
for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
entry = GetEntry(&drive.gpt, PRIMARY, i);
if (IsZero(&entry->type))
continue;
if (!numeric && CGPT_OK == ResolveType(&entry->type, type)) {
} else {
GuidToStr(&entry->type, type);
}
printf(PARTITION_FMT, (int)entry->starting_lba,
(int)(entry->ending_lba - entry->starting_lba + 1),
i+1, type);
}
} else { // show all partitions
if (CGPT_OK != ReadPMBR(&drive)) {
Error("Unable to read PMBR\n");
return CGPT_FAILED;
}
printf(TITLE_FMT, "start", "size", "part", "contents");
char buf[256];
PMBRToStr(&drive.pmbr, buf);
printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
if (drive.gpt.valid_headers & MASK_PRIMARY) {
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "", "Pri GPT header");
if (verbose) {
GptHeader *header;
char indent[64];
snprintf(indent, sizeof(indent), GPT_MORE);
header = (GptHeader*)drive.gpt.primary_header;
HeaderDetails(header, indent, numeric);
}
} else {
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
}
printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
(int)GPT_ENTRIES_SECTORS,
drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
"Pri GPT table");
if (drive.gpt.valid_entries & MASK_PRIMARY)
EntriesDetails(&drive.gpt, PRIMARY, numeric);
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
GPT_ENTRIES_SECTORS),
(int)GPT_ENTRIES_SECTORS,
drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
"Sec GPT table");
/* We show secondary table details if any of following is true.
* 1. only secondary is valid.
* 2. secondary is not identical to promary.
*/
if ((drive.gpt.valid_entries & MASK_SECONDARY) &&
(!(drive.gpt.valid_entries & MASK_PRIMARY) ||
memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
TOTAL_ENTRIES_SIZE))) {
EntriesDetails(&drive.gpt, SECONDARY, numeric);
}
if (drive.gpt.valid_headers & MASK_SECONDARY)
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
(int)GPT_HEADER_SECTOR, "", "Sec GPT header");
else
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
/* We show secondary header if any of following is true:
* 1. only secondary is valid.
* 2. secondary is not synonymous to primary.
*/
if ((drive.gpt.valid_headers & MASK_SECONDARY) &&
(!(drive.gpt.valid_headers & MASK_PRIMARY) ||
!IsSynonymous((GptHeader*)drive.gpt.primary_header,
(GptHeader*)drive.gpt.secondary_header))) {
if (verbose) {
GptHeader *header;
char indent[64];
snprintf(indent, sizeof(indent), GPT_MORE);
header = (GptHeader*)drive.gpt.secondary_header;
HeaderDetails(header, indent, numeric);
}
}
}
(void) CheckValid(&drive);
(void) DriveClose(&drive, 0);
return CGPT_OK;
}

44
cgpt/endian.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_
#define VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_
// Newer distros already have this. For those that don't, we add it here.
#include <endian.h>
#ifndef le16toh
# include <byteswap.h>
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define htobe16(x) __bswap_16 (x)
# define htole16(x) (x)
# define be16toh(x) __bswap_16 (x)
# define le16toh(x) (x)
# define htobe32(x) __bswap_32 (x)
# define htole32(x) (x)
# define be32toh(x) __bswap_32 (x)
# define le32toh(x) (x)
# define htobe64(x) __bswap_64 (x)
# define htole64(x) (x)
# define be64toh(x) __bswap_64 (x)
# define le64toh(x) (x)
# else
# define htobe16(x) (x)
# define htole16(x) __bswap_16 (x)
# define be16toh(x) (x)
# define le16toh(x) __bswap_16 (x)
# define htobe32(x) (x)
# define htole32(x) __bswap_32 (x)
# define be32toh(x) (x)
# define le32toh(x) __bswap_32 (x)
# define htobe64(x) (x)
# define htole64(x) __bswap_64 (x)
# define be64toh(x) (x)
# define le64toh(x) __bswap_64 (x)
# endif
#endif
#endif // VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_

View File

@@ -126,6 +126,8 @@ runtests:
./kernel_rollback_tests
# Helper Library Tests
./cgptlib_test
# Tool tests
./run_cgpt_tests.sh
clean:
rm -f $(TEST_BINS)

View File

@@ -136,8 +136,8 @@ static void BuildTestGptData(GptData* gpt) {
Memcpy(header->signature, GPT_HEADER_SIGNATURE,
sizeof(GPT_HEADER_SIGNATURE));
header->revision = GPT_HEADER_REVISION;
header->size = sizeof(GptHeader) - sizeof(header->padding);
header->reserved = 0;
header->size = sizeof(GptHeader);
header->reserved_zero = 0;
header->my_lba = 1;
header->alternate_lba = DEFAULT_DRIVE_SECTORS - 1;
header->first_usable_lba = 34;
@@ -157,7 +157,6 @@ static void BuildTestGptData(GptData* gpt) {
Memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel));
entries[3].starting_lba = 334;
entries[3].ending_lba = 430;
Memset(header->padding, 0, sizeof(header->padding));
/* build secondary */
header2 = (GptHeader*)gpt->secondary_header;
@@ -355,8 +354,8 @@ static int ReservedFieldsTest() {
GptHeader* h2 = (GptHeader*)gpt->secondary_header;
BuildTestGptData(gpt);
h1->reserved ^= 0x12345678; /* whatever random */
h2->reserved ^= 0x12345678; /* whatever random */
h1->reserved_zero ^= 0x12345678; /* whatever random */
h2->reserved_zero ^= 0x12345678; /* whatever random */
RefreshCrc32(gpt);
EXPECT(1 == CheckHeader(h1, 0, gpt->drive_sectors));
EXPECT(1 == CheckHeader(h2, 1, gpt->drive_sectors));

View File

@@ -30,10 +30,21 @@ COL_STOP='\E[0;m'
hash_algos=( sha1 sha256 sha512 )
key_lengths=( 1024 2048 4096 8192 )
function check_test_keys {
if [ ! -d ${TESTKEY_DIR} ]
then
echo "You must run gen_test_keys.sh to generate test keys first."
exit 1
fi
function happy {
echo -e "${COL_GREEN}$*${COL_STOP}" 1>&2
}
function warning {
echo -e "${COL_YELLOW}WARNING: $*${COL_STOP}" 1>&2
}
function error {
echo -e "${COL_RED}ERROR: $*${COL_STOP}" 1>&2
exit 1
}
function check_test_keys {
[ -d ${TESTKEY_DIR} ] || \
error "You must run gen_test_keys.sh to generate test keys first."
}

114
tests/run_cgpt_tests.sh Executable file
View File

@@ -0,0 +1,114 @@
#!/bin/bash -eu
# 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.
#
# Run tests for RSA Signature verification.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
GPT=${1:-../cgpt/cgpt}
[ -x "$GPT" ] || error "Can't execute $GPT"
warning "testing $GPT"
echo "Create an empty file to use as the device..."
NUM_SECTORS=1000
DEV=$(mktemp)
BOOTFILE=$(mktemp)
dd if=/dev/zero of=${DEV} conv=notrunc bs=512 count=${NUM_SECTORS} 2>/dev/null
trap "rm -f ${DEV}" EXIT
echo "Create a bunch of partitions, using the real GUID types..."
DATA_START=100
DATA_SIZE=20
DATA_LABEL="data stuff"
DATA_GUID='ebd0a0a2-b9e5-4433-87c0-68b6b72699c7'
DATA_NUM=1
KERN_START=200
KERN_SIZE=30
KERN_LABEL="kernel stuff"
KERN_GUID='fe3a2a5d-4f32-41a7-b725-accc3285a309'
KERN_NUM=2
ROOTFS_START=300
ROOTFS_SIZE=40
ROOTFS_LABEL="rootfs stuff"
ROOTFS_GUID='3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec'
ROOTFS_NUM=3
ESP_START=400
ESP_SIZE=50
ESP_LABEL="ESP stuff"
ESP_GUID='c12a7328-f81f-11d2-ba4b-00a0c93ec93b'
ESP_NUM=4
FUTURE_START=500
FUTURE_SIZE=60
FUTURE_LABEL="future stuff"
FUTURE_GUID='2e0a753d-9e48-43b0-8337-b15192cb1b5e'
FUTURE_NUM=5
RANDOM_START=600
RANDOM_SIZE=70
RANDOM_LABEL="random stuff"
RANDOM_GUID='2364a860-bf63-42fb-a83d-9ad3e057fcf5'
RANDOM_NUM=6
$GPT create ${DEV}
$GPT add -b ${DATA_START} -s ${DATA_SIZE} -t ${DATA_GUID} \
-l "${DATA_LABEL}" ${DEV}
$GPT add -b ${KERN_START} -s ${KERN_SIZE} -t ${KERN_GUID} \
-l "${KERN_LABEL}" ${DEV}
$GPT add -b ${ROOTFS_START} -s ${ROOTFS_SIZE} -t ${ROOTFS_GUID} \
-l "${ROOTFS_LABEL}" ${DEV}
$GPT add -b ${ESP_START} -s ${ESP_SIZE} -t ${ESP_GUID} \
-l "${ESP_LABEL}" ${DEV}
$GPT add -b ${FUTURE_START} -s ${FUTURE_SIZE} -t ${FUTURE_GUID} \
-l "${FUTURE_LABEL}" ${DEV}
$GPT add -b ${RANDOM_START} -s ${RANDOM_SIZE} -t ${RANDOM_GUID} \
-l "${RANDOM_LABEL}" ${DEV}
echo "Extract the start and size of given partitions..."
X=$($GPT show -b -i $DATA_NUM ${DEV})
Y=$($GPT show -s -i $DATA_NUM ${DEV})
[ "$X $Y" = "$DATA_START $DATA_SIZE" ] || error "fail at line $LINENO"
X=$($GPT show -b -i $KERN_NUM ${DEV})
Y=$($GPT show -s -i $KERN_NUM ${DEV})
[ "$X $Y" = "$KERN_START $KERN_SIZE" ] || error "fail at line $LINENO"
X=$($GPT show -b -i $ROOTFS_NUM ${DEV})
Y=$($GPT show -s -i $ROOTFS_NUM ${DEV})
[ "$X $Y" = "$ROOTFS_START $ROOTFS_SIZE" ] || error "fail at line $LINENO"
X=$($GPT show -b -i $ESP_NUM ${DEV})
Y=$($GPT show -s -i $ESP_NUM ${DEV})
[ "$X $Y" = "$ESP_START $ESP_SIZE" ] || error "fail at line $LINENO"
X=$($GPT show -b -i $FUTURE_NUM ${DEV})
Y=$($GPT show -s -i $FUTURE_NUM ${DEV})
[ "$X $Y" = "$FUTURE_START $FUTURE_SIZE" ] || error "fail at line $LINENO"
X=$($GPT show -b -i $RANDOM_NUM ${DEV})
Y=$($GPT show -s -i $RANDOM_NUM ${DEV})
[ "$X $Y" = "$RANDOM_START $RANDOM_SIZE" ] || error "fail at line $LINENO"
echo "Set the boot partition.."
$GPT boot -i ${KERN_NUM} ${DEV} >/dev/null
echo "Check the PMBR's idea of the boot partition..."
X=$($GPT boot ${DEV})
Y=$($GPT show -u -i $KERN_NUM $DEV)
[ "$X" = "$Y" ] || error "fail at line $LINENO"
echo "Done."
happy "All tests passed."

View File

@@ -22,9 +22,8 @@ LIBS = $(TOP)/misclibs/file_keys.o \
$(TOP)/vkernel/kernel_image.o \
$(HOSTLIB) \
$(FWLIB)
SUBDIRS = cgpt
DESTDIR ?= /opt/bin
DESTDIR ?= /usr/bin
TARGET_BINS = dumpRSAPublicKey \
firmware_utility \
@@ -36,14 +35,7 @@ TARGET_BINS = dumpRSAPublicKey \
vbutil_keyblock \
verify_data
all: $(TARGET_BINS) subdirs
.PHONY: subdirs
subdirs:
set -e; \
for i in $(SUBDIRS); do \
$(MAKE) -C $$i $(MAKECMDGOALS); \
done
all: $(TARGET_BINS)
dumpRSAPublicKey: dumpRSAPublicKey.c
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ -lcrypto
@@ -75,13 +67,9 @@ verify_data: verify_data.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
clean:
set -e; \
for i in $(SUBDIRS); do \
$(MAKE) -C $$i clean; \
done
rm -f $(TARGET_BINS)
install: $(TARGET_BINS) subdirs
install: $(TARGET_BINS)
mkdir -p $(DESTDIR)
cp -f $(TARGET_BINS) $(DESTDIR)
chmod a+rx $(patsubst %,$(DESTDIR)/%,$(TARGET_BINS))

View File

@@ -1,30 +0,0 @@
# Copyright (c) 2009 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.
TOP ?= ../../
CC ?= cc
# Include /usr/include from inside the chroot, so that we get a version
# of endian.h which contains endian-conversion macros - htole32(), etc.
INCLUDES += -I$(TOP)/common/include -I$(TOP)/../../../chroot/usr/include/
CFLAGS += -Wall -Werror -ggdb
LIBS += $(FWLIB)
DESTDIR ?= /opt/bin
all: cgpt
cgpt: cgpt.o cgpt_add_modify_delete.o cgpt_attribute.o cgpt_dev.o \
cgpt_options.o cgpt_repair.o cgpt_show.o cgpt_tofix.o $(LIBS)
$(CC) -o cgpt $(CFLAGS) $^
.c.o: $(INCLUDES)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
rm -f cgpt *.o *~
install: cgpt
mkdir -p $(DESTDIR)
cp -f $^ $(DESTDIR)
chmod a+rx $(patsubst %,$(DESTDIR)/%,$^)

View File

@@ -1,457 +0,0 @@
/* 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.
*
* Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
* files for more details.
*/
/* To compile on host without compatility to BSD, we include
* endian.h under chroot. */
#define _BSD_SOURCE
#include "endian.h"
#define __USE_LARGEFILE64
#define __USE_FILE_OFFSET64
#define _LARGEFILE64_SOURCE
#include "cgpt.h"
#include "cgpt_tofix.h"
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "cgptlib_internal.h"
#include "utility.h"
/* For usage print */
const char* progname;
/* Lists all command here. */
struct {
const char *name;
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"},
};
/* Shows main menu. If 'message' is non-NULL, shows it as header. Then, this
* traverses cmds[] and shows supported commands and their comments. */
void Usage(const char *message) {
int i;
if (message) printf("%s\n", message);
printf("Usage: %s COMMAND [OPTIONS]\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);
}
printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname);
}
/* GUID conversion functions. Accepted format:
*
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
*
* Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
*/
int StrToGuid(const char *str, Guid *guid) {
uint32_t time_low, time_mid, time_high_and_version;
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,
(unsigned int *)&guid->u.Uuid.clock_seq_high_and_reserved,
(unsigned int *)&guid->u.Uuid.clock_seq_low,
(unsigned int *)&guid->u.Uuid.node[0],
(unsigned int *)&guid->u.Uuid.node[1],
(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])) 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) {
sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid),
le16toh(guid->u.Uuid.time_high_and_version),
guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low,
guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2],
guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]);
}
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
* Caller must prepare enough space for UTF8. The rough estimation is:
*
* utf8 length = bytecount(utf16) * 1.5
*/
#define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8)
{
size_t s8idx, s16idx, s16len;
uint32_t utfchar;
unsigned int next_utf16;
for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len);
*utf8 = s8idx = s16idx = 0;
while (s16idx < s16len) {
utfchar = le16toh(utf16[s16idx++]);
if ((utfchar & 0xf800) == 0xd800) {
next_utf16 = le16toh(utf16[s16idx]);
if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00)
utfchar = 0xfffd;
else
s16idx++;
}
if (utfchar < 0x80) {
utf8[s8idx++] = utfchar;
} else if (utfchar < 0x800) {
utf8[s8idx++] = 0xc0 | (utfchar >> 6);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
} else if (utfchar < 0x10000) {
utf8[s8idx++] = 0xe0 | (utfchar >> 12);
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
} else if (utfchar < 0x200000) {
utf8[s8idx++] = 0xf0 | (utfchar >> 18);
utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
}
}
utf8[s8idx++] = 0;
}
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
* Caller must prepare enough space for UTF16. The conservative estimation is:
*
* utf16 bytecount = bytecount(utf8) / 3 * 4
*/
void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
{
size_t s16idx, s8idx, s8len;
uint32_t utfchar;
unsigned int c, utfbytes;
for (s8len = 0; utf8[s8len]; ++s8len);
s8idx = s16idx = 0;
utfbytes = 0;
do {
c = utf8[s8idx++];
if ((c & 0xc0) != 0x80) {
/* Initial characters. */
if (utfbytes != 0) {
/* Incomplete encoding. */
utf16[s16idx++] = 0xfffd;
}
if ((c & 0xf8) == 0xf0) {
utfchar = c & 0x07;
utfbytes = 3;
} else if ((c & 0xf0) == 0xe0) {
utfchar = c & 0x0f;
utfbytes = 2;
} else if ((c & 0xe0) == 0xc0) {
utfchar = c & 0x1f;
utfbytes = 1;
} else {
utfchar = c & 0x7f;
utfbytes = 0;
}
} else {
/* Followup characters. */
if (utfbytes > 0) {
utfchar = (utfchar << 6) + (c & 0x3f);
utfbytes--;
} else if (utfbytes == 0)
utfbytes = -1;
utfchar = 0xfffd;
}
if (utfbytes == 0) {
if (utfchar >= 0x10000) {
utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40));
if (s16idx >= SIZEOF_GPTENTRY_NAME) break;
utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff));
} else {
utf16[s16idx++] = htole16(utfchar);
}
}
} while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME);
if (s16idx < SIZEOF_GPTENTRY_NAME)
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 System 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"},
{GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"},
};
/* 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().
*
* fd -- file descriptot.
* buf -- pointer to buffer pointer
* sector -- offset of starting sector (in sectors)
* sector_bytes -- bytes per sector
* sector_count -- number of sectors to load
*
* Returns CGPT_OK for successful. Aborts if any error occurs.
*/
int Load(const int fd, uint8_t **buf,
const uint64_t sector,
const uint64_t sector_bytes,
const uint64_t sector_count) {
int count; /* byte count to read */
int nread;
assert(buf);
count = sector_bytes * sector_count;
*buf = Malloc(count);
assert(*buf);
if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET))
goto error_free;
nread = read(fd, *buf, count);
if (nread < count)
goto error_free;
return CGPT_OK;
error_free:
Free(*buf);
*buf = 0;
abort();
}
/* Saves sectors to 'fd'.
*
* fd -- file descriptot.
* buf -- pointer to buffer
* sector -- starting sector offset
* sector_bytes -- bytes per sector
* sector_count -- number of sector to save
*
* Returns CGPT_OK for successful, CGPT_FAILED for failed.
*/
int Save(const int fd, const uint8_t *buf,
const uint64_t sector,
const uint64_t sector_bytes,
const uint64_t sector_count) {
int count; /* byte count to write */
int nwrote;
assert(buf);
count = sector_bytes * sector_count;
if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET))
return CGPT_FAILED;
nwrote = write(fd, buf, count);
if (nwrote < count)
return CGPT_FAILED;
return CGPT_OK;
}
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 '%s repair' first\n", progname);
return CGPT_FAILED;
}
return CGPT_OK;
}
/* Opens a block device (a regular file works well too).
*
* Returns CGPT_FAILED if any error happens.
* Returns CGPT_OK if success and information are stored in 'drive'. */
int DriveOpen(const char *drive_path, struct drive *drive) {
struct stat stat;
int gpt_retval;
assert(drive_path);
assert(drive);
Memset(drive, 0, sizeof(struct drive));
drive->fd = open(drive_path, O_RDWR | O_LARGEFILE);
if (drive->fd == -1) {
printf("[ERROR] Cannot open drive file [%s]: %s\n",
drive_path, strerror(errno));
return CGPT_FAILED;
}
if (fstat(drive->fd, &stat) == -1) {
goto error_close;
}
if ((stat.st_mode & S_IFMT) != S_IFREG) {
if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
printf("[ERROR] Cannot get sector size from drive file [%s]: %s\n",
drive_path, strerror(errno));
goto error_close;
}
if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) {
printf("[ERROR] Cannot get drive size from drive file [%s]: %s\n",
drive_path, strerror(errno));
goto error_close;
}
} else {
drive->gpt.sector_bytes = 512; /* bytes */
drive->size = stat.st_size;
}
if (drive->size % drive->gpt.sector_bytes) {
printf("[ERROR] Media size (%llu) is not the multiple of sector size(%d)\n",
(long long unsigned int)drive->size, drive->gpt.sector_bytes);
goto error_close;
}
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
Load(drive->fd, &drive->gpt.secondary_header,
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
Load(drive->fd, &drive->gpt.primary_entries,
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
Load(drive->fd, &drive->gpt.secondary_entries,
drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
printf("[ERROR] GptSanityCheck(): %s\n", GptError(gpt_retval));
goto error_close;
}
drive->inited = 1;
return CGPT_OK;
error_close:
close(drive->fd);
return CGPT_FAILED;
}
int DriveClose(struct drive *drive) {
if (drive->inited) {
if (drive->gpt.modified & GPT_MODIFIED_HEADER1)
assert(CGPT_OK ==
Save(drive->fd, drive->gpt.primary_header, GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
if (drive->gpt.modified & GPT_MODIFIED_HEADER2)
assert(CGPT_OK ==
Save(drive->fd, drive->gpt.secondary_header,
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1)
assert(CGPT_OK ==
Save(drive->fd, drive->gpt.primary_entries,
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2)
assert(CGPT_OK ==
Save(drive->fd, drive->gpt.secondary_entries,
drive->gpt.drive_sectors - GPT_HEADER_SECTOR -
GPT_ENTRIES_SECTORS,
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
close(drive->fd);
}
Free(drive->gpt.primary_header);
drive->gpt.primary_header = 0;
Free(drive->gpt.primary_entries);
drive->gpt.primary_entries = 0;
Free(drive->gpt.secondary_header);
drive->gpt.secondary_header = 0;
Free(drive->gpt.secondary_entries);
drive->gpt.secondary_entries = 0;
drive->inited = 0;
return CGPT_OK;
}
int main(int argc, char *argv[]) {
char *cmd;
int i;
progname = argv[0];
cmd = argv[optind++];
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
if (cmd && !strcmp(cmds[i].name, cmd))
return cmds[i].fp(argc, argv);
}
Usage(0);
return CGPT_FAILED;
}

View File

@@ -1,158 +0,0 @@
/* 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.
*
* Header file for cgpt.
*/
#ifndef VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
#define VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
#include <getopt.h>
#include <stdint.h>
#include "cgptlib.h"
#include "gpt.h"
enum {
CGPT_OK = 0,
CGPT_FAILED, /* generic error */
};
#define NOT_INITED (-1) /* to indicated a signed integer is not initialed. */
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
/* 'struct option' of getopt_long() is not enough for our usage.
* Therefore, we define the extra information to make option parsing
* more organizable.
* Note that please make sure every entry in struct option is mapped into an
* individual entry in this struct. */
struct option_details {
char *comment;
/* If has_arg is 'required_argument', 'validator' is called to check whether
* the 'argument' is valid or not. Once the argument is valid, the value is
* stored in 'parsed'.
*
* If has_arg is 'no_argument', 'validator' is called to load 'valid_range'
* into 'parsed' ('argument' is 0 in this case). Since getopt_long() only
* supports integer type for 'flag' and 'val', this can support for any type.
*
* If has_arg is 'optional_argument', like 'required_argument', 'validator' is
* called to check if 'argument' is valid or not. 'argument' indicates if
* argument is present or not.
*
* 'validator' returns CGPT_OK if argument is valid; otherwise CGPT_FAILED
* if invalid. */
int (*validator)(const char *argument, void *valid_range, void *parsed);
void *valid_range; /* The structure passed to validator. */
void *parsed; /* The structure passed to validator. */
};
/* This is a special 'validator'. It assists those options without an argument,
* 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;
};
int InNumberRange(const char *argument, void *valid_range, void *parsed);
void ShowOptions(const struct option *opts,
const struct option_details *details,
const int num);
/* Handles all options from given argc and argv. This function supports both
* short and long options.
*
* Assumptions:
* 1. every short option has a corresponding long option and the short option
* is equal to 'val' of that long option.
* 2. every entry in 'options' has a corresponding entry in 'details'.
* One by one and in order.
*
* Returns CGPT_OK if given options in argv are good, otherwise CGPT_FAILED.
* Note that the global variable 'optind' points to next non-option after
* this function returns.
*/
int HandleOptions(const int argc,
char *const *argv,
const char *short_option,
const int option_count,
const struct option *options,
const struct option_details *details);
struct drive;
int OpenDriveInLastArgument(const int argc,
char *const *argv,
struct drive *drive);
/* GUID conversion functions. Accepted format:
*
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
*
* At least GUID_STRLEN bytes should be reserved in 'str' (included the tailing
* '\0').
*/
#define GUID_STRLEN 37
int StrToGuid(const char *str, Guid *guid);
void GuidToStr(const Guid *guid, char *str);
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
* Caller must prepare enough space for UTF8. The rough estimation is:
*
* utf8 length = bytecount(utf16) * 1.5
*/
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
* Caller must prepare enough space for UTF16. The conservative estimation is:
*
* utf16 bytecount = bytecount(utf8) / 3 * 4
*/
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);
void EntryDetails(GptEntry *entry, int index, int raw);
/* Describes the drive storing the GPT. */
struct drive {
int inited; /* indicated if this structure is valid */
int fd; /* file descriptor */
uint64_t size; /* total size (in bytes) */
GptData gpt;
};
extern const char* progname;
/* Given a hard drive path, this function loads GPT sectors from that drive,
* and fills 'drive' structure. All memory allocated in drive_open() will be
* freed at drive_close().
*
* If 'drive_path' starts with '/', it is treated as absolute path.
* If 'drive_path' starts with '.', it is treated as relative path.
* Otherwise, it will be prepended with '/dev/' to comply with gpt.
*
* Returns CGPT_FAILED if any error happens.
* Returns CGPT_OK if success and information are stored in 'drive'.
*/
int DriveOpen(const char *drive_path, struct drive *drive);
int DriveClose(struct drive *drive);
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[]);
#endif /* VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_ */

View File

@@ -1,276 +0,0 @@
/* 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 "cgpt_tofix.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) {
Memcpy(&entry->type, &guid_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

@@ -1,148 +0,0 @@
/* 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 "cgpt_tofix.h"
#include "utility.h"
static struct number_range range_1_0 = {1, 0};
static struct number_range range_15_0 = {15, 0};
static struct number_range range_16_1 = {16, 1};
/* Integers to store parsed argument. */
static int help, partition, successful, tries, priority;
/* 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 attribute_options[] = {
{.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
{.name = "partition", .has_arg = required_argument, .flag = 0, .val = 'i'},
{.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
* add/remove any line in attribute_options[]. */
static struct option_details attribute_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
/* partition */
{ .comment = "partition number "
"(default: first ChromeOS kernel)",
.validator = InNumberRange,
.valid_range = &range_16_1,
.parsed = &partition},
/* 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},
{ /* last element, which should be zero. */ }
};
void AttributeHelp() {
printf("\nUsage: %s attribute [OPTIONS] device_name\n\n", progname);
ShowOptions(attribute_options, attribute_options_details,
ARRAY_COUNT(attribute_options));
}
/* Parses all options (and validates them), then opens the drive and sets
* corresponding bits in GPT entry. */
int CgptAttribute(int argc, char *argv[]) {
struct drive drive;
GptEntry *entry;
/* 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(attribute_options) ==
ARRAY_COUNT(attribute_options_details));
help = partition = successful = tries = priority = NOT_INITED;
if (CGPT_OK != HandleOptions(argc, argv,
"hi:b:s:t:p:",
ARRAY_COUNT(attribute_options),
attribute_options,
attribute_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
AttributeHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
if (CheckValid(&drive) != CGPT_OK) return CGPT_FAILED;
/* partition is not specified, search for the first Chromeos kernel. */
if (partition == NOT_INITED) {
int i;
for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
entry = GetEntry(&drive.gpt, PRIMARY, i);
if (!Memcmp(&guid_chromeos_kernel, &entry->type, sizeof(Guid))) {
partition = i+1;
break;
}
}
if (partition == NOT_INITED) {
printf("[ERROR] No ChromeOS kernel partition found. "
"Please use --partition to specify.\n");
return CGPT_FAILED;
} else {
debug("No --partition is specified. "
"Found the first ChromeOS kernel in partition [%d].\n",
partition);
}
}
int index = partition - 1;
if (successful != NOT_INITED)
SetSuccessful(&drive.gpt, PRIMARY, index, successful);
if (tries != NOT_INITED)
SetTries(&drive.gpt, PRIMARY, index, tries);
if (priority != NOT_INITED)
SetPriority(&drive.gpt, PRIMARY, index, priority);
/* Display state */
entry = GetEntry(&drive.gpt, PRIMARY, index);
EntryDetails(entry, index, NOT_INITED);
/* Claims primary is good, then secondary will be overwritten. */
/* TODO: rspangler broke this during cgptlib refactoring; need to
* update this to match new internal APIs. */
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;
}

View File

@@ -1,126 +0,0 @@
/* 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

@@ -1,134 +0,0 @@
/* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "utility.h"
/* Special validator. Set 'integer' as 1 to indicate the option is present. */
int AssignTrue(const char *argument, void *pointer, void *integer) {
*(int*)integer = 1;
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) {
struct number_range *range = valid_range;
char *endptr;
int number;
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);
return CGPT_FAILED;
} else if (number > range->max) {
printf("[ERROR] argument is too large (max is %d, but you gave: %d).\n",
range->max, number);
return CGPT_FAILED;
} else {
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,
const struct option_details *details,
const int num) {
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);
}
}
int HandleOptions(const int argc,
char *const *argv,
const char *short_options,
const int option_count,
const struct option *options,
const struct option_details *details) {
while (1) {
int index;
int option;
/* We assume every short option has an entry in long option (for validator).
* So please add corresponding entry in attribute_options if you add short
* option. */
index = NOT_INITED;
option = getopt_long(argc, argv, short_options, options, &index);
if (option == -1) {
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. */
if (index == NOT_INITED) {
for (index = 0; index < option_count; ++index)
if (option == options[index].val) break;
/* assumes every short option has a corresponding long option. */
assert(index < option_count);
}
assert(option == options[index].val);
/* Calls validator if an argument is provided. */
if (details[index].validator &&
CGPT_OK != details[index].validator(
optarg ? argv[optind - 1] : 0,
details[index].valid_range,
details[index].parsed)) {
printf("[ERROR] The argument of '%s' is invalid.\n",
options[index].name);
return CGPT_FAILED;
}
}
}
return CGPT_OK;
}
int OpenDriveInLastArgument(const int argc,
char *const *argv,
struct drive *drive) {
if (optind != (argc - 1)) {
printf("[ERROR] One (and only one) non-option argument is required.\n");
return CGPT_FAILED;
}
return DriveOpen(argv[optind], drive);
}

View File

@@ -1,84 +0,0 @@
/* 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.
*
* Repair headers and tables.
*
* If primary header or table is invalid, it copies from secondary (vice versa).
*/
#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;
/* 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 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
* add/remove any line in attribute_options[]. */
static struct option_details repair_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
{ /* last element, which should be zero. */ }
};
void RepairHelp() {
printf("\nUsage: %s repair [OPTIONS] device_name\n\n", progname);
ShowOptions(repair_options, repair_options_details,
ARRAY_COUNT(repair_options));
printf("\n");
}
/* Parses all options (and validates them), then opens the drive and sets
* corresponding bits in GPT entry. */
int CgptRepair(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(repair_options) ==
ARRAY_COUNT(repair_options_details));
help = NOT_INITED;
if (CGPT_OK != HandleOptions(argc, argv,
"hr",
ARRAY_COUNT(repair_options),
repair_options,
repair_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
RepairHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
GptRepair(&drive.gpt);
if (drive.gpt.modified & GPT_MODIFIED_HEADER1)
printf("* Pri Header is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1)
printf("* Pri Table Entries is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2)
printf("* Sec Table Entries is updated.\n");
if (drive.gpt.modified & GPT_MODIFIED_HEADER2)
printf("* Sec Header is updated.\n");
DriveClose(&drive);
return CGPT_OK;
}

View File

@@ -1,304 +0,0 @@
/* 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.
*
* Show GPT details.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "cgpt_tofix.h"
#include "utility.h"
/* Integers to store parsed argument. */
static int help, number, verbose;
/* 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 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
* add/remove any line in attribute_options[]. */
static struct option_details show_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
/* number */
{ .comment = "print raw numbers (don't interpret)",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &number},
/* verbose */
{ .comment = "verbose print",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &verbose},
{ /* last element, which should be zero. */ }
};
void ShowHelp() {
printf("\nUsage: %s show [OPTIONS] device_name\n\n", progname);
ShowOptions(show_options, show_options_details, ARRAY_COUNT(show_options));
printf("\n");
}
/* Generate output like:
*
* [AB-CD-EF-01] for group = 1
* [ABCD-EF01] for group = 3 (low byte first)
*
* Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
*/
#define BUFFER_SIZE(size) (size *3 - 1 + 3)
static short Uint8To2Chars(const uint8_t t) {
int h = t >> 4;
int l = t & 0xf;
h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
return (h << 8) + l;
}
static void RawDump(const uint8_t *memory, const int size,
char *buf, int group) {
int i, outlen = 0;
buf[outlen++] = '[';
for (i = 0; i < size; ++i) {
short c2 = Uint8To2Chars(memory[i]);
buf[outlen++] = c2 >> 8;
buf[outlen++] = c2 & 0xff;
if (i != (size - 1) && ((i + 1) % group) == 0)
buf[outlen++] = '-';
}
buf[outlen++] = ']';
buf[outlen++] = '\0';
}
/* Outpur formatters */
#define TITLE_FMT "%10s%10s%8s %s\n"
#define GPT_FMT "%10d%10d%8s %s\n"
#define GPT_MORE "%10s%10s%8s ", "", "", ""
#define PARTITION_FMT "%10d%10d%8d %s\n"
#define PARTITION_MORE "%10s%10s%8s %s%s\n", "", "", ""
static void HeaderDetails(GptHeader *header, const char *indent, int raw) {
int i;
printf("%sSig: ", indent);
if (raw == NOT_INITED) {
printf("[");
for (i = 0; i < sizeof(header->signature); ++i)
printf("%c", header->signature[i]);
printf("]");
} else {
char buf[BUFFER_SIZE(sizeof(header->signature))];
RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
printf("%s", buf);
}
printf("\n");
printf("%sRev: 0x%08x\n", indent, header->revision);
printf("%sSize: %d\n", indent, header->size);
printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32);
printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
{ /* For disk guid */
char buf[GUID_STRLEN];
GuidToStr(&header->disk_uuid, buf);
printf("%sDisk UUID: %s\n", indent, buf);
}
printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
printf("%sSize of entry: %d\n", indent, header->size_of_entry);
printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
}
void EntryDetails(GptEntry *entry, int index, int raw) {
char contents[256];
if (raw == NOT_INITED) {
uint8_t label[sizeof(entry->name) * 3 / 2];
char type[GUID_STRLEN], unique[GUID_STRLEN];;
UTF16ToUTF8(entry->name, label);
snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
printf(PARTITION_FMT, (int)entry->starting_lba,
(int)(entry->ending_lba - entry->starting_lba + 1),
index+1, contents);
if (CGPT_OK == ResolveType(&entry->type, type)) {
printf(PARTITION_MORE, "Type: ", type);
} else {
GuidToStr(&entry->type, type);
printf(PARTITION_MORE, "Type: ", type);
}
GuidToStr(&entry->unique, unique);
printf(PARTITION_MORE, "UUID: ", unique);
if (!Memcmp(&guid_chromeos_kernel, &entry->type, sizeof(Guid))) {
int tries = (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
CGPT_ATTRIBUTE_TRIES_OFFSET;
int successful = (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
int priority = (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
snprintf(contents, sizeof(contents),
"priority=%d tries=%d successful=%d",
priority, tries, successful);
printf(PARTITION_MORE, "Attr: ", contents);
}
} else {
char label[BUFFER_SIZE(sizeof(entry->name))];
char type[GUID_STRLEN], unique[GUID_STRLEN];
RawDump((void*)entry->name, sizeof(entry->name), label, 2);
snprintf(contents, sizeof(contents), "Label: %s", label);
printf(PARTITION_FMT, (int)entry->starting_lba,
(int)(entry->ending_lba - entry->starting_lba + 1),
index+1, contents);
GuidToStr(&entry->type, type);
printf(PARTITION_MORE, "Type: ", type);
GuidToStr(&entry->unique, unique);
printf(PARTITION_MORE, "UUID: ", unique);
snprintf(contents, sizeof(contents), "[%016lx]", entry->attributes);
printf(PARTITION_MORE, "Attr: ", contents);
}
}
void EntriesDetails(GptData *gpt, const int secondary, int raw) {
int i;
for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, i);
if (!Memcmp(&guid_unused, &entry->type, sizeof(Guid))) continue;
EntryDetails(entry, i, raw);
}
}
/* Parses all options (and validates them), then opens the drive.
* Show GPT information in following order:
*
* Primary header sector
* details (if -v applied)
*
* Primary table sectors
*
* 1st partition
* details (if -v applied)
* :
* last partition
* details (if -v applied)
*
* Secondary table sectors
*
* Secondary header sector
* details (if -v applied)
*/
int CgptShow(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(show_options) ==
ARRAY_COUNT(show_options_details));
help = number = NOT_INITED;
if (CGPT_OK != HandleOptions(argc, argv,
"hnv",
ARRAY_COUNT(show_options),
show_options,
show_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
ShowHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
printf(TITLE_FMT, "start", "size", "part", "contents");
printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", "PMBR");
if (drive.gpt.valid_headers & MASK_PRIMARY) {
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "", "Pri GPT header");
if (verbose) {
GptHeader *header;
char indent[64];
snprintf(indent, sizeof(indent), GPT_MORE);
header = (GptHeader*)drive.gpt.primary_header;
HeaderDetails(header, indent, number);
}
} else {
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
}
printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
(int)GPT_ENTRIES_SECTORS,
drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
"Pri GPT table");
if (drive.gpt.valid_entries & MASK_PRIMARY)
EntriesDetails(&drive.gpt, PRIMARY, number);
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
GPT_ENTRIES_SECTORS),
(int)GPT_ENTRIES_SECTORS,
drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
"Sec GPT table");
/* We show secondary table details if any of following is true.
* 1. only secondary is valid.
* 2. secondary is not identical to promary.
*/
if ((drive.gpt.valid_entries & MASK_SECONDARY) &&
(!(drive.gpt.valid_entries & MASK_PRIMARY) ||
Memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
TOTAL_ENTRIES_SIZE))) {
EntriesDetails(&drive.gpt, SECONDARY, number);
}
if (drive.gpt.valid_headers & MASK_SECONDARY)
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
(int)GPT_HEADER_SECTOR, "", "Sec GPT header");
else
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
(int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
/* We show secondary header if any of following is true:
* 1. only secondary is valid.
* 2. secondary is not synonymous to primary.
*/
if ((drive.gpt.valid_headers & MASK_SECONDARY) &&
(!(drive.gpt.valid_headers & MASK_PRIMARY) ||
!IsSynonymous((GptHeader*)drive.gpt.primary_header,
(GptHeader*)drive.gpt.secondary_header))) {
if (verbose) {
GptHeader *header;
char indent[64];
snprintf(indent, sizeof(indent), GPT_MORE);
header = (GptHeader*)drive.gpt.secondary_header;
HeaderDetails(header, indent, number);
}
}
CheckValid(&drive);
DriveClose(&drive);
return CGPT_OK;
}

View File

@@ -1,269 +0,0 @@
/* 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.
*
* Functions to fix, after cgptlib cleanup.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "cgpt_tofix.h"
#include "crc32.h"
#include "utility.h"
const char *GptError(int errno) {
const char *error_string[] = {
/* GPT_SUCCESS */ "Success",
/* GPT_ERROR_NO_VALID_KERNEL */ "No valid kernel entry",
/* GPT_ERROR_INVALID_HEADERS */ "Both primary and secondary headers are "
"invalid.",
/* GPT_ERROR_INVALID_ENTRIES */ "Both primary and secondary entries are "
"invalid.",
/* GPT_ERROR_INVALID_SECTOR_SIZE */ "Invalid sector size",
/* GPT_ERROR_INVALID_SECTOR_NUMBER */ "Invalid sector number",
/* GPT_ERROR_INVALID_UPDATE_TYPE */ "Invalid update type",
};
return error_string[errno];
}
/* Update CRC value if necessary. */
void UpdateCrc(GptData *gpt) {
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
secondary_header = (GptHeader*)gpt->secondary_header;
if (gpt->modified & GPT_MODIFIED_ENTRIES1) {
primary_header->entries_crc32 =
Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE);
}
if (gpt->modified & GPT_MODIFIED_ENTRIES2) {
secondary_header->entries_crc32 =
Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
}
if (gpt->modified & GPT_MODIFIED_HEADER1) {
primary_header->header_crc32 = 0;
primary_header->header_crc32 = Crc32(
(const uint8_t *)primary_header, primary_header->size);
}
if (gpt->modified & GPT_MODIFIED_HEADER2) {
secondary_header->header_crc32 = 0;
secondary_header->header_crc32 = Crc32(
(const uint8_t *)secondary_header, secondary_header->size);
}
}
/* Helper function to get a pointer to the partition entry.
* 'secondary' is either PRIMARY or SECONDARY.
* 'entry_index' is the partition index: [0, number_of_entries).
*/
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) {
uint8_t *entries;
if (secondary == PRIMARY) {
entries = gpt->primary_entries;
} else {
entries = gpt->secondary_entries;
}
return (GptEntry*)(&entries[GetNumberOfEntries(gpt) * entry_index]);
}
/* The following functions are helpers to access attributes bit more easily.
* 'secondary' is either PRIMARY or SECONDARY.
* 'entry_index' is the partition index: [0, number_of_entries).
*
* Get*() return the exact value (shifted and masked).
*/
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET;
}
int GetPriority(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
}
void SetBad(GptData *gpt, int secondary, int entry_index, int bad) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
// There is no bad attribute
assert(0);
}
int GetBad(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
// There is no bad attribute
assert(0);
return 0;
}
void SetTries(GptData *gpt, int secondary, int entry_index, int tries) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK;
entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET;
}
int GetTries(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
CGPT_ATTRIBUTE_TRIES_OFFSET;
}
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
}
int GetSuccessful(GptData *gpt, int secondary, int entry_index) {
GptEntry *entry;
entry = GetEntry(gpt, secondary, entry_index);
return (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
}
uint32_t GetNumberOfEntries(const GptData *gpt) {
GptHeader *header = 0;
if (gpt->valid_headers & MASK_PRIMARY)
header = (GptHeader*)gpt->primary_header;
else if (gpt->valid_headers & MASK_SECONDARY)
header = (GptHeader*)gpt->secondary_header;
else
assert(0);
return header->number_of_entries;
}
/* Two headers are NOT bitwise identical. For example, my_lba pointers to header
* itself so that my_lba in primary and secondary is definitely different.
* Only the following fields should be identical.
*
* first_usable_lba
* last_usable_lba
* number_of_entries
* size_of_entry
* disk_uuid
*
* If any of above field are not matched, overwrite secondary with primary since
* we always trust primary.
* If any one of header is invalid, copy from another. */
int IsSynonymous(const GptHeader* a, const GptHeader* b) {
if ((a->first_usable_lba == b->first_usable_lba) &&
(a->last_usable_lba == b->last_usable_lba) &&
(a->number_of_entries == b->number_of_entries) &&
(a->size_of_entry == b->size_of_entry) &&
(!Memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid))))
return 1;
return 0;
}
/* Primary entries and secondary entries should be bitwise identical.
* If two entries tables are valid, compare them. If not the same,
* overwrites secondary with primary (primary always has higher priority),
* and marks secondary as modified.
* If only one is valid, overwrites invalid one.
* If all are invalid, does nothing.
* This function returns bit masks for GptData.modified field.
* Note that CRC is NOT re-computed in this function.
*/
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) {
if (valid_entries == MASK_BOTH) {
if (Memcmp(gpt->primary_entries, gpt->secondary_entries,
TOTAL_ENTRIES_SIZE)) {
Memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES2;
}
} else if (valid_entries == MASK_PRIMARY) {
Memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES2;
} else if (valid_entries == MASK_SECONDARY) {
Memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
return GPT_MODIFIED_ENTRIES1;
}
return 0;
}
/* The above five fields are shared between primary and secondary headers.
* We can recover one header from another through copying those fields. */
void CopySynonymousParts(GptHeader* target, const GptHeader* source) {
target->first_usable_lba = source->first_usable_lba;
target->last_usable_lba = source->last_usable_lba;
target->number_of_entries = source->number_of_entries;
target->size_of_entry = source->size_of_entry;
Memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid));
}
/* This function repairs primary and secondary headers if possible.
* If both headers are valid (CRC32 is correct) but
* a) indicate inconsistent usable LBA ranges,
* b) inconsistent partition entry size and number,
* c) inconsistent disk_uuid,
* we will use the primary header to overwrite secondary header.
* If primary is invalid (CRC32 is wrong), then we repair it from secondary.
* If secondary is invalid (CRC32 is wrong), then we repair it from primary.
* This function returns the bitmasks for modified header.
* Note that CRC value is NOT re-computed in this function. UpdateCrc() will
* do it later.
*/
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) {
GptHeader *primary_header, *secondary_header;
primary_header = (GptHeader*)gpt->primary_header;
secondary_header = (GptHeader*)gpt->secondary_header;
if (valid_headers == MASK_BOTH) {
if (!IsSynonymous(primary_header, secondary_header)) {
CopySynonymousParts(secondary_header, primary_header);
return GPT_MODIFIED_HEADER2;
}
} else if (valid_headers == MASK_PRIMARY) {
Memcpy(secondary_header, primary_header, primary_header->size);
secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */
secondary_header->entries_lba = secondary_header->my_lba -
GPT_ENTRIES_SECTORS;
return GPT_MODIFIED_HEADER2;
} else if (valid_headers == MASK_SECONDARY) {
Memcpy(primary_header, secondary_header, secondary_header->size);
primary_header->my_lba = GPT_PMBR_SECTOR; /* the second sector on drive */
primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTOR;
return GPT_MODIFIED_HEADER1;
}
return 0;
}
/* TODO: HORRIBLY broken non-implemented functions. These will be
* fixed as part of a second stage of refactoring to use the new
* cgptlib_internal functions. */
uint32_t CheckOverlappedPartition(GptData *gpt) {
return 1;
}
uint32_t CheckValidEntries(GptData *gpt) {
return 1;
}
int NonZeroGuid(const Guid *guid) {
return 1;
}

View File

@@ -1,40 +0,0 @@
/* 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.
*/
#ifndef CGPT_TOFIX_H_
#define CGPT_TOFIX_H_
#include <stdint.h>
#include "cgptlib.h"
#include "cgptlib_internal.h"
#include "gpt.h"
/* TODO: This is stuff copied out of cgptlib. cgptlib doesn't need it anymore,but currently the cgpt tool does. */
const char *GptError(int errno);
int IsSynonymous(const GptHeader* a, const GptHeader* b);
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
void UpdateCrc(GptData *gpt);
int NonZeroGuid(const Guid *guid);
uint32_t CheckValidEntries(GptData *gpt);
uint32_t CheckOverlappedPartition(GptData *gpt);
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index);
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority);
int GetPriority(GptData *gpt, int secondary, int entry_index);
void SetBad(GptData *gpt, int secondary, int entry_index, int bad);
int GetBad(GptData *gpt, int secondary, int entry_index);
void SetTries(GptData *gpt, int secondary, int entry_index, int tries);
int GetTries(GptData *gpt, int secondary, int entry_index);
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success);
int GetSuccessful(GptData *gpt, int secondary, int entry_index);
/* Get number of entries value in primary header */
uint32_t GetNumberOfEntries(const GptData *gpt);
#endif /* CGPT_TOFIX_H_ */

View File

@@ -57,7 +57,7 @@ int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors) {
return 1;
/* Reserved fields must be zero. */
if (h->reserved)
if (h->reserved_zero)
return 1;
/* TODO: Padding must be set to zero. */
@@ -174,7 +174,7 @@ int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) {
return 1;
if (h1->size != h2->size)
return 1;
if (h1->reserved != h2->reserved)
if (h1->reserved_zero != h2->reserved_zero)
return 1;
if (h1->first_usable_lba != h2->first_usable_lba)
return 1;

View File

@@ -73,7 +73,7 @@ typedef struct {
uint32_t revision;
uint32_t size;
uint32_t header_crc32;
uint32_t reserved;
uint32_t reserved_zero;
uint64_t my_lba;
uint64_t alternate_lba;
uint64_t first_usable_lba;
@@ -84,7 +84,7 @@ typedef struct {
uint32_t number_of_entries;
uint32_t size_of_entry;
uint32_t entries_crc32;
uint8_t padding[512 - 92]; /* Pad to end of sector */
uint8_t reserved_padding[]; /* entire sector reserved for header */
} GptHeader;
/* GPT partition entry defines the starting and ending LBAs of a partition.
@@ -98,7 +98,8 @@ typedef struct {
uint64_t starting_lba;
uint64_t ending_lba;
uint64_t attributes;
uint16_t name[36]; /* UTF-16 encoded partition name */
uint16_t name[36]; /* UTF-16 encoded partition name */
uint8_t reserved[]; /* nothing, really */
} GptEntry;
#endif /* VBOOT_REFERENCE_CGPTLIB_GPT_H_ */