mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-25 18:55:24 +00:00
Nearly complete rewrite of cgpt tool.
This fixes a number of bugs, adds a bunch of commands, and essentially makes cgpt ready to use as a replacement for gpt. Still to do is to add commands and options that will let it generated intentionally bad partitions, for use in testing. Review URL: http://codereview.chromium.org/2719008
This commit is contained in:
4
Makefile
4
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
|
||||
|
||||
45
cgpt/Makefile
Normal file
45
cgpt/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
CC ?= gcc
|
||||
TOP ?= ..
|
||||
CFLAGS ?= -Wall -DNDEBUG -O3 -Werror
|
||||
CFLAGS += -static
|
||||
LDFLAGS += -luuid
|
||||
FWDIR=$(TOP)/vboot_firmware
|
||||
|
||||
INCLUDES = -I$(FWDIR)/lib/cgptlib/include
|
||||
LIBS = $(FWDIR)/vboot_fw.a
|
||||
|
||||
DESTDIR ?= /usr/bin
|
||||
|
||||
PROGNAME = cgpt
|
||||
|
||||
OBJS= \
|
||||
cgpt.o \
|
||||
cmd_show.o \
|
||||
cmd_repair.o \
|
||||
cmd_create.o \
|
||||
cmd_add.o \
|
||||
cmd_boot.o \
|
||||
cgpt_common.o
|
||||
|
||||
|
||||
all: $(PROGNAME)
|
||||
|
||||
$(PROGNAME): $(OBJS) $(LIBS)
|
||||
$(CC) -o $(PROGNAME) $(CFLAGS) $^ $(LDFLAGS)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(PROGNAME) *.o *~
|
||||
|
||||
install: $(PROGNAME)
|
||||
mkdir -p $(DESTDIR)
|
||||
cp -f $^ $(DESTDIR)
|
||||
chmod a+rx $(patsubst %,$(DESTDIR)/%,$^)
|
||||
|
||||
.PHONY: all clean install
|
||||
75
cgpt/cgpt.c
Normal file
75
cgpt/cgpt.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
|
||||
* files for more details.
|
||||
*/
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
const char* progname;
|
||||
const char* command;
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
int (*fp)(int argc, char *argv[]);
|
||||
const char *comment;
|
||||
} cmds[] = {
|
||||
{"create", cmd_create, "Create or reset GPT headers and tables"},
|
||||
{"add", cmd_add, "Add, edit or remove a partition entry"},
|
||||
{"show", cmd_show, "Show partition table and entries"},
|
||||
{"repair", cmd_repair, "Repair damaged GPT headers and tables"},
|
||||
{"boot", cmd_boot, "Edit the PMBR sector for legacy BIOSes"},
|
||||
};
|
||||
|
||||
|
||||
void Usage(void) {
|
||||
int i;
|
||||
|
||||
printf("Usage: %s COMMAND [OPTIONS] DRIVE\n\n"
|
||||
"Supported COMMANDs:\n\n",
|
||||
progname);
|
||||
|
||||
for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
||||
printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
|
||||
}
|
||||
printf("\nFor more detailed usage, use %s COMMAND -h\n\n", progname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
|
||||
progname = strrchr(argv[0], '/');
|
||||
if (progname)
|
||||
progname++;
|
||||
else
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 2) {
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
// increment optind now, so that getopt skips argv[0] in command function
|
||||
command = argv[optind++];
|
||||
|
||||
// Find the command to invoke.
|
||||
for (i = 0; command && i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
|
||||
if (0 == strcmp(cmds[i].name, command)) {
|
||||
return cmds[i].fp(argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find the command.
|
||||
Usage();
|
||||
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
130
cgpt/cgpt.h
Normal file
130
cgpt/cgpt.h
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
|
||||
#define VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
#include "endian.h"
|
||||
#include "gpt.h"
|
||||
#include "cgptlib.h"
|
||||
|
||||
|
||||
// Just for clarity
|
||||
enum {
|
||||
CGPT_OK = 0,
|
||||
CGPT_FAILED,
|
||||
};
|
||||
|
||||
|
||||
struct legacy_partition {
|
||||
uint8_t status;
|
||||
uint8_t f_head;
|
||||
uint8_t f_sect;
|
||||
uint8_t f_cyl;
|
||||
uint8_t type;
|
||||
uint8_t l_head;
|
||||
uint8_t l_sect;
|
||||
uint8_t l_cyl;
|
||||
uint32_t f_lba;
|
||||
uint32_t num_sect;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
// syslinux uses this format:
|
||||
struct pmbr {
|
||||
uint8_t bootcode[424];
|
||||
Guid boot_guid;
|
||||
uint32_t disk_id;
|
||||
uint8_t magic[2]; // 0x1d, 0x9a
|
||||
struct legacy_partition part[4];
|
||||
uint8_t sig[2]; // 0x55, 0xaa
|
||||
} __attribute__((packed));
|
||||
|
||||
void PMBRToStr(struct pmbr *pmbr, char *str);
|
||||
|
||||
// Handle to the drive storing the GPT.
|
||||
struct drive {
|
||||
int fd; /* file descriptor */
|
||||
uint64_t size; /* total size (in bytes) */
|
||||
GptData gpt;
|
||||
struct pmbr pmbr;
|
||||
};
|
||||
|
||||
|
||||
int DriveOpen(const char *drive_path, struct drive *drive);
|
||||
int DriveClose(struct drive *drive, int update_as_needed);
|
||||
int CheckValid(const struct drive *drive);
|
||||
|
||||
/* GUID conversion functions. Accepted format:
|
||||
*
|
||||
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
|
||||
*
|
||||
* At least GUID_STRLEN bytes should be reserved in 'str' (included the tailing
|
||||
* '\0').
|
||||
*/
|
||||
#define GUID_STRLEN 37
|
||||
int StrToGuid(const char *str, Guid *guid);
|
||||
void GuidToStr(const Guid *guid, char *str);
|
||||
int IsZero(const Guid *guid);
|
||||
|
||||
|
||||
int ReadPMBR(struct drive *drive);
|
||||
int WritePMBR(struct drive *drive);
|
||||
|
||||
|
||||
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
|
||||
* Caller must prepare enough space for UTF8. The rough estimation is:
|
||||
*
|
||||
* utf8 length = bytecount(utf16) * 1.5
|
||||
*/
|
||||
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8);
|
||||
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
|
||||
* Caller must prepare enough space for UTF16. The conservative estimation is:
|
||||
*
|
||||
* utf16 bytecount = bytecount(utf8) / 3 * 4
|
||||
*/
|
||||
void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16);
|
||||
|
||||
/* Helper functions for supported GPT types. */
|
||||
int ResolveType(const Guid *type, char *buf);
|
||||
int SupportedType(const char *name, Guid *type);
|
||||
void PrintTypes(void);
|
||||
void EntryDetails(GptEntry *entry, int index, int raw);
|
||||
|
||||
uint32_t GetNumberOfEntries(const GptData *gpt);
|
||||
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index);
|
||||
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority);
|
||||
int GetPriority(GptData *gpt, int secondary, int entry_index);
|
||||
void SetTries(GptData *gpt, int secondary, int entry_index, int tries);
|
||||
int GetTries(GptData *gpt, int secondary, int entry_index);
|
||||
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success);
|
||||
int GetSuccessful(GptData *gpt, int secondary, int entry_index);
|
||||
|
||||
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers);
|
||||
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries);
|
||||
void UpdateCrc(GptData *gpt);
|
||||
int IsSynonymous(const GptHeader* a, const GptHeader* b);
|
||||
|
||||
// For usage and error messages.
|
||||
extern const char* progname;
|
||||
extern const char* command;
|
||||
void Error(const char *format, ...);
|
||||
|
||||
|
||||
// Command functions.
|
||||
int cmd_show(int argc, char *argv[]);
|
||||
int cmd_repair(int argc, char *argv[]);
|
||||
int cmd_create(int argc, char *argv[]);
|
||||
int cmd_add(int argc, char *argv[]);
|
||||
int cmd_boot(int argc, char *argv[]);
|
||||
|
||||
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
|
||||
const char *GptError(int errnum);
|
||||
|
||||
|
||||
#endif // VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_
|
||||
726
cgpt/cgpt_common.c
Normal file
726
cgpt/cgpt_common.c
Normal file
@@ -0,0 +1,726 @@
|
||||
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
|
||||
* files for more details.
|
||||
*/
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
#include "crc32.h"
|
||||
|
||||
|
||||
void Error(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, "ERROR: %s %s: ", progname, command);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
int CheckValid(const struct drive *drive) {
|
||||
if ((drive->gpt.valid_headers != MASK_BOTH) ||
|
||||
(drive->gpt.valid_entries != MASK_BOTH)) {
|
||||
fprintf(stderr, "\nWARNING: one of the GPT header/entries is invalid, "
|
||||
"please run '%s repair'\n", progname);
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
return CGPT_OK;
|
||||
}
|
||||
|
||||
/* Loads sectors from 'fd'.
|
||||
* *buf is pointed to an allocated memory when returned, and should be
|
||||
* freed by cgpt_close().
|
||||
*
|
||||
* fd -- file descriptot.
|
||||
* buf -- pointer to buffer pointer
|
||||
* sector -- offset of starting sector (in sectors)
|
||||
* sector_bytes -- bytes per sector
|
||||
* sector_count -- number of sectors to load
|
||||
*
|
||||
* Returns CGPT_OK for successful. Aborts if any error occurs.
|
||||
*/
|
||||
static int Load(const int fd, uint8_t **buf,
|
||||
const uint64_t sector,
|
||||
const uint64_t sector_bytes,
|
||||
const uint64_t sector_count) {
|
||||
int count; /* byte count to read */
|
||||
int nread;
|
||||
|
||||
assert(buf);
|
||||
count = sector_bytes * sector_count;
|
||||
*buf = malloc(count);
|
||||
assert(*buf);
|
||||
|
||||
if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
|
||||
goto error_free;
|
||||
|
||||
nread = read(fd, *buf, count);
|
||||
if (nread < count)
|
||||
goto error_free;
|
||||
|
||||
return CGPT_OK;
|
||||
|
||||
error_free:
|
||||
free(*buf);
|
||||
*buf = 0;
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
|
||||
int ReadPMBR(struct drive *drive) {
|
||||
if (-1 == lseek(drive->fd, 0, SEEK_SET))
|
||||
return CGPT_FAILED;
|
||||
|
||||
int nread = read(drive->fd, &drive->pmbr, sizeof(struct pmbr));
|
||||
if (nread != sizeof(struct pmbr))
|
||||
return CGPT_FAILED;
|
||||
|
||||
return CGPT_OK;
|
||||
}
|
||||
|
||||
int WritePMBR(struct drive *drive) {
|
||||
if (-1 == lseek(drive->fd, 0, SEEK_SET))
|
||||
return CGPT_FAILED;
|
||||
|
||||
int nwrote = write(drive->fd, &drive->pmbr, sizeof(struct pmbr));
|
||||
if (nwrote != sizeof(struct pmbr))
|
||||
return CGPT_FAILED;
|
||||
|
||||
return CGPT_OK;
|
||||
}
|
||||
|
||||
/* Saves sectors to 'fd'.
|
||||
*
|
||||
* fd -- file descriptot.
|
||||
* buf -- pointer to buffer
|
||||
* sector -- starting sector offset
|
||||
* sector_bytes -- bytes per sector
|
||||
* sector_count -- number of sector to save
|
||||
*
|
||||
* Returns CGPT_OK for successful, CGPT_FAILED for failed.
|
||||
*/
|
||||
static int Save(const int fd, const uint8_t *buf,
|
||||
const uint64_t sector,
|
||||
const uint64_t sector_bytes,
|
||||
const uint64_t sector_count) {
|
||||
int count; /* byte count to write */
|
||||
int nwrote;
|
||||
|
||||
assert(buf);
|
||||
count = sector_bytes * sector_count;
|
||||
|
||||
if (-1 == lseek(fd, sector * sector_bytes, SEEK_SET))
|
||||
return CGPT_FAILED;
|
||||
|
||||
nwrote = write(fd, buf, count);
|
||||
if (nwrote < count)
|
||||
return CGPT_FAILED;
|
||||
|
||||
return CGPT_OK;
|
||||
}
|
||||
|
||||
|
||||
// Opens a block device or file, loads raw GPT data from it.
|
||||
//
|
||||
// Returns CGPT_FAILED if any error happens.
|
||||
// Returns CGPT_OK if success and information are stored in 'drive'. */
|
||||
int DriveOpen(const char *drive_path, struct drive *drive) {
|
||||
struct stat stat;
|
||||
|
||||
assert(drive_path);
|
||||
assert(drive);
|
||||
|
||||
// Clear struct for proper error handling.
|
||||
memset(drive, 0, sizeof(struct drive));
|
||||
|
||||
drive->fd = open(drive_path, O_RDWR | O_LARGEFILE);
|
||||
if (drive->fd == -1) {
|
||||
Error("Can't open %s: %s\n", drive_path, strerror(errno));
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (fstat(drive->fd, &stat) == -1) {
|
||||
goto error_close;
|
||||
}
|
||||
if ((stat.st_mode & S_IFMT) != S_IFREG) {
|
||||
if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
|
||||
Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno));
|
||||
goto error_close;
|
||||
}
|
||||
if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) {
|
||||
Error("Can't read sector size from %s: %s\n",
|
||||
drive_path, strerror(errno));
|
||||
goto error_close;
|
||||
}
|
||||
} else {
|
||||
drive->gpt.sector_bytes = 512; /* bytes */
|
||||
drive->size = stat.st_size;
|
||||
}
|
||||
if (drive->size % drive->gpt.sector_bytes) {
|
||||
Error("Media size (%llu) is not a multiple of sector size(%d)\n",
|
||||
(long long unsigned int)drive->size, drive->gpt.sector_bytes);
|
||||
goto error_close;
|
||||
}
|
||||
drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
|
||||
|
||||
// Read the data.
|
||||
if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_header,
|
||||
GPT_PMBR_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
|
||||
goto error_close;
|
||||
}
|
||||
if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_header,
|
||||
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
|
||||
goto error_close;
|
||||
}
|
||||
if (CGPT_OK != Load(drive->fd, &drive->gpt.primary_entries,
|
||||
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
|
||||
goto error_close;
|
||||
}
|
||||
if (CGPT_OK != Load(drive->fd, &drive->gpt.secondary_entries,
|
||||
drive->gpt.drive_sectors - GPT_HEADER_SECTOR
|
||||
- GPT_ENTRIES_SECTORS,
|
||||
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
// We just load the data. Caller must validate it.
|
||||
return CGPT_OK;
|
||||
|
||||
error_close:
|
||||
(void) DriveClose(drive, 0);
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
|
||||
int DriveClose(struct drive *drive, int update_as_needed) {
|
||||
int errors = 0;
|
||||
|
||||
if (update_as_needed) {
|
||||
if (drive->gpt.modified & GPT_MODIFIED_HEADER1) {
|
||||
if (CGPT_OK != Save(drive->fd, drive->gpt.primary_header,
|
||||
GPT_PMBR_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
|
||||
errors++;
|
||||
Error("Cannot write primary header: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
|
||||
if(CGPT_OK != Save(drive->fd, drive->gpt.secondary_header,
|
||||
drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_HEADER_SECTOR)) {
|
||||
errors++;
|
||||
Error("Cannot write secondary header: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) {
|
||||
if (CGPT_OK != Save(drive->fd, drive->gpt.primary_entries,
|
||||
GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
|
||||
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
|
||||
errors++;
|
||||
Error("Cannot write primary entries: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) {
|
||||
if (CGPT_OK != Save(drive->fd, drive->gpt.secondary_entries,
|
||||
drive->gpt.drive_sectors - GPT_HEADER_SECTOR
|
||||
- GPT_ENTRIES_SECTORS,
|
||||
drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS)) {
|
||||
errors++;
|
||||
Error("Cannot write secondary entries: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(drive->fd);
|
||||
|
||||
if (drive->gpt.primary_header)
|
||||
free(drive->gpt.primary_header);
|
||||
drive->gpt.primary_header = 0;
|
||||
if (drive->gpt.primary_entries)
|
||||
free(drive->gpt.primary_entries);
|
||||
drive->gpt.primary_entries = 0;
|
||||
if (drive->gpt.secondary_header)
|
||||
free(drive->gpt.secondary_header);
|
||||
drive->gpt.secondary_header = 0;
|
||||
if (drive->gpt.secondary_entries)
|
||||
free(drive->gpt.secondary_entries);
|
||||
drive->gpt.secondary_entries = 0;
|
||||
|
||||
return errors ? CGPT_FAILED : CGPT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* GUID conversion functions. Accepted format:
|
||||
*
|
||||
* "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
|
||||
*
|
||||
* Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
|
||||
*/
|
||||
int StrToGuid(const char *str, Guid *guid) {
|
||||
uint32_t time_low;
|
||||
uint16_t time_mid;
|
||||
uint16_t time_high_and_version;
|
||||
unsigned int chunk[11];
|
||||
|
||||
if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
chunk+0,
|
||||
chunk+1,
|
||||
chunk+2,
|
||||
chunk+3,
|
||||
chunk+4,
|
||||
chunk+5,
|
||||
chunk+6,
|
||||
chunk+7,
|
||||
chunk+8,
|
||||
chunk+9,
|
||||
chunk+10)) {
|
||||
printf("FAILED\n");
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
time_low = chunk[0] & 0xffffffff;
|
||||
time_mid = chunk[1] & 0xffff;
|
||||
time_high_and_version = chunk[2] & 0xffff;
|
||||
|
||||
guid->u.Uuid.time_low = htole32(time_low);
|
||||
guid->u.Uuid.time_mid = htole16(time_mid);
|
||||
guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
|
||||
|
||||
guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff;
|
||||
guid->u.Uuid.clock_seq_low = chunk[4] & 0xff;
|
||||
guid->u.Uuid.node[0] = chunk[5] & 0xff;
|
||||
guid->u.Uuid.node[1] = chunk[6] & 0xff;
|
||||
guid->u.Uuid.node[2] = chunk[7] & 0xff;
|
||||
guid->u.Uuid.node[3] = chunk[8] & 0xff;
|
||||
guid->u.Uuid.node[4] = chunk[9] & 0xff;
|
||||
guid->u.Uuid.node[5] = chunk[10] & 0xff;
|
||||
|
||||
return CGPT_OK;
|
||||
}
|
||||
void GuidToStr(const Guid *guid, char *str) {
|
||||
sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid),
|
||||
le16toh(guid->u.Uuid.time_high_and_version),
|
||||
guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low,
|
||||
guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2],
|
||||
guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]);
|
||||
}
|
||||
|
||||
/* Convert UTF16 string to UTF8. Rewritten from gpt utility.
|
||||
* Caller must prepare enough space for UTF8. The rough estimation is:
|
||||
*
|
||||
* utf8 length = bytecount(utf16) * 1.5
|
||||
*/
|
||||
#define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */
|
||||
void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8)
|
||||
{
|
||||
size_t s8idx, s16idx, s16len;
|
||||
uint32_t utfchar;
|
||||
unsigned int next_utf16;
|
||||
|
||||
for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len);
|
||||
|
||||
*utf8 = s8idx = s16idx = 0;
|
||||
while (s16idx < s16len) {
|
||||
utfchar = le16toh(utf16[s16idx++]);
|
||||
if ((utfchar & 0xf800) == 0xd800) {
|
||||
next_utf16 = le16toh(utf16[s16idx]);
|
||||
if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00)
|
||||
utfchar = 0xfffd;
|
||||
else
|
||||
s16idx++;
|
||||
}
|
||||
if (utfchar < 0x80) {
|
||||
utf8[s8idx++] = utfchar;
|
||||
} else if (utfchar < 0x800) {
|
||||
utf8[s8idx++] = 0xc0 | (utfchar >> 6);
|
||||
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
|
||||
} else if (utfchar < 0x10000) {
|
||||
utf8[s8idx++] = 0xe0 | (utfchar >> 12);
|
||||
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
|
||||
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
|
||||
} else if (utfchar < 0x200000) {
|
||||
utf8[s8idx++] = 0xf0 | (utfchar >> 18);
|
||||
utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
|
||||
utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
|
||||
utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
|
||||
}
|
||||
}
|
||||
utf8[s8idx++] = 0;
|
||||
}
|
||||
|
||||
/* Convert UTF8 string to UTF16. Rewritten from gpt utility.
|
||||
* Caller must prepare enough space for UTF16. The conservative estimation is:
|
||||
*
|
||||
* utf16 bytecount = bytecount(utf8) / 3 * 4
|
||||
*/
|
||||
void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
|
||||
{
|
||||
size_t s16idx, s8idx, s8len;
|
||||
uint32_t utfchar;
|
||||
unsigned int c, utfbytes;
|
||||
|
||||
for (s8len = 0; utf8[s8len]; ++s8len);
|
||||
|
||||
s8idx = s16idx = 0;
|
||||
utfbytes = 0;
|
||||
do {
|
||||
c = utf8[s8idx++];
|
||||
if ((c & 0xc0) != 0x80) {
|
||||
/* Initial characters. */
|
||||
if (utfbytes != 0) {
|
||||
/* Incomplete encoding. */
|
||||
utf16[s16idx++] = 0xfffd;
|
||||
}
|
||||
if ((c & 0xf8) == 0xf0) {
|
||||
utfchar = c & 0x07;
|
||||
utfbytes = 3;
|
||||
} else if ((c & 0xf0) == 0xe0) {
|
||||
utfchar = c & 0x0f;
|
||||
utfbytes = 2;
|
||||
} else if ((c & 0xe0) == 0xc0) {
|
||||
utfchar = c & 0x1f;
|
||||
utfbytes = 1;
|
||||
} else {
|
||||
utfchar = c & 0x7f;
|
||||
utfbytes = 0;
|
||||
}
|
||||
} else {
|
||||
/* Followup characters. */
|
||||
if (utfbytes > 0) {
|
||||
utfchar = (utfchar << 6) + (c & 0x3f);
|
||||
utfbytes--;
|
||||
} else if (utfbytes == 0)
|
||||
utfbytes = -1;
|
||||
utfchar = 0xfffd;
|
||||
}
|
||||
if (utfbytes == 0) {
|
||||
if (utfchar >= 0x10000) {
|
||||
utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40));
|
||||
if (s16idx >= SIZEOF_GPTENTRY_NAME) break;
|
||||
utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff));
|
||||
} else {
|
||||
utf16[s16idx++] = htole16(utfchar);
|
||||
}
|
||||
}
|
||||
} while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME);
|
||||
if (s16idx < SIZEOF_GPTENTRY_NAME)
|
||||
utf16[s16idx++] = 0;
|
||||
}
|
||||
|
||||
struct {
|
||||
Guid type;
|
||||
char *name;
|
||||
char *description;
|
||||
} supported_types[] = {
|
||||
{GPT_ENT_TYPE_CHROMEOS_KERNEL, "kernel", "ChromeOS kernel"},
|
||||
{GPT_ENT_TYPE_CHROMEOS_ROOTFS, "rootfs", "ChromeOS rootfs"},
|
||||
{GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"},
|
||||
{GPT_ENT_TYPE_CHROMEOS_RESERVED, "reserved", "ChromeOS reserved"},
|
||||
{GPT_ENT_TYPE_EFI, "efi", "EFI System Partition"},
|
||||
{GPT_ENT_TYPE_UNUSED, "unused", "Unused (nonexistent) partition"},
|
||||
};
|
||||
|
||||
/* Resolves human-readable GPT type.
|
||||
* Returns CGPT_OK if found.
|
||||
* Returns CGPT_FAILED if no known type found. */
|
||||
int ResolveType(const Guid *type, char *buf) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
|
||||
if (!memcmp(type, &supported_types[i].type, sizeof(Guid))) {
|
||||
strcpy(buf, supported_types[i].description);
|
||||
return CGPT_OK;
|
||||
}
|
||||
}
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
int SupportedType(const char *name, Guid *type) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
|
||||
if (!strcmp(name, supported_types[i].name)) {
|
||||
memcpy(type, &supported_types[i].type, sizeof(Guid));
|
||||
return CGPT_OK;
|
||||
}
|
||||
}
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
void PrintTypes(void) {
|
||||
int i;
|
||||
printf("The partition type may also be given as one of these aliases:\n\n");
|
||||
for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
|
||||
printf(" %-10s %s\n", supported_types[i].name,
|
||||
supported_types[i].description);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
uint32_t GetNumberOfEntries(const GptData *gpt) {
|
||||
GptHeader *header = 0;
|
||||
if (gpt->valid_headers & MASK_PRIMARY)
|
||||
header = (GptHeader*)gpt->primary_header;
|
||||
else if (gpt->valid_headers & MASK_SECONDARY)
|
||||
header = (GptHeader*)gpt->secondary_header;
|
||||
else
|
||||
return 0;
|
||||
return header->number_of_entries;
|
||||
}
|
||||
|
||||
static uint32_t GetSizeOfEntries(const GptData *gpt) {
|
||||
GptHeader *header = 0;
|
||||
if (gpt->valid_headers & MASK_PRIMARY)
|
||||
header = (GptHeader*)gpt->primary_header;
|
||||
else if (gpt->valid_headers & MASK_SECONDARY)
|
||||
header = (GptHeader*)gpt->secondary_header;
|
||||
else
|
||||
return 0;
|
||||
return header->number_of_entries;
|
||||
}
|
||||
|
||||
GptEntry *GetEntry(GptData *gpt, int secondary, int entry_index) {
|
||||
uint8_t *entries;
|
||||
int stride = GetSizeOfEntries(gpt);
|
||||
if (!stride)
|
||||
return 0;
|
||||
|
||||
if (secondary == PRIMARY) {
|
||||
entries = gpt->primary_entries;
|
||||
} else {
|
||||
entries = gpt->secondary_entries;
|
||||
}
|
||||
|
||||
return (GptEntry*)(&entries[stride * entry_index]);
|
||||
}
|
||||
|
||||
void SetPriority(GptData *gpt, int secondary, int entry_index, int priority) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
|
||||
assert(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
|
||||
entry->attributes &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
|
||||
entry->attributes |= (uint64_t)priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET;
|
||||
}
|
||||
|
||||
int GetPriority(GptData *gpt, int secondary, int entry_index) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
return (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
|
||||
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
|
||||
}
|
||||
|
||||
void SetTries(GptData *gpt, int secondary, int entry_index, int tries) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
|
||||
assert(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
|
||||
entry->attributes &= ~CGPT_ATTRIBUTE_TRIES_MASK;
|
||||
entry->attributes |= (uint64_t)tries << CGPT_ATTRIBUTE_TRIES_OFFSET;
|
||||
}
|
||||
|
||||
int GetTries(GptData *gpt, int secondary, int entry_index) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
return (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
|
||||
CGPT_ATTRIBUTE_TRIES_OFFSET;
|
||||
}
|
||||
|
||||
void SetSuccessful(GptData *gpt, int secondary, int entry_index, int success) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
|
||||
assert(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
|
||||
entry->attributes &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
|
||||
entry->attributes |= (uint64_t)success << CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
|
||||
}
|
||||
|
||||
int GetSuccessful(GptData *gpt, int secondary, int entry_index) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, entry_index);
|
||||
return (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
|
||||
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
#define TOSTRING(A) #A
|
||||
const char *GptError(int errnum) {
|
||||
const char *error_string[] = {
|
||||
TOSTRING(GPT_SUCCESS),
|
||||
TOSTRING(GPT_ERROR_NO_VALID_KERNEL),
|
||||
TOSTRING(GPT_ERROR_INVALID_HEADERS),
|
||||
TOSTRING(GPT_ERROR_INVALID_ENTRIES),
|
||||
TOSTRING(GPT_ERROR_INVALID_SECTOR_SIZE),
|
||||
TOSTRING(GPT_ERROR_INVALID_SECTOR_NUMBER),
|
||||
TOSTRING(GPT_ERROR_INVALID_UPDATE_TYPE)
|
||||
};
|
||||
if (errnum < 0 || errnum >= ARRAY_COUNT(error_string))
|
||||
return "<illegal value>";
|
||||
return error_string[errnum];
|
||||
}
|
||||
|
||||
/* Update CRC value if necessary. */
|
||||
void UpdateCrc(GptData *gpt) {
|
||||
GptHeader *primary_header, *secondary_header;
|
||||
|
||||
primary_header = (GptHeader*)gpt->primary_header;
|
||||
secondary_header = (GptHeader*)gpt->secondary_header;
|
||||
|
||||
if (gpt->modified & GPT_MODIFIED_ENTRIES1) {
|
||||
primary_header->entries_crc32 =
|
||||
Crc32(gpt->primary_entries, TOTAL_ENTRIES_SIZE);
|
||||
}
|
||||
if (gpt->modified & GPT_MODIFIED_ENTRIES2) {
|
||||
secondary_header->entries_crc32 =
|
||||
Crc32(gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
|
||||
}
|
||||
if (gpt->modified & GPT_MODIFIED_HEADER1) {
|
||||
primary_header->header_crc32 = 0;
|
||||
primary_header->header_crc32 = Crc32(
|
||||
(const uint8_t *)primary_header, primary_header->size);
|
||||
}
|
||||
if (gpt->modified & GPT_MODIFIED_HEADER2) {
|
||||
secondary_header->header_crc32 = 0;
|
||||
secondary_header->header_crc32 = Crc32(
|
||||
(const uint8_t *)secondary_header, secondary_header->size);
|
||||
}
|
||||
}
|
||||
/* Two headers are NOT bitwise identical. For example, my_lba pointers to header
|
||||
* itself so that my_lba in primary and secondary is definitely different.
|
||||
* Only the following fields should be identical.
|
||||
*
|
||||
* first_usable_lba
|
||||
* last_usable_lba
|
||||
* number_of_entries
|
||||
* size_of_entry
|
||||
* disk_uuid
|
||||
*
|
||||
* If any of above field are not matched, overwrite secondary with primary since
|
||||
* we always trust primary.
|
||||
* If any one of header is invalid, copy from another. */
|
||||
int IsSynonymous(const GptHeader* a, const GptHeader* b) {
|
||||
if ((a->first_usable_lba == b->first_usable_lba) &&
|
||||
(a->last_usable_lba == b->last_usable_lba) &&
|
||||
(a->number_of_entries == b->number_of_entries) &&
|
||||
(a->size_of_entry == b->size_of_entry) &&
|
||||
(!memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid))))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Primary entries and secondary entries should be bitwise identical.
|
||||
* If two entries tables are valid, compare them. If not the same,
|
||||
* overwrites secondary with primary (primary always has higher priority),
|
||||
* and marks secondary as modified.
|
||||
* If only one is valid, overwrites invalid one.
|
||||
* If all are invalid, does nothing.
|
||||
* This function returns bit masks for GptData.modified field.
|
||||
* Note that CRC is NOT re-computed in this function.
|
||||
*/
|
||||
uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) {
|
||||
if (valid_entries == MASK_BOTH) {
|
||||
if (memcmp(gpt->primary_entries, gpt->secondary_entries,
|
||||
TOTAL_ENTRIES_SIZE)) {
|
||||
memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
|
||||
return GPT_MODIFIED_ENTRIES2;
|
||||
}
|
||||
} else if (valid_entries == MASK_PRIMARY) {
|
||||
memcpy(gpt->secondary_entries, gpt->primary_entries, TOTAL_ENTRIES_SIZE);
|
||||
return GPT_MODIFIED_ENTRIES2;
|
||||
} else if (valid_entries == MASK_SECONDARY) {
|
||||
memcpy(gpt->primary_entries, gpt->secondary_entries, TOTAL_ENTRIES_SIZE);
|
||||
return GPT_MODIFIED_ENTRIES1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The above five fields are shared between primary and secondary headers.
|
||||
* We can recover one header from another through copying those fields. */
|
||||
void CopySynonymousParts(GptHeader* target, const GptHeader* source) {
|
||||
target->first_usable_lba = source->first_usable_lba;
|
||||
target->last_usable_lba = source->last_usable_lba;
|
||||
target->number_of_entries = source->number_of_entries;
|
||||
target->size_of_entry = source->size_of_entry;
|
||||
memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid));
|
||||
}
|
||||
|
||||
/* This function repairs primary and secondary headers if possible.
|
||||
* If both headers are valid (CRC32 is correct) but
|
||||
* a) indicate inconsistent usable LBA ranges,
|
||||
* b) inconsistent partition entry size and number,
|
||||
* c) inconsistent disk_uuid,
|
||||
* we will use the primary header to overwrite secondary header.
|
||||
* If primary is invalid (CRC32 is wrong), then we repair it from secondary.
|
||||
* If secondary is invalid (CRC32 is wrong), then we repair it from primary.
|
||||
* This function returns the bitmasks for modified header.
|
||||
* Note that CRC value is NOT re-computed in this function. UpdateCrc() will
|
||||
* do it later.
|
||||
*/
|
||||
uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) {
|
||||
GptHeader *primary_header, *secondary_header;
|
||||
|
||||
primary_header = (GptHeader*)gpt->primary_header;
|
||||
secondary_header = (GptHeader*)gpt->secondary_header;
|
||||
|
||||
if (valid_headers == MASK_BOTH) {
|
||||
if (!IsSynonymous(primary_header, secondary_header)) {
|
||||
CopySynonymousParts(secondary_header, primary_header);
|
||||
return GPT_MODIFIED_HEADER2;
|
||||
}
|
||||
} else if (valid_headers == MASK_PRIMARY) {
|
||||
memcpy(secondary_header, primary_header, primary_header->size);
|
||||
secondary_header->my_lba = gpt->drive_sectors - 1; /* the last sector */
|
||||
secondary_header->alternate_lba = primary_header->my_lba;
|
||||
secondary_header->entries_lba = secondary_header->my_lba -
|
||||
GPT_ENTRIES_SECTORS;
|
||||
return GPT_MODIFIED_HEADER2;
|
||||
} else if (valid_headers == MASK_SECONDARY) {
|
||||
memcpy(primary_header, secondary_header, secondary_header->size);
|
||||
primary_header->my_lba = GPT_PMBR_SECTOR; /* the second sector on drive */
|
||||
primary_header->alternate_lba = secondary_header->my_lba;
|
||||
primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTOR;
|
||||
return GPT_MODIFIED_HEADER1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int IsZero(const Guid *gp) {
|
||||
return (0 == memcmp(gp, &guid_unused, sizeof(Guid)));
|
||||
}
|
||||
|
||||
void PMBRToStr(struct pmbr *pmbr, char *str) {
|
||||
char buf[256];
|
||||
if (IsZero(&pmbr->boot_guid)) {
|
||||
sprintf(str, "PMBR");
|
||||
} else {
|
||||
GuidToStr(&pmbr->boot_guid, buf);
|
||||
sprintf(str, "PMBR (Boot GUID: %s)", buf);
|
||||
}
|
||||
}
|
||||
|
||||
276
cgpt/cmd_add.c
Normal file
276
cgpt/cmd_add.c
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
printf("\nUsage: %s add [OPTIONS] DRIVE\n\n"
|
||||
"Add, edit, or remove a partition entry.\n\n"
|
||||
"Options:\n"
|
||||
" -i NUM Specify partition (default is next available)\n"
|
||||
" -b NUM Beginning sector\n"
|
||||
" -s NUM Size in sectors\n"
|
||||
" -t GUID Partition Type GUID\n"
|
||||
" -u GUID Partition Unique ID\n"
|
||||
" -l LABEL Label\n"
|
||||
" -S NUM set Successful flag (0|1)\n"
|
||||
" -T NUM set Tries flag (0-15)\n"
|
||||
" -P NUM set Priority flag (0-15)\n"
|
||||
" -A NUM set raw 64-bit attribute value\n"
|
||||
"\n"
|
||||
"Use the -i option to modify an existing partition.\n"
|
||||
"The -b, -s, and -t options must be given for new partitions.\n"
|
||||
"\n", progname);
|
||||
PrintTypes();
|
||||
}
|
||||
|
||||
int cmd_add(int argc, char *argv[]) {
|
||||
struct drive drive;
|
||||
int partition = 0;
|
||||
uint64_t begin = 0;
|
||||
uint64_t size = 0;
|
||||
Guid type_guid;
|
||||
Guid unique_guid;
|
||||
char *label = 0;
|
||||
int successful = 0;
|
||||
int tries = 0;
|
||||
int priority = 0;
|
||||
uint64_t raw_value = 0;
|
||||
int set_begin = 0;
|
||||
int set_size = 0;
|
||||
int set_type = 0;
|
||||
int set_unique = 0;
|
||||
int set_successful = 0;
|
||||
int set_tries = 0;
|
||||
int set_priority = 0;
|
||||
int set_raw = 0;
|
||||
|
||||
int gpt_retval;
|
||||
GptEntry *entry;
|
||||
int index;
|
||||
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
char *e = 0;
|
||||
|
||||
opterr = 0; // quiet, you
|
||||
while ((c=getopt(argc, argv, ":hi:b:s:t:u:l:S:T:P:A:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'i':
|
||||
partition = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
set_begin = 1;
|
||||
begin = strtoull(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
set_size = 1;
|
||||
size = strtoull(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
set_type = 1;
|
||||
if (CGPT_OK != SupportedType(optarg, &type_guid) &&
|
||||
CGPT_OK != StrToGuid(optarg, &type_guid)) {
|
||||
Error("invalid argument to -%c: %s\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
set_unique = 1;
|
||||
if (CGPT_OK != StrToGuid(optarg, &unique_guid)) {
|
||||
Error("invalid argument to -%c: %s\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
label = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
set_successful = 1;
|
||||
successful = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
if (successful < 0 || successful > 1) {
|
||||
Error("value for -%c must be between 0 and 1", c);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
set_tries = 1;
|
||||
tries = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
|
||||
progname, c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
if (tries < 0 || tries > 15) {
|
||||
Error("value for -%c must be between 0 and 15", c);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
set_priority = 1;
|
||||
priority = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
if (priority < 0 || priority > 15) {
|
||||
Error("value for -%c must be between 0 and 15", c);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
set_raw = 1;
|
||||
raw_value = strtoull(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
Usage();
|
||||
return CGPT_OK;
|
||||
case '?':
|
||||
Error("unrecognized option: -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
case ':':
|
||||
Error("missing argument to -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
default:
|
||||
errorcnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorcnt)
|
||||
{
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
Error("missing drive argument\n");
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
||||
return CGPT_FAILED;
|
||||
|
||||
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
|
||||
Error("GptSanityCheck() returned %d: %s\n",
|
||||
gpt_retval, GptError(gpt_retval));
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
int max_part = GetNumberOfEntries(&drive.gpt);
|
||||
if (partition) {
|
||||
if (partition > max_part) {
|
||||
Error("invalid partition number: %d\n", partition);
|
||||
goto bad;
|
||||
}
|
||||
index = partition - 1;
|
||||
entry = GetEntry(&drive.gpt, PRIMARY, index);
|
||||
} else {
|
||||
// find next empty partition
|
||||
for (index = 0; index < max_part; index++) {
|
||||
entry = GetEntry(&drive.gpt, PRIMARY, index);
|
||||
if (IsZero(&entry->type)) {
|
||||
partition = index + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= max_part) {
|
||||
Error("no unused partitions available\n");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
// New partitions must specify type, begin, and size.
|
||||
if (IsZero(&entry->type)) {
|
||||
if (!set_begin || !set_size || !set_type) {
|
||||
Error("-t, -b, and -s options are required for new partitions\n");
|
||||
goto bad;
|
||||
}
|
||||
if (IsZero(&type_guid)) {
|
||||
Error("New partitions must have a type other than \"unused\"\n");
|
||||
goto bad;
|
||||
}
|
||||
if (!set_unique)
|
||||
uuid_generate((uint8_t *)&entry->unique);
|
||||
}
|
||||
|
||||
if (set_begin)
|
||||
entry->starting_lba = begin;
|
||||
if (set_size)
|
||||
entry->ending_lba = begin + size - 1;
|
||||
if (set_type)
|
||||
memcpy(&entry->type, &type_guid, sizeof(Guid));
|
||||
if (set_unique)
|
||||
memcpy(&entry->unique, &unique_guid, sizeof(Guid));
|
||||
if (label) {
|
||||
uint16_t buf[128];
|
||||
UTF8ToUTF16((uint8_t *)label, buf);
|
||||
memcpy(entry->name, buf, sizeof(entry->name));
|
||||
}
|
||||
if (set_raw) {
|
||||
entry->attributes = raw_value;
|
||||
} else {
|
||||
if (set_successful)
|
||||
SetSuccessful(&drive.gpt, PRIMARY, index, successful);
|
||||
if (set_tries)
|
||||
SetTries(&drive.gpt, PRIMARY, index, tries);
|
||||
if (set_priority)
|
||||
SetPriority(&drive.gpt, PRIMARY, index, priority);
|
||||
}
|
||||
|
||||
RepairEntries(&drive.gpt, MASK_PRIMARY);
|
||||
RepairHeader(&drive.gpt, MASK_PRIMARY);
|
||||
|
||||
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
|
||||
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
|
||||
UpdateCrc(&drive.gpt);
|
||||
|
||||
|
||||
// Write it all out
|
||||
return DriveClose(&drive, 1);
|
||||
|
||||
bad:
|
||||
(void) DriveClose(&drive, 0);
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
167
cgpt/cmd_boot.c
Normal file
167
cgpt/cmd_boot.c
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
#include "endian.h"
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
printf("\nUsage: %s boot [OPTIONS] DRIVE\n\n"
|
||||
"Edit the PMBR sector for legacy BIOSes\n\n"
|
||||
"Options:\n"
|
||||
" -i NUM Set bootable partition\n"
|
||||
" -b FILE Install bootloader code in the PMBR\n"
|
||||
" -p Create legacy PMBR partition table\n"
|
||||
"\n"
|
||||
"With no options, it will just print the PMBR boot guid\n"
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
|
||||
int cmd_boot(int argc, char *argv[]) {
|
||||
struct drive drive;
|
||||
int partition = 0;
|
||||
char *bootfile = 0;
|
||||
int create_pmbr = 0;
|
||||
int retval = 1;
|
||||
int gpt_retval;
|
||||
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
char *e = 0;
|
||||
|
||||
opterr = 0; // quiet, you
|
||||
while ((c=getopt(argc, argv, ":hi:b:p")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'i':
|
||||
partition = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
bootfile = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
create_pmbr = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
Usage();
|
||||
return CGPT_OK;
|
||||
case '?':
|
||||
Error("unrecognized option: -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
case ':':
|
||||
Error("missing argument to -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
default:
|
||||
errorcnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorcnt)
|
||||
{
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
Error("missing drive argument\n");
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
||||
return CGPT_FAILED;
|
||||
|
||||
if (CGPT_OK != ReadPMBR(&drive)) {
|
||||
Error("Unable to read PMBR\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (create_pmbr) {
|
||||
drive.pmbr.magic[0] = 0x1d;
|
||||
drive.pmbr.magic[1] = 0x9a;
|
||||
drive.pmbr.sig[0] = 0x55;
|
||||
drive.pmbr.sig[1] = 0xaa;
|
||||
memset(&drive.pmbr.part, 0, sizeof(drive.pmbr.part));
|
||||
drive.pmbr.part[0].f_head = 0x00;
|
||||
drive.pmbr.part[0].f_sect = 0x02;
|
||||
drive.pmbr.part[0].f_cyl = 0x00;
|
||||
drive.pmbr.part[0].type = 0xee;
|
||||
drive.pmbr.part[0].l_head = 0xff;
|
||||
drive.pmbr.part[0].l_sect = 0xff;
|
||||
drive.pmbr.part[0].l_cyl = 0xff;
|
||||
drive.pmbr.part[0].f_lba = htole32(1);
|
||||
uint32_t max = 0xffffffff;
|
||||
if (drive.gpt.drive_sectors < 0xffffffff)
|
||||
max = drive.gpt.drive_sectors - 1;
|
||||
drive.pmbr.part[0].num_sect = htole32(max);
|
||||
}
|
||||
|
||||
if (partition) {
|
||||
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
|
||||
Error("GptSanityCheck() returned %d: %s\n",
|
||||
gpt_retval, GptError(gpt_retval));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (partition > GetNumberOfEntries(&drive.gpt)) {
|
||||
Error("invalid partition number: %d\n", partition);
|
||||
goto done;
|
||||
}
|
||||
|
||||
int index = partition - 1;
|
||||
GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
|
||||
memcpy(&drive.pmbr.boot_guid, &entry->unique, sizeof(Guid));
|
||||
}
|
||||
|
||||
if (bootfile) {
|
||||
int fd = open(bootfile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
Error("Can't read %s: %s\n", bootfile, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
int n = read(fd, drive.pmbr.bootcode, sizeof(drive.pmbr.bootcode));
|
||||
if (n < 1) {
|
||||
Error("problem reading %s: %s\n", bootfile, strerror(errno));
|
||||
close(fd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
GuidToStr(&drive.pmbr.boot_guid, buf);
|
||||
printf("%s\n", buf);
|
||||
|
||||
// Write it all out
|
||||
if (CGPT_OK == WritePMBR(&drive))
|
||||
retval = 0;
|
||||
|
||||
done:
|
||||
(void) DriveClose(&drive, 1);
|
||||
return retval;
|
||||
}
|
||||
106
cgpt/cmd_create.c
Normal file
106
cgpt/cmd_create.c
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
printf("\nUsage: %s create [OPTIONS] DRIVE\n\n"
|
||||
"Create or reset an empty GPT.\n\n"
|
||||
"Options:\n"
|
||||
" -z Zero the sectors of the GPT table and entries\n"
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
int cmd_create(int argc, char *argv[]) {
|
||||
struct drive drive;
|
||||
int zap = 0;
|
||||
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
|
||||
opterr = 0; // quiet, you
|
||||
while ((c=getopt(argc, argv, ":hz")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'z':
|
||||
zap = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
Usage();
|
||||
return CGPT_OK;
|
||||
case '?':
|
||||
Error("unrecognized option: -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
case ':':
|
||||
Error("missing argument to -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
default:
|
||||
errorcnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorcnt)
|
||||
{
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
||||
return CGPT_FAILED;
|
||||
|
||||
// Erase the data
|
||||
memset(drive.gpt.primary_header, 0,
|
||||
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
|
||||
memset(drive.gpt.secondary_header, 0,
|
||||
drive.gpt.sector_bytes * GPT_HEADER_SECTOR);
|
||||
memset(drive.gpt.primary_entries, 0,
|
||||
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
|
||||
memset(drive.gpt.secondary_entries, 0,
|
||||
drive.gpt.sector_bytes * GPT_ENTRIES_SECTORS);
|
||||
|
||||
drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
|
||||
GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
|
||||
|
||||
// Initialize a blank set
|
||||
if (!zap)
|
||||
{
|
||||
GptHeader *h = (GptHeader *)drive.gpt.primary_header;
|
||||
memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
|
||||
h->revision = GPT_HEADER_REVISION;
|
||||
h->size = sizeof(GptHeader);
|
||||
h->my_lba = 1;
|
||||
h->first_usable_lba = 1 + 1 + GPT_ENTRIES_SECTORS;
|
||||
h->last_usable_lba = drive.gpt.drive_sectors - 1 - GPT_ENTRIES_SECTORS - 1;
|
||||
uuid_generate((uint8_t *)&h->disk_uuid);
|
||||
h->entries_lba = 2;
|
||||
h->number_of_entries = 128;
|
||||
h->size_of_entry = sizeof(GptEntry);
|
||||
|
||||
// Copy to secondary
|
||||
RepairHeader(&drive.gpt, MASK_PRIMARY);
|
||||
|
||||
UpdateCrc(&drive.gpt);
|
||||
}
|
||||
|
||||
// Write it all out
|
||||
return DriveClose(&drive, 1);
|
||||
}
|
||||
85
cgpt/cmd_repair.c
Normal file
85
cgpt/cmd_repair.c
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
printf("\nUsage: %s repair [OPTIONS] DRIVE\n\n"
|
||||
"Repair damaged GPT headers and tables.\n\n"
|
||||
"Options:\n"
|
||||
" -v Verbose\n"
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
int cmd_repair(int argc, char *argv[]) {
|
||||
struct drive drive;
|
||||
int verbose = 0;
|
||||
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
|
||||
opterr = 0; // quiet, you
|
||||
while ((c=getopt(argc, argv, ":hv")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
Usage();
|
||||
return CGPT_OK;
|
||||
case '?':
|
||||
Error("unrecognized option: -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
case ':':
|
||||
Error("missing argument to -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
default:
|
||||
errorcnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorcnt)
|
||||
{
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
Error("missing drive argument\n");
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
||||
return CGPT_FAILED;
|
||||
|
||||
int gpt_retval = GptSanityCheck(&drive.gpt);
|
||||
if (verbose)
|
||||
printf("GptSanityCheck() returned %d: %s\n",
|
||||
gpt_retval, GptError(gpt_retval));
|
||||
|
||||
GptRepair(&drive.gpt);
|
||||
if (drive.gpt.modified & GPT_MODIFIED_HEADER1)
|
||||
printf("Primary Header is updated.\n");
|
||||
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1)
|
||||
printf("Primary Entries is updated.\n");
|
||||
if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2)
|
||||
printf("Secondary Entries is updated.\n");
|
||||
if (drive.gpt.modified & GPT_MODIFIED_HEADER2)
|
||||
printf("Secondary Header is updated.\n");
|
||||
|
||||
return DriveClose(&drive, 1);
|
||||
}
|
||||
413
cgpt/cmd_show.c
Normal file
413
cgpt/cmd_show.c
Normal file
@@ -0,0 +1,413 @@
|
||||
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "cgpt.h"
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cgptlib_internal.h"
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
printf("\nUsage: %s show [OPTIONS] DRIVE\n\n"
|
||||
"Display the GPT table\n\n"
|
||||
"Options:\n"
|
||||
" -n Numeric output only\n"
|
||||
" -v Verbose output\n"
|
||||
" -q Quick output\n"
|
||||
" -i NUM Show specified partition only - pick one of:\n"
|
||||
" -b beginning sector\n"
|
||||
" -s partition size\n"
|
||||
" -t type guid\n"
|
||||
" -u unique guid\n"
|
||||
" -l label\n"
|
||||
" -S Successful flag\n"
|
||||
" -T Tries flag\n"
|
||||
" -P Priority flag\n"
|
||||
" -A raw 64-bit attribute value\n"
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
|
||||
/* Generate output like:
|
||||
*
|
||||
* [AB-CD-EF-01] for group = 1
|
||||
* [ABCD-EF01] for group = 3 (low byte first)
|
||||
*
|
||||
* Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
|
||||
*/
|
||||
#define BUFFER_SIZE(size) (size *3 - 1 + 3)
|
||||
static short Uint8To2Chars(const uint8_t t) {
|
||||
int h = t >> 4;
|
||||
int l = t & 0xf;
|
||||
h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
|
||||
l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
|
||||
return (h << 8) + l;
|
||||
}
|
||||
static void RawDump(const uint8_t *memory, const int size,
|
||||
char *buf, int group) {
|
||||
int i, outlen = 0;
|
||||
buf[outlen++] = '[';
|
||||
for (i = 0; i < size; ++i) {
|
||||
short c2 = Uint8To2Chars(memory[i]);
|
||||
buf[outlen++] = c2 >> 8;
|
||||
buf[outlen++] = c2 & 0xff;
|
||||
if (i != (size - 1) && ((i + 1) % group) == 0)
|
||||
buf[outlen++] = '-';
|
||||
}
|
||||
buf[outlen++] = ']';
|
||||
buf[outlen++] = '\0';
|
||||
}
|
||||
|
||||
/* Output formatters */
|
||||
|
||||
|
||||
|
||||
#define TITLE_FMT "%10s%10s%8s %s\n"
|
||||
#define GPT_FMT "%10d%10d%8s %s\n"
|
||||
#define GPT_MORE "%10s%10s%8s ", "", "", ""
|
||||
#define PARTITION_FMT "%10d%10d%8d %s\n"
|
||||
#define PARTITION_MORE "%10s%10s%8s %s%s\n", "", "", ""
|
||||
|
||||
static void HeaderDetails(GptHeader *header, const char *indent, int raw) {
|
||||
int i;
|
||||
|
||||
printf("%sSig: ", indent);
|
||||
if (!raw) {
|
||||
printf("[");
|
||||
for (i = 0; i < sizeof(header->signature); ++i)
|
||||
printf("%c", header->signature[i]);
|
||||
printf("]");
|
||||
} else {
|
||||
char buf[BUFFER_SIZE(sizeof(header->signature))];
|
||||
RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
|
||||
printf("%s", buf);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("%sRev: 0x%08x\n", indent, header->revision);
|
||||
printf("%sSize: %d\n", indent, header->size);
|
||||
printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32);
|
||||
printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
|
||||
printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
|
||||
printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
|
||||
|
||||
{ /* For disk guid */
|
||||
char buf[GUID_STRLEN];
|
||||
GuidToStr(&header->disk_uuid, buf);
|
||||
printf("%sDisk UUID: %s\n", indent, buf);
|
||||
}
|
||||
|
||||
printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
|
||||
printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
|
||||
printf("%sSize of entry: %d\n", indent, header->size_of_entry);
|
||||
printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
|
||||
}
|
||||
|
||||
void EntryDetails(GptEntry *entry, int index, int raw) {
|
||||
char contents[256];
|
||||
uint8_t label[sizeof(entry->name) * 3 / 2];
|
||||
|
||||
if (!raw) {
|
||||
char type[GUID_STRLEN], unique[GUID_STRLEN];;
|
||||
|
||||
UTF16ToUTF8(entry->name, label);
|
||||
snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
|
||||
printf(PARTITION_FMT, (int)entry->starting_lba,
|
||||
(int)(entry->ending_lba - entry->starting_lba + 1),
|
||||
index+1, contents);
|
||||
if (CGPT_OK == ResolveType(&entry->type, type)) {
|
||||
printf(PARTITION_MORE, "Type: ", type);
|
||||
} else {
|
||||
GuidToStr(&entry->type, type);
|
||||
printf(PARTITION_MORE, "Type: ", type);
|
||||
}
|
||||
GuidToStr(&entry->unique, unique);
|
||||
printf(PARTITION_MORE, "UUID: ", unique);
|
||||
if (!memcmp(&guid_chromeos_kernel, &entry->type, sizeof(Guid))) {
|
||||
int tries = (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
|
||||
CGPT_ATTRIBUTE_TRIES_OFFSET;
|
||||
int successful = (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
|
||||
CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
|
||||
int priority = (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
|
||||
CGPT_ATTRIBUTE_PRIORITY_OFFSET;
|
||||
snprintf(contents, sizeof(contents),
|
||||
"priority=%d tries=%d successful=%d",
|
||||
priority, tries, successful);
|
||||
printf(PARTITION_MORE, "Attr: ", contents);
|
||||
}
|
||||
} else {
|
||||
char type[GUID_STRLEN], unique[GUID_STRLEN];
|
||||
|
||||
UTF16ToUTF8(entry->name, label);
|
||||
snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
|
||||
printf(PARTITION_FMT, (int)entry->starting_lba,
|
||||
(int)(entry->ending_lba - entry->starting_lba + 1),
|
||||
index+1, contents);
|
||||
GuidToStr(&entry->type, type);
|
||||
printf(PARTITION_MORE, "Type: ", type);
|
||||
GuidToStr(&entry->unique, unique);
|
||||
printf(PARTITION_MORE, "UUID: ", unique);
|
||||
snprintf(contents, sizeof(contents), "[%" PRIx64 "]", entry->attributes);
|
||||
printf(PARTITION_MORE, "Attr: ", contents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EntriesDetails(GptData *gpt, const int secondary, int raw) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
|
||||
GptEntry *entry;
|
||||
entry = GetEntry(gpt, secondary, i);
|
||||
|
||||
if (!memcmp(&guid_unused, &entry->type, sizeof(Guid))) continue;
|
||||
|
||||
EntryDetails(entry, i, raw);
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_show(int argc, char *argv[]) {
|
||||
struct drive drive;
|
||||
int numeric = 0;
|
||||
int verbose = 0;
|
||||
int quick = 0;
|
||||
int partition = 0;
|
||||
int single_item = 0;
|
||||
int gpt_retval;
|
||||
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
char *e = 0;
|
||||
|
||||
opterr = 0; // quiet, you
|
||||
while ((c=getopt(argc, argv, ":hnvqi:bstulSTPA")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'n':
|
||||
numeric = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'q':
|
||||
quick = 1;
|
||||
break;
|
||||
case 'i':
|
||||
partition = (uint32_t)strtoul(optarg, &e, 0);
|
||||
if (!*optarg || (e && *e))
|
||||
{
|
||||
Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
||||
errorcnt++;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'l':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'P':
|
||||
case 'A':
|
||||
single_item = c;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
Usage();
|
||||
return CGPT_OK;
|
||||
case '?':
|
||||
Error("unrecognized option: -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
case ':':
|
||||
Error("missing argument to -%c\n", optopt);
|
||||
errorcnt++;
|
||||
break;
|
||||
default:
|
||||
errorcnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorcnt)
|
||||
{
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
Error("missing drive argument\n");
|
||||
Usage();
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
||||
return CGPT_FAILED;
|
||||
|
||||
if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
|
||||
Error("GptSanityCheck() returned %d: %s\n",
|
||||
gpt_retval, GptError(gpt_retval));
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
if (partition) { // show single partition
|
||||
|
||||
if (partition > GetNumberOfEntries(&drive.gpt)) {
|
||||
Error("invalid partition number: %d\n", partition);
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
int index = partition - 1;
|
||||
GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
|
||||
char buf[256];
|
||||
|
||||
if (single_item) {
|
||||
switch(single_item) {
|
||||
case 'b':
|
||||
printf("%" PRId64 "\n", entry->starting_lba);
|
||||
break;
|
||||
case 's':
|
||||
printf("%" PRId64 "\n", entry->ending_lba - entry->starting_lba + 1);
|
||||
break;
|
||||
case 't':
|
||||
GuidToStr(&entry->type, buf);
|
||||
printf("%s\n", buf);
|
||||
break;
|
||||
case 'u':
|
||||
GuidToStr(&entry->unique, buf);
|
||||
printf("%s\n", buf);
|
||||
break;
|
||||
case 'l':
|
||||
UTF16ToUTF8(entry->name, (uint8_t *)buf);
|
||||
printf("%s\n", buf);
|
||||
break;
|
||||
case 'S':
|
||||
printf("%d\n", GetSuccessful(&drive.gpt, PRIMARY, index));
|
||||
break;
|
||||
case 'T':
|
||||
printf("%d\n", GetTries(&drive.gpt, PRIMARY, index));
|
||||
break;
|
||||
case 'P':
|
||||
printf("%d\n", GetPriority(&drive.gpt, PRIMARY, index));
|
||||
break;
|
||||
case 'A':
|
||||
printf("0x%" PRIx64 "\n", entry->attributes);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf(TITLE_FMT, "start", "size", "part", "contents");
|
||||
EntryDetails(entry, index, numeric);
|
||||
}
|
||||
|
||||
} else if (quick) { // show all partitions, quickly
|
||||
int i;
|
||||
GptEntry *entry;
|
||||
char type[GUID_STRLEN];
|
||||
|
||||
for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
|
||||
entry = GetEntry(&drive.gpt, PRIMARY, i);
|
||||
|
||||
if (IsZero(&entry->type))
|
||||
continue;
|
||||
|
||||
if (!numeric && CGPT_OK == ResolveType(&entry->type, type)) {
|
||||
} else {
|
||||
GuidToStr(&entry->type, type);
|
||||
}
|
||||
printf(PARTITION_FMT, (int)entry->starting_lba,
|
||||
(int)(entry->ending_lba - entry->starting_lba + 1),
|
||||
i+1, type);
|
||||
}
|
||||
|
||||
} else { // show all partitions
|
||||
|
||||
if (CGPT_OK != ReadPMBR(&drive)) {
|
||||
Error("Unable to read PMBR\n");
|
||||
return CGPT_FAILED;
|
||||
}
|
||||
|
||||
printf(TITLE_FMT, "start", "size", "part", "contents");
|
||||
char buf[256];
|
||||
PMBRToStr(&drive.pmbr, buf);
|
||||
printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
|
||||
|
||||
if (drive.gpt.valid_headers & MASK_PRIMARY) {
|
||||
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
||||
(int)GPT_HEADER_SECTOR, "", "Pri GPT header");
|
||||
if (verbose) {
|
||||
GptHeader *header;
|
||||
char indent[64];
|
||||
|
||||
snprintf(indent, sizeof(indent), GPT_MORE);
|
||||
header = (GptHeader*)drive.gpt.primary_header;
|
||||
HeaderDetails(header, indent, numeric);
|
||||
}
|
||||
} else {
|
||||
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
||||
(int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
|
||||
}
|
||||
|
||||
printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
|
||||
(int)GPT_ENTRIES_SECTORS,
|
||||
drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
|
||||
"Pri GPT table");
|
||||
|
||||
if (drive.gpt.valid_entries & MASK_PRIMARY)
|
||||
EntriesDetails(&drive.gpt, PRIMARY, numeric);
|
||||
|
||||
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
|
||||
GPT_ENTRIES_SECTORS),
|
||||
(int)GPT_ENTRIES_SECTORS,
|
||||
drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
|
||||
"Sec GPT table");
|
||||
/* We show secondary table details if any of following is true.
|
||||
* 1. only secondary is valid.
|
||||
* 2. secondary is not identical to promary.
|
||||
*/
|
||||
if ((drive.gpt.valid_entries & MASK_SECONDARY) &&
|
||||
(!(drive.gpt.valid_entries & MASK_PRIMARY) ||
|
||||
memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
|
||||
TOTAL_ENTRIES_SIZE))) {
|
||||
EntriesDetails(&drive.gpt, SECONDARY, numeric);
|
||||
}
|
||||
|
||||
if (drive.gpt.valid_headers & MASK_SECONDARY)
|
||||
printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
|
||||
(int)GPT_HEADER_SECTOR, "", "Sec GPT header");
|
||||
else
|
||||
printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
||||
(int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
|
||||
/* We show secondary header if any of following is true:
|
||||
* 1. only secondary is valid.
|
||||
* 2. secondary is not synonymous to primary.
|
||||
*/
|
||||
if ((drive.gpt.valid_headers & MASK_SECONDARY) &&
|
||||
(!(drive.gpt.valid_headers & MASK_PRIMARY) ||
|
||||
!IsSynonymous((GptHeader*)drive.gpt.primary_header,
|
||||
(GptHeader*)drive.gpt.secondary_header))) {
|
||||
if (verbose) {
|
||||
GptHeader *header;
|
||||
char indent[64];
|
||||
|
||||
snprintf(indent, sizeof(indent), GPT_MORE);
|
||||
header = (GptHeader*)drive.gpt.secondary_header;
|
||||
HeaderDetails(header, indent, numeric);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(void) CheckValid(&drive);
|
||||
(void) DriveClose(&drive, 0);
|
||||
|
||||
return CGPT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
44
cgpt/endian.h
Normal file
44
cgpt/endian.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_
|
||||
#define VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_
|
||||
|
||||
// Newer distros already have this. For those that don't, we add it here.
|
||||
#include <endian.h>
|
||||
|
||||
#ifndef le16toh
|
||||
|
||||
# include <byteswap.h>
|
||||
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define htobe16(x) __bswap_16 (x)
|
||||
# define htole16(x) (x)
|
||||
# define be16toh(x) __bswap_16 (x)
|
||||
# define le16toh(x) (x)
|
||||
|
||||
# define htobe32(x) __bswap_32 (x)
|
||||
# define htole32(x) (x)
|
||||
# define be32toh(x) __bswap_32 (x)
|
||||
# define le32toh(x) (x)
|
||||
|
||||
# define htobe64(x) __bswap_64 (x)
|
||||
# define htole64(x) (x)
|
||||
# define be64toh(x) __bswap_64 (x)
|
||||
# define le64toh(x) (x)
|
||||
# else
|
||||
# define htobe16(x) (x)
|
||||
# define htole16(x) __bswap_16 (x)
|
||||
# define be16toh(x) (x)
|
||||
# define le16toh(x) __bswap_16 (x)
|
||||
|
||||
# define htobe32(x) (x)
|
||||
# define htole32(x) __bswap_32 (x)
|
||||
# define be32toh(x) (x)
|
||||
# define le32toh(x) __bswap_32 (x)
|
||||
|
||||
# define htobe64(x) (x)
|
||||
# define htole64(x) __bswap_64 (x)
|
||||
# define be64toh(x) (x)
|
||||
# define le64toh(x) __bswap_64 (x)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
#endif // VBOOT_REFERENCE_UTILITY_CGPT_ENDIAN_H_
|
||||
@@ -126,6 +126,8 @@ runtests:
|
||||
./kernel_rollback_tests
|
||||
# Helper Library Tests
|
||||
./cgptlib_test
|
||||
# Tool tests
|
||||
./run_cgpt_tests.sh
|
||||
|
||||
clean:
|
||||
rm -f $(TEST_BINS)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -30,10 +30,21 @@ COL_STOP='\E[0;m'
|
||||
hash_algos=( sha1 sha256 sha512 )
|
||||
key_lengths=( 1024 2048 4096 8192 )
|
||||
|
||||
function check_test_keys {
|
||||
if [ ! -d ${TESTKEY_DIR} ]
|
||||
then
|
||||
echo "You must run gen_test_keys.sh to generate test keys first."
|
||||
exit 1
|
||||
fi
|
||||
function happy {
|
||||
echo -e "${COL_GREEN}$*${COL_STOP}" 1>&2
|
||||
}
|
||||
|
||||
function warning {
|
||||
echo -e "${COL_YELLOW}WARNING: $*${COL_STOP}" 1>&2
|
||||
}
|
||||
|
||||
function error {
|
||||
echo -e "${COL_RED}ERROR: $*${COL_STOP}" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function check_test_keys {
|
||||
[ -d ${TESTKEY_DIR} ] || \
|
||||
error "You must run gen_test_keys.sh to generate test keys first."
|
||||
}
|
||||
|
||||
|
||||
114
tests/run_cgpt_tests.sh
Executable file
114
tests/run_cgpt_tests.sh
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/bash -eu
|
||||
|
||||
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
# Run tests for RSA Signature verification.
|
||||
|
||||
# Load common constants and variables.
|
||||
. "$(dirname "$0")/common.sh"
|
||||
|
||||
GPT=${1:-../cgpt/cgpt}
|
||||
[ -x "$GPT" ] || error "Can't execute $GPT"
|
||||
warning "testing $GPT"
|
||||
|
||||
echo "Create an empty file to use as the device..."
|
||||
NUM_SECTORS=1000
|
||||
DEV=$(mktemp)
|
||||
BOOTFILE=$(mktemp)
|
||||
dd if=/dev/zero of=${DEV} conv=notrunc bs=512 count=${NUM_SECTORS} 2>/dev/null
|
||||
trap "rm -f ${DEV}" EXIT
|
||||
|
||||
|
||||
echo "Create a bunch of partitions, using the real GUID types..."
|
||||
DATA_START=100
|
||||
DATA_SIZE=20
|
||||
DATA_LABEL="data stuff"
|
||||
DATA_GUID='ebd0a0a2-b9e5-4433-87c0-68b6b72699c7'
|
||||
DATA_NUM=1
|
||||
|
||||
KERN_START=200
|
||||
KERN_SIZE=30
|
||||
KERN_LABEL="kernel stuff"
|
||||
KERN_GUID='fe3a2a5d-4f32-41a7-b725-accc3285a309'
|
||||
KERN_NUM=2
|
||||
|
||||
ROOTFS_START=300
|
||||
ROOTFS_SIZE=40
|
||||
ROOTFS_LABEL="rootfs stuff"
|
||||
ROOTFS_GUID='3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec'
|
||||
ROOTFS_NUM=3
|
||||
|
||||
ESP_START=400
|
||||
ESP_SIZE=50
|
||||
ESP_LABEL="ESP stuff"
|
||||
ESP_GUID='c12a7328-f81f-11d2-ba4b-00a0c93ec93b'
|
||||
ESP_NUM=4
|
||||
|
||||
FUTURE_START=500
|
||||
FUTURE_SIZE=60
|
||||
FUTURE_LABEL="future stuff"
|
||||
FUTURE_GUID='2e0a753d-9e48-43b0-8337-b15192cb1b5e'
|
||||
FUTURE_NUM=5
|
||||
|
||||
RANDOM_START=600
|
||||
RANDOM_SIZE=70
|
||||
RANDOM_LABEL="random stuff"
|
||||
RANDOM_GUID='2364a860-bf63-42fb-a83d-9ad3e057fcf5'
|
||||
RANDOM_NUM=6
|
||||
|
||||
$GPT create ${DEV}
|
||||
|
||||
$GPT add -b ${DATA_START} -s ${DATA_SIZE} -t ${DATA_GUID} \
|
||||
-l "${DATA_LABEL}" ${DEV}
|
||||
$GPT add -b ${KERN_START} -s ${KERN_SIZE} -t ${KERN_GUID} \
|
||||
-l "${KERN_LABEL}" ${DEV}
|
||||
$GPT add -b ${ROOTFS_START} -s ${ROOTFS_SIZE} -t ${ROOTFS_GUID} \
|
||||
-l "${ROOTFS_LABEL}" ${DEV}
|
||||
$GPT add -b ${ESP_START} -s ${ESP_SIZE} -t ${ESP_GUID} \
|
||||
-l "${ESP_LABEL}" ${DEV}
|
||||
$GPT add -b ${FUTURE_START} -s ${FUTURE_SIZE} -t ${FUTURE_GUID} \
|
||||
-l "${FUTURE_LABEL}" ${DEV}
|
||||
$GPT add -b ${RANDOM_START} -s ${RANDOM_SIZE} -t ${RANDOM_GUID} \
|
||||
-l "${RANDOM_LABEL}" ${DEV}
|
||||
|
||||
|
||||
echo "Extract the start and size of given partitions..."
|
||||
|
||||
X=$($GPT show -b -i $DATA_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $DATA_NUM ${DEV})
|
||||
[ "$X $Y" = "$DATA_START $DATA_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
X=$($GPT show -b -i $KERN_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $KERN_NUM ${DEV})
|
||||
[ "$X $Y" = "$KERN_START $KERN_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
X=$($GPT show -b -i $ROOTFS_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $ROOTFS_NUM ${DEV})
|
||||
[ "$X $Y" = "$ROOTFS_START $ROOTFS_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
X=$($GPT show -b -i $ESP_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $ESP_NUM ${DEV})
|
||||
[ "$X $Y" = "$ESP_START $ESP_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
X=$($GPT show -b -i $FUTURE_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $FUTURE_NUM ${DEV})
|
||||
[ "$X $Y" = "$FUTURE_START $FUTURE_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
X=$($GPT show -b -i $RANDOM_NUM ${DEV})
|
||||
Y=$($GPT show -s -i $RANDOM_NUM ${DEV})
|
||||
[ "$X $Y" = "$RANDOM_START $RANDOM_SIZE" ] || error "fail at line $LINENO"
|
||||
|
||||
|
||||
echo "Set the boot partition.."
|
||||
$GPT boot -i ${KERN_NUM} ${DEV} >/dev/null
|
||||
|
||||
echo "Check the PMBR's idea of the boot partition..."
|
||||
X=$($GPT boot ${DEV})
|
||||
Y=$($GPT show -u -i $KERN_NUM $DEV)
|
||||
[ "$X" = "$Y" ] || error "fail at line $LINENO"
|
||||
|
||||
echo "Done."
|
||||
|
||||
happy "All tests passed."
|
||||
@@ -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))
|
||||
|
||||
@@ -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)/%,$^)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user