diff options
author | Jay Srinivasan <jaysri@chromium.org> | 2012-02-16 17:40:45 -0800 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-02-16 19:18:08 -0800 |
commit | 250549d3e742cddaf72b4f53d5739e54faf5db96 (patch) | |
tree | 646e9eee48897fc1d912a25443f1736191ac0354 /cgpt | |
parent | 2ddd5f64515b4be9847a16de793c59b161221e1b (diff) | |
download | vboot-250549d3e742cddaf72b4f53d5739e54faf5db96.tar.gz |
Implementation of CgptManager C++ library and unit tests.
CgptManager exposes the cgpt commands via a C++ library so that
the post-installer for 32- to 64-bit upgrade can link directly
against a library and thus avoid any shell dependency.
The default make target will not build libcgpt-cc.a since it
requires some dependencies that are available only in chroot.
A separate follow-up checkin to the vboot_reference
ebuild will enable emerging the libcgpt-cc.a by default.
BUG=chromium-os:25374
TEST=Tested with the new unit tests for CgptManager,
ran existing cgpt unit tests, as well as running the
cgpt commands manually. Built on both amd64 and x86.
Tested that vboot_reference is also buildable outside of chroot.
Tested that vboot_reference-firmware and vboot_reference-tests
also build fine with these changes.
CQ-DEPEND=I99f6c321e09c2425eaa8171d78685d2d731954c8
Change-Id: I59a896255b8ea2fc8b1b2150ae7c4ff9d0769699
Reviewed-on: https://gerrit.chromium.org/gerrit/15730
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
Diffstat (limited to 'cgpt')
-rw-r--r-- | cgpt/CgptManager.cc | 427 | ||||
-rw-r--r-- | cgpt/CgptManager.h | 172 | ||||
-rw-r--r-- | cgpt/Makefile | 18 | ||||
-rw-r--r-- | cgpt/cgpt.h | 5 | ||||
-rw-r--r-- | cgpt/cgpt_add.c | 188 | ||||
-rw-r--r-- | cgpt/cgpt_boot.c | 51 | ||||
-rw-r--r-- | cgpt/cgpt_create.c | 2 | ||||
-rw-r--r-- | cgpt/cgpt_find.c | 10 | ||||
-rw-r--r-- | cgpt/cgpt_params.h | 36 | ||||
-rw-r--r-- | cgpt/cgpt_prioritize.c | 2 | ||||
-rw-r--r-- | cgpt/cgpt_repair.c | 2 | ||||
-rw-r--r-- | cgpt/cgpt_show.c | 42 | ||||
-rw-r--r-- | cgpt/cmd_add.c | 4 | ||||
-rw-r--r-- | cgpt/cmd_boot.c | 2 | ||||
-rw-r--r-- | cgpt/cmd_create.c | 2 | ||||
-rw-r--r-- | cgpt/cmd_find.c | 2 | ||||
-rw-r--r-- | cgpt/cmd_prioritize.c | 2 | ||||
-rw-r--r-- | cgpt/cmd_repair.c | 2 | ||||
-rw-r--r-- | cgpt/cmd_show.c | 2 |
19 files changed, 924 insertions, 47 deletions
diff --git a/cgpt/CgptManager.cc b/cgpt/CgptManager.cc new file mode 100644 index 00000000..67ed5cce --- /dev/null +++ b/cgpt/CgptManager.cc @@ -0,0 +1,427 @@ +// 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 <string.h> + +#include "CgptManager.h" + +extern "C" { +#include "cgpt_params.h" +} + +using std::string; + +// We don't use these variables for the libcgpt version. +const char* progname = ""; +const char* command = ""; + +// This file implements the C++ wrapper methods over the C cgpt methods. + +CgptManager::CgptManager(): + is_initialized_(false) { +} + +CgptManager::~CgptManager() { +} + +CgptErrorCode CgptManager::Initialize(const string& device_name) { + device_name_ = device_name; + is_initialized_ = true; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::ClearAll() { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptCreateParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.zap = 0; + + int retval = cgpt_create(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::AddPartition(const string& label, + const Guid& partition_type_guid, + const Guid& unique_id, + uint64_t beginning_offset, + uint64_t num_sectors) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.label = const_cast<char *>(label.c_str()); + + params.type_guid = partition_type_guid; + params.set_type = 1; + + params.begin = beginning_offset; + params.set_begin = 1; + + params.size = num_sectors; + params.set_size = 1; + + if (!IsZero(&unique_id)) { + params.unique_guid = unique_id; + params.set_unique = 1; + } + + int retval = cgpt_add(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetNumNonEmptyPartitions(uint8_t* num_partitions) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!num_partitions) + return kCgptInvalidArgument; + + CgptShowParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + int retval = cgpt_get_num_non_empty_partitions(¶ms); + + if (retval != CGPT_OK) + return kCgptUnknownError; + + *num_partitions = params.num_partitions; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetPmbr(uint32_t boot_partition_number, + const string& boot_file_name, + bool should_create_legacy_partition) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptBootParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + if (!boot_file_name.empty()) + params.bootfile = const_cast<char *>(boot_file_name.c_str()); + + params.partition = boot_partition_number; + params.create_pmbr = should_create_legacy_partition; + + int retval = cgpt_boot(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetPmbrBootPartitionNumber( + uint32_t* boot_partition) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!boot_partition) + return kCgptInvalidArgument; + + CgptBootParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + + int retval = cgpt_get_boot_partition_number(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *boot_partition = params.partition; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetSuccessful( + uint32_t partition_number, + bool is_successful) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + params.successful = is_successful; + params.set_successful = true; + + int retval = cgpt_set_attributes(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetSuccessful(uint32_t partition_number, + bool* is_successful) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!is_successful) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *is_successful = params.successful; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetNumTriesLeft(uint32_t partition_number, + int numTries) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + params.tries = numTries; + params.set_tries = true; + + int retval = cgpt_set_attributes(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetNumTriesLeft(uint32_t partition_number, + int* numTries) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!numTries) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *numTries = params.tries; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetPriority(uint32_t partition_number, + uint8_t priority) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + params.priority = priority; + params.set_priority = true; + + int retval = cgpt_set_attributes(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetPriority(uint32_t partition_number, + uint8_t* priority) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!priority) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *priority = params.priority; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetBeginningOffset(uint32_t partition_number, + uint64_t* offset) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!offset) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *offset = params.begin; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetNumSectors(uint32_t partition_number, + uint64_t* num_sectors) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!num_sectors) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *num_sectors = params.size; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetPartitionTypeId(uint32_t partition_number, + Guid* type_id) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!type_id) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *type_id = params.type_guid; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetPartitionUniqueId(uint32_t partition_number, + Guid* unique_id) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!unique_id) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.partition = partition_number; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *unique_id = params.unique_guid; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::GetPartitionNumberByUniqueId( + const Guid& unique_id, + uint32_t* partition_number) const { + if (!is_initialized_) + return kCgptNotInitialized; + + if (!partition_number) + return kCgptInvalidArgument; + + CgptAddParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.unique_guid = unique_id; + params.set_unique = 1; + + int retval = cgpt_get_partition_details(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + *partition_number = params.partition; + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetHighestPriority(uint32_t partition_number, + uint8_t highest_priority) { + if (!is_initialized_) + return kCgptNotInitialized; + + CgptPrioritizeParams params; + memset(¶ms, 0, sizeof(params)); + + params.drive_name = const_cast<char *>(device_name_.c_str()); + params.set_partition = partition_number; + params.max_priority = highest_priority; + + int retval = cgpt_prioritize(¶ms); + if (retval != CGPT_OK) + return kCgptUnknownError; + + return kCgptSuccess; +} + +CgptErrorCode CgptManager::SetHighestPriority(uint32_t partition_number) { + // The internal implementation in cgpt_prioritize automatically computes the + // right priority number if we supply 0 for the highest_priority argument. + return SetHighestPriority(partition_number, 0); +} + +CgptErrorCode CgptManager::Validate() { + if (!is_initialized_) + return kCgptNotInitialized; + + uint8_t num_partitions; + + // GetNumNonEmptyPartitions does the check for GptSanityCheck. + // so call it (ignore the num_partitions result) and just return + // its success/failure result. + return GetNumNonEmptyPartitions(&num_partitions); +} diff --git a/cgpt/CgptManager.h b/cgpt/CgptManager.h new file mode 100644 index 00000000..85fd882e --- /dev/null +++ b/cgpt/CgptManager.h @@ -0,0 +1,172 @@ +// 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_CGPTMANAGER_H_ +#define VBOOT_REFERENCE_CGPT_CGPTMANAGER_H_ + +#include <string> +#include <base/basictypes.h> +#include "gpt.h" + +// This file defines a simple C++ wrapper class interface for the cgpt methods. + +// These are the possible error codes that can be returned by the CgptManager. +typedef enum CgptErrorCode +{ + kCgptSuccess = 0, + kCgptNotInitialized = 1, + kCgptUnknownError = 2, + kCgptInvalidArgument = 3, +} CgptErrorCode; + + +// CgptManager exposes methods to manipulate the Guid Partition Table as needed +// for ChromeOS scenarios. +class CgptManager { + public: + // Default constructor. The Initialize method must be called before + // any other method can be called on this class. + CgptManager(); + + // Destructor. Automatically closes any opened device. + ~CgptManager(); + + // Opens the given device_name (e.g. "/dev/sdc") and initializes + // with the Guid Partition Table of that device. This is the first method + // that should be called on this class. Otherwise those methods will + // return kCgptNotInitialized. + // Returns kCgptSuccess or an appropriate error code. + // This device is automatically closed when this object is destructed. + CgptErrorCode Initialize(const std::string& device_name); + + // Clears all the existing contents of the GPT and PMBR on the current + // device. + CgptErrorCode ClearAll(); + + // Adds a new partition at the end of the existing partitions + // with the new label, type, unique Id, offset and size. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode AddPartition(const std::string& label, + const Guid& partition_type_guid, + const Guid& unique_id, + uint64_t beginning_offset, + uint64_t num_sectors); + + // Populates num_partitions parameter with the number of partitions + // that are currently on this device and not empty. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetNumNonEmptyPartitions(uint8_t* num_partitions) const; + + // Sets the Protective Master Boot Record on this device with the given + // boot_partition number after populating the MBR with the contents of the + // given boot_file_name. It also creates a legacy partition if + // should_create_legacy_partition is true. + // Note: Strictly speaking, the PMBR is not part of the GPT, but it is + // included here for ease of use. + CgptErrorCode SetPmbr(uint32_t boot_partition_number, + const std::string& boot_file_name, + bool should_create_legacy_partition); + + // Populates boot_partition with the partition number that's set to + // boot in the PMBR. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetPmbrBootPartitionNumber(uint32_t* boot_partition) const; + + // Sets the "successful" attribute of the given kernelPartition to 0 or 1 + // based on the value of is_successful being true (1) or false(0) + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode SetSuccessful(uint32_t partition_number, bool is_successful); + + // Populates is_successful to true if the successful attribute in the + // given kernelPartition is non-zero, or to false if it's zero. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetSuccessful(uint32_t partition_number, + bool* is_successful) const; + + // Sets the "NumTriesLeft" attribute of the given kernelPartition to + // the given num_tries_left value. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode SetNumTriesLeft(uint32_t partition_number, + int num_tries_left); + + // Populates the num_tries_left parameter with the value of the + // NumTriesLeft attribute of the given kernelPartition. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetNumTriesLeft(uint32_t partition_number, + int* num_tries_left) const; + + // Sets the "Priority" attribute of the given kernelPartition to + // the given priority value. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode SetPriority(uint32_t partition_number, + uint8_t priority); + + // Populates the priority parameter with the value of the Priority + // attribute of the given kernelPartition. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetPriority(uint32_t partition_number, + uint8_t* priority) const; + + // Populates the offset parameter with the beginning offset of the + // given partition. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetBeginningOffset(uint32_t partition_number, + uint64_t* offset) const; + + // Populates the number of sectors in the given partition. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetNumSectors(uint32_t partition_number, + uint64_t* num_sectors) const; + + // Populates the type_id parameter with the partition type id + // (these are the standard ids for kernel, rootfs, etc.) + // of the partition corresponding to the given partition_number. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetPartitionTypeId(uint32_t partition_number, + Guid* type_id) const; + + // Populates the unique_id parameter with the Guid that uniquely identifies + // the given partition_number. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetPartitionUniqueId(uint32_t partition_number, + Guid* unique_id) const; + + // Populates the partition_number parameter with the partition number of + // the partition which is uniquely identified by the given unique_id. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode GetPartitionNumberByUniqueId( + const Guid& unique_id, + uint32_t* partition_number) const; + + // Sets the "Priority" attribute of given kernelPartition to the value + // specified in higestPriority parameter. In addition, also reduces the + // priorities of all the other kernel partitions, if necessary, to ensure + // no other partition has a higher priority. It does preserve the relative + // ordering among the remaining partitions and doesn't touch the partitions + // whose priorities are zero. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode SetHighestPriority(uint32_t partition_number, + uint8_t highest_priority); + + // Same as SetHighestPriority above but works without having to explicitly + // give a value for highest_priority. The internal implementation figures + // out the best highest number that needs to be given depending on the + // existing priorities. + // Returns kCgptSuccess or an appropriate error code. + CgptErrorCode SetHighestPriority(uint32_t partition_number); + + // Runs the sanity checks on the CGPT and MBR and + // Returns kCgptSuccess if everything is valid or an appropriate error code + // if there's anything invalid or if there's any error encountered during + // the validation. + CgptErrorCode Validate(); + + private: + std::string device_name_; + bool is_initialized_; + + DISALLOW_COPY_AND_ASSIGN(CgptManager); +}; + +#endif // VBOOT_REFERENCE_CGPT_CGPTMANAGER_H_ diff --git a/cgpt/Makefile b/cgpt/Makefile index 2bd30299..d3ca978e 100644 --- a/cgpt/Makefile +++ b/cgpt/Makefile @@ -2,8 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -CFLAGS += -static -LDFLAGS += -luuid +LDFLAGS += -luuid -static BUILD_ROOT := ${BUILD}/cgpt INCLUDES = -I$(FWDIR)/lib/cgptlib/include -I$(FWDIR)/include @@ -13,6 +12,8 @@ DESTDIR ?= /usr/bin PROGNAME = ${BUILD_ROOT}/cgpt +LIB_CGPT_CC = ${BUILD_ROOT}/libcgpt-cc.a + ALL_SRCS = \ cgpt.c \ cgpt_create.c \ @@ -31,10 +32,22 @@ ALL_SRCS = \ cmd_prioritize.c \ cgpt_common.c +LIB_CGPT_CC_SRCS = \ + CgptManager.cc + main: $(PROGNAME) include ../common.mk +LIB_CGPT_CC_OBJS = $(LIB_CGPT_CC_SRCS:%.cc=${BUILD_ROOT}/%.o) +LIB_CGPT_CC_DEPS = $(LIB_CGPT_CC_OBJS:%.o=%.o.d) + +libcgpt_cc: main $(LIB_CGPT_CC) + +$(LIB_CGPT_CC): $(ALL_OBJS) $(LIB_CGPT_CC_OBJS) + rm -f $@ + ar qc $@ $^ + $(PROGNAME): $(ALL_OBJS) $(LIBS) $(CC) -o $(PROGNAME) $(CFLAGS) $^ $(LDFLAGS) @@ -44,3 +57,4 @@ install: $(PROGNAME) chmod a+rx $(patsubst ${BUILD_ROOT}/%,$(DESTDIR)/%,$^) .PHONY: all install + diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h index 322f1e26..d510f5ad 100644 --- a/cgpt/cgpt.h +++ b/cgpt/cgpt.h @@ -1,11 +1,14 @@ -// 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. #ifndef VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_ #define VBOOT_REFERENCE_UTILITY_CGPT_CGPT_H_ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #define _FILE_OFFSET_BITS 64 #include <features.h> #include <stdint.h> diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c index f989fe4d..5a3aeec7 100644 --- a/cgpt/cgpt_add.c +++ b/cgpt/cgpt_add.c @@ -9,8 +9,27 @@ #include "cgptlib_internal.h" #include "cgpt_params.h" -int cgpt_add(CgptAddParams *params) { +// This is an internal helper function which assumes no NULL args are passed. +// It sets the given attribute values for a single entry at the given index. +static void set_entry_attributes(struct drive drive, + GptEntry *entry, + uint32_t index, + CgptAddParams *params) { + 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); + } +} +// Set the attributes such as is_successful, num_tries_left, priority, etc. +// from the given values in params. +int cgpt_set_attributes(CgptAddParams *params) { struct drive drive; int gpt_retval; @@ -20,20 +39,164 @@ int cgpt_add(CgptAddParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &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; + goto bad; } 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"); + goto bad; + } + + if (params->partition == 0) { + Error("invalid partition number: %d\n", params->partition); + goto bad; + } + + uint32_t max_part = GetNumberOfEntries(&drive.gpt); + 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); + + set_entry_attributes(drive, entry, index, params); + + 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: + DriveClose(&drive, 0); + return CGPT_FAILED; +} + +// This method gets the partition details such as the attributes, the +// guids of the partitions, etc. Input is the partition number or the +// unique id of the partition. Output is populated in the respective +// fields of params. +int cgpt_get_partition_details(CgptAddParams *params) { + struct drive drive; + + int gpt_retval; + GptEntry *entry; + uint32_t index; + int result = CGPT_FAILED; + + if (params == NULL) + return result; + + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) { + Error("Unable to open drive: %s\n", params->drive_name); + return result; + } + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + goto bad; + } + + 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"); + goto bad; + } + + 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; + } + + // A valid partition number has been specified, so get the entry directly. + index = params->partition - 1; + entry = GetEntry(&drive.gpt, PRIMARY, index); + } else { + // Partition number is not specified, try looking up by the unique id. + if (!params->set_unique) { + Error("either partition or unique_id must be specified\n"); + goto bad; + } + + // A unique id is specified. find the entry that matches it. + for (index = 0; index < max_part; index++) { + entry = GetEntry(&drive.gpt, PRIMARY, index); + if (GuidEqual(&entry->unique, ¶ms->unique_guid)) { + params->partition = index + 1; + break; + } + } + + if (index >= max_part) { + Error("no partitions with the given unique id available\n"); + goto bad; + } + } + + // At this point, irrespective of whether a partition number is specified + // or a unique id is specified, we have valid non-null values for all these: + // index, entry, params->partition. + + params->begin = entry->starting_lba; + params->size = entry->ending_lba - entry->starting_lba + 1; + memcpy(¶ms->type_guid, &entry->type, sizeof(Guid)); + memcpy(¶ms->unique_guid, &entry->unique, sizeof(Guid)); + + params->raw_value = entry->attrs.fields.gpt_att; + params->successful = GetSuccessful(&drive.gpt, PRIMARY, index); + params->tries = GetTries(&drive.gpt, PRIMARY, index); + params->priority = GetPriority(&drive.gpt, PRIMARY, index); + result = CGPT_OK; + +bad: + DriveClose(&drive, 0); + return result; +} + + +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->drive_name, &drive)) return CGPT_FAILED; + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + goto bad; + } + + 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"); + goto bad; } uint32_t max_part = GetNumberOfEntries(&drive.gpt); @@ -45,7 +208,7 @@ int cgpt_add(CgptAddParams *params) { index = params->partition - 1; entry = GetEntry(&drive.gpt, PRIMARY, index); } else { - // find next empty partition + // Find next empty partition. for (index = 0; index < max_part; index++) { entry = GetEntry(&drive.gpt, PRIMARY, index); if (IsZero(&entry->type)) { @@ -88,16 +251,8 @@ int cgpt_add(CgptAddParams *params) { 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); - } + + set_entry_attributes(drive, entry, index, params); RepairEntries(&drive.gpt, MASK_PRIMARY); RepairHeader(&drive.gpt, MASK_PRIMARY); @@ -106,10 +261,11 @@ int cgpt_add(CgptAddParams *params) { GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); UpdateCrc(&drive.gpt); - // Write it all out + // Write it all out. return DriveClose(&drive, 1); bad: - (void) DriveClose(&drive, 0); + DriveClose(&drive, 0); return CGPT_FAILED; } + diff --git a/cgpt/cgpt_boot.c b/cgpt/cgpt_boot.c index 15e98cfa..33c5471c 100644 --- a/cgpt/cgpt_boot.c +++ b/cgpt/cgpt_boot.c @@ -12,6 +12,55 @@ #include "endian.h" #include "cgpt_params.h" + +int cgpt_get_boot_partition_number(CgptBootParams *params) { + struct drive drive; + int gpt_retval= 0; + int retval; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) + return CGPT_FAILED; + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + retval = CGPT_FAILED; + goto done; + } + + if (CGPT_OK != ReadPMBR(&drive)) { + Error("Unable to read PMBR\n"); + goto done; + } + + char buf[GUID_STRLEN]; + GuidToStr(&drive.pmbr.boot_guid, buf, sizeof(buf)); + + int numEntries = GetNumberOfEntries(&drive.gpt); + int i; + for(i = 0; i < numEntries; i++) { + GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i); + + if (GuidEqual(&entry->unique, &drive.pmbr.boot_guid)) { + params->partition = i + 1; + retval = CGPT_OK; + goto done; + } + } + + Error("Didn't find any boot partition\n"); + params->partition = 0; + retval = CGPT_FAILED; + +done: + (void) DriveClose(&drive, 1); + return retval; +} + + int cgpt_boot(CgptBootParams *params) { struct drive drive; int retval = 1; @@ -20,7 +69,7 @@ int cgpt_boot(CgptBootParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; if (CGPT_OK != ReadPMBR(&drive)) { diff --git a/cgpt/cgpt_create.c b/cgpt/cgpt_create.c index 61f1133b..eab61225 100644 --- a/cgpt/cgpt_create.c +++ b/cgpt/cgpt_create.c @@ -15,7 +15,7 @@ int cgpt_create(CgptCreateParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; // Erase the data diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c index 30d0e8b0..20070209 100644 --- a/cgpt/cgpt_find.c +++ b/cgpt/cgpt_find.c @@ -17,7 +17,7 @@ // fill comparebuf with the data to be examined, returning true on success. -static int FillBuffer(CgptFindParams *params, int fd, uint64_t pos, +static int FillBuffer(CgptFindParams *params, int fd, uint64_t pos, uint64_t count) { uint8_t *bufptr = params->comparebuf; @@ -38,7 +38,7 @@ static int FillBuffer(CgptFindParams *params, int fd, uint64_t pos, } // check partition data content. return true for match, 0 for no match or error -static int match_content(CgptFindParams *params, struct drive *drive, +static int match_content(CgptFindParams *params, struct drive *drive, GptEntry *entry) { uint64_t part_size; @@ -70,7 +70,7 @@ static int match_content(CgptFindParams *params, struct drive *drive, } // This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3, /dev/sda -> /dev/sda3 -static void showmatch(CgptFindParams *params, char *filename, +static void showmatch(CgptFindParams *params, char *filename, int partnum, GptEntry *entry) { char * format = "%s%d\n"; if (strncmp("/dev/mmcblk", filename, 11) == 0) @@ -217,8 +217,8 @@ void cgpt_find(CgptFindParams *params) { if (params == NULL) return; - if (params->driveName != NULL) - do_search(params, params->driveName); + if (params->drive_name != NULL) + do_search(params, params->drive_name); else scan_real_devs(params); } diff --git a/cgpt/cgpt_params.h b/cgpt/cgpt_params.h index 1bfb54d1..3daf34a8 100644 --- a/cgpt/cgpt_params.h +++ b/cgpt/cgpt_params.h @@ -8,16 +8,16 @@ #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 +// This is the interface for the callers such as the cgpt tool or the C++ post installer // executable. typedef struct CgptCreateParams { - char *driveName; + char *drive_name; int zap; } CgptCreateParams; typedef struct CgptAddParams { - char *driveName; + char *drive_name; uint32_t partition; uint64_t begin; uint64_t size; @@ -39,28 +39,31 @@ typedef struct CgptAddParams { } CgptAddParams; typedef struct CgptShowParams { - char *driveName; + char *drive_name; int numeric; int verbose; int quick; uint32_t partition; int single_item; + + // This is filled in by the relevant methods in cgpt_show.c + int num_partitions; } CgptShowParams; typedef struct CgptRepairParams { - char *driveName; + char *drive_name; int verbose; } CgptRepairParams; typedef struct CgptBootParams { - char *driveName; + char *drive_name; uint32_t partition; char *bootfile; int create_pmbr; } CgptBootParams; typedef struct CgptPrioritizeParams { - char *driveName; + char *drive_name; uint32_t set_partition; int set_friends; @@ -69,7 +72,7 @@ typedef struct CgptPrioritizeParams { } CgptPrioritizeParams; typedef struct CgptFindParams { - char *driveName; + char *drive_name; int verbose; int set_unique; @@ -88,11 +91,28 @@ typedef struct CgptFindParams { int match_partnum; // 0 for no match, 1-N for match } CgptFindParams; +// create related methods. int cgpt_create(CgptCreateParams *params); + +// add/attribute/details related methods int cgpt_add(CgptAddParams *params); +int cgpt_set_attributes(CgptAddParams *params); +int cgpt_get_partition_details(CgptAddParams *params); + +// boot related methods. int cgpt_boot(CgptBootParams *params); +int cgpt_get_boot_partition_number(CgptBootParams *params); + +// show/get related methods. int cgpt_show(CgptShowParams *params); +int cgpt_get_num_non_empty_partitions(CgptShowParams *params); + +// repair related methods. int cgpt_repair(CgptRepairParams *params); + +// priority related methods. int cgpt_prioritize(CgptPrioritizeParams *params); + +// find related methods. void cgpt_find(CgptFindParams *params); #endif // VBOOT_REFERENCE_CGPT_CGPT_PARAMS_H_ diff --git a/cgpt/cgpt_prioritize.c b/cgpt/cgpt_prioritize.c index b28e84c1..107c00a9 100644 --- a/cgpt/cgpt_prioritize.c +++ b/cgpt/cgpt_prioritize.c @@ -108,7 +108,7 @@ int cgpt_prioritize(CgptPrioritizeParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { diff --git a/cgpt/cgpt_repair.c b/cgpt/cgpt_repair.c index 3d7ca64c..96d3fb1c 100644 --- a/cgpt/cgpt_repair.c +++ b/cgpt/cgpt_repair.c @@ -15,7 +15,7 @@ int cgpt_repair(CgptRepairParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; int gpt_retval = GptSanityCheck(&drive.gpt); diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c index 068895cb..d4170b1c 100644 --- a/cgpt/cgpt_show.c +++ b/cgpt/cgpt_show.c @@ -178,6 +178,42 @@ void EntriesDetails(GptData *gpt, const int secondary, int raw) { } } +int cgpt_get_num_non_empty_partitions(CgptShowParams *params) { + struct drive drive; + int gpt_retval; + int retval; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) + return CGPT_FAILED; + + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { + Error("GptSanityCheck() returned %d: %s\n", + gpt_retval, GptError(gpt_retval)); + retval = CGPT_FAILED; + goto done; + } + + params->num_partitions = 0; + int numEntries = GetNumberOfEntries(&drive.gpt); + int i; + for(i = 0; i < numEntries; i++) { + GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i); + if (IsZero(&entry->type)) + continue; + + params->num_partitions++; + } + + retval = CGPT_OK; + +done: + DriveClose(&drive, 0); + return retval; +} + int cgpt_show(CgptShowParams *params) { struct drive drive; int gpt_retval; @@ -185,7 +221,7 @@ int cgpt_show(CgptShowParams *params) { if (params == NULL) return CGPT_FAILED; - if (CGPT_OK != DriveOpen(params->driveName, &drive)) + if (CGPT_OK != DriveOpen(params->drive_name, &drive)) return CGPT_FAILED; if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { @@ -339,8 +375,8 @@ int cgpt_show(CgptShowParams *params) { } } - (void) CheckValid(&drive); - (void) DriveClose(&drive, 0); + CheckValid(&drive); + DriveClose(&drive, 0); return CGPT_OK; } diff --git a/cgpt/cmd_add.c b/cgpt/cmd_add.c index 380bc78a..62b15996 100644 --- a/cgpt/cmd_add.c +++ b/cgpt/cmd_add.c @@ -165,13 +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; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_add(¶ms); } diff --git a/cgpt/cmd_boot.c b/cgpt/cmd_boot.c index a953688d..fc5c36e7 100644 --- a/cgpt/cmd_boot.c +++ b/cgpt/cmd_boot.c @@ -81,7 +81,7 @@ int cmd_boot(int argc, char *argv[]) { return CGPT_FAILED; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_boot(¶ms); } diff --git a/cgpt/cmd_create.c b/cgpt/cmd_create.c index 1e081f8c..f982be8a 100644 --- a/cgpt/cmd_create.c +++ b/cgpt/cmd_create.c @@ -63,7 +63,7 @@ int cmd_create(int argc, char *argv[]) { return CGPT_FAILED; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_create(¶ms); } diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c index 9b945465..459c101a 100644 --- a/cgpt/cmd_find.c +++ b/cgpt/cmd_find.c @@ -152,7 +152,7 @@ int cmd_find(int argc, char *argv[]) { if (optind < argc) { for (i=optind; i<argc; i++) { - params.driveName = argv[i]; + params.drive_name = argv[i]; cgpt_find(¶ms); } } else { diff --git a/cgpt/cmd_prioritize.c b/cgpt/cmd_prioritize.c index cb655f28..eca72ac8 100644 --- a/cgpt/cmd_prioritize.c +++ b/cgpt/cmd_prioritize.c @@ -104,7 +104,7 @@ int cmd_prioritize(int argc, char *argv[]) { return CGPT_FAILED; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_prioritize(¶ms); } diff --git a/cgpt/cmd_repair.c b/cgpt/cmd_repair.c index 10d4ee8b..493b22b6 100644 --- a/cgpt/cmd_repair.c +++ b/cgpt/cmd_repair.c @@ -58,7 +58,7 @@ int cmd_repair(int argc, char *argv[]) { return CGPT_FAILED; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_repair(¶ms); } diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c index 509085ee..3f22751a 100644 --- a/cgpt/cmd_show.c +++ b/cgpt/cmd_show.c @@ -103,7 +103,7 @@ int cmd_show(int argc, char *argv[]) { return CGPT_FAILED; } - params.driveName = argv[optind]; + params.drive_name = argv[optind]; return cgpt_show(¶ms); } |