blob: 3db038f03fd5a8aa3d66fda963b53b3dee8d2e42 [file] [log] [blame]
Yifan Hongaf766e62021-06-14 13:24:19 -07001/*
2 * Copyright (C) 2021 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 "UtilsHost.h"
18
19#include <poll.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/wait.h>
23
24#include <sstream>
25
26#include <log/log.h>
27
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -070028#include "Utils.h"
29
Yifan Hongaf766e62021-06-14 13:24:19 -070030namespace android {
31
32CommandResult::~CommandResult() {
33 if (!pid.has_value()) return;
34 if (*pid == 0) {
35 ALOGW("%s: PID is unexpectedly 0, won't kill it", __PRETTY_FUNCTION__);
36 return;
37 }
38
39 ALOGE_IF(kill(*pid, SIGKILL) != 0, "kill(%d): %s", *pid, strerror(errno));
40
41 while (pid.has_value()) {
42 int status;
43 LOG_HOST("%s: Waiting for PID %d to exit.", __PRETTY_FUNCTION__, *pid);
44 int waitres = waitpid(*pid, &status, 0);
45 if (waitres == -1) {
46 ALOGE("%s: waitpid(%d): %s", __PRETTY_FUNCTION__, *pid, strerror(errno));
47 break;
48 }
49 if (WIFEXITED(status)) {
50 LOG_HOST("%s: PID %d exited.", __PRETTY_FUNCTION__, *pid);
51 pid.reset();
52 } else if (WIFSIGNALED(status)) {
53 LOG_HOST("%s: PID %d terminated by signal %d.", __PRETTY_FUNCTION__, *pid,
54 WTERMSIG(status));
55 pid.reset();
56 } else if (WIFSTOPPED(status)) {
57 ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *pid);
58 } else if (WIFCONTINUED(status)) {
59 ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *pid);
60 }
61 }
62}
63
64std::ostream& operator<<(std::ostream& os, const CommandResult& res) {
65 if (res.exitCode) os << "code=" << *res.exitCode;
66 if (res.signal) os << "signal=" << *res.signal;
67 if (res.pid) os << ", pid=" << *res.pid;
Colin Crossc9a77aa2021-09-13 16:31:38 -070068 return os << ", stdout=" << res.stdoutStr << ", stderr=" << res.stderrStr;
Yifan Hongaf766e62021-06-14 13:24:19 -070069}
70
71std::string CommandResult::toString() const {
72 std::stringstream ss;
73 ss << (*this);
74 return ss.str();
75}
76
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -070077std::optional<CommandResult> execute(std::vector<std::string> argStringVec,
78 const std::function<bool(const CommandResult&)>& end) {
Yifan Hongaf766e62021-06-14 13:24:19 -070079 // turn vector<string> into null-terminated char* vector.
80 std::vector<char*> argv;
81 argv.reserve(argStringVec.size() + 1);
82 for (auto& arg : argStringVec) argv.push_back(arg.data());
83 argv.push_back(nullptr);
84
85 CommandResult ret;
86 android::base::unique_fd outWrite;
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -070087 if (!android::base::Pipe(&ret.outPipe, &outWrite)) {
88 PLOGE("pipe() for outPipe");
89 return {};
90 }
Yifan Hongaf766e62021-06-14 13:24:19 -070091 android::base::unique_fd errWrite;
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -070092 if (!android::base::Pipe(&ret.errPipe, &errWrite)) {
93 PLOGE("pipe() for errPipe");
94 return {};
95 }
Yifan Hongaf766e62021-06-14 13:24:19 -070096
97 int pid = fork();
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -070098 if (pid == -1) {
99 PLOGE("fork()");
100 return {};
101 }
Yifan Hongaf766e62021-06-14 13:24:19 -0700102 if (pid == 0) {
103 // child
104 ret.outPipe.reset();
105 ret.errPipe.reset();
106
107 int res = TEMP_FAILURE_RETRY(dup2(outWrite.get(), STDOUT_FILENO));
108 LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(outPipe): %s", strerror(errno));
109 outWrite.reset();
110
111 res = TEMP_FAILURE_RETRY(dup2(errWrite.get(), STDERR_FILENO));
112 LOG_ALWAYS_FATAL_IF(-1 == res, "dup2(errPipe): %s", strerror(errno));
113 errWrite.reset();
114
115 execvp(argv[0], argv.data());
116 LOG_ALWAYS_FATAL("execvp() returns");
117 }
118 // parent
119 outWrite.reset();
120 errWrite.reset();
121 ret.pid = pid;
122
George Burgess IVa4198302021-07-19 07:31:21 +0000123 auto handlePoll = [](android::base::unique_fd* fd, const pollfd* pfd, std::string* s) {
Yifan Hongaf766e62021-06-14 13:24:19 -0700124 if (!fd->ok()) return true;
George Burgess IVa4198302021-07-19 07:31:21 +0000125 if (pfd->revents & POLLIN) {
Yifan Hongaf766e62021-06-14 13:24:19 -0700126 char buf[1024];
127 ssize_t n = TEMP_FAILURE_RETRY(read(fd->get(), buf, sizeof(buf)));
128 if (n < 0) return false;
129 if (n > 0) *s += std::string_view(buf, n);
130 }
George Burgess IVa4198302021-07-19 07:31:21 +0000131 if (pfd->revents & POLLHUP) {
Yifan Hongaf766e62021-06-14 13:24:19 -0700132 fd->reset();
133 }
134 return true;
135 };
136
137 // Drain both stdout and stderr. Check end() regularly until both are closed.
138 while (ret.outPipe.ok() || ret.errPipe.ok()) {
139 pollfd fds[2];
140 pollfd *outPollFd = nullptr, *errPollFd = nullptr;
141 memset(fds, 0, sizeof(fds));
142 nfds_t nfds = 0;
143 if (ret.outPipe.ok()) {
144 outPollFd = &fds[nfds++];
145 *outPollFd = {.fd = ret.outPipe.get(), .events = POLLIN};
146 }
147 if (ret.errPipe.ok()) {
148 errPollFd = &fds[nfds++];
149 *errPollFd = {.fd = ret.errPipe.get(), .events = POLLIN};
150 }
151 int pollRet = poll(fds, nfds, 1000 /* ms timeout */);
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -0700152 if (pollRet == -1) {
153 PLOGE("poll()");
154 return {};
155 }
Yifan Hongaf766e62021-06-14 13:24:19 -0700156
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -0700157 if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdoutStr)) {
158 PLOGE("read(stdout)");
159 return {};
160 }
161 if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderrStr)) {
162 PLOGE("read(stderr)");
163 return {};
164 }
Yifan Hongaf766e62021-06-14 13:24:19 -0700165
166 if (end && end(ret)) return ret;
167 }
168
169 // If both stdout and stderr are closed by the subprocess, it may or may not be terminated.
170 while (ret.pid.has_value()) {
171 int status;
172 auto exitPid = waitpid(pid, &status, 0);
Tomasz Wasilczyk88aa8c32023-11-01 09:46:07 -0700173 if (exitPid == -1) {
174 PLOGE("waitpid(%d)", pid);
175 return {};
176 }
Yifan Hongaf766e62021-06-14 13:24:19 -0700177 if (exitPid == pid) {
178 if (WIFEXITED(status)) {
179 ret.pid = std::nullopt;
180 ret.exitCode = WEXITSTATUS(status);
181 } else if (WIFSIGNALED(status)) {
182 ret.pid = std::nullopt;
183 ret.signal = WTERMSIG(status);
184 } else if (WIFSTOPPED(status)) {
185 ALOGW("%s: pid %d stopped", __PRETTY_FUNCTION__, *ret.pid);
186 } else if (WIFCONTINUED(status)) {
187 ALOGW("%s: pid %d continued", __PRETTY_FUNCTION__, *ret.pid);
188 }
189 }
190 // ret is not changed unless the process is terminated (where pid == nullopt). Hence there
191 // is no need to check the predicate `end(ret)`.
192 }
193
194 return ret;
195}
196} // namespace android