Index: src/platform/update_engine/set_bootable_flag_action.cc |
diff --git a/src/platform/update_engine/set_bootable_flag_action.cc b/src/platform/update_engine/set_bootable_flag_action.cc |
index 8075b2cb992ee346def8654171865c4ad85bbdeb..ad574ccf31e08bf358587af4dc4b1cba70e83f04 100644 |
--- a/src/platform/update_engine/set_bootable_flag_action.cc |
+++ b/src/platform/update_engine/set_bootable_flag_action.cc |
@@ -8,110 +8,70 @@ |
#include <errno.h> |
#include <fcntl.h> |
#include <string> |
+#include <vector> |
+#include "update_engine/subprocess.h" |
#include "update_engine/utils.h" |
using std::string; |
+using std::vector; |
namespace chromeos_update_engine { |
-void SetBootableFlagAction::PerformAction() { |
- ScopedActionCompleter completer(processor_, this); |
- |
- if (!HasInputObject() || GetInputObject().empty()) { |
- LOG(ERROR) << "SetBootableFlagAction: No input object."; |
- return; |
- } |
- string device = GetInputObject(); |
- |
- if (device.size() < 2) { |
- LOG(ERROR) << "Device name too short: " << device; |
- return; |
- } |
- |
- // Make sure device is valid. |
- const char last_char = device[device.size() - 1]; |
- if ((last_char < '1') || (last_char > '4')) { |
- LOG(ERROR) << "Bad device:" << device; |
- return; |
- } |
- |
- // We were passed the partition_number'th partition; indexed from 1, not 0 |
- int partition_number = last_char - '0'; |
- |
- const char second_to_last_char = device[device.size() - 2]; |
- if ((second_to_last_char >= '0') && (second_to_last_char <= '9')) { |
- LOG(ERROR) << "Bad device:" << device; |
- return; |
- } |
- |
- // Strip trailing 1-4 off end of device |
- device.resize(device.size() - 1); |
- |
- char mbr[512]; // MBR is the first 512 bytes of the device |
- if (!ReadMbr(mbr, sizeof(mbr), device.c_str())) |
- return; |
- |
- // Check MBR. Verify that last two byes are 0x55aa. This is the MBR signature. |
- if ((mbr[510] != static_cast<char>(0x55)) || |
- (mbr[511] != static_cast<char>(0xaa))) { |
- LOG(ERROR) << "Bad MBR signature"; |
- return; |
- } |
- |
- // Mark partition passed in bootable and all other partitions non bootable. |
- // There are 4 partition table entries, each 16 bytes, stored consecutively |
- // beginning at byte 446. Within each entry, the first byte is the |
- // bootable flag. It's set to 0x80 (bootable) or 0x00 (not bootable). |
- for (int i = 0; i < 4; i++) { |
- int offset = 446 + 16 * i; |
- |
- // partition_number is indexed from 1, not 0 |
- if ((i + 1) == partition_number) |
- mbr[offset] = 0x80; |
- else |
- mbr[offset] = '\0'; |
- } |
- |
- // Write MBR back to disk |
- bool success = WriteMbr(mbr, sizeof(mbr), device.c_str()); |
- if (success) { |
- completer.set_success(true); |
- if (HasOutputPipe()) { |
- SetOutputObject(GetInputObject()); |
- } |
- } |
-} |
- |
-bool SetBootableFlagAction::ReadMbr(char* buffer, |
- int buffer_len, |
- const char* device) { |
- int fd = open(device, O_RDONLY, 0); |
- TEST_AND_RETURN_FALSE(fd >= 0); |
- |
- ssize_t r = read(fd, buffer, buffer_len); |
- close(fd); |
- TEST_AND_RETURN_FALSE(r == buffer_len); |
- |
- return true; |
+namespace { |
+const char* const kGpt = "/usr/bin/gpt"; |
+const ssize_t kPmbrLength = 512; |
} |
-bool SetBootableFlagAction::WriteMbr(const char* buffer, |
- int buffer_len, |
- const char* device) { |
- int fd = open(device, O_WRONLY, 0666); |
- TEST_AND_RETURN_FALSE(fd >= 0); |
- ScopedFdCloser fd_closer(&fd); |
+void SetBootableFlagAction::PerformAction() { |
+ ScopedActionCompleter completer(processor_, this); |
- ssize_t bytes_written = 0; |
- while (bytes_written < buffer_len) { |
- ssize_t r = write(fd, buffer + bytes_written, buffer_len - bytes_written); |
- TEST_AND_RETURN_FALSE_ERRNO(r >= 0); |
- bytes_written += r; |
+ TEST_AND_RETURN(HasInputObject()); |
+ const InstallPlan install_plan = GetInputObject(); |
+ TEST_AND_RETURN(!install_plan.install_path.empty()); |
+ const string partition = install_plan.install_path; |
+ string root_device = utils::RootDevice(partition); |
+ string partition_number = utils::PartitionNumber(partition); |
+ |
+ utils::BootLoader boot_loader; |
+ TEST_AND_RETURN(utils::GetBootloader(&boot_loader)); |
+ |
+ // For now, only support Syslinux bootloader |
+ TEST_AND_RETURN(boot_loader == utils::BootLoader_SYSLINUX); |
+ |
+ string temp_file; |
+ TEST_AND_RETURN(utils::MakeTempFile("/tmp/pmbr_copy.XXXXXX", |
+ &temp_file, |
+ NULL)); |
+ ScopedPathUnlinker temp_file_unlinker(temp_file); |
+ |
+ // Copy existing PMBR to temp file |
+ vector<char> buf(kPmbrLength); |
+ { |
+ int fd = open(root_device.c_str(), O_RDONLY); |
+ TEST_AND_RETURN(fd >= 0); |
+ ScopedFdCloser fd_closer(&fd); |
+ ssize_t bytes_read; |
+ TEST_AND_RETURN(utils::PReadAll(fd, &buf[0], buf.size(), 0, &bytes_read)); |
} |
- TEST_AND_RETURN_FALSE(bytes_written == buffer_len); |
- |
- return true; |
+ TEST_AND_RETURN(utils::WriteFile(temp_file.c_str(), &buf[0], buf.size())); |
+ |
+ // Call gpt tool to do the work |
+ vector<string> command; |
+ command.push_back(kGpt); |
+ command.push_back("-S"); |
+ command.push_back("boot"); |
+ command.push_back("-i"); |
+ command.push_back(partition_number); |
+ command.push_back("-b"); |
+ command.push_back(temp_file); |
+ command.push_back(root_device); |
+ int rc = 0; |
+ Subprocess::SynchronousExec(command, &rc); |
+ TEST_AND_RETURN(rc == 0); |
+ |
+ completer.set_success(true); |
+ if (HasOutputPipe()) |
+ SetOutputObject(GetInputObject()); |
} |
- |
} // namespace chromeos_update_engine |