AU: Many minor cleanup changes
postinstall: Run postinst twice, once for pre-commit (ie, before we
mark the install partition bootable in the partition table), and
post-commit (for after we do). This behavior is needed for specific
types of firmware update.
download action: flush caches, as we found was necessary in
memento_updater.sh
omaha request prep action: update the names of keys we look for in
lsb-release, also get the AU server url from a file, rather than
hard-code it.
set bootable flag action: GPT support.
also, some misc utility functions.
BUG=None
TEST=attached unittests
Review URL: http://codereview.chromium.org/1881001
diff --git a/download_action.cc b/download_action.cc
index 5387821..eee25cc 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -5,10 +5,15 @@
#include "update_engine/download_action.h"
#include <errno.h>
#include <algorithm>
+#include <string>
+#include <vector>
#include <glib.h>
#include "update_engine/action_pipe.h"
+#include "update_engine/subprocess.h"
using std::min;
+using std::string;
+using std::vector;
namespace chromeos_update_engine {
@@ -84,6 +89,22 @@
omaha_hash_calculator_.Update(bytes, length);
}
+namespace {
+void FlushLinuxCaches() {
+ vector<string> command;
+ command.push_back("/bin/sync");
+ int rc;
+ LOG(INFO) << "FlushLinuxCaches/sync...";
+ Subprocess::SynchronousExec(command, &rc);
+ LOG(INFO) << "FlushLinuxCaches/drop_caches...";
+
+ const char* const drop_cmd = "3\n";
+ utils::WriteFile("/proc/sys/vm/drop_caches", drop_cmd, strlen(drop_cmd));
+
+ LOG(INFO) << "FlushLinuxCaches done.";
+}
+}
+
void DownloadAction::TransferComplete(HttpFetcher *fetcher, bool successful) {
if (writer_) {
CHECK_EQ(writer_->Close(), 0) << errno;
@@ -99,6 +120,8 @@
successful = false;
}
}
+
+ FlushLinuxCaches();
// Write the path to the output pipe if we're successful
if (successful && HasOutputPipe())
diff --git a/main.cc b/main.cc
index a796a98..4725967 100644
--- a/main.cc
+++ b/main.cc
@@ -29,7 +29,9 @@
gboolean SetupInMainLoop(void* arg) {
// TODO(adlr): Tell update_attempter to start working.
// Comment this in for that:
- //UpdateAttempter* update_attempter = reinterpret_cast<UpdateAttempter*>(arg);
+ UpdateAttempter* update_attempter = reinterpret_cast<UpdateAttempter*>(arg);
+ LOG(INFO) << "Starting update!";
+ update_attempter->Update(false);
return FALSE; // Don't call this callback function again
}
@@ -59,7 +61,6 @@
if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
g_warning("Got result code %u from requesting name", request_name_ret);
g_error_free(error);
- exit(1);
LOG(FATAL) << "Got result code " << request_name_ret
<< " from requesting name, but expected "
<< DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
diff --git a/omaha_request_prep_action.cc b/omaha_request_prep_action.cc
index 9e144a0..6ee2c24 100644
--- a/omaha_request_prep_action.cc
+++ b/omaha_request_prep_action.cc
@@ -28,9 +28,11 @@
ScopedActionCompleter completer(processor_, this);
string machine_id;
TEST_AND_RETURN(GetMachineId(&machine_id));
- const string version(GetLsbValue("GOOGLE_RELEASE"));
+ const string version(GetLsbValue("CHROMEOS_RELEASE_VERSION", ""));
const string sp(version + "_" + GetMachineType());
- const string track(GetLsbValue("GOOGLE_TRACK"));
+ const string track(GetLsbValue("CHROMEOS_RELEASE_TRACK", ""));
+ const string update_url(GetLsbValue("CHROMEOS_AUSERVER",
+ UpdateCheckParams::kUpdateUrl));
UpdateCheckParams out(machine_id, // machine_id
machine_id, // user_id (use machine_id)
@@ -39,8 +41,9 @@
sp, // e.g. 0.2.3.3_i686
UpdateCheckParams::kAppId,
version, // app version (from lsb-release)
- "en-US", //lang
- track); // track
+ "en-US", // lang
+ track, // track
+ UpdateCheckParams::kUpdateUrl);
CHECK(HasOutputPipe());
SetOutputObject(out);
@@ -89,10 +92,13 @@
return true;
}
-std::string OmahaRequestPrepAction::GetLsbValue(const std::string& key) const {
+string OmahaRequestPrepAction::GetLsbValue(
+ const string& key, const string& default_value) const {
string files[] = {string(utils::kStatefulPartition) + "/etc/lsb-release",
"/etc/lsb-release"};
for (unsigned int i = 0; i < arraysize(files); i++) {
+ // TODO(adlr): make sure files checked are owned as root (and all
+ // their parents are recursively, too).
string file_data;
if (!utils::ReadFileToString(root_ + files[i], &file_data))
continue;
@@ -111,10 +117,10 @@
return file_data.substr(pos, length);
}
// not found
- return "";
+ return default_value;
}
-std::string OmahaRequestPrepAction::GetMachineType() const {
+string OmahaRequestPrepAction::GetMachineType() const {
struct utsname buf;
string ret;
if (uname(&buf) == 0)
diff --git a/omaha_request_prep_action.h b/omaha_request_prep_action.h
index cb82a9f..d6030f5 100644
--- a/omaha_request_prep_action.h
+++ b/omaha_request_prep_action.h
@@ -54,7 +54,8 @@
// Fetches the value for a given key from
// /mnt/stateful_partition/etc/lsb-release if possible. Failing that,
// it looks for the key in /etc/lsb-release .
- std::string GetLsbValue(const std::string& key) const;
+ std::string GetLsbValue(const std::string& key,
+ const std::string& default_value) const;
// Gets the machine type (e.g. "i686")
std::string GetMachineType() const;
diff --git a/omaha_request_prep_action_unittest.cc b/omaha_request_prep_action_unittest.cc
index d5a95e0..01016c3 100644
--- a/omaha_request_prep_action_unittest.cc
+++ b/omaha_request_prep_action_unittest.cc
@@ -111,7 +111,9 @@
{
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
- "GOOGLE_FOO=bar\nGOOGLE_RELEASE=0.2.2.3\nGOOGLE_TRACK=footrack"));
+ "CHROMEOS_RELEASE_FOO=bar\n"
+ "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+ "CHROMEOS_RELEASE_TRACK=footrack"));
UpdateCheckParams out;
EXPECT_TRUE(DoTest(false, &out));
EXPECT_TRUE(IsValidGuid(out.machine_id)) << "id: " << out.machine_id;
@@ -134,7 +136,9 @@
{
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
- "GOOGLE_FOO=bar\nGOOGLE_RELEASE=0.2.2.3\nGOOGLE_TRXCK=footrack"));
+ "CHROMEOS_RELEASE_FOO=bar\n"
+ "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+ "CHROMEOS_RELEASE_TRXCK=footrack"));
UpdateCheckParams out;
EXPECT_TRUE(DoTest(false, &out));
EXPECT_TRUE(IsValidGuid(out.machine_id));
@@ -157,8 +161,9 @@
{
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
- "GOOGLE_FOO=GOOGLE_RELEASE=1.2.3.4\n"
- "GOOGLE_RELEASE=0.2.2.3\nGOOGLE_TRXCK=footrack"));
+ "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
+ "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+ "CHROMEOS_RELEASE_TRXCK=footrack"));
UpdateCheckParams out;
EXPECT_TRUE(DoTest(false, &out));
EXPECT_TRUE(IsValidGuid(out.machine_id)) << out.machine_id;
@@ -180,8 +185,9 @@
utils::kStatefulPartition + "/etc"));
ASSERT_TRUE(WriteFileString(
kTestDir + "/etc/lsb-release",
- "GOOGLE_FOO=GOOGLE_RELEASE=1.2.3.4\n"
- "GOOGLE_RELEASE=0.2.2.3\nGOOGLE_TRXCK=footrack"));
+ "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
+ "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
+ "CHROMEOS_RELEASE_TRXCK=footrack"));
UpdateCheckParams out1;
EXPECT_TRUE(DoTest(false, &out1));
string machine_id;
diff --git a/postinstall_runner_action.cc b/postinstall_runner_action.cc
index 98de1bd..e8f5cc2 100644
--- a/postinstall_runner_action.cc
+++ b/postinstall_runner_action.cc
@@ -5,45 +5,70 @@
#include "update_engine/postinstall_runner_action.h"
#include <sys/mount.h>
#include <stdlib.h>
+#include <vector>
+#include "update_engine/subprocess.h"
#include "update_engine/utils.h"
namespace chromeos_update_engine {
using std::string;
+using std::vector;
namespace {
-const string kMountPath(string(utils::kStatefulPartition) + "/au_destination");
const string kPostinstallScript("/postinst");
}
void PostinstallRunnerAction::PerformAction() {
CHECK(HasInputObject());
- const string install_device = GetInputObject();
+ const InstallPlan install_plan = GetInputObject();
+ const string install_device = install_plan.install_path;
+ ScopedActionCompleter completer(processor_, this);
+
+ utils::BootLoader boot_loader;
+ TEST_AND_RETURN(utils::GetBootloader(&boot_loader));
- int rc = mount(install_device.c_str(), kMountPath.c_str(), "ext3", 0, NULL);
- if (rc < 0) {
- LOG(ERROR) << "Unable to mount destination device " << install_device
- << " onto " << kMountPath;
- processor_->ActionComplete(this, false);
- return;
+ bool read_only = (boot_loader == utils::BootLoader_CHROME_FIRMWARE);
+
+ // Make mountpoint
+ string temp_dir;
+ TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
+ &temp_dir));
+ ScopedDirRemover temp_dir_remover(temp_dir);
+
+ {
+ // Scope for the mount
+ unsigned long mountflags = read_only ? MS_RDONLY : 0;
+
+ int rc = mount(install_device.c_str(),
+ temp_dir.c_str(),
+ "ext3",
+ mountflags,
+ NULL);
+ if (rc < 0) {
+ LOG(ERROR) << "Unable to mount destination device " << install_device
+ << " onto " << temp_dir;
+ return;
+ }
+ ScopedFilesystemUnmounter unmounter(temp_dir);
+
+ // run postinstall script
+ vector<string> command;
+ command.push_back(temp_dir + kPostinstallScript);
+ command.push_back(install_device);
+ command.push_back(precommit_ ? "" : "--postcommit");
+ rc = 0;
+ TEST_AND_RETURN(Subprocess::SynchronousExec(command, &rc));
+ bool success = (rc == 0);
+ if (!success) {
+ LOG(ERROR) << "Postinst command failed with code: " << rc;
+ return;
+ }
}
- // run postinstall script
- rc = system((kMountPath + kPostinstallScript + " " + install_device).c_str());
- bool success = (rc == 0);
- if (!success) {
- LOG(ERROR) << "Postinst command failed with code: " << rc;
+ if (HasOutputPipe()) {
+ SetOutputObject(install_plan);
}
-
- rc = umount(kMountPath.c_str());
- if (rc < 0) {
- // non-fatal
- LOG(ERROR) << "Unable to umount destination device";
- }
- if (success && HasOutputPipe()) {
- SetOutputObject(install_device);
- }
- processor_->ActionComplete(this, success);
+ completer.set_success(true);
}
} // namespace chromeos_update_engine
diff --git a/postinstall_runner_action.h b/postinstall_runner_action.h
index 00478cc..1169af9 100644
--- a/postinstall_runner_action.h
+++ b/postinstall_runner_action.h
@@ -7,6 +7,7 @@
#include <string>
#include "update_engine/action.h"
+#include "update_engine/install_plan.h"
// The Postinstall Runner Action is responsible for running the postinstall
// script of a successfully downloaded update.
@@ -20,14 +21,14 @@
class ActionTraits<PostinstallRunnerAction> {
public:
// Takes the device path as input
- typedef std::string InputObjectType;
+ typedef InstallPlan InputObjectType;
// Passes the device path as output
- typedef std::string OutputObjectType;
+ typedef InstallPlan OutputObjectType;
};
class PostinstallRunnerAction : public Action<PostinstallRunnerAction> {
public:
- PostinstallRunnerAction() {}
+ explicit PostinstallRunnerAction(bool precommit) : precommit_(precommit) {}
typedef ActionTraits<PostinstallRunnerAction>::InputObjectType
InputObjectType;
typedef ActionTraits<PostinstallRunnerAction>::OutputObjectType
@@ -43,6 +44,10 @@
std::string Type() const { return StaticType(); }
private:
+ // If true, this action runs before we've committed to the new update
+ // (by marking it as bootable in the partition table).
+ bool precommit_;
+
DISALLOW_COPY_AND_ASSIGN(PostinstallRunnerAction);
};
diff --git a/postinstall_runner_action_unittest.cc b/postinstall_runner_action_unittest.cc
index 7c1993e..9b19158 100644
--- a/postinstall_runner_action_unittest.cc
+++ b/postinstall_runner_action_unittest.cc
@@ -110,11 +110,13 @@
ASSERT_EQ(0, System(string("losetup ") + dev + " " + cwd + "/image.dat"));
ActionProcessor processor;
- ObjectFeederAction<string> feeder_action;
- feeder_action.set_obj(dev);
- PostinstallRunnerAction runner_action;
+ ObjectFeederAction<InstallPlan> feeder_action;
+ InstallPlan install_plan;
+ install_plan.install_path = dev;
+ feeder_action.set_obj(install_plan);
+ PostinstallRunnerAction runner_action(true);
BondActions(&feeder_action, &runner_action);
- ObjectCollectorAction<string> collector_action;
+ ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&runner_action, &collector_action);
PostinstActionProcessorDelegate delegate;
processor.EnqueueAction(&feeder_action);
@@ -127,9 +129,10 @@
EXPECT_TRUE(delegate.success_set_);
EXPECT_EQ(do_losetup && !do_err_script, delegate.success_);
- EXPECT_EQ(do_losetup && !do_err_script, !collector_action.object().empty());
+ EXPECT_EQ(do_losetup && !do_err_script,
+ !collector_action.object().install_path.empty());
if (do_losetup && !do_err_script) {
- EXPECT_EQ(dev, collector_action.object());
+ EXPECT_TRUE(install_plan == collector_action.object());
}
struct stat stbuf;
@@ -148,7 +151,7 @@
// Death tests don't seem to be working on Hardy
TEST_F(PostinstallRunnerActionTest, DISABLED_RunAsRootDeathTest) {
ASSERT_EQ(0, getuid());
- PostinstallRunnerAction runner_action;
+ PostinstallRunnerAction runner_action(true);
ASSERT_DEATH({ runner_action.TerminateProcessing(); },
"postinstall_runner_action.h:.*] Check failed");
}
diff --git a/set_bootable_flag_action.cc b/set_bootable_flag_action.cc
index 8075b2c..ad574cc 100644
--- a/set_bootable_flag_action.cc
+++ b/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 {
+namespace {
+const char* const kGpt = "/usr/bin/gpt";
+const ssize_t kPmbrLength = 512;
+}
+
void SetBootableFlagAction::PerformAction() {
ScopedActionCompleter completer(processor_, this);
- if (!HasInputObject() || GetInputObject().empty()) {
- LOG(ERROR) << "SetBootableFlagAction: No input object.";
- return;
+ 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));
}
- string device = GetInputObject();
+ TEST_AND_RETURN(utils::WriteFile(temp_file.c_str(), &buf[0], buf.size()));
- if (device.size() < 2) {
- LOG(ERROR) << "Device name too short: " << device;
- return;
- }
+ // 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);
- // 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());
- }
- }
+ 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;
-}
-
-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);
-
- 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_FALSE(bytes_written == buffer_len);
-
- return true;
-}
-
-
} // namespace chromeos_update_engine
diff --git a/set_bootable_flag_action.h b/set_bootable_flag_action.h
index 44e9555..2b45df3 100644
--- a/set_bootable_flag_action.h
+++ b/set_bootable_flag_action.h
@@ -7,6 +7,7 @@
#include <string>
#include "update_engine/action.h"
+#include "update_engine/install_plan.h"
// This class takes in a device via the input pipe. The device is the
// partition (e.g. /dev/sda1), not the full device (e.g. /dev/sda).
@@ -22,9 +23,9 @@
class ActionTraits<SetBootableFlagAction> {
public:
// Takes the device path as input.
- typedef std::string InputObjectType;
+ typedef InstallPlan InputObjectType;
// Passes the device path as output
- typedef std::string OutputObjectType;
+ typedef InstallPlan OutputObjectType;
};
class SetBootableFlagAction : public Action<SetBootableFlagAction> {
@@ -45,11 +46,6 @@
std::string Type() const { return StaticType(); }
private:
- // Returns true on success
- bool ReadMbr(char* buffer, int buffer_len, const char* device);
-
- // Returns true on success
- bool WriteMbr(const char* buffer, int buffer_len, const char* device);
DISALLOW_COPY_AND_ASSIGN(SetBootableFlagAction);
};
diff --git a/set_bootable_flag_action_unittest.cc b/set_bootable_flag_action_unittest.cc
index 023c7bd..d2a211b 100644
--- a/set_bootable_flag_action_unittest.cc
+++ b/set_bootable_flag_action_unittest.cc
@@ -17,137 +17,17 @@
namespace chromeos_update_engine {
-class SetBootableFlagActionProcessorDelegate : public ActionProcessorDelegate {
- public:
- SetBootableFlagActionProcessorDelegate()
- : success_(false), success_set_(false) {}
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- bool success) {
- if (action->Type() == SetBootableFlagAction::StaticType()) {
- success_ = success;
- success_set_ = true;
- }
- }
- bool success_;
- bool success_set_;
-};
+class SetBootableFlagActionTest : public ::testing::Test {};
-class SetBootableFlagActionTest : public ::testing::Test {
- public:
- SetBootableFlagActionTest();
- protected:
- enum TestFlags {
- EXPECT_SUCCESS = 0x01,
- WRITE_FILE = 0x02,
- SKIP_INPUT_OBJECT = 0x04
- };
- static const char* kTestDir;
- virtual void SetUp() {
- EXPECT_EQ(0, mkdir(kTestDir, 0755));
- }
- virtual void TearDown() {
- EXPECT_EQ(0, System(string("rm -rf ") + kTestDir));
- }
- vector<char> DoTest(vector<char> mbr_in,
- const string& filename,
- uint32_t test_flags);
- // first partition bootable, no others bootable
- const vector<char> sample_mbr_;
-};
-
-const char* SetBootableFlagActionTest::kTestDir =
- "SetBootableFlagActionTestDir";
-
-SetBootableFlagActionTest::SetBootableFlagActionTest()
- : sample_mbr_(GenerateSampleMbr()) {}
-
-vector<char> SetBootableFlagActionTest::DoTest(vector<char> mbr_in,
- const string& filename,
- uint32_t flags) {
- CHECK(!filename.empty());
- const string root_filename(filename.begin(), --filename.end());
- if (flags & WRITE_FILE)
- EXPECT_TRUE(WriteFileVector(root_filename, mbr_in));
-
- ActionProcessor processor;
- SetBootableFlagActionProcessorDelegate delegate;
- processor.set_delegate(&delegate);
-
- ObjectFeederAction<string> feeder_action;
- feeder_action.set_obj(filename);
- SetBootableFlagAction set_bootable_action;
- if (!(flags & SKIP_INPUT_OBJECT))
- BondActions(&feeder_action, &set_bootable_action);
- ObjectCollectorAction<string> collector_action;
- BondActions(&set_bootable_action, &collector_action);
- processor.EnqueueAction(&feeder_action);
- processor.EnqueueAction(&set_bootable_action);
- processor.EnqueueAction(&collector_action);
- processor.StartProcessing();
- EXPECT_TRUE(!processor.IsRunning())
- << "Update test to handle non-asynch actions";
-
- EXPECT_TRUE(delegate.success_set_);
- EXPECT_EQ(flags & EXPECT_SUCCESS, delegate.success_);
-
- vector<char> new_mbr;
- if (flags & WRITE_FILE)
- utils::ReadFile(root_filename, &new_mbr);
-
- unlink(root_filename.c_str());
- return new_mbr;
+// These disabled tests are a reminder this needs to change.
+TEST_F(SetBootableFlagActionTest, DISABLED_SimpleTest) {
+ // TODO(adlr): find a way to test this object.
}
-TEST_F(SetBootableFlagActionTest, SimpleTest) {
- for (int i = 0; i < 4; i++) {
- vector<char> expected_new_mbr = sample_mbr_;
- for (int j = 0; j < 4; j++)
- expected_new_mbr[446 + 16 * j] = '\0'; // mark non-bootable
- expected_new_mbr[446 + 16 * i] = 0x80; // mark bootable
-
- string filename(string(kTestDir) + "/SetBootableFlagActionTest.devX");
- filename[filename.size() - 1] = '1' + i;
-
- vector<char> actual_new_mbr = DoTest(expected_new_mbr, filename,
- EXPECT_SUCCESS | WRITE_FILE);
-
- ExpectVectorsEq(expected_new_mbr, actual_new_mbr);
- }
+TEST_F(SetBootableFlagActionTest, DISABLED_BadDeviceTest) {
}
-TEST_F(SetBootableFlagActionTest, BadDeviceTest) {
- vector<char> actual_new_mbr = DoTest(sample_mbr_,
- string(kTestDir) +
- "SetBootableFlagActionTest.dev5",
- WRITE_FILE);
- ExpectVectorsEq(sample_mbr_, actual_new_mbr); // no change
-
- actual_new_mbr = DoTest(sample_mbr_,
- string(kTestDir) + "SetBootableFlagActionTest.dev13",
- WRITE_FILE);
- ExpectVectorsEq(sample_mbr_, actual_new_mbr); // no change
-
- actual_new_mbr = DoTest(sample_mbr_,
- "/some/nonexistent/file3",
- 0);
- EXPECT_TRUE(actual_new_mbr.empty());
-
- vector<char> bad_mbr = sample_mbr_;
- bad_mbr[510] = 'x'; // makes signature invalid
-
- actual_new_mbr = DoTest(bad_mbr,
- string(kTestDir) + "SetBootableFlagActionTest.dev2",
- WRITE_FILE);
- ExpectVectorsEq(bad_mbr, actual_new_mbr); // no change
-}
-
-TEST_F(SetBootableFlagActionTest, NoInputObjectTest) {
- vector<char> actual_new_mbr = DoTest(sample_mbr_,
- string(kTestDir) +
- "SetBootableFlagActionTest.dev5",
- WRITE_FILE | SKIP_INPUT_OBJECT);
- ExpectVectorsEq(sample_mbr_, actual_new_mbr); // no change
+TEST_F(SetBootableFlagActionTest, DISABLED_NoInputObjectTest) {
}
} // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 84410ad..e12fed9 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -36,14 +36,16 @@
new OmahaResponseHandlerAction);
shared_ptr<FilesystemCopierAction> filesystem_copier_action(
new FilesystemCopierAction(false));
- shared_ptr<FilesystemCopierAction> filesystem_copier_action_kernel(
+ shared_ptr<FilesystemCopierAction> kernel_filesystem_copier_action(
new FilesystemCopierAction(true));
shared_ptr<DownloadAction> download_action(
new DownloadAction(new LibcurlHttpFetcher));
- shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
- new PostinstallRunnerAction);
+ shared_ptr<PostinstallRunnerAction> postinstall_runner_action_precommit(
+ new PostinstallRunnerAction(true));
shared_ptr<SetBootableFlagAction> set_bootable_flag_action(
new SetBootableFlagAction);
+ shared_ptr<PostinstallRunnerAction> postinstall_runner_action_postcommit(
+ new PostinstallRunnerAction(false));
response_handler_action_ = response_handler_action;
@@ -52,10 +54,13 @@
actions_.push_back(shared_ptr<AbstractAction>(response_handler_action));
actions_.push_back(shared_ptr<AbstractAction>(filesystem_copier_action));
actions_.push_back(shared_ptr<AbstractAction>(
- filesystem_copier_action_kernel));
+ kernel_filesystem_copier_action));
actions_.push_back(shared_ptr<AbstractAction>(download_action));
- actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
+ actions_.push_back(shared_ptr<AbstractAction>(
+ postinstall_runner_action_precommit));
actions_.push_back(shared_ptr<AbstractAction>(set_bootable_flag_action));
+ actions_.push_back(shared_ptr<AbstractAction>(
+ postinstall_runner_action_postcommit));
// Enqueue the actions
for (vector<shared_ptr<AbstractAction> >::iterator it = actions_.begin();
@@ -69,13 +74,14 @@
BondActions(update_check_action.get(), response_handler_action.get());
BondActions(response_handler_action.get(), filesystem_copier_action.get());
BondActions(response_handler_action.get(),
- filesystem_copier_action_kernel.get());
- BondActions(filesystem_copier_action_kernel.get(),
+ kernel_filesystem_copier_action.get());
+ BondActions(kernel_filesystem_copier_action.get(),
download_action.get());
- // TODO(adlr): Bond these actions together properly
- // BondActions(download_action.get(), install_action.get());
- // BondActions(install_action.get(), postinstall_runner_action.get());
- BondActions(postinstall_runner_action.get(), set_bootable_flag_action.get());
+ BondActions(download_action.get(), postinstall_runner_action_precommit.get());
+ BondActions(postinstall_runner_action_precommit.get(),
+ set_bootable_flag_action.get());
+ BondActions(set_bootable_flag_action.get(),
+ postinstall_runner_action_postcommit.get());
processor_.StartProcessing();
}
diff --git a/update_check_action.cc b/update_check_action.cc
index b92e788..106400b 100644
--- a/update_check_action.cc
+++ b/update_check_action.cc
@@ -22,6 +22,8 @@
"{87efface-864d-49a5-9bb3-4b050a7c227a}");
const char* const UpdateCheckParams::kOsPlatform("Chrome OS");
const char* const UpdateCheckParams::kOsVersion("Indy");
+const char* const UpdateCheckParams::kUpdateUrl(
+ "https://tools.google.com/service/update2");
namespace {
@@ -105,7 +107,7 @@
http_fetcher_->set_delegate(this);
string request_post(FormatRequest(params_));
http_fetcher_->SetPostData(request_post.data(), request_post.size());
- http_fetcher_->BeginTransfer("https://tools.google.com/service/update2");
+ http_fetcher_->BeginTransfer(params_.update_url);
}
void UpdateCheckAction::TerminateProcessing() {
diff --git a/update_check_action.h b/update_check_action.h
index da48aba..831039d 100644
--- a/update_check_action.h
+++ b/update_check_action.h
@@ -39,7 +39,8 @@
const std::string& in_app_id,
const std::string& in_app_version,
const std::string& in_app_lang,
- const std::string& in_app_track)
+ const std::string& in_app_track,
+ const std::string& in_update_url)
: machine_id(in_machine_id),
user_id(in_user_id),
os_platform(in_os_platform),
@@ -48,22 +49,26 @@
app_id(in_app_id),
app_version(in_app_version),
app_lang(in_app_lang),
- app_track(in_app_track) {}
+ app_track(in_app_track),
+ update_url(in_update_url) {}
- std::string machine_id;
- std::string user_id;
- std::string os_platform;
- std::string os_version;
- std::string os_sp;
- std::string app_id;
- std::string app_version;
- std::string app_lang;
- std::string app_track;
+ std::string machine_id;
+ std::string user_id;
+ std::string os_platform;
+ std::string os_version;
+ std::string os_sp;
+ std::string app_id;
+ std::string app_version;
+ std::string app_lang;
+ std::string app_track;
+
+ std::string update_url;
// Suggested defaults
static const char* const kAppId;
static const char* const kOsPlatform;
static const char* const kOsVersion;
+ static const char* const kUpdateUrl;
};
// This struct encapsulates the data Omaha returns for the update check.
diff --git a/update_check_action_unittest.cc b/update_check_action_unittest.cc
index c57e2cd..c730b40 100644
--- a/update_check_action_unittest.cc
+++ b/update_check_action_unittest.cc
@@ -162,7 +162,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest");
+ "unittest",
+ ""); // url
UpdateCheckResponse response;
ASSERT_TRUE(
TestUpdateCheckAction(params,
@@ -182,7 +183,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ ""); // url
UpdateCheckResponse response;
ASSERT_TRUE(
TestUpdateCheckAction(params,
@@ -216,7 +218,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest");
+ "unittest",
+ ""); // url
const string http_response(GetNoUpdateResponse(UpdateCheckParams::kAppId));
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
@@ -248,7 +251,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_FALSE(
TestUpdateCheckAction(params,
@@ -268,7 +272,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_FALSE(TestUpdateCheckAction(
params,
@@ -291,7 +296,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_FALSE(TestUpdateCheckAction(
params,
@@ -314,7 +320,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_FALSE(TestUpdateCheckAction(
params,
@@ -337,7 +344,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_TRUE(TestUpdateCheckAction(params,
string("<?xml version=\"1.0\" "
@@ -395,7 +403,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest");
+ "unittest",
+ "http://url");
string http_response("doesn't matter");
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
@@ -434,7 +443,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_FALSE(
TestUpdateCheckAction(params,
@@ -461,7 +471,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_TRUE(
TestUpdateCheckAction(params,
@@ -490,7 +501,8 @@
UpdateCheckParams::kAppId,
"0.1.0.0",
"en-US",
- "unittest_track");
+ "unittest_track",
+ "http://url");
UpdateCheckResponse response;
ASSERT_TRUE(
TestUpdateCheckAction(params,
diff --git a/utils.cc b/utils.cc
index 83096d2..b19e6fc 100644
--- a/utils.cc
+++ b/utils.cc
@@ -195,6 +195,30 @@
return true;
}
+string RootDevice(const string& partition_device) {
+ CHECK(!partition_device.empty());
+ string::const_iterator it = --partition_device.end();
+ for (; it >= partition_device.begin(); --it) {
+ if (!isdigit(*it))
+ break;
+ }
+ // Some devices contain a p before the partitions. For example:
+ // /dev/mmc0p4 should be shortened to /dev/mmc0.
+ if (*it == 'p')
+ --it;
+ return string(partition_device.begin(), it + 1);
+}
+
+string PartitionNumber(const string& partition_device) {
+ CHECK(!partition_device.empty());
+ string::const_iterator it = --partition_device.end();
+ for (; it >= partition_device.begin(); --it) {
+ if (!isdigit(*it))
+ break;
+ }
+ return string(it + 1, partition_device.end());
+}
+
std::string ErrnoNumberAsString(int err) {
char buf[100];
buf[0] = '\0';
@@ -357,6 +381,12 @@
return true;
}
+bool GetBootloader(BootLoader* out_bootloader) {
+ // For now, hardcode to syslinux.
+ *out_bootloader = BootLoader_SYSLINUX;
+ return true;
+}
+
const char* GetGErrorMessage(const GError* error) {
if (!error)
return "Unknown error.";
diff --git a/utils.h b/utils.h
index e5d099f..c6edb7d 100644
--- a/utils.h
+++ b/utils.h
@@ -77,12 +77,28 @@
// This WILL cross filesystem boundaries.
bool RecursiveUnlinkDir(const std::string& path);
+// Returns the root device for a partition. For example,
+// RootDevice("/dev/sda3") returns "/dev/sda".
+std::string RootDevice(const std::string& partition_device);
+
+// Returns the partition number, as a string, of partition_device. For example,
+// PartitionNumber("/dev/sda3") return "3".
+std::string PartitionNumber(const std::string& partition_device);
+
// Synchronously mount or unmount a filesystem. Return true on success.
// Mounts as ext3 with default options.
bool MountFilesystem(const std::string& device, const std::string& mountpoint,
unsigned long flags);
bool UnmountFilesystem(const std::string& mountpoint);
+enum BootLoader {
+ BootLoader_SYSLINUX = 0,
+ BootLoader_CHROME_FIRMWARE = 1
+};
+// Detects which bootloader this system uses and returns it via the out
+// param. Returns true on success.
+bool GetBootloader(BootLoader* out_bootloader);
+
// Returns the error message, if any, from a GError pointer.
const char* GetGErrorMessage(const GError* error);
diff --git a/utils_unittest.cc b/utils_unittest.cc
index 5ab78cd..a66e739 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -125,4 +125,14 @@
EXPECT_FALSE(utils::StringHasSuffix(result, "XXXXXX"));
}
+TEST(UtilsTest, RootDeviceTest) {
+ EXPECT_EQ("/dev/sda", utils::RootDevice("/dev/sda3"));
+ EXPECT_EQ("/dev/mmc0", utils::RootDevice("/dev/mmc0p3"));
+}
+
+TEST(UtilsTest, PartitionNumberTest) {
+ EXPECT_EQ("3", utils::PartitionNumber("/dev/sda3"));
+ EXPECT_EQ("3", utils::PartitionNumber("/dev/mmc0p3"));
+}
+
} // namespace chromeos_update_engine