summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Srinivasan <jaysri@chromium.org>2012-02-16 17:40:45 -0800
committerGerrit <chrome-bot@google.com>2012-02-16 19:18:08 -0800
commit250549d3e742cddaf72b4f53d5739e54faf5db96 (patch)
tree646e9eee48897fc1d912a25443f1736191ac0354
parent2ddd5f64515b4be9847a16de793c59b161221e1b (diff)
downloadvboot-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>
-rw-r--r--Makefile7
-rw-r--r--cgpt/CgptManager.cc427
-rw-r--r--cgpt/CgptManager.h172
-rw-r--r--cgpt/Makefile18
-rw-r--r--cgpt/cgpt.h5
-rw-r--r--cgpt/cgpt_add.c188
-rw-r--r--cgpt/cgpt_boot.c51
-rw-r--r--cgpt/cgpt_create.c2
-rw-r--r--cgpt/cgpt_find.c10
-rw-r--r--cgpt/cgpt_params.h36
-rw-r--r--cgpt/cgpt_prioritize.c2
-rw-r--r--cgpt/cgpt_repair.c2
-rw-r--r--cgpt/cgpt_show.c42
-rw-r--r--cgpt/cmd_add.c4
-rw-r--r--cgpt/cmd_boot.c2
-rw-r--r--cgpt/cmd_create.c2
-rw-r--r--cgpt/cmd_find.c2
-rw-r--r--cgpt/cmd_prioritize.c2
-rw-r--r--cgpt/cmd_repair.c2
-rw-r--r--cgpt/cmd_show.c2
-rw-r--r--common.mk3
-rw-r--r--tests/CgptManagerTests.cc397
-rw-r--r--tests/Makefile20
23 files changed, 1351 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index d939768c..9b4e1622 100644
--- a/Makefile
+++ b/Makefile
@@ -105,6 +105,10 @@ all:
make -C $$i; \
done
+libcgpt_cc: all
+ $(MAKE) -C cgpt libcgpt_cc
+ $(MAKE) -C tests CgptManagerTests
+
clean:
/bin/rm -rf ${BUILD}
@@ -115,6 +119,9 @@ install:
runtests:
$(MAKE) -C tests runtests
+runcgptmanagertests:
+ $(MAKE) -C tests runcgptmanagertests
+
rbtest:
$(MAKE) -C tests rbtest
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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.zap = 0;
+
+ int retval = cgpt_create(&params);
+ 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(&params, 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(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ int retval = cgpt_get_num_non_empty_partitions(&params);
+
+ 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(&params, 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(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+
+ int retval = cgpt_get_boot_partition_number(&params);
+ 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(&params, 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(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 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(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 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(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 0, sizeof(params));
+
+ params.drive_name = const_cast<char *>(device_name_.c_str());
+ params.partition = partition_number;
+
+ int retval = cgpt_get_partition_details(&params);
+ 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(&params, 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(&params);
+ 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(&params, 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(&params);
+ 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, &params->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(&params->type_guid, &entry->type, sizeof(Guid));
+ memcpy(&params->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(&params);
}
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(&params);
}
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(&params);
}
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(&params);
}
} 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(&params);
}
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(&params);
}
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(&params);
}
diff --git a/common.mk b/common.mk
index f0de8798..177605e5 100644
--- a/common.mk
+++ b/common.mk
@@ -17,4 +17,7 @@ all: ${ALL_OBJS}
${BUILD_ROOT}/%.o : %.c
$(CC) $(CFLAGS) $(INCLUDES) -MMD -MF $@.d -c -o $@ $<
+${BUILD_ROOT}/%.o : %.cc
+ $(CXX) $(CFLAGS) $(INCLUDES) -MMD -MF $@.d -c -o $@ $<
+
-include ${ALL_DEPS}
diff --git a/tests/CgptManagerTests.cc b/tests/CgptManagerTests.cc
new file mode 100644
index 00000000..dee6b6c9
--- /dev/null
+++ b/tests/CgptManagerTests.cc
@@ -0,0 +1,397 @@
+// 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.
+
+// Unit tests for CgptManager class.
+#include <string>
+
+#include "../cgpt/CgptManager.h"
+
+// We use some specific GUID constants for some of the tests,
+// so pulling in cgpt.h. Make sure this is included after
+// CgptManager.h so that we can test the actual usage of
+// CgptManager.h as the post-install package would use.
+// Example: this would catch an incorrect usage of a GUID
+// that's defined only in cgpt.h and being accidentally
+// used in CgptManager.h (which should not have any cgpt.h
+// dependencies).
+extern "C" {
+#include "../cgpt/cgpt.h"
+}
+
+#include <base/logging.h>
+#include <gflags/gflags.h>
+#include <gtest/gtest.h>
+
+using std::string;
+
+static const Guid p2guid = {{{0, 1, 2, 3, 4, {2, 2, 2, 2, 2, 2}}}};
+static const Guid p3guid = {{{0, 6, 5, 4, 2, {3, 3, 3, 3, 3, 3}}}};
+
+#define EXPECT_SUCCESS(c) EXPECT_EQ(kCgptSuccess, c)
+
+// The --v flag controls the log verbosity level.
+DEFINE_int32(v, 0, 0);
+
+// This class unit tests the CgptManager class.
+class CgptManagerUnitTest : public ::testing::Test {
+public:
+ CgptManagerUnitTest() { }
+
+ void SetUp() {
+ const string device_name = "/tmp/DummyFileForCgptManagerTests.bin";
+
+ CreateDummyDevice(device_name);
+
+ LOG(INFO) << "Initializing cgpt with " << device_name;
+ EXPECT_SUCCESS(cgpt_manager.Initialize(device_name));
+ EXPECT_SUCCESS(cgpt_manager.ClearAll());
+
+ CheckPartitionCount(0);
+ }
+
+ virtual ~CgptManagerUnitTest() { }
+
+protected:
+ CgptManager cgpt_manager;
+
+ void CreateDummyDevice(const string& dummy_device) {
+ FILE* fp = fopen(dummy_device.c_str(), "w");
+
+ ASSERT_TRUE(fp != NULL);
+
+ const int kNumSectors = 1000;
+ const int kSectorSize = 512;
+ const char kFillChar = '7'; // Some character, value doesn't matter.
+
+ for(int i = 0; i < kNumSectors * kSectorSize; i++) {
+ EXPECT_EQ(kFillChar, fputc(kFillChar, fp));
+ }
+
+ fclose(fp);
+ }
+
+ void CheckEquality(string field,
+ uint64_t expected,
+ uint64_t actual) {
+
+
+ VLOG(1) << field << ":"
+ << "Expected = " << expected
+ << ";Actual = " << actual;
+
+ EXPECT_EQ(expected, actual);
+ }
+
+
+ void CheckGuidEquality(string field,
+ const Guid& expected_id,
+ const Guid& actual_id) {
+ char expected_id_str[GUID_STRLEN];
+ GuidToStr(&expected_id, expected_id_str, sizeof(expected_id_str));
+
+ char actual_id_str[GUID_STRLEN];
+ GuidToStr(&actual_id, actual_id_str, sizeof(actual_id_str));
+
+ VLOG(1) << field << ":"
+ << "Expected = " << expected_id_str
+ << ";Actual = " << actual_id_str;
+
+ EXPECT_TRUE(GuidEqual(&expected_id, &actual_id));
+ }
+
+ // Checks if the current number of partitions in the device matches
+ // the value of expected_num_partitions.
+ void CheckPartitionCount(uint8 expected_num_partitions) {
+ uint8_t actual_num_partitions;
+ EXPECT_SUCCESS(cgpt_manager.GetNumNonEmptyPartitions(
+ &actual_num_partitions));
+
+ CheckEquality("NumPartitions",
+ expected_num_partitions,
+ actual_num_partitions);
+ }
+
+ void SetAndCheckSuccessfulBit(uint32_t partition_number,
+ bool expected_is_successful) {
+ EXPECT_SUCCESS(cgpt_manager.SetSuccessful(partition_number,
+ expected_is_successful));
+
+ bool actual_is_successful;
+ EXPECT_SUCCESS(cgpt_manager.GetSuccessful(partition_number,
+ &actual_is_successful));
+ EXPECT_EQ(expected_is_successful, actual_is_successful);
+ }
+
+
+ void SetAndCheckNumTriesLeft(uint32_t partition_number,
+ int expected_num_tries) {
+ EXPECT_SUCCESS(cgpt_manager.SetNumTriesLeft(partition_number,
+ expected_num_tries));
+
+ int actual_num_tries;
+ EXPECT_SUCCESS(cgpt_manager.GetNumTriesLeft(partition_number,
+ &actual_num_tries));
+ CheckEquality("NumTries", expected_num_tries, actual_num_tries);
+ }
+
+ void SetAndCheckPriority(uint32_t partition_number,
+ uint8_t expected_priority) {
+ EXPECT_SUCCESS(cgpt_manager.SetPriority(partition_number,
+ expected_priority));
+
+ uint8_t actual_priority;
+ EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number,
+ &actual_priority));
+ CheckEquality("Priority", expected_priority, actual_priority);
+ }
+
+ void CheckPriority(uint32_t partition_number,
+ uint8_t expected_priority) {
+ uint8_t actual_priority;
+ EXPECT_SUCCESS(cgpt_manager.GetPriority(partition_number,
+ &actual_priority));
+ CheckEquality("Priority", expected_priority, actual_priority);
+ }
+
+
+ void CheckBeginningOffset(uint32_t partition_number,
+ uint64_t expected_offset) {
+ uint64_t actual_offset;
+ EXPECT_SUCCESS(cgpt_manager.GetBeginningOffset(partition_number,
+ &actual_offset));
+ CheckEquality("Beginning Offset", expected_offset, actual_offset);
+ }
+
+
+ void CheckNumSectors(uint32_t partition_number,
+ uint64_t expected_num_sectors) {
+ uint64_t actual_num_sectors;
+ EXPECT_SUCCESS(cgpt_manager.GetNumSectors(partition_number,
+ &actual_num_sectors));
+ CheckEquality("Num Sectors", expected_num_sectors, actual_num_sectors);
+ }
+
+
+ void CheckPartitionTypeId(int partition_number,
+ const Guid& expected_partition_type_id) {
+ // Get the partition type id and check if it matches the expected value.
+ Guid actual_partition_type_id;
+ EXPECT_SUCCESS(cgpt_manager.GetPartitionTypeId(partition_number,
+ &actual_partition_type_id));
+
+ CheckGuidEquality("PartitionTypeId",
+ expected_partition_type_id,
+ actual_partition_type_id);
+ }
+
+ void CheckPartitionUniqueId(int partition_number,
+ const Guid& expected_partition_unique_id) {
+ // Get the partition unique id and check if it matches the expected value.
+ Guid actual_partition_unique_id;
+ EXPECT_SUCCESS(cgpt_manager.GetPartitionUniqueId(
+ partition_number,
+ &actual_partition_unique_id));
+
+ CheckGuidEquality("PartitionUniqueId",
+ expected_partition_unique_id,
+ actual_partition_unique_id);
+ }
+
+ void CheckPartitionNumberByUniqueId(const Guid& unique_id,
+ uint32_t expected_partition_number) {
+ // Get the partition number for the unique id and check
+ // if it matches the expected value.
+ uint32_t actual_partition_number;
+ EXPECT_SUCCESS(cgpt_manager.GetPartitionNumberByUniqueId(
+ unique_id,
+ &actual_partition_number));
+
+ CheckEquality("PartitionNumberForUniqueId",
+ expected_partition_number,
+ actual_partition_number);
+ }
+
+
+ void CreateBootFile(const string& boot_file_name) {
+ FILE* fp = fopen(boot_file_name.c_str(), "w");
+
+ ASSERT_TRUE(fp != NULL);
+
+ const int kNumSectors = 1;
+ const int kSectorSize = 512;
+ const char kFillChar = '8'; // Some character, value doesn't matter.
+
+ for(int i = 0; i < kNumSectors * kSectorSize; i++) {
+ EXPECT_EQ(kFillChar, fputc(kFillChar, fp));
+ }
+
+ fclose(fp);
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(CgptManagerUnitTest);
+};
+
+TEST_F(CgptManagerUnitTest, AutoPrioritizationTest) {
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("k1",
+ guid_chromeos_kernel,
+ guid_unused,
+ 100,
+ 10));
+ CheckPartitionCount(1);
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("k2",
+ guid_chromeos_kernel,
+ p2guid,
+ 200,
+ 20));
+ CheckPartitionCount(2);
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("k3",
+ guid_chromeos_kernel,
+ p3guid,
+ 300,
+ 30));
+ CheckPartitionCount(3);
+
+ uint8_t expectedk1Priority = 1;
+ uint8_t expectedk2Priority = 2;
+ uint8_t expectedk3Priority = 0;
+
+ // Calling SetAndCheckPriority will do a set and get of the above priorities.
+ SetAndCheckPriority(1, expectedk1Priority);
+ SetAndCheckPriority(2, expectedk2Priority);
+ SetAndCheckPriority(3, expectedk3Priority);
+
+ EXPECT_SUCCESS(cgpt_manager.SetHighestPriority(1));
+
+ expectedk1Priority = 2;
+ expectedk2Priority = 1;
+
+ CheckPriority(1, expectedk1Priority);
+ CheckPriority(2, expectedk2Priority);
+ CheckPriority(3, expectedk3Priority);
+}
+
+
+TEST_F(CgptManagerUnitTest, AddPartitionTest) {
+ int p2_offset = 200;
+ int p2_size = 20;
+ int p3_offset = 300;
+ int p3_size = 30;
+
+ VLOG(1) << "Adding various types of partitions ... ";
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("data stuff",
+ guid_linux_data,
+ guid_unused,
+ 100,
+ 10));
+ CheckPartitionCount(1);
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("kernel stuff",
+ guid_chromeos_kernel,
+ p2guid,
+ p2_offset,
+ p2_size));
+ CheckPartitionCount(2);
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("rootfs stuff",
+ guid_chromeos_rootfs,
+ p3guid,
+ p3_offset,
+ p3_size));
+ CheckPartitionCount(3);
+
+ uint32_t pmbr_boot_partition_number = 4;
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("ESP stuff",
+ guid_efi,
+ guid_unused,
+ 400,
+ 40));
+ CheckPartitionCount(4);
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("fture stuff",
+ guid_chromeos_reserved,
+ guid_unused,
+ 500,
+ 50));
+ CheckPartitionCount(5);
+
+ Guid guid_random = {{{0x2364a860, 0xbf63, 0x42fb, 0xa8, 0x3d,
+ {0x9a, 0xd3, 0xe0, 0x57, 0xfc, 0xf5}}}};
+
+ EXPECT_SUCCESS(cgpt_manager.AddPartition("random stuff",
+ guid_random,
+ guid_unused,
+ 600,
+ 60));
+
+ CheckPartitionCount(6);
+
+ string boot_file_name = "/tmp/BootFileForCgptManagerTests.bin";
+ LOG(INFO) << "Adding EFI partition to PMBR with bootfile: "
+ << boot_file_name;
+
+ CreateBootFile(boot_file_name);
+ EXPECT_SUCCESS(cgpt_manager.SetPmbr(pmbr_boot_partition_number,
+ boot_file_name,
+ true));
+
+ VLOG(1) << "Checking if contents of GPT match values set in AddPartition.";
+
+ uint32_t actual_boot_partition_number;
+ EXPECT_SUCCESS(cgpt_manager.GetPmbrBootPartitionNumber(
+ &actual_boot_partition_number));
+ EXPECT_EQ(pmbr_boot_partition_number, actual_boot_partition_number);
+
+ // Set the successful attribute for some partition to various Values
+ // and check if the settings are preserved.
+ SetAndCheckSuccessfulBit(2, true);
+ SetAndCheckSuccessfulBit(2, false);
+
+ // Set the number of tries for some partition to various Values
+ // and check if the settings are preserved.
+ SetAndCheckNumTriesLeft(2, 6);
+ SetAndCheckNumTriesLeft(2, 5);
+
+ // Set the priority for some partition to various Values
+ // and check if the settings are preserved.
+ SetAndCheckPriority(2, 2);
+ SetAndCheckPriority(2, 0);
+
+ // Check if the beginning offset for some of the partitions
+ // are the same as what was set in AddPartition.
+ CheckBeginningOffset(2, p2_offset);
+ CheckBeginningOffset(3, p3_offset);
+
+ // Check if the number of sectors for some of the partitions
+ // are same as what was set in AddPartition.
+ CheckNumSectors(2, p2_size);
+ CheckNumSectors(3, p3_size);
+
+ // Check if the partition type IDs for some of the partitions
+ // are same as what was set in AddPartition.
+ CheckPartitionTypeId(2, guid_chromeos_kernel);
+ CheckPartitionTypeId(4, guid_efi);
+
+ // Check if the partition unique IDs for some of the partitions
+ // same as what was set in AddPartition.
+ CheckPartitionUniqueId(2, p2guid);
+ CheckPartitionUniqueId(3, p3guid);
+
+ // Check if the partition numbers for some of the partitions are
+ // retrievable by their unique IDs set in AddPartition.
+ CheckPartitionNumberByUniqueId(p2guid, 2);
+ CheckPartitionNumberByUniqueId(p3guid, 3);
+}
+
+int main(int argc, char **argv) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ ::testing::InitGoogleTest(&argc, argv);
+
+ // VLOG(2) logs at level -2. So if user gives --v=2, we should
+ // set MinLogLevel to -2, so VLOG(2) and VLOG(1) will show up.
+ logging::SetMinLogLevel(-FLAGS_v);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/Makefile b/tests/Makefile
index 9fcb5c76..7ab641fc 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,12 +2,18 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+ifeq ($(FIRMWARE_ARCH),)
+CFLAGS += -DCHROMEOS_ENVIRONMENT
+CXXFLAGS += -DCHROMEOS_ENVIRONMENT
+endif
+
INCLUDES += -I./include \
-I$(FWDIR)/lib/include \
-I$(FWDIR)/lib/cgptlib/include \
-I$(FWDIR)/lib/cryptolib/include \
-I$(FWDIR)/lib/tpm_lite/include \
-I$(HOSTDIR)/include
+
BUILD_ROOT = ${BUILD}/tests
TEST_NAMES = cgptlib_test \
@@ -40,6 +46,8 @@ TEST_LIB_OBJS = $(TEST_LIB_SRCS:%.c=${BUILD_ROOT}/%.o)
ALL_DEPS = $(addsuffix .d,${TEST_BINS} ${TEST_LIB_OBJS})
# Allow multiple definitions, so tests can mock functions from other libraries
CFLAGS += -MMD -MF $@.d -Xlinker --allow-multiple-definition
+CXXFLAGS += -MMD -MF $@.d -Xlinker --allow-multiple-definition
+LDFLAGS += -luuid
LIBS := ${TEST_LIB} $(HOSTLIB)
@@ -55,6 +63,14 @@ ${TEST_LIB}: ${TEST_LIB_OBJS}
rm -f $@
ar qc $@ $^
+
+${BUILD_ROOT}/CgptManagerTests.o: CgptManagerTests.cc
+ $(CXX) -DWITH_UTIL_MAIN $(CXXFLAGS) $(INCLUDES) -c $< -o $@
+
+CgptManagerTests: ${BUILD_ROOT}/CgptManagerTests.o ${LIBS}
+ $(CXX) $(CXXFLAGS) $(INCLUDES) $(LDFLAGS) -lgtest -lgflags $^ \
+ ${BUILD}/cgpt/libcgpt-cc.a ${FWLIB} $(HOSTLIB) -lbase -lpthread -lrt -o ${BUILD_ROOT}/$@
+
${BUILD_ROOT}/vboot_audio_for_test.o : $(FWDIR)/lib/vboot_audio.c
$(CC) $(CFLAGS) -DCUSTOM_MUSIC $(INCLUDES) \
-MMD -MF $@.d -c -o $@ $<
@@ -114,6 +130,10 @@ runcgpttests:
${BUILD_ROOT}/cgptlib_test
./run_cgpt_tests.sh ${BUILD}/cgpt/cgpt
+# Run CgptManager tests
+runcgptmanagertests:
+ ${BUILD_ROOT}/CgptManagerTests --v=1
+
# Run crypto tests
runcryptotests:
./run_rsa_tests.sh