blob: 1baa9ec49453a444c3646a86d910e29dfd085e1e [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"
6#include <sys/mount.h>
7#include <stdlib.h>
Andrew de los Reyesf9714432010-05-04 10:21:23 -07008#include <vector>
9#include "update_engine/subprocess.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000010#include "update_engine/utils.h"
11
12namespace chromeos_update_engine {
13
14using std::string;
Andrew de los Reyesf9714432010-05-04 10:21:23 -070015using std::vector;
adlr@google.com3defe6a2009-12-04 20:57:17 +000016
17namespace {
Darin Petkov6f03a3b2010-11-10 14:27:14 -080018const char kPostinstallScript[] = "/postinst";
Jay Srinivasanae4697c2013-03-18 17:08:08 -070019const char kPowerwashMarkerFile[] =
20 "/mnt/stateful_partition/factory_install_reset";
21const char kPowerwashCommand[] = "safe fast\n";
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
58 // Runs the postinstall script asynchronously to free up the main loop while
59 // it's running.
60 vector<string> command;
61 command.push_back(temp_rootfs_dir_ + kPostinstallScript);
62 command.push_back(install_device);
Darin Petkov58dd1342011-05-06 12:05:13 -070063 if (!Subprocess::Get().Exec(command, StaticCompletePostinstall, this)) {
64 CompletePostinstall(1);
65 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080066}
67
68void PostinstallRunnerAction::CompletePostinstall(int return_code) {
69 ScopedActionCompleter completer(processor_, this);
70 ScopedTempUnmounter temp_unmounter(temp_rootfs_dir_);
71 if (return_code != 0) {
72 LOG(ERROR) << "Postinst command failed with code: " << return_code;
Andrew de los Reyesfe57d542011-06-07 09:00:36 -070073 if (return_code == 3) {
Andrew de los Reyesc1d5c932011-04-20 17:15:47 -070074 // This special return code means that we tried to update firmware,
75 // but couldn't because we booted from FW B, and we need to reboot
76 // to get back to FW A.
77 completer.set_code(kActionCodePostinstallBootedFromFirmwareB);
78 }
Darin Petkov6f03a3b2010-11-10 14:27:14 -080079 return;
80 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -070081
82 LOG(INFO) << "Postinst command succeeded";
83 CHECK(HasInputObject());
84 const InstallPlan install_plan = GetInputObject();
85
86 if (install_plan.powerwash_required) {
87 if (utils::WriteFile(kPowerwashMarkerFile,
88 kPowerwashCommand,
89 strlen(kPowerwashCommand))) {
90 LOG(INFO) << "Configured clobber-state to do powerwash on next reboot";
91 } else {
92 LOG(ERROR) << "Error in configuring clobber-state to do powerwash";
93 completer.set_code(kActionCodePostinstallPowerwashError);
94 return;
95 }
adlr@google.com3defe6a2009-12-04 20:57:17 +000096 }
Jay Srinivasanae4697c2013-03-18 17:08:08 -070097
98 if (HasOutputPipe())
99 SetOutputObject(install_plan);
100
Darin Petkovc1a8b422010-07-19 11:34:49 -0700101 completer.set_code(kActionCodeSuccess);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000102}
103
Darin Petkov6f03a3b2010-11-10 14:27:14 -0800104void PostinstallRunnerAction::StaticCompletePostinstall(int return_code,
105 const string& output,
106 void* p) {
107 reinterpret_cast<PostinstallRunnerAction*>(p)->CompletePostinstall(
108 return_code);
109}
110
adlr@google.com3defe6a2009-12-04 20:57:17 +0000111} // namespace chromeos_update_engine