blob: 0760bd5ec2d73bd18f4a272a3e7443cf22b23a31 [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 <stdlib.h>
Alex Vakulenko44cab302014-07-23 13:12:15 -07008#include <sys/mount.h>
Andrew de los Reyesf9714432010-05-04 10:21:23 -07009#include <vector>
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070010
Alex Deymo461b2592015-07-24 20:10:52 -070011#include <base/bind.h>
12
Chris Sosabe45bef2013-04-09 18:25:12 -070013#include "update_engine/action_processor.h"
Andrew de los Reyesf9714432010-05-04 10:21:23 -070014#include "update_engine/subprocess.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000015#include "update_engine/utils.h"
16
17namespace chromeos_update_engine {
18
19using std::string;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070020using std::vector;
adlr@google.com3defe6a2009-12-04 20:57:17 +000021
22namespace {
Alex Deymo032e7722014-03-25 17:53:56 -070023// The absolute path to the post install command.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080024const char kPostinstallScript[] = "/postinst";
Alex Deymo032e7722014-03-25 17:53:56 -070025
26// Path to the binary file used by kPostinstallScript. Used to get and log the
27// file format of the binary to debug issues when the ELF format on the update
28// doesn't match the one on the current system. This path is not executed.
29const char kDebugPostinstallBinaryPath[] = "/usr/bin/cros_installer";
adlr@google.com3defe6a2009-12-04 20:57:17 +000030}
31
32void PostinstallRunnerAction::PerformAction() {
33 CHECK(HasInputObject());
Chris Sosad317e402013-06-12 13:47:09 -070034 install_plan_ = GetInputObject();
35 const string install_device = install_plan_.install_path;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070036 ScopedActionCompleter completer(processor_, this);
Darin Petkovc1a8b422010-07-19 11:34:49 -070037
Darin Petkov6f03a3b2010-11-10 14:27:14 -080038 // Make mountpoint.
Andrew de los Reyesf9714432010-05-04 10:21:23 -070039 TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
Darin Petkov6f03a3b2010-11-10 14:27:14 -080040 &temp_rootfs_dir_));
41 ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
Andrew de los Reyesf9714432010-05-04 10:21:23 -070042
Nam T. Nguyena78b28c2015-03-06 22:30:12 -080043 const string mountable_device =
44 utils::MakePartitionNameForMount(install_device);
45 if (mountable_device.empty()) {
46 LOG(ERROR) << "Cannot make mountable device from " << install_device;
Darin Petkov6f03a3b2010-11-10 14:27:14 -080047 return;
Nam T. Nguyena78b28c2015-03-06 22:30:12 -080048 }
49
50 if (!utils::MountFilesystem(mountable_device, temp_rootfs_dir_, MS_RDONLY))
51 return;
52
53 LOG(INFO) << "Performing postinst with install device " << install_device
54 << " and mountable device " << mountable_device;
adlr@google.com3defe6a2009-12-04 20:57:17 +000055
Darin Petkov6f03a3b2010-11-10 14:27:14 -080056 temp_dir_remover.set_should_remove(false);
57 completer.set_should_complete(false);
58
Chris Sosad317e402013-06-12 13:47:09 -070059 if (install_plan_.powerwash_required) {
Gilad Arnold30dedd82013-07-03 06:19:09 -070060 if (utils::CreatePowerwashMarkerFile(powerwash_marker_file_)) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070061 powerwash_marker_created_ = true;
62 } else {
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -070063 completer.set_code(ErrorCode::kPostinstallPowerwashError);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070064 return;
65 }
66 }
67
Alex Deymo032e7722014-03-25 17:53:56 -070068 // Logs the file format of the postinstall script we are about to run. This
69 // will help debug when the postinstall script doesn't match the architecture
70 // of our build.
71 LOG(INFO) << "Format file for new " << kPostinstallScript << " is: "
72 << utils::GetFileFormat(temp_rootfs_dir_ + kPostinstallScript);
73 LOG(INFO) << "Format file for new " << kDebugPostinstallBinaryPath << " is: "
74 << utils::GetFileFormat(
75 temp_rootfs_dir_ + kDebugPostinstallBinaryPath);
76
Darin Petkov6f03a3b2010-11-10 14:27:14 -080077 // Runs the postinstall script asynchronously to free up the main loop while
78 // it's running.
79 vector<string> command;
Chris Sosa000ecb32014-04-23 12:21:18 -070080 if (!install_plan_.download_url.empty()) {
81 command.push_back(temp_rootfs_dir_ + kPostinstallScript);
82 } else {
83 // TODO(sosa): crbug.com/366207.
84 // If we're doing a rollback, just run our own postinstall.
85 command.push_back(kPostinstallScript);
86 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080087 command.push_back(install_device);
Alex Deymo461b2592015-07-24 20:10:52 -070088 if (!Subprocess::Get().Exec(command,
89 base::Bind(
90 &PostinstallRunnerAction::CompletePostinstall,
91 base::Unretained(this)))) {
92 CompletePostinstall(1, "Postinstall didn't launch");
Darin Petkov58dd1342011-05-06 12:05:13 -070093 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080094}
95
Alex Deymo461b2592015-07-24 20:10:52 -070096void PostinstallRunnerAction::CompletePostinstall(int return_code,
97 const string& output) {
Darin Petkov6f03a3b2010-11-10 14:27:14 -080098 ScopedActionCompleter completer(processor_, this);
99 ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
100 if (return_code != 0) {
101 LOG(ERROR) << "Postinst command failed with code: " << return_code;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700102
103 // Undo any changes done to trigger Powerwash using clobber-state.
104 if (powerwash_marker_created_)
Gilad Arnold30dedd82013-07-03 06:19:09 -0700105 utils::DeletePowerwashMarkerFile(powerwash_marker_file_);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700106
Andrew de los Reyesfe57d542011-06-07 09:00:36 -0700107 if (return_code == 3) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700108 // This special return code means that we tried to update firmware,
109 // but couldn't because we booted from FW B, and we need to reboot
110 // to get back to FW A.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700111 completer.set_code(ErrorCode::kPostinstallBootedFromFirmwareB);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700112 }
Don Garrett81018e02013-07-30 18:46:31 -0700113
114 if (return_code == 4) {
115 // This special return code means that we tried to update firmware,
116 // but couldn't because we booted from FW B, and we need to reboot
117 // to get back to FW A.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700118 completer.set_code(ErrorCode::kPostinstallFirmwareRONotUpdatable);
Don Garrett81018e02013-07-30 18:46:31 -0700119 }
120
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800121 return;
122 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700123
124 LOG(INFO) << "Postinst command succeeded";
Chris Sosad317e402013-06-12 13:47:09 -0700125 if (HasOutputPipe()) {
126 SetOutputObject(install_plan_);
127 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700128
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700129 completer.set_code(ErrorCode::kSuccess);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000130}
131
adlr@google.com3defe6a2009-12-04 20:57:17 +0000132} // namespace chromeos_update_engine