blob: f8bcc361a18070997c49c8e143e1c37235df750c [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 {
Alex Deymo032e7722014-03-25 17:53:56 -070021// The absolute path to the post install command.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080022const char kPostinstallScript[] = "/postinst";
Alex Deymo032e7722014-03-25 17:53:56 -070023
24// Path to the binary file used by kPostinstallScript. Used to get and log the
25// file format of the binary to debug issues when the ELF format on the update
26// doesn't match the one on the current system. This path is not executed.
27const char kDebugPostinstallBinaryPath[] = "/usr/bin/cros_installer";
adlr@google.com3defe6a2009-12-04 20:57:17 +000028}
29
30void PostinstallRunnerAction::PerformAction() {
31 CHECK(HasInputObject());
Chris Sosad317e402013-06-12 13:47:09 -070032 install_plan_ = GetInputObject();
33 const string install_device = install_plan_.install_path;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070034 ScopedActionCompleter completer(processor_, this);
Darin Petkovc1a8b422010-07-19 11:34:49 -070035
Darin Petkov6f03a3b2010-11-10 14:27:14 -080036 // Make mountpoint.
Andrew de los Reyesf9714432010-05-04 10:21:23 -070037 TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
Darin Petkov6f03a3b2010-11-10 14:27:14 -080038 &temp_rootfs_dir_));
39 ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
Andrew de los Reyesf9714432010-05-04 10:21:23 -070040
Darin Petkov6f03a3b2010-11-10 14:27:14 -080041 unsigned long mountflags = MS_RDONLY;
42 int rc = mount(install_device.c_str(),
43 temp_rootfs_dir_.c_str(),
Andrew de los Reyesbfabc302011-01-31 17:23:50 -080044 "ext2",
Andrew de los Reyes3270f742010-07-15 22:28:14 -070045 mountflags,
46 NULL);
Chris Sosad317e402013-06-12 13:47:09 -070047 // TODO(sosa): Remove once crbug.com/208022 is resolved.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080048 if (rc < 0) {
Chris Sosad317e402013-06-12 13:47:09 -070049 LOG(INFO) << "Failed to mount install part "
50 << install_device << " as ext2. Trying ext3.";
Darin Petkov6f03a3b2010-11-10 14:27:14 -080051 rc = mount(install_device.c_str(),
52 temp_rootfs_dir_.c_str(),
53 "ext3",
54 mountflags,
55 NULL);
56 }
57 if (rc < 0) {
58 LOG(ERROR) << "Unable to mount destination device " << install_device
59 << " onto " << temp_rootfs_dir_;
60 return;
adlr@google.com3defe6a2009-12-04 20:57:17 +000061 }
62
Darin Petkov6f03a3b2010-11-10 14:27:14 -080063 temp_dir_remover.set_should_remove(false);
64 completer.set_should_complete(false);
65
Chris Sosad317e402013-06-12 13:47:09 -070066 if (install_plan_.powerwash_required) {
Gilad Arnold30dedd82013-07-03 06:19:09 -070067 if (utils::CreatePowerwashMarkerFile(powerwash_marker_file_)) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070068 powerwash_marker_created_ = true;
69 } else {
David Zeuthena99981f2013-04-29 13:42:47 -070070 completer.set_code(kErrorCodePostinstallPowerwashError);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070071 return;
72 }
73 }
74
Alex Deymo032e7722014-03-25 17:53:56 -070075 // Logs the file format of the postinstall script we are about to run. This
76 // will help debug when the postinstall script doesn't match the architecture
77 // of our build.
78 LOG(INFO) << "Format file for new " << kPostinstallScript << " is: "
79 << utils::GetFileFormat(temp_rootfs_dir_ + kPostinstallScript);
80 LOG(INFO) << "Format file for new " << kDebugPostinstallBinaryPath << " is: "
81 << utils::GetFileFormat(
82 temp_rootfs_dir_ + kDebugPostinstallBinaryPath);
83
Darin Petkov6f03a3b2010-11-10 14:27:14 -080084 // Runs the postinstall script asynchronously to free up the main loop while
85 // it's running.
86 vector<string> command;
87 command.push_back(temp_rootfs_dir_ + kPostinstallScript);
88 command.push_back(install_device);
Darin Petkov58dd1342011-05-06 12:05:13 -070089 if (!Subprocess::Get().Exec(command, StaticCompletePostinstall, this)) {
90 CompletePostinstall(1);
91 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080092}
93
94void PostinstallRunnerAction::CompletePostinstall(int return_code) {
95 ScopedActionCompleter completer(processor_, this);
96 ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
97 if (return_code != 0) {
98 LOG(ERROR) << "Postinst command failed with code: " << return_code;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070099
100 // Undo any changes done to trigger Powerwash using clobber-state.
101 if (powerwash_marker_created_)
Gilad Arnold30dedd82013-07-03 06:19:09 -0700102 utils::DeletePowerwashMarkerFile(powerwash_marker_file_);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700103
Andrew de los Reyesfe57d542011-06-07 09:00:36 -0700104 if (return_code == 3) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700105 // This special return code means that we tried to update firmware,
106 // but couldn't because we booted from FW B, and we need to reboot
107 // to get back to FW A.
David Zeuthena99981f2013-04-29 13:42:47 -0700108 completer.set_code(kErrorCodePostinstallBootedFromFirmwareB);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700109 }
Don Garrett81018e02013-07-30 18:46:31 -0700110
111 if (return_code == 4) {
112 // This special return code means that we tried to update firmware,
113 // but couldn't because we booted from FW B, and we need to reboot
114 // to get back to FW A.
115 completer.set_code(kErrorCodePostinstallFirmwareRONotUpdatable);
116 }
117
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800118 return;
119 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700120
121 LOG(INFO) << "Postinst command succeeded";
Chris Sosad317e402013-06-12 13:47:09 -0700122 if (HasOutputPipe()) {
123 SetOutputObject(install_plan_);
124 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700125
David Zeuthena99981f2013-04-29 13:42:47 -0700126 completer.set_code(kErrorCodeSuccess);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000127}
128
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800129void PostinstallRunnerAction::StaticCompletePostinstall(int return_code,
130 const string& output,
131 void* p) {
132 reinterpret_cast<PostinstallRunnerAction*>(p)->CompletePostinstall(
133 return_code);
134}
135
adlr@google.com3defe6a2009-12-04 20:57:17 +0000136} // namespace chromeos_update_engine