blob: 747ff43b9970fb8623daa61d5a35850c224a2ccc [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2011 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
adlr@google.com3defe6a2009-12-04 20:57:17 +000016
17#include "update_engine/postinstall_runner_action.h"
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070018
adlr@google.com3defe6a2009-12-04 20:57:17 +000019#include <stdlib.h>
Alex Vakulenko44cab302014-07-23 13:12:15 -070020#include <sys/mount.h>
Andrew de los Reyesf9714432010-05-04 10:21:23 -070021#include <vector>
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070022
Alex Deymo461b2592015-07-24 20:10:52 -070023#include <base/bind.h>
24
Chris Sosabe45bef2013-04-09 18:25:12 -070025#include "update_engine/action_processor.h"
Andrew de los Reyesf9714432010-05-04 10:21:23 -070026#include "update_engine/subprocess.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000027#include "update_engine/utils.h"
28
29namespace chromeos_update_engine {
30
31using std::string;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070032using std::vector;
adlr@google.com3defe6a2009-12-04 20:57:17 +000033
34namespace {
Alex Deymo032e7722014-03-25 17:53:56 -070035// The absolute path to the post install command.
Darin Petkov6f03a3b2010-11-10 14:27:14 -080036const char kPostinstallScript[] = "/postinst";
Alex Deymo032e7722014-03-25 17:53:56 -070037
38// Path to the binary file used by kPostinstallScript. Used to get and log the
39// file format of the binary to debug issues when the ELF format on the update
40// doesn't match the one on the current system. This path is not executed.
41const char kDebugPostinstallBinaryPath[] = "/usr/bin/cros_installer";
adlr@google.com3defe6a2009-12-04 20:57:17 +000042}
43
44void PostinstallRunnerAction::PerformAction() {
45 CHECK(HasInputObject());
Chris Sosad317e402013-06-12 13:47:09 -070046 install_plan_ = GetInputObject();
47 const string install_device = install_plan_.install_path;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070048 ScopedActionCompleter completer(processor_, this);
Darin Petkovc1a8b422010-07-19 11:34:49 -070049
Darin Petkov6f03a3b2010-11-10 14:27:14 -080050 // Make mountpoint.
Andrew de los Reyesf9714432010-05-04 10:21:23 -070051 TEST_AND_RETURN(utils::MakeTempDirectory("/tmp/au_postint_mount.XXXXXX",
Darin Petkov6f03a3b2010-11-10 14:27:14 -080052 &temp_rootfs_dir_));
53 ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
Andrew de los Reyesf9714432010-05-04 10:21:23 -070054
Nam T. Nguyena78b28c2015-03-06 22:30:12 -080055 const string mountable_device =
56 utils::MakePartitionNameForMount(install_device);
57 if (mountable_device.empty()) {
58 LOG(ERROR) << "Cannot make mountable device from " << install_device;
Darin Petkov6f03a3b2010-11-10 14:27:14 -080059 return;
Nam T. Nguyena78b28c2015-03-06 22:30:12 -080060 }
61
62 if (!utils::MountFilesystem(mountable_device, temp_rootfs_dir_, MS_RDONLY))
63 return;
64
65 LOG(INFO) << "Performing postinst with install device " << install_device
66 << " and mountable device " << mountable_device;
adlr@google.com3defe6a2009-12-04 20:57:17 +000067
Darin Petkov6f03a3b2010-11-10 14:27:14 -080068 temp_dir_remover.set_should_remove(false);
69 completer.set_should_complete(false);
70
Chris Sosad317e402013-06-12 13:47:09 -070071 if (install_plan_.powerwash_required) {
Gilad Arnold30dedd82013-07-03 06:19:09 -070072 if (utils::CreatePowerwashMarkerFile(powerwash_marker_file_)) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070073 powerwash_marker_created_ = true;
74 } else {
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -070075 completer.set_code(ErrorCode::kPostinstallPowerwashError);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070076 return;
77 }
78 }
79
Alex Deymo032e7722014-03-25 17:53:56 -070080 // Logs the file format of the postinstall script we are about to run. This
81 // will help debug when the postinstall script doesn't match the architecture
82 // of our build.
83 LOG(INFO) << "Format file for new " << kPostinstallScript << " is: "
84 << utils::GetFileFormat(temp_rootfs_dir_ + kPostinstallScript);
85 LOG(INFO) << "Format file for new " << kDebugPostinstallBinaryPath << " is: "
86 << utils::GetFileFormat(
87 temp_rootfs_dir_ + kDebugPostinstallBinaryPath);
88
Darin Petkov6f03a3b2010-11-10 14:27:14 -080089 // Runs the postinstall script asynchronously to free up the main loop while
90 // it's running.
91 vector<string> command;
Chris Sosa000ecb32014-04-23 12:21:18 -070092 if (!install_plan_.download_url.empty()) {
93 command.push_back(temp_rootfs_dir_ + kPostinstallScript);
94 } else {
95 // TODO(sosa): crbug.com/366207.
96 // If we're doing a rollback, just run our own postinstall.
97 command.push_back(kPostinstallScript);
98 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080099 command.push_back(install_device);
Alex Deymo461b2592015-07-24 20:10:52 -0700100 if (!Subprocess::Get().Exec(command,
101 base::Bind(
102 &PostinstallRunnerAction::CompletePostinstall,
103 base::Unretained(this)))) {
104 CompletePostinstall(1, "Postinstall didn't launch");
Darin Petkov58dd1342011-05-06 12:05:13 -0700105 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800106}
107
Alex Deymo461b2592015-07-24 20:10:52 -0700108void PostinstallRunnerAction::CompletePostinstall(int return_code,
109 const string& output) {
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800110 ScopedActionCompleter completer(processor_, this);
111 ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
112 if (return_code != 0) {
113 LOG(ERROR) << "Postinst command failed with code: " << return_code;
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700114
115 // Undo any changes done to trigger Powerwash using clobber-state.
116 if (powerwash_marker_created_)
Gilad Arnold30dedd82013-07-03 06:19:09 -0700117 utils::DeletePowerwashMarkerFile(powerwash_marker_file_);
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700118
Andrew de los Reyesfe57d542011-06-07 09:00:36 -0700119 if (return_code == 3) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700120 // This special return code means that we tried to update firmware,
121 // but couldn't because we booted from FW B, and we need to reboot
122 // to get back to FW A.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700123 completer.set_code(ErrorCode::kPostinstallBootedFromFirmwareB);
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -0700124 }
Don Garrett81018e02013-07-30 18:46:31 -0700125
126 if (return_code == 4) {
127 // This special return code means that we tried to update firmware,
128 // but couldn't because we booted from FW B, and we need to reboot
129 // to get back to FW A.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700130 completer.set_code(ErrorCode::kPostinstallFirmwareRONotUpdatable);
Don Garrett81018e02013-07-30 18:46:31 -0700131 }
132
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800133 return;
134 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700135
136 LOG(INFO) << "Postinst command succeeded";
Chris Sosad317e402013-06-12 13:47:09 -0700137 if (HasOutputPipe()) {
138 SetOutputObject(install_plan_);
139 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700140
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700141 completer.set_code(ErrorCode::kSuccess);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000142}
143
adlr@google.com3defe6a2009-12-04 20:57:17 +0000144} // namespace chromeos_update_engine