From a05814398202c4147a5e3f28474830ec0a9a0a90 Mon Sep 17 00:00:00 2001 From: Jay Srinivasan Date: Thu, 26 Jan 2012 21:50:05 -0800 Subject: Refactor of cgpt tool for 32->64 autoupdate work. This check-in splits the cgpt into two layers. The top layer (cmd_* files) does the command-line parsing and the bottom layer (cgpt_* files) does the actual cgpt work. This is done so that the bottom layer can be reused for the monolithic C++ post-installer code that will be done in subsequent checkins. BUG=chromium-os:25374 TEST=Tested with existing cgpt unit tests as well as running the cgpt commands manually. Change-Id: I69a31eb3e867a1430cac9a694581331368aa7bb4 Reviewed-on: https://gerrit.chromium.org/gerrit/14940 Reviewed-by: Jay Srinivasan Tested-by: Jay Srinivasan Commit-Ready: Jay Srinivasan --- cgpt/Makefile | 9 +- cgpt/cgpt_add.c | 115 ++++++++++++++++ cgpt/cgpt_boot.c | 96 ++++++++++++++ cgpt/cgpt_create.c | 58 +++++++++ cgpt/cgpt_find.c | 224 ++++++++++++++++++++++++++++++++ cgpt/cgpt_params.h | 98 ++++++++++++++ cgpt/cgpt_prioritize.c | 217 +++++++++++++++++++++++++++++++ cgpt/cgpt_repair.c | 37 ++++++ cgpt/cgpt_show.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++ cgpt/cmd_add.c | 170 +++++------------------- cgpt/cmd_boot.c | 102 ++------------- cgpt/cmd_create.c | 54 ++------ cgpt/cmd_find.c | 283 +++++----------------------------------- cgpt/cmd_prioritize.c | 230 ++------------------------------ cgpt/cmd_repair.c | 39 ++---- cgpt/cmd_show.c | 336 ++--------------------------------------------- 16 files changed, 1312 insertions(+), 1102 deletions(-) create mode 100644 cgpt/cgpt_add.c create mode 100644 cgpt/cgpt_boot.c create mode 100644 cgpt/cgpt_create.c create mode 100644 cgpt/cgpt_find.c create mode 100644 cgpt/cgpt_params.h create mode 100644 cgpt/cgpt_prioritize.c create mode 100644 cgpt/cgpt_repair.c create mode 100644 cgpt/cgpt_show.c diff --git a/cgpt/Makefile b/cgpt/Makefile index d8c2022d..2bd30299 100644 --- a/cgpt/Makefile +++ b/cgpt/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +# Copyright (c) 2012 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. @@ -15,6 +15,13 @@ PROGNAME = ${BUILD_ROOT}/cgpt ALL_SRCS = \ cgpt.c \ + cgpt_create.c \ + cgpt_add.c \ + cgpt_boot.c \ + cgpt_show.c \ + cgpt_repair.c \ + cgpt_prioritize.c \ + cgpt_find.c \ cmd_show.c \ cmd_repair.c \ cmd_create.c \ diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c new file mode 100644 index 00000000..f989fe4d --- /dev/null +++ b/cgpt/cgpt_add.c @@ -0,0 +1,115 @@ +// Copyright (c) 2012 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 + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +int cgpt_add(CgptAddParams *params) { + + struct drive drive; + + int gpt_retval; + GptEntry *entry; + uint32_t index; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &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 (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) || + ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) { + Error("one of the GPT header/entries is invalid.\n" + "please run 'cgpt repair' before adding anything.\n"); + return CGPT_FAILED; + } + + uint32_t max_part = GetNumberOfEntries(&drive.gpt); + if (params->partition) { + if (params->partition > max_part) { + Error("invalid partition number: %d\n", params->partition); + goto bad; + } + index = params->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)) { + params->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 (!params->set_begin || !params->set_size || !params->set_type) { + Error("-t, -b, and -s options are required for new partitions\n"); + goto bad; + } + if (IsZero(¶ms->type_guid)) { + Error("New partitions must have a type other than \"unused\"\n"); + goto bad; + } + if (!params->set_unique) + uuid_generate((uint8_t *)&entry->unique); + } + + if (params->set_begin) + entry->starting_lba = params->begin; + if (params->set_size) + entry->ending_lba = params->begin + params->size - 1; + if (params->set_type) + memcpy(&entry->type, ¶ms->type_guid, sizeof(Guid)); + if (params->set_unique) + memcpy(&entry->unique, ¶ms->unique_guid, sizeof(Guid)); + if (params->label) { + if (CGPT_OK != UTF8ToUTF16((uint8_t *)params->label, entry->name, + sizeof(entry->name) / sizeof(entry->name[0]))) { + Error("The label cannot be converted to UTF16.\n"); + goto bad; + } + } + if (params->set_raw) { + entry->attrs.fields.gpt_att = params->raw_value; + } else { + if (params->set_successful) + SetSuccessful(&drive.gpt, PRIMARY, index, params->successful); + if (params->set_tries) + SetTries(&drive.gpt, PRIMARY, index, params->tries); + if (params->set_priority) + SetPriority(&drive.gpt, PRIMARY, index, params->priority); + } + + RepairEntries(&drive.gpt, MASK_PRIMARY); + RepairHeader(&drive.gpt, MASK_PRIMARY); + + drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | + GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); + UpdateCrc(&drive.gpt); + + // Write it all out + return DriveClose(&drive, 1); + +bad: + (void) DriveClose(&drive, 0); + return CGPT_FAILED; +} diff --git a/cgpt/cgpt_boot.c b/cgpt/cgpt_boot.c new file mode 100644 index 00000000..15e98cfa --- /dev/null +++ b/cgpt/cgpt_boot.c @@ -0,0 +1,96 @@ +// Copyright (c) 2012 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 +#include +#include + +#include "cgptlib_internal.h" +#include "endian.h" +#include "cgpt_params.h" + +int cgpt_boot(CgptBootParams *params) { + struct drive drive; + int retval = 1; + int gpt_retval= 0; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &drive)) + return CGPT_FAILED; + + if (CGPT_OK != ReadPMBR(&drive)) { + Error("Unable to read PMBR\n"); + goto done; + } + + if (params->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 (params->partition) { + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + goto done; + } + + if (params->partition > GetNumberOfEntries(&drive.gpt)) { + Error("invalid partition number: %d\n", params->partition); + goto done; + } + + uint32_t index = params->partition - 1; + GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index); + memcpy(&drive.pmbr.boot_guid, &entry->unique, sizeof(Guid)); + } + + if (params->bootfile) { + int fd = open(params->bootfile, O_RDONLY); + if (fd < 0) { + Error("Can't read %s: %s\n", params->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", params->bootfile, strerror(errno)); + close(fd); + goto done; + } + + close(fd); + } + + char buf[GUID_STRLEN]; + GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf)); + printf("%s\n", buf); + + // Write it all out + if (CGPT_OK == WritePMBR(&drive)) + retval = 0; + +done: + (void) DriveClose(&drive, 1); + return retval; +} diff --git a/cgpt/cgpt_create.c b/cgpt/cgpt_create.c new file mode 100644 index 00000000..61f1133b --- /dev/null +++ b/cgpt/cgpt_create.c @@ -0,0 +1,58 @@ +// Copyright (c) 2012 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 + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +int cgpt_create(CgptCreateParams *params) { + struct drive drive; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &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 (!params->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->alternate_lba = drive.gpt.drive_sectors - 1; + h->first_usable_lba = 1 + 1 + GPT_ENTRIES_SECTORS; + h->last_usable_lba = drive.gpt.drive_sectors - 1 - GPT_ENTRIES_SECTORS - 1; + uuid_generate((uint8_t *)&h->disk_uuid); + h->entries_lba = 2; + h->number_of_entries = 128; + h->size_of_entry = sizeof(GptEntry); + + // Copy to secondary + RepairHeader(&drive.gpt, MASK_PRIMARY); + + UpdateCrc(&drive.gpt); + } + + // Write it all out + return DriveClose(&drive, 1); +} diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c new file mode 100644 index 00000000..30d0e8b0 --- /dev/null +++ b/cgpt/cgpt_find.c @@ -0,0 +1,224 @@ +// Copyright (c) 2012 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 +#include +#include + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +#define BUFSIZE 1024 +// FIXME: currently we only support 512-byte sectors. +#define LBA_SIZE 512 + + +// fill comparebuf with the data to be examined, returning true on success. +static int FillBuffer(CgptFindParams *params, int fd, uint64_t pos, + uint64_t count) { + uint8_t *bufptr = params->comparebuf; + + if (-1 == lseek(fd, pos, SEEK_SET)) + return 0; + + // keep reading until done or error + while (count) { + ssize_t bytes_read = read(fd, bufptr, count); + // negative means error, 0 means (unexpected) EOF + if (bytes_read <= 0) + return 0; + count -= bytes_read; + bufptr += bytes_read; + } + + return 1; +} + +// check partition data content. return true for match, 0 for no match or error +static int match_content(CgptFindParams *params, struct drive *drive, + GptEntry *entry) { + uint64_t part_size; + + if (!params->matchlen) + return 1; + + // Ensure that the region we want to match against is inside the partition. + part_size = LBA_SIZE * (entry->ending_lba - entry->starting_lba + 1); + if (params->matchoffset + params->matchlen > part_size) { + return 0; + } + + // Read the partition data. + if (!FillBuffer(params, + drive->fd, + (LBA_SIZE * entry->starting_lba) + params->matchoffset, + params->matchlen)) { + Error("unable to read partition data\n"); + return 0; + } + + // Compare it + if (0 == memcmp(params->matchbuf, params->comparebuf, params->matchlen)) { + return 1; + } + + // Nope. + return 0; +} + +// This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3, /dev/sda -> /dev/sda3 +static void showmatch(CgptFindParams *params, char *filename, + int partnum, GptEntry *entry) { + char * format = "%s%d\n"; + if (strncmp("/dev/mmcblk", filename, 11) == 0) + format = "%sp%d\n"; + if (params->numeric) + printf("%d\n", partnum); + else + printf(format, filename, partnum); + if (params->verbose > 0) + EntryDetails(entry, partnum - 1, params->numeric); +} + +// This returns true if a GPT partition matches the search criteria. If a match +// isn't found (or if the file doesn't contain a GPT), it returns false. The +// filename and partition number that matched is left in a global, since we +// could have multiple hits. +static int do_search(CgptFindParams *params, char *fileName) { + int retval = 0; + int i; + struct drive drive; + GptEntry *entry; + char partlabel[GPT_PARTNAME_LEN]; + + if (CGPT_OK != DriveOpen(fileName, &drive)) + return 0; + + if (GPT_SUCCESS != GptSanityCheck(&drive.gpt)) { + (void) DriveClose(&drive, 0); + return 0; + } + + for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) { + entry = GetEntry(&drive.gpt, ANY_VALID, i); + + if (IsZero(&entry->type)) + continue; + + int found = 0; + if ((params->set_unique && GuidEqual(¶ms->unique_guid, &entry->unique)) + || (params->set_type && GuidEqual(¶ms->type_guid, &entry->type))) { + found = 1; + } else if (params->set_label) { + if (CGPT_OK != UTF16ToUTF8(entry->name, + sizeof(entry->name) / sizeof(entry->name[0]), + (uint8_t *)partlabel, sizeof(partlabel))) { + Error("The label cannot be converted from UTF16, so abort.\n"); + return 0; + } + if (!strncmp(params->label, partlabel, sizeof(partlabel))) + found = 1; + } + if (found && match_content(params, &drive, entry)) { + params->hits++; + retval++; + showmatch(params, fileName, i+1, entry); + if (!params->match_partnum) + params->match_partnum = i+1; + } + } + + (void) DriveClose(&drive, 0); + + return retval; +} + + +#define PROC_PARTITIONS "/proc/partitions" +#define DEV_DIR "/dev" +#define SYS_BLOCK_DIR "/sys/block" + +static const char *devdirs[] = { "/dev", "/devices", "/devfs", 0 }; + +// Given basename "foo", see if we can find a whole, real device by that name. +// This is copied from the logic in the linux utility 'findfs', although that +// does more exhaustive searching. +static char *is_wholedev(const char *basename) { + int i; + struct stat statbuf; + static char pathname[BUFSIZE]; // we'll return this. + char tmpname[BUFSIZE]; + + // It should be a block device under /dev/, + for (i = 0; devdirs[i]; i++) { + sprintf(pathname, "%s/%s", devdirs[i], basename); + + if (0 != stat(pathname, &statbuf)) + continue; + + if (!S_ISBLK(statbuf.st_mode)) + continue; + + // It should have a symlink called /sys/block/*/device + sprintf(tmpname, "%s/%s/device", SYS_BLOCK_DIR, basename); + + if (0 != lstat(tmpname, &statbuf)) + continue; + + if (!S_ISLNK(statbuf.st_mode)) + continue; + + // found it + return pathname; + } + + return 0; +} + + +// This scans all the physical devices it can find, looking for a match. It +// returns true if any matches were found, false otherwise. +static int scan_real_devs(CgptFindParams *params) { + int found = 0; + char line[BUFSIZE]; + char partname[128]; // max size for /proc/partition lines? + FILE *fp; + char *pathname; + + fp = fopen(PROC_PARTITIONS, "r"); + if (!fp) { + perror("can't read " PROC_PARTITIONS); + return found; + } + + while (fgets(line, sizeof(line), fp)) { + int ma, mi; + long long unsigned int sz; + + if (sscanf(line, " %d %d %llu %127[^\n ]", &ma, &mi, &sz, partname) != 4) + continue; + + if ((pathname = is_wholedev(partname))) { + if (do_search(params, pathname)) { + found++; + } + } + } + + fclose(fp); + return found; +} + + +void cgpt_find(CgptFindParams *params) { + if (params == NULL) + return; + + if (params->driveName != NULL) + do_search(params, params->driveName); + else + scan_real_devs(params); +} diff --git a/cgpt/cgpt_params.h b/cgpt/cgpt_params.h new file mode 100644 index 00000000..1bfb54d1 --- /dev/null +++ b/cgpt/cgpt_params.h @@ -0,0 +1,98 @@ +// Copyright (c) 2012 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_CGPT_CGPT_PARAMS_H_ +#define VBOOT_REFERENCE_CGPT_CGPT_PARAMS_H_ + +#include "cgpt.h" + +// This file defines the internal methods that use the user-mode cgpt programatically. +// This is the interface for the callers such as the cgpt tool or the C++ post installer +// executable. + +typedef struct CgptCreateParams { + char *driveName; + int zap; +} CgptCreateParams; + +typedef struct CgptAddParams { + char *driveName; + uint32_t partition; + uint64_t begin; + uint64_t size; + Guid type_guid; + Guid unique_guid; + char *label; + int successful; + int tries; + int priority; + uint16_t raw_value; + int set_begin; + int set_size; + int set_type; + int set_unique; + int set_successful; + int set_tries; + int set_priority; + int set_raw; +} CgptAddParams; + +typedef struct CgptShowParams { + char *driveName; + int numeric; + int verbose; + int quick; + uint32_t partition; + int single_item; +} CgptShowParams; + +typedef struct CgptRepairParams { + char *driveName; + int verbose; +} CgptRepairParams; + +typedef struct CgptBootParams { + char *driveName; + uint32_t partition; + char *bootfile; + int create_pmbr; +} CgptBootParams; + +typedef struct CgptPrioritizeParams { + char *driveName; + + uint32_t set_partition; + int set_friends; + int max_priority; + int orig_priority; +} CgptPrioritizeParams; + +typedef struct CgptFindParams { + char *driveName; + + int verbose; + int set_unique; + int set_type; + int set_label; + int oneonly; + int numeric; + uint8_t *matchbuf; + uint64_t matchlen; + uint64_t matchoffset; + uint8_t *comparebuf; + Guid unique_guid; + Guid type_guid; + char *label; + int hits; + int match_partnum; // 0 for no match, 1-N for match +} CgptFindParams; + +int cgpt_create(CgptCreateParams *params); +int cgpt_add(CgptAddParams *params); +int cgpt_boot(CgptBootParams *params); +int cgpt_show(CgptShowParams *params); +int cgpt_repair(CgptRepairParams *params); +int cgpt_prioritize(CgptPrioritizeParams *params); +void cgpt_find(CgptFindParams *params); +#endif // VBOOT_REFERENCE_CGPT_CGPT_PARAMS_H_ diff --git a/cgpt/cgpt_prioritize.c b/cgpt/cgpt_prioritize.c new file mode 100644 index 00000000..b28e84c1 --- /dev/null +++ b/cgpt/cgpt_prioritize.c @@ -0,0 +1,217 @@ +// Copyright (c) 2012 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 + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +////////////////////////////////////////////////////////////////////////////// +// We need a sorted list of priority groups, where each element in the list +// contains an unordered list of GPT partition numbers. + +#define MAX_GROUPS 17 // 0-15, plus one "higher" + +typedef struct { + int priority; // priority of this group + int num_parts; // number of partitions in this group + uint32_t *part; // array of partitions in this group +} group_t; + +typedef struct { + int max_parts; // max number of partitions in any group + int num_groups; // number of non-empty groups + group_t group[MAX_GROUPS]; // array of groups +} group_list_t; + + +static group_list_t *NewGroupList(int max_p) { + int i; + group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t)); + require(gl); + gl->max_parts = max_p; + gl->num_groups = 0; + // reserve space for the maximum number of partitions in every group + for (i=0; igroup[i].priority = -1; + gl->group[i].num_parts = 0; + gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p); + require(gl->group[i].part); + } + + return gl; +} + +static void FreeGroups(group_list_t *gl) { + int i; + for (i=0; igroup[i].part); + free(gl); +} + +static void AddToGroup(group_list_t *gl, int priority, int partition) { + int i; + // See if I've already got a group with this priority + for (i=0; inum_groups; i++) + if (gl->group[i].priority == priority) + break; + if (i == gl->num_groups) { + // no, add a group + require(i < MAX_GROUPS); + gl->num_groups++; + gl->group[i].priority = priority; + } + // add the partition to it + int j = gl->group[i].num_parts; + gl->group[i].part[j] = partition; + gl->group[i].num_parts++; +} + +static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) { + int i; + for (i=0; inum_groups; i++) + if (gl->group[i].priority == old_priority) { + gl->group[i].priority = new_priority; + break; + } +} + +static void SortGroups(group_list_t *gl) { + int i, j; + group_t tmp; + + // straight insertion sort is fast enough + for (i=1; inum_groups; i++) { + tmp = gl->group[i]; + for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--) + gl->group[j] = gl->group[j-1]; + gl->group[j] = tmp; + } +} + +int cgpt_prioritize(CgptPrioritizeParams *params) { + struct drive drive; + + int priority; + + int gpt_retval; + GptEntry *entry; + uint32_t index; + uint32_t max_part; + int num_kernels; + int i,j; + group_list_t *groups; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &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; + } + + max_part = GetNumberOfEntries(&drive.gpt); + + if (params->set_partition) { + if (params->set_partition < 1 || params->set_partition > max_part) { + Error("invalid partition number: %d (must be between 1 and %d\n", + params->set_partition, max_part); + goto bad; + } + index = params->set_partition - 1; + // it must be a kernel + entry = GetEntry(&drive.gpt, PRIMARY, index); + if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) { + Error("partition %d is not a ChromeOS kernel\n", params->set_partition); + goto bad; + } + } + + // How many kernel partitions do I have? + num_kernels = 0; + for (i = 0; i < max_part; i++) { + entry = GetEntry(&drive.gpt, PRIMARY, i); + if (GuidEqual(&entry->type, &guid_chromeos_kernel)) + num_kernels++; + } + + if (num_kernels) { + // Determine the current priority groups + groups = NewGroupList(num_kernels); + for (i = 0; i < max_part; i++) { + entry = GetEntry(&drive.gpt, PRIMARY, i); + if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) + continue; + + priority = GetPriority(&drive.gpt, PRIMARY, i); + + // Is this partition special? + if (params->set_partition && (i+1 == params->set_partition)) { + params->orig_priority = priority; // remember the original priority + if (params->set_friends) + AddToGroup(groups, priority, i); // we'll move them all later + else + AddToGroup(groups, 99, i); // move only this one + } else { + AddToGroup(groups, priority, i); // just remember + } + } + + // If we're including friends, then change the original group priority + if (params->set_partition && params->set_friends) { + ChangeGroup(groups, params->orig_priority, 99); + } + + // Sorting gives the new order. Now we just need to reassign the + // priorities. + SortGroups(groups); + + // We'll never lower anything to zero, so if the last group is priority zero + // we can ignore it. + i = groups->num_groups; + if (groups->group[i-1].priority == 0) + groups->num_groups--; + + // Where do we start? + if (params->max_priority) + priority = params->max_priority; + else + priority = groups->num_groups > 15 ? 15 : groups->num_groups; + + // Figure out what the new values should be + for (i=0; inum_groups; i++) { + groups->group[i].priority = priority; + if (priority > 1) + priority--; + } + + // Now apply the ranking to the GPT + for (i=0; inum_groups; i++) + for (j=0; jgroup[i].num_parts; j++) + SetPriority(&drive.gpt, PRIMARY, + groups->group[i].part[j], groups->group[i].priority); + + FreeGroups(groups); + } + + // Write it all out + 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); + + return DriveClose(&drive, 1); + +bad: + (void) DriveClose(&drive, 0); + return CGPT_FAILED; +} diff --git a/cgpt/cgpt_repair.c b/cgpt/cgpt_repair.c new file mode 100644 index 00000000..3d7ca64c --- /dev/null +++ b/cgpt/cgpt_repair.c @@ -0,0 +1,37 @@ +// Copyright (c) 2012 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 + +#include "cgptlib_internal.h" +#include "cgpt_params.h" + +int cgpt_repair(CgptRepairParams *params) { + struct drive drive; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &drive)) + return CGPT_FAILED; + + int gpt_retval = GptSanityCheck(&drive.gpt); + if (params->verbose) + printf("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + + GptRepair(&drive.gpt); + if (drive.gpt.modified & GPT_MODIFIED_HEADER1) + printf("Primary Header is updated.\n"); + if (drive.gpt.modified & GPT_MODIFIED_ENTRIES1) + printf("Primary Entries is updated.\n"); + if (drive.gpt.modified & GPT_MODIFIED_ENTRIES2) + printf("Secondary Entries is updated.\n"); + if (drive.gpt.modified & GPT_MODIFIED_HEADER2) + printf("Secondary Header is updated.\n"); + + return DriveClose(&drive, 1); +} diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c new file mode 100644 index 00000000..068895cb --- /dev/null +++ b/cgpt/cgpt_show.c @@ -0,0 +1,346 @@ +// Copyright (c) 2012 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 + +#include "cgptlib_internal.h" +#include "cgpt_params.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("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_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, GUID_STRLEN); + 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, uint32_t index, int raw) { + char contents[256]; // scratch buffer for formatting output + uint8_t label[GPT_PARTNAME_LEN]; + + if (!raw) { + char type[GUID_STRLEN], unique[GUID_STRLEN]; + + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + label, sizeof(label)); + require(snprintf(contents, sizeof(contents), + "Label: \"%s\"", label) < sizeof(contents)); + 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, GUID_STRLEN); + printf(PARTITION_MORE, "Type: ", type); + } + GuidToStr(&entry->unique, unique, GUID_STRLEN); + printf(PARTITION_MORE, "UUID: ", unique); + if (GuidEqual(&guid_chromeos_kernel, &entry->type)) { + int tries = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_TRIES_MASK) >> + CGPT_ATTRIBUTE_TRIES_OFFSET; + int successful = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> + CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; + int priority = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_PRIORITY_MASK) >> + CGPT_ATTRIBUTE_PRIORITY_OFFSET; + require(snprintf(contents, sizeof(contents), + "priority=%d tries=%d successful=%d", + priority, tries, successful) < sizeof(contents)); + printf(PARTITION_MORE, "Attr: ", contents); + } + } else { + char type[GUID_STRLEN], unique[GUID_STRLEN]; + + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + label, sizeof(label)); + require(snprintf(contents, sizeof(contents), + "Label: \"%s\"", label) < sizeof(contents)); + printf(PARTITION_FMT, (int)entry->starting_lba, + (int)(entry->ending_lba - entry->starting_lba + 1), + index+1, contents); + GuidToStr(&entry->type, type, GUID_STRLEN); + printf(PARTITION_MORE, "Type: ", type); + GuidToStr(&entry->unique, unique, GUID_STRLEN); + printf(PARTITION_MORE, "UUID: ", unique); + require(snprintf(contents, sizeof(contents), + "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents)); + printf(PARTITION_MORE, "Attr: ", contents); + } +} + + +void EntriesDetails(GptData *gpt, const int secondary, int raw) { + uint32_t i; + + for (i = 0; i < GetNumberOfEntries(gpt); ++i) { + GptEntry *entry; + entry = GetEntry(gpt, secondary, i); + + if (IsZero(&entry->type)) + continue; + + EntryDetails(entry, i, raw); + } +} + +int cgpt_show(CgptShowParams *params) { + struct drive drive; + int gpt_retval; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &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 (params->partition) { // show single partition + + if (params->partition > GetNumberOfEntries(&drive.gpt)) { + Error("invalid partition number: %d\n", params->partition); + return CGPT_FAILED; + } + + uint32_t index = params->partition - 1; + GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index); + char buf[256]; // scratch buffer for string conversion + + if (params->single_item) { + switch(params->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, sizeof(buf)); + printf("%s\n", buf); + break; + case 'u': + GuidToStr(&entry->unique, buf, sizeof(buf)); + printf("%s\n", buf); + break; + case 'l': + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + (uint8_t *)buf, sizeof(buf)); + printf("%s\n", buf); + break; + case 'S': + printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index)); + break; + case 'T': + printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index)); + break; + case 'P': + printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index)); + break; + case 'A': + printf("0x%x\n", entry->attrs.fields.gpt_att); + break; + } + } else { + printf(TITLE_FMT, "start", "size", "part", "contents"); + EntryDetails(entry, index, params->numeric); + } + + } else if (params->quick) { // show all partitions, quickly + uint32_t i; + GptEntry *entry; + char type[GUID_STRLEN]; + + for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) { + entry = GetEntry(&drive.gpt, ANY_VALID, i); + + if (IsZero(&entry->type)) + continue; + + if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) { + } else { + GuidToStr(&entry->type, type, GUID_STRLEN); + } + 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]; // buffer for formatted PMBR content + PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small + 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 (params->verbose) { + GptHeader *header; + char indent[64]; + + require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); + header = (GptHeader*)drive.gpt.primary_header; + HeaderDetails(header, indent, params->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, params->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, params->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 (params->verbose) { + GptHeader *header; + char indent[64]; + + require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); + header = (GptHeader*)drive.gpt.secondary_header; + HeaderDetails(header, indent, params->numeric); + } + } + } + + (void) CheckValid(&drive); + (void) DriveClose(&drive, 0); + + return CGPT_OK; +} diff --git a/cgpt/cmd_add.c b/cgpt/cmd_add.c index 81b0dfa1..380bc78a 100644 --- a/cgpt/cmd_add.c +++ b/cgpt/cmd_add.c @@ -1,16 +1,13 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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 -#include -#include #include -#include -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -35,25 +32,9 @@ static void Usage(void) } int cmd_add(int argc, char *argv[]) { - struct drive drive; - uint32_t 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; - uint16_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; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); int gpt_retval; GptEntry *entry; @@ -69,7 +50,7 @@ int cmd_add(int argc, char *argv[]) { switch (c) { case 'i': - partition = (uint32_t)strtoul(optarg, &e, 0); + params.partition = (uint32_t)strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -77,8 +58,8 @@ int cmd_add(int argc, char *argv[]) { } break; case 'b': - set_begin = 1; - begin = strtoull(optarg, &e, 0); + params.set_begin = 1; + params.begin = strtoull(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -86,8 +67,8 @@ int cmd_add(int argc, char *argv[]) { } break; case 's': - set_size = 1; - size = strtoull(optarg, &e, 0); + params.set_size = 1; + params.size = strtoull(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -95,66 +76,66 @@ int cmd_add(int argc, char *argv[]) { } break; case 't': - set_type = 1; - if (CGPT_OK != SupportedType(optarg, &type_guid) && - CGPT_OK != StrToGuid(optarg, &type_guid)) { + params.set_type = 1; + if (CGPT_OK != SupportedType(optarg, ¶ms.type_guid) && + CGPT_OK != StrToGuid(optarg, ¶ms.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)) { + params.set_unique = 1; + if (CGPT_OK != StrToGuid(optarg, ¶ms.unique_guid)) { Error("invalid argument to -%c: %s\n", c, optarg); errorcnt++; } break; case 'l': - label = optarg; + params.label = optarg; break; case 'S': - set_successful = 1; - successful = (uint32_t)strtoul(optarg, &e, 0); + params.set_successful = 1; + params.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) { + if (params.successful < 0 || params.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); + params.set_tries = 1; + params.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) { + if (params.tries < 0 || params.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); + params.set_priority = 1; + params.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) { + if (params.priority < 0 || params.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); + params.set_raw = 1; + params.raw_value = strtoull(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -184,102 +165,13 @@ int cmd_add(int argc, char *argv[]) { return CGPT_FAILED; } - if (optind >= argc) { + 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; - } - - if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) || - ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) { - Error("one of the GPT header/entries is invalid.\n" - "please run 'cgpt repair' before adding anything.\n"); - return CGPT_FAILED; - } - - uint32_t 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) { - if (CGPT_OK != UTF8ToUTF16((uint8_t *)label, entry->name, - sizeof(entry->name) / sizeof(entry->name[0]))) { - Error("The label cannot be converted to UTF16.\n"); - goto bad; - } - } - if (set_raw) { - entry->attrs.fields.gpt_att = 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); + params.driveName = argv[optind]; -bad: - (void) DriveClose(&drive, 0); - return CGPT_FAILED; + return cgpt_add(¶ms); } diff --git a/cgpt/cmd_boot.c b/cgpt/cmd_boot.c index 669e9ae7..a953688d 100644 --- a/cgpt/cmd_boot.c +++ b/cgpt/cmd_boot.c @@ -1,22 +1,13 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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 -#include #include -#include -#include #include -#include -#include -#include -#include -#include "cgptlib_internal.h" -#include "endian.h" +#include "cgpt_params.h" static void Usage(void) { @@ -34,11 +25,10 @@ static void Usage(void) int cmd_boot(int argc, char *argv[]) { struct drive drive; - uint32_t partition = 0; - char *bootfile = 0; - int create_pmbr = 0; - int retval = 1; - int gpt_retval; + + CgptBootParams params; + memset(¶ms, 0, sizeof(params)); + int c; int errorcnt = 0; @@ -50,7 +40,7 @@ int cmd_boot(int argc, char *argv[]) { switch (c) { case 'i': - partition = (uint32_t)strtoul(optarg, &e, 0); + params.partition = (uint32_t)strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -58,10 +48,10 @@ int cmd_boot(int argc, char *argv[]) { } break; case 'b': - bootfile = optarg; + params.bootfile = optarg; break; case 'p': - create_pmbr = 1; + params.create_pmbr = 1; break; case 'h': @@ -91,77 +81,7 @@ int cmd_boot(int argc, char *argv[]) { 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; - } - - uint32_t index = partition - 1; - GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, 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[GUID_STRLEN]; - GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf)); - printf("%s\n", buf); - - // Write it all out - if (CGPT_OK == WritePMBR(&drive)) - retval = 0; + params.driveName = argv[optind]; -done: - (void) DriveClose(&drive, 1); - return retval; + return cgpt_boot(¶ms); } diff --git a/cgpt/cmd_create.c b/cgpt/cmd_create.c index 6dabde3a..1e081f8c 100644 --- a/cgpt/cmd_create.c +++ b/cgpt/cmd_create.c @@ -1,16 +1,13 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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 -#include -#include #include -#include -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -23,7 +20,9 @@ static void Usage(void) int cmd_create(int argc, char *argv[]) { struct drive drive; - int zap = 0; + + CgptCreateParams params; + memset(¶ms, 0, sizeof(params)); int c; int errorcnt = 0; @@ -34,7 +33,7 @@ int cmd_create(int argc, char *argv[]) { switch (c) { case 'z': - zap = 1; + params.zap = 1; break; case 'h': @@ -64,44 +63,7 @@ int cmd_create(int argc, char *argv[]) { 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->alternate_lba = drive.gpt.drive_sectors - 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); - } + params.driveName = argv[optind]; - // Write it all out - return DriveClose(&drive, 1); + return cgpt_create(¶ms); } diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c index 7a0523ff..9b945465 100644 --- a/cgpt/cmd_find.c +++ b/cgpt/cmd_find.c @@ -1,20 +1,13 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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 -#include -#include #include -#include -#include -#include -#include - -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -36,34 +29,6 @@ static void Usage(void) PrintTypes(); } - -// globals -static int verbose = 0; -static int set_unique = 0; -static int set_type = 0; -static int set_label = 0; -static int oneonly = 0; -static int numeric = 0; -static uint8_t *matchbuf = NULL; -static uint64_t matchlen = 0; -static uint64_t matchoffset = 0; -static uint8_t *comparebuf = NULL; - -static Guid unique_guid; -static Guid type_guid; -static char *label; -static int hits = 0; - -#define BUFSIZE 1024 -// FIXME: currently we only support 512-byte sectors. -#define LBA_SIZE 512 - - -// remember one of the possibly many hits -static int match_partnum = 0; // 0 for no match, 1-N for match -static char match_filename[BUFSIZE]; // matching filename - - // read a file into a buffer, return buffer and update size static uint8_t *ReadFile(const char *filename, uint64_t *size) { FILE *f; @@ -94,203 +59,11 @@ static uint8_t *ReadFile(const char *filename, uint64_t *size) { return buf; } -// fill comparebuf with the data to be examined, returning true on success. -static int FillBuffer(int fd, uint64_t pos, uint64_t count) { - uint8_t *bufptr = comparebuf; - - if (-1 == lseek(fd, pos, SEEK_SET)) - return 0; - - // keep reading until done or error - while (count) { - ssize_t bytes_read = read(fd, bufptr, count); - // negative means error, 0 means (unexpected) EOF - if (bytes_read <= 0) - return 0; - count -= bytes_read; - bufptr += bytes_read; - } - - return 1; -} - -// check partition data content. return true for match, 0 for no match or error -static int match_content(struct drive *drive, GptEntry *entry) { - uint64_t part_size; - - if (!matchlen) - return 1; - - // Ensure that the region we want to match against is inside the partition. - part_size = LBA_SIZE * (entry->ending_lba - entry->starting_lba + 1); - if (matchoffset + matchlen > part_size) { - return 0; - } - - // Read the partition data. - if (!FillBuffer(drive->fd, - (LBA_SIZE * entry->starting_lba) + matchoffset, - matchlen)) { - Error("unable to read partition data\n"); - return 0; - } - - // Compare it - if (0 == memcmp(matchbuf, comparebuf, matchlen)) { - return 1; - } - - // Nope. - return 0; -} - -// This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3, /dev/sda -> /dev/sda3 -static void showmatch(char *filename, int partnum, GptEntry *entry) { - char * format = "%s%d\n"; - if (strncmp("/dev/mmcblk", filename, 11) == 0) - format = "%sp%d\n"; - if (numeric) - printf("%d\n", partnum); - else - printf(format, filename, partnum); - if (verbose > 0) - EntryDetails(entry, partnum - 1, numeric); -} - -// This returns true if a GPT partition matches the search criteria. If a match -// isn't found (or if the file doesn't contain a GPT), it returns false. The -// filename and partition number that matched is left in a global, since we -// could have multiple hits. -static int do_search(char *filename) { - int retval = 0; - int i; - struct drive drive; - GptEntry *entry; - char partlabel[GPT_PARTNAME_LEN]; - - if (CGPT_OK != DriveOpen(filename, &drive)) - return 0; - - if (GPT_SUCCESS != GptSanityCheck(&drive.gpt)) { - (void) DriveClose(&drive, 0); - return 0; - } - - for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) { - entry = GetEntry(&drive.gpt, ANY_VALID, i); - - if (IsZero(&entry->type)) - continue; - - int found = 0; - if ((set_unique && GuidEqual(&unique_guid, &entry->unique)) || - (set_type && GuidEqual(&type_guid, &entry->type))) { - found = 1; - } else if (set_label) { - if (CGPT_OK != UTF16ToUTF8(entry->name, - sizeof(entry->name) / sizeof(entry->name[0]), - (uint8_t *)partlabel, sizeof(partlabel))) { - Error("The label cannot be converted from UTF16, so abort.\n"); - return 0; - } - if (!strncmp(label, partlabel, sizeof(partlabel))) { - found = 1; - } - } - if (found && match_content(&drive, entry)) { - hits++; - retval++; - showmatch(filename, i+1, entry); - if (!match_partnum) { - match_partnum = i+1; - strcpy(match_filename, filename); - } - } - } - - (void) DriveClose(&drive, 0); - - return retval; -} - - -#define PROC_PARTITIONS "/proc/partitions" -#define DEV_DIR "/dev" -#define SYS_BLOCK_DIR "/sys/block" - -static const char *devdirs[] = { "/dev", "/devices", "/devfs", 0 }; - -// Given basename "foo", see if we can find a whole, real device by that name. -// This is copied from the logic in the linux utility 'findfs', although that -// does more exhaustive searching. -static char *is_wholedev(const char *basename) { - int i; - struct stat statbuf; - static char pathname[BUFSIZE]; // we'll return this. - char tmpname[BUFSIZE]; - - // It should be a block device under /dev/, - for (i = 0; devdirs[i]; i++) { - sprintf(pathname, "%s/%s", devdirs[i], basename); - - if (0 != stat(pathname, &statbuf)) - continue; - - if (!S_ISBLK(statbuf.st_mode)) - continue; - - // It should have a symlink called /sys/block/*/device - sprintf(tmpname, "%s/%s/device", SYS_BLOCK_DIR, basename); - - if (0 != lstat(tmpname, &statbuf)) - continue; - - if (!S_ISLNK(statbuf.st_mode)) - continue; - - // found it - return pathname; - } - - return 0; -} - - -// This scans all the physical devices it can find, looking for a match. It -// returns true if any matches were found, false otherwise. -static int scan_real_devs(void) { - int found = 0; - char line[BUFSIZE]; - char partname[128]; // max size for /proc/partition lines? - FILE *fp; - char *pathname; - - fp = fopen(PROC_PARTITIONS, "r"); - if (!fp) { - perror("can't read " PROC_PARTITIONS); - return found; - } - - while (fgets(line, sizeof(line), fp)) { - int ma, mi; - long long unsigned int sz; - - if (sscanf(line, " %d %d %llu %127[^\n ]", &ma, &mi, &sz, partname) != 4) - continue; - - if ((pathname = is_wholedev(partname))) { - if (do_search(pathname)) { - found++; - } - } - } - - fclose(fp); - return found; -} +int cmd_find(int argc, char *argv[]) { + CgptFindParams params; + memset(¶ms, 0, sizeof(params)); -int cmd_find(int argc, char *argv[]) { int i; int errorcnt = 0; char *e = 0; @@ -302,49 +75,49 @@ int cmd_find(int argc, char *argv[]) { switch (c) { case 'v': - verbose++; + params.verbose++; break; case 'n': - numeric = 1; + params.numeric = 1; break; case '1': - oneonly = 1; + params.oneonly = 1; break; case 'l': - set_label = 1; - label = optarg; + params.set_label = 1; + params.label = optarg; break; case 't': - set_type = 1; - if (CGPT_OK != SupportedType(optarg, &type_guid) && - CGPT_OK != StrToGuid(optarg, &type_guid)) { + params.set_type = 1; + if (CGPT_OK != SupportedType(optarg, ¶ms.type_guid) && + CGPT_OK != StrToGuid(optarg, ¶ms.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)) { + params.set_unique = 1; + if (CGPT_OK != StrToGuid(optarg, ¶ms.unique_guid)) { Error("invalid argument to -%c: %s\n", c, optarg); errorcnt++; } break; case 'M': - matchbuf = ReadFile(optarg, &matchlen); - if (!matchbuf || !matchlen) { + params.matchbuf = ReadFile(optarg, ¶ms.matchlen); + if (!params.matchbuf || !params.matchlen) { Error("Unable to read from %s\n", optarg); errorcnt++; } // Go ahead and allocate space for the comparison too - comparebuf = (uint8_t *)malloc(matchlen); - if (!comparebuf) { + params.comparebuf = (uint8_t *)malloc(params.matchlen); + if (!params.comparebuf) { Error("Unable to allocate %" PRIu64 "bytes for comparison buffer\n", - matchlen); + params.matchlen); errorcnt++; } break; case 'O': - matchoffset = strtoull(optarg, &e, 0); + params.matchoffset = strtoull(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); errorcnt++; @@ -367,7 +140,7 @@ int cmd_find(int argc, char *argv[]) { break; } } - if (!set_unique && !set_type && !set_label) { + if (!params.set_unique && !params.set_type && !params.set_label) { Error("You must specify at least one of -t, -u, or -l\n"); errorcnt++; } @@ -378,17 +151,19 @@ int cmd_find(int argc, char *argv[]) { } if (optind < argc) { - for (i=optind; i #include #include #include #include -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -33,107 +31,12 @@ static void Usage(void) "\n", progname); } -////////////////////////////////////////////////////////////////////////////// -// I want a sorted list of priority groups, where each element in the list -// contains an unordered list of GPT partition numbers. This is a stupid -// implementation, but our needs are simple and don't justify the time or space -// it would take to write a "better" one. -#define MAX_GROUPS 17 // 0-15, plus one "higher" - -typedef struct { - int priority; // priority of this group - int num_parts; // number of partitions in this group - uint32_t *part; // array of partitions in this group -} group_t; - -typedef struct { - int max_parts; // max number of partitions in any group - int num_groups; // number of non-empty groups - group_t group[MAX_GROUPS]; // array of groups -} group_list_t; - - -static group_list_t *NewGroupList(int max_p) { - int i; - group_list_t *gl = (group_list_t *)malloc(sizeof(group_list_t)); - require(gl); - gl->max_parts = max_p; - gl->num_groups = 0; - // reserve space for the maximum number of partitions in every group - for (i=0; igroup[i].priority = -1; - gl->group[i].num_parts = 0; - gl->group[i].part = (uint32_t *)malloc(sizeof(uint32_t) * max_p); - require(gl->group[i].part); - } - - return gl; -} - -static void FreeGroups(group_list_t *gl) { - int i; - for (i=0; igroup[i].part); - free(gl); -} - -static void AddToGroup(group_list_t *gl, int priority, int partition) { - int i; - // See if I've already got a group with this priority - for (i=0; inum_groups; i++) - if (gl->group[i].priority == priority) - break; - if (i == gl->num_groups) { - // no, add a group - require(i < MAX_GROUPS); - gl->num_groups++; - gl->group[i].priority = priority; - } - // add the partition to it - int j = gl->group[i].num_parts; - gl->group[i].part[j] = partition; - gl->group[i].num_parts++; -} - -static void ChangeGroup(group_list_t *gl, int old_priority, int new_priority) { - int i; - for (i=0; inum_groups; i++) - if (gl->group[i].priority == old_priority) { - gl->group[i].priority = new_priority; - break; - } -} - -static void SortGroups(group_list_t *gl) { - int i, j; - group_t tmp; - - // straight insertion sort is fast enough - for (i=1; inum_groups; i++) { - tmp = gl->group[i]; - for (j=i; j && (gl->group[j-1].priority < tmp.priority); j--) - gl->group[j] = gl->group[j-1]; - gl->group[j] = tmp; - } -} - - -////////////////////////////////////////////////////////////////////////////// - int cmd_prioritize(int argc, char *argv[]) { struct drive drive; - uint32_t set_partition = 0; - int set_friends = 0; - int max_priority = 0; - int priority; - int orig_priority = 0; - int gpt_retval; - GptEntry *entry; - uint32_t index; - uint32_t max_part; - int num_kernels; - int i,j; - group_list_t *groups; + + CgptPrioritizeParams params; + memset(¶ms, 0, sizeof(params)); + int c; int errorcnt = 0; @@ -145,7 +48,7 @@ int cmd_prioritize(int argc, char *argv[]) { switch (c) { case 'i': - set_partition = (uint32_t)strtoul(optarg, &e, 0); + params.set_partition = (uint32_t)strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -153,16 +56,16 @@ int cmd_prioritize(int argc, char *argv[]) { } break; case 'f': - set_friends = 1; + params.set_friends = 1; break; case 'P': - max_priority = (int)strtol(optarg, &e, 0); + params.max_priority = (int)strtol(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); errorcnt++; } - if (max_priority < 1 || max_priority > 15) { + if (params.max_priority < 1 || params.max_priority > 15) { Error("value for -%c must be between 1 and 15\n", c); errorcnt++; } @@ -190,7 +93,7 @@ int cmd_prioritize(int argc, char *argv[]) { return CGPT_FAILED; } - if (set_friends && !set_partition) { + if (params.set_friends && !params.set_partition) { Error("the -f option is only useful with the -i option\n"); Usage(); return CGPT_FAILED; @@ -201,114 +104,7 @@ int cmd_prioritize(int argc, char *argv[]) { 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; - } - - max_part = GetNumberOfEntries(&drive.gpt); - - if (set_partition) { - if (set_partition < 1 || set_partition > max_part) { - Error("invalid partition number: %d (must be between 1 and %d\n", - set_partition, max_part); - goto bad; - } - index = set_partition - 1; - // it must be a kernel - entry = GetEntry(&drive.gpt, PRIMARY, index); - if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) { - Error("partition %d is not a ChromeOS kernel\n", set_partition); - goto bad; - } - } - - // How many kernel partitions do I have? - num_kernels = 0; - for (i = 0; i < max_part; i++) { - entry = GetEntry(&drive.gpt, PRIMARY, i); - if (GuidEqual(&entry->type, &guid_chromeos_kernel)) - num_kernels++; - } - - if (!num_kernels) - // nothing to do, so don't - goto good; - - // Determine the current priority groups - groups = NewGroupList(num_kernels); - for (i = 0; i < max_part; i++) { - entry = GetEntry(&drive.gpt, PRIMARY, i); - if (!GuidEqual(&entry->type, &guid_chromeos_kernel)) - continue; - - priority = GetPriority(&drive.gpt, PRIMARY, i); - - // Is this partition special? - if (set_partition && (i+1 == set_partition)) { - orig_priority = priority; // remember the original priority - if (set_friends) - AddToGroup(groups, priority, i); // we'll move them all later - else - AddToGroup(groups, 99, i); // move only this one - } else { - AddToGroup(groups, priority, i); // just remember - } - } - - // If we're including friends, then change the original group priority - if (set_partition && set_friends) { - ChangeGroup(groups, orig_priority, 99); - } - - // Sorting gives the new order. Now we just need to reassign the - // priorities. - SortGroups(groups); - - // We'll never lower anything to zero, so if the last group is priority zero - // we can ignore it. - i = groups->num_groups; - if (groups->group[i-1].priority == 0) - groups->num_groups--; - - // Where do we start? - if (max_priority) - priority = max_priority; - else - priority = groups->num_groups > 15 ? 15 : groups->num_groups; - - // Figure out what the new values should be - for (i=0; inum_groups; i++) { - groups->group[i].priority = priority; - if (priority > 1) - priority--; - } - - // Now apply the ranking to the GPT - for (i=0; inum_groups; i++) - for (j=0; jgroup[i].num_parts; j++) - SetPriority(&drive.gpt, PRIMARY, - groups->group[i].part[j], groups->group[i].priority); - - FreeGroups(groups); - - - // Write it all out -good: - 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); - - return DriveClose(&drive, 1); + params.driveName = argv[optind]; -bad: - (void) DriveClose(&drive, 0); - return CGPT_FAILED; + return cgpt_prioritize(¶ms); } diff --git a/cgpt/cmd_repair.c b/cgpt/cmd_repair.c index aafdc938..10d4ee8b 100644 --- a/cgpt/cmd_repair.c +++ b/cgpt/cmd_repair.c @@ -1,15 +1,13 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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 -#include -#include #include -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -22,8 +20,10 @@ static void Usage(void) int cmd_repair(int argc, char *argv[]) { struct drive drive; - int verbose = 0; - + + CgptRepairParams params; + memset(¶ms, 0, sizeof(params)); + int c; int errorcnt = 0; @@ -33,7 +33,7 @@ int cmd_repair(int argc, char *argv[]) { switch (c) { case 'v': - verbose++; + params.verbose++; break; case 'h': @@ -58,28 +58,7 @@ int cmd_repair(int argc, char *argv[]) { 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"); + params.driveName = argv[optind]; - return DriveClose(&drive, 1); + return cgpt_repair(¶ms); } diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c index 4942251f..509085ee 100644 --- a/cgpt/cmd_show.c +++ b/cgpt/cmd_show.c @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -7,11 +7,8 @@ #define __STDC_FORMAT_MACROS #include #include -#include -#include #include - -#include "cgptlib_internal.h" +#include "cgpt_params.h" static void Usage(void) { @@ -34,163 +31,11 @@ static void Usage(void) "\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("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_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, GUID_STRLEN); - 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, uint32_t index, int raw) { - char contents[256]; // scratch buffer for formatting output - uint8_t label[GPT_PARTNAME_LEN]; - - if (!raw) { - char type[GUID_STRLEN], unique[GUID_STRLEN]; - - UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), - label, sizeof(label)); - require(snprintf(contents, sizeof(contents), - "Label: \"%s\"", label) < sizeof(contents)); - 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, GUID_STRLEN); - printf(PARTITION_MORE, "Type: ", type); - } - GuidToStr(&entry->unique, unique, GUID_STRLEN); - printf(PARTITION_MORE, "UUID: ", unique); - if (GuidEqual(&guid_chromeos_kernel, &entry->type)) { - int tries = (entry->attrs.fields.gpt_att & - CGPT_ATTRIBUTE_TRIES_MASK) >> - CGPT_ATTRIBUTE_TRIES_OFFSET; - int successful = (entry->attrs.fields.gpt_att & - CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> - CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; - int priority = (entry->attrs.fields.gpt_att & - CGPT_ATTRIBUTE_PRIORITY_MASK) >> - CGPT_ATTRIBUTE_PRIORITY_OFFSET; - require(snprintf(contents, sizeof(contents), - "priority=%d tries=%d successful=%d", - priority, tries, successful) < sizeof(contents)); - printf(PARTITION_MORE, "Attr: ", contents); - } - } else { - char type[GUID_STRLEN], unique[GUID_STRLEN]; - - UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), - label, sizeof(label)); - require(snprintf(contents, sizeof(contents), - "Label: \"%s\"", label) < sizeof(contents)); - printf(PARTITION_FMT, (int)entry->starting_lba, - (int)(entry->ending_lba - entry->starting_lba + 1), - index+1, contents); - GuidToStr(&entry->type, type, GUID_STRLEN); - printf(PARTITION_MORE, "Type: ", type); - GuidToStr(&entry->unique, unique, GUID_STRLEN); - printf(PARTITION_MORE, "UUID: ", unique); - require(snprintf(contents, sizeof(contents), - "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents)); - printf(PARTITION_MORE, "Attr: ", contents); - } -} - - -void EntriesDetails(GptData *gpt, const int secondary, int raw) { - uint32_t i; - - for (i = 0; i < GetNumberOfEntries(gpt); ++i) { - GptEntry *entry; - entry = GetEntry(gpt, secondary, i); - - if (IsZero(&entry->type)) - continue; - - EntryDetails(entry, i, raw); - } -} - int cmd_show(int argc, char *argv[]) { struct drive drive; - int numeric = 0; - int verbose = 0; - int quick = 0; - uint32_t partition = 0; - int single_item = 0; - int gpt_retval; + + CgptShowParams params; + memset(¶ms, 0, sizeof(params)); int c; int errorcnt = 0; @@ -202,16 +47,16 @@ int cmd_show(int argc, char *argv[]) { switch (c) { case 'n': - numeric = 1; + params.numeric = 1; break; case 'v': - verbose = 1; + params.verbose = 1; break; case 'q': - quick = 1; + params.quick = 1; break; case 'i': - partition = (uint32_t)strtoul(optarg, &e, 0); + params.partition = (uint32_t)strtoul(optarg, &e, 0); if (!*optarg || (e && *e)) { Error("invalid argument to -%c: \"%s\"\n", c, optarg); @@ -227,7 +72,7 @@ int cmd_show(int argc, char *argv[]) { case 'T': case 'P': case 'A': - single_item = c; + params.single_item = c; break; case 'h': @@ -258,164 +103,7 @@ int cmd_show(int argc, char *argv[]) { 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; - } - - uint32_t index = partition - 1; - GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index); - char buf[256]; // scratch buffer for string conversion - - 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, sizeof(buf)); - printf("%s\n", buf); - break; - case 'u': - GuidToStr(&entry->unique, buf, sizeof(buf)); - printf("%s\n", buf); - break; - case 'l': - UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), - (uint8_t *)buf, sizeof(buf)); - printf("%s\n", buf); - break; - case 'S': - printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index)); - break; - case 'T': - printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index)); - break; - case 'P': - printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index)); - break; - case 'A': - printf("0x%x\n", entry->attrs.fields.gpt_att); - break; - } - } else { - printf(TITLE_FMT, "start", "size", "part", "contents"); - EntryDetails(entry, index, numeric); - } - - } else if (quick) { // show all partitions, quickly - uint32_t i; - GptEntry *entry; - char type[GUID_STRLEN]; - - for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) { - entry = GetEntry(&drive.gpt, ANY_VALID, i); - - if (IsZero(&entry->type)) - continue; - - if (!numeric && CGPT_OK == ResolveType(&entry->type, type)) { - } else { - GuidToStr(&entry->type, type, GUID_STRLEN); - } - 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]; // buffer for formatted PMBR content - PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small - 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]; - - require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); - 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]; - - require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); - header = (GptHeader*)drive.gpt.secondary_header; - HeaderDetails(header, indent, numeric); - } - } - } - - (void) CheckValid(&drive); - (void) DriveClose(&drive, 0); + params.driveName = argv[optind]; - return CGPT_OK; + return cgpt_show(¶ms); } -- cgit v1.2.1