aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--cgpt/Makefile45
-rw-r--r--cgpt/cgpt.c75
-rw-r--r--cgpt/cgpt.h130
-rw-r--r--cgpt/cgpt_common.c726
-rw-r--r--cgpt/cmd_add.c276
-rw-r--r--cgpt/cmd_boot.c167
-rw-r--r--cgpt/cmd_create.c106
-rw-r--r--cgpt/cmd_repair.c85
-rw-r--r--cgpt/cmd_show.c413
-rw-r--r--cgpt/endian.h44
-rw-r--r--tests/Makefile2
-rw-r--r--tests/cgptlib_test.c9
-rwxr-xr-xtests/common.sh21
-rwxr-xr-xtests/run_cgpt_tests.sh114
-rw-r--r--utility/Makefile18
-rw-r--r--utility/cgpt/Makefile30
-rw-r--r--utility/cgpt/cgpt.c457
-rw-r--r--utility/cgpt/cgpt.h158
-rw-r--r--utility/cgpt/cgpt_add_modify_delete.c276
-rw-r--r--utility/cgpt/cgpt_attribute.c148
-rw-r--r--utility/cgpt/cgpt_dev.c126
-rw-r--r--utility/cgpt/cgpt_options.c134
-rw-r--r--utility/cgpt/cgpt_repair.c84
-rw-r--r--utility/cgpt/cgpt_show.c304
-rw-r--r--utility/cgpt/cgpt_tofix.c269
-rw-r--r--utility/cgpt/cgpt_tofix.h40
-rw-r--r--vboot_firmware/lib/cgptlib/cgptlib_internal.c4
-rw-r--r--vboot_firmware/lib/cgptlib/include/gpt.h7
29 files changed, 2215 insertions, 2057 deletions
diff --git a/Makefile b/Makefile
index e30d7162..853bfbfa 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/cgpt/Makefile b/cgpt/Makefile
new file mode 100644
index 00000000..1f8deded
--- /dev/null
+++ b/cgpt/Makefile
@@ -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
diff --git a/cgpt/cgpt.c b/cgpt/cgpt.c
new file mode 100644
index 00000000..d80bffea
--- /dev/null
+++ b/cgpt/cgpt.c
@@ -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;
+}
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
new file mode 100644
index 00000000..504e6dd7
--- /dev/null
+++ b/cgpt/cgpt.h
@@ -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_
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
new file mode 100644
index 00000000..f165f7a7
--- /dev/null
+++ b/cgpt/cgpt_common.c
@@ -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);
+ }
+}
+
diff --git a/cgpt/cmd_add.c b/cgpt/cmd_add.c
new file mode 100644
index 00000000..18a0285e
--- /dev/null
+++ b/cgpt/cmd_add.c
@@ -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;
+}
diff --git a/cgpt/cmd_boot.c b/cgpt/cmd_boot.c
new file mode 100644
index 00000000..784684a2
--- /dev/null
+++ b/cgpt/cmd_boot.c
@@ -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;
+}
diff --git a/cgpt/cmd_create.c b/cgpt/cmd_create.c
new file mode 100644
index 00000000..4e6eb653
--- /dev/null
+++ b/cgpt/cmd_create.c
@@ -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);
+}
diff --git a/cgpt/cmd_repair.c b/cgpt/cmd_repair.c
new file mode 100644
index 00000000..aafdc938
--- /dev/null
+++ b/cgpt/cmd_repair.c
@@ -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);
+}
diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c
new file mode 100644
index 00000000..9f52cb1d
--- /dev/null
+++ b/cgpt/cmd_show.c
@@ -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;
+}
+
+
+
diff --git a/cgpt/endian.h b/cgpt/endian.h
new file mode 100644
index 00000000..ab62ebc9
--- /dev/null
+++ b/cgpt/endian.h
@@ -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_
diff --git a/tests/Makefile b/tests/Makefile
index d52b2822..5ad4b740 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -126,6 +126,8 @@ runtests:
./kernel_rollback_tests
# Helper Library Tests
./cgptlib_test
+ # Tool tests
+ ./run_cgpt_tests.sh
clean:
rm -f $(TEST_BINS)
diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c
index 1ab5342a..f016b212 100644
--- a/tests/cgptlib_test.c
+++ b/tests/cgptlib_test.c
@@ -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));
diff --git a/tests/common.sh b/tests/common.sh
index 421f6290..6afcd776 100755
--- a/tests/common.sh
+++ b/tests/common.sh
@@ -30,10 +30,21 @@ COL_STOP='\E[0;m'
hash_algos=( sha1 sha256 sha512 )
key_lengths=( 1024 2048 4096 8192 )
+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 {
- if [ ! -d ${TESTKEY_DIR} ]
- then
- echo "You must run gen_test_keys.sh to generate test keys first."
- exit 1
- fi
+ [ -d ${TESTKEY_DIR} ] || \
+ error "You must run gen_test_keys.sh to generate test keys first."
}
+
diff --git a/tests/run_cgpt_tests.sh b/tests/run_cgpt_tests.sh
new file mode 100755
index 00000000..2dcca997
--- /dev/null
+++ b/tests/run_cgpt_tests.sh
@@ -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."
diff --git a/utility/Makefile b/utility/Makefile
index 666f7731..697cc9ec 100644
--- a/utility/Makefile
+++ b/utility/Makefile
@@ -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))
diff --git a/utility/cgpt/Makefile b/utility/cgpt/Makefile
deleted file mode 100644
index 78de27f7..00000000
--- a/utility/cgpt/Makefile
+++ /dev/null
@@ -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)/%,$^)
diff --git a/utility/cgpt/cgpt.c b/utility/cgpt/cgpt.c
deleted file mode 100644
index 5bcba17c..00000000
--- a/utility/cgpt/cgpt.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt.h b/utility/cgpt/cgpt.h
deleted file mode 100644
index 1782fe14..00000000
--- a/utility/cgpt/cgpt.h
+++ /dev/null
@@ -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_ */
diff --git a/utility/cgpt/cgpt_add_modify_delete.c b/utility/cgpt/cgpt_add_modify_delete.c
deleted file mode 100644
index c4ddc46a..00000000
--- a/utility/cgpt/cgpt_add_modify_delete.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_attribute.c b/utility/cgpt/cgpt_attribute.c
deleted file mode 100644
index 37477dc6..00000000
--- a/utility/cgpt/cgpt_attribute.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_dev.c b/utility/cgpt/cgpt_dev.c
deleted file mode 100644
index ca53c4cf..00000000
--- a/utility/cgpt/cgpt_dev.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_options.c b/utility/cgpt/cgpt_options.c
deleted file mode 100644
index b434eeaf..00000000
--- a/utility/cgpt/cgpt_options.c
+++ /dev/null
@@ -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);
-}
diff --git a/utility/cgpt/cgpt_repair.c b/utility/cgpt/cgpt_repair.c
deleted file mode 100644
index f75e4a2c..00000000
--- a/utility/cgpt/cgpt_repair.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_show.c b/utility/cgpt/cgpt_show.c
deleted file mode 100644
index 2dfad40e..00000000
--- a/utility/cgpt/cgpt_show.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_tofix.c b/utility/cgpt/cgpt_tofix.c
deleted file mode 100644
index 50aed529..00000000
--- a/utility/cgpt/cgpt_tofix.c
+++ /dev/null
@@ -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;
-}
diff --git a/utility/cgpt/cgpt_tofix.h b/utility/cgpt/cgpt_tofix.h
deleted file mode 100644
index 8e645df4..00000000
--- a/utility/cgpt/cgpt_tofix.h
+++ /dev/null
@@ -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_ */
diff --git a/vboot_firmware/lib/cgptlib/cgptlib_internal.c b/vboot_firmware/lib/cgptlib/cgptlib_internal.c
index 8aff0bd7..0a4f46d5 100644
--- a/vboot_firmware/lib/cgptlib/cgptlib_internal.c
+++ b/vboot_firmware/lib/cgptlib/cgptlib_internal.c
@@ -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;
diff --git a/vboot_firmware/lib/cgptlib/include/gpt.h b/vboot_firmware/lib/cgptlib/include/gpt.h
index a199755d..7a1d5768 100644
--- a/vboot_firmware/lib/cgptlib/include/gpt.h
+++ b/vboot_firmware/lib/cgptlib/include/gpt.h
@@ -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_ */