summaryrefslogtreecommitdiff
path: root/cgpt
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 /cgpt
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>
Diffstat (limited to 'cgpt')
-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
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(&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);
}