1 /*
2 * Copyright (C) 2018 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 */
16
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/wait.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <signal.h>
28
29 #include <algorithm>
30 #include <cstdlib>
31 #include <fstream>
32 #include <iomanip>
33 #include <memory>
34 #include <sstream>
35 #include <string>
36 #include <vector>
37
38 #include <gflags/gflags.h>
39 #include <android-base/logging.h>
40
41 #include "common/libs/fs/shared_buf.h"
42 #include "common/libs/fs/shared_fd.h"
43 #include "common/libs/fs/shared_select.h"
44 #include "common/libs/utils/environment.h"
45 #include "host/commands/run_cvd/runner_defs.h"
46 #include "host/libs/config/cuttlefish_config.h"
47 #include "host/libs/vm_manager/vm_manager.h"
48
49 DEFINE_int32(instance_num, cuttlefish::GetInstance(),
50 "Which instance to powerwash");
51
52 DEFINE_int32(wait_for_launcher, 30,
53 "How many seconds to wait for the launcher to respond to the status "
54 "command. A value of zero means wait indefinetly");
55
56 DEFINE_int32(boot_timeout, 1000, "How many seconds to wait for the device to "
57 "reboot.");
58
59 namespace cuttlefish {
60 namespace {
61
PowerwashCvdMain(int argc,char ** argv)62 int PowerwashCvdMain(int argc, char** argv) {
63 ::android::base::InitLogging(argv, android::base::StderrLogger);
64 google::ParseCommandLineFlags(&argc, &argv, true);
65
66 auto config = CuttlefishConfig::Get();
67 if (!config) {
68 LOG(ERROR) << "Failed to obtain config object";
69 return 1;
70 }
71
72 auto instance = config->ForInstance(FLAGS_instance_num);
73 auto monitor_path = instance.launcher_monitor_socket_path();
74 if (monitor_path.empty()) {
75 LOG(ERROR) << "No path to launcher monitor found";
76 return 2;
77 }
78 auto monitor_socket = SharedFD::SocketLocalClient(
79 monitor_path.c_str(), false, SOCK_STREAM, FLAGS_wait_for_launcher);
80 if (!monitor_socket->IsOpen()) {
81 LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
82 << ": " << monitor_socket->StrError();
83 return 3;
84 }
85 auto request = LauncherAction::kPowerwash;
86 auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
87 if (bytes_sent < 0) {
88 LOG(ERROR) << "Error sending launcher monitor the status command: "
89 << monitor_socket->StrError();
90 return 4;
91 }
92 // Perform a select with a timeout to guard against launcher hanging
93 SharedFDSet read_set;
94 read_set.Set(monitor_socket);
95 struct timeval timeout = {FLAGS_wait_for_launcher, 0};
96 int selected = Select(&read_set, nullptr, nullptr,
97 FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
98 if (selected < 0){
99 LOG(ERROR) << "Failed communication with the launcher monitor: "
100 << strerror(errno);
101 return 5;
102 }
103 if (selected == 0) {
104 LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
105 return 6;
106 }
107 LauncherResponse response;
108 auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
109 if (bytes_recv < 0) {
110 LOG(ERROR) << "Error receiving response from launcher monitor: "
111 << monitor_socket->StrError();
112 return 7;
113 }
114 LOG(INFO) << "Requesting powerwash";
115 if (response != LauncherResponse::kSuccess) {
116 LOG(ERROR) << "Received '" << static_cast<char>(response)
117 << "' response from launcher monitor for powerwash request";
118 return 8;
119 }
120 LOG(INFO) << "Waiting for device to boot up again";
121
122 read_set.Set(monitor_socket);
123 timeout = {FLAGS_boot_timeout, 0};
124 selected = Select(&read_set, nullptr, nullptr,
125 FLAGS_boot_timeout <= 0 ? nullptr : &timeout);
126 if (selected < 0){
127 LOG(ERROR) << "Failed communication with the launcher monitor: "
128 << strerror(errno);
129 return 5;
130 }
131 if (selected == 0) {
132 LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
133 return 6;
134 }
135
136 RunnerExitCodes exit_code;
137 bytes_recv = ReadExactBinary(monitor_socket, &exit_code);
138 if (bytes_recv < 0) {
139 LOG(ERROR) << "Error in stream response: " << monitor_socket->StrError();
140 return 9;
141 } else if (bytes_recv == 0) {
142 LOG(ERROR) << "Launcher socket closed unexpectedly";
143 return 10;
144 } else if (bytes_recv != sizeof(exit_code)) {
145 LOG(ERROR) << "Launcher response was too short";
146 return 11;
147 } else if (exit_code == RunnerExitCodes::kVirtualDeviceBootFailed) {
148 LOG(ERROR) << "Boot failed";
149 return 12;
150 } else if (exit_code != RunnerExitCodes::kSuccess) {
151 LOG(ERROR) << "Unknown response: " << (int) exit_code;
152 return 13;
153 }
154 LOG(INFO) << "Powerwash successful";
155 return 0;
156 }
157
158 } // namespace
159 } // namespace cuttlefish
160
main(int argc,char ** argv)161 int main(int argc, char** argv) {
162 return cuttlefish::PowerwashCvdMain(argc, argv);
163 }
164