blob: 20dfae99a48bf47a1ff47de5d66ddcb90b9370db [file] [log] [blame]
Darin Petkov58dd1342011-05-06 12:05:13 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
adlr@google.com3defe6a2009-12-04 20:57:17 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/postinstall_runner_action.h"
Jay Srinivasan1c0fe792013-03-28 16:45:25 -07006
adlr@google.com3defe6a2009-12-04 20:57:17 +00007#include <sys/mount.h>
8#include <stdlib.h>
Andrew de los Reyesf9714432010-05-04 10:21:23 -07009#include <vector>
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070010
Chris Sosabe45bef2013-04-09 18:25:12 -070011#include "update_engine/action_processor.h"
Andrew de los Reyesf9714432010-05-04 10:21:23 -070012#include "update_engine/subprocess.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000013#include "update_engine/utils.h"
14
15namespace chromeos_update_engine {
16
17using std::string;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070018using std::vector;
adlr@google.com3defe6a2009-12-04 20:57:17 +000019
20namespace {
Darin Petkov6f03a3b2010-11-10 14:27:14 -080021const char kPostinstallScript[] = "/postinst";
adlr@google.com3defe6a2009-12-04 20:57:17 +000022}
23
24void PostinstallRunnerAction::PerformAction() {
25 CHECK(HasInputObject());
Andrew de los Reyesf9714432010-05-04 10:21:23 -070026 const InstallPlan install_plan = GetInputObject();
27 const string install_device = install_plan.install_path;
28 ScopedActionCompleter completer(processor_, this);
Darin Petkovc1a8b422010-07-19 11:34:49 -070029
Darin Petkov6f03a3b2010-11-10 14:27:14 -080030 // Make mountpoint.
Andrew de los Reyesf9714432010-05-04 10:21:23 -070031 TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
Darin Petkov6f03a3b2010-11-10 14:27:14 -080032 &temp_rootfs_dir_));
33 ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
Andrew de los Reyesf9714432010-05-04 10:21:23 -070034
Darin Petkov6f03a3b2010-11-10 14:27:14 -080035 unsigned long mountflags = MS_RDONLY;
36 int rc = mount(install_device.c_str(),
37 temp_rootfs_dir_.c_str(),
Andrew de los Reyesbfabc302011-01-31 17:23:50 -080038 "ext2",
Andrew de los Reyes3270f742010-07-15 22:28:14 -070039 mountflags,
40 NULL);
Darin Petkov6f03a3b2010-11-10 14:27:14 -080041 if (rc < 0) {
Andrew de los Reyesbfabc302011-01-31 17:23:50 -080042 LOG(INFO) << "Failed to mount install part as ext2. Trying ext3.";
Darin Petkov6f03a3b2010-11-10 14:27:14 -080043 rc = mount(install_device.c_str(),
44 temp_rootfs_dir_.c_str(),
45 "ext3",
46 mountflags,
47 NULL);
48 }
49 if (rc < 0) {
50 LOG(ERROR) << "Unable to mount destination device " << install_device
51 << " onto " << temp_rootfs_dir_;
52 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +000053 }
54
Darin Petkov6f03a3b2010-11-10 14:27:14 -080055 temp_dir_remover.set_should_remove(false);
56 completer.set_should_complete(false);
57
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070058 if (install_plan.powerwash_required) {
59 if (utils::CreatePowerwashMarkerFile()) {
60 powerwash_marker_created_ = true;
61 } else {
David Zeuthena99981f2013-04-29 13:42:47 -070062 completer.set_code(kErrorCodePostinstallPowerwashError);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070063 return;
64 }
65 }
66
Darin Petkov6f03a3b2010-11-10 14:27:14 -080067 // Runs the postinstall script asynchronously to free up the main loop while
68 // it's running.
69 vector<string> command;
70 command.push_back(temp_rootfs_dir_ + kPostinstallScript);
71 command.push_back(install_device);
Darin Petkov58dd1342011-05-06 12:05:13 -070072 if (!Subprocess::Get().Exec(command, StaticCompletePostinstall, this)) {
73 CompletePostinstall(1);
74 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080075}
76
77void PostinstallRunnerAction::CompletePostinstall(int return_code) {
78 ScopedActionCompleter completer(processor_, this);
79 ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
80 if (return_code != 0) {
81 LOG(ERROR) << "Postinst command failed with code: " << return_code;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070082
83 // Undo any changes done to trigger Powerwash using clobber-state.
84 if (powerwash_marker_created_)
85 utils::DeletePowerwashMarkerFile();
86
Andrew de los Reyesfe57d542011-06-07 09:00:36 -070087 if (return_code == 3) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070088 // This special return code means that we tried to update firmware,
89 // but couldn't because we booted from FW B, and we need to reboot
90 // to get back to FW A.
David Zeuthena99981f2013-04-29 13:42:47 -070091 completer.set_code(kErrorCodePostinstallBootedFromFirmwareB);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070092 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080093 return;
94 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -070095
96 LOG(INFO) << "Postinst command succeeded";
97 CHECK(HasInputObject());
98 const InstallPlan install_plan = GetInputObject();
99
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700100 if (HasOutputPipe())
101 SetOutputObject(install_plan);
102
David Zeuthena99981f2013-04-29 13:42:47 -0700103 completer.set_code(kErrorCodeSuccess);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000104}
105
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800106void PostinstallRunnerAction::StaticCompletePostinstall(int return_code,
107 const string& output,
108 void* p) {
109 reinterpret_cast<PostinstallRunnerAction*>(p)->CompletePostinstall(
110 return_code);
111}
112
adlr@google.com3defe6a2009-12-04 20:57:17 +0000113} // namespace chromeos_update_engine