blob: 463d4580cfd71847c0e1ca48b8082d7fb6e8ea58 [file] [log] [blame]
David Sehr97c381e2017-02-01 15:09:58 -08001/*
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 */
16
17#include "exec_utils.h"
18
19#include <sys/types.h>
20#include <sys/wait.h>
21#include <string>
22#include <vector>
23
24#include "android-base/stringprintf.h"
25#include "android-base/strings.h"
26
27#include "runtime.h"
28
29namespace art {
30
David Sehr97c381e2017-02-01 15:09:58 -080031using android::base::StringPrintf;
32
Orion Hodsondd732cc2021-01-15 16:31:30 +000033namespace {
David Sehr97c381e2017-02-01 15:09:58 -080034
Orion Hodsondd732cc2021-01-15 16:31:30 +000035std::string ToCommandLine(const std::vector<std::string>& args) {
36 return android::base::Join(args, ' ');
37}
38
39// Fork and execute a command specified in a subprocess.
40// If there is a runtime (Runtime::Current != nullptr) then the subprocess is created with the
41// same environment that existed when the runtime was started.
42// Returns the process id of the child process on success, -1 otherwise.
43pid_t ExecWithoutWait(std::vector<std::string>& arg_vector) {
David Sehr97c381e2017-02-01 15:09:58 -080044 // Convert the args to char pointers.
45 const char* program = arg_vector[0].c_str();
46 std::vector<char*> args;
Orion Hodsondd732cc2021-01-15 16:31:30 +000047 for (const auto& arg : arg_vector) {
48 args.push_back(const_cast<char*>(arg.c_str()));
David Sehr97c381e2017-02-01 15:09:58 -080049 }
50 args.push_back(nullptr);
51
52 // fork and exec
53 pid_t pid = fork();
54 if (pid == 0) {
55 // no allocation allowed between fork and exec
56
57 // change process groups, so we don't get reaped by ProcessManager
58 setpgid(0, 0);
59
60 // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
61 // Use the snapshot of the environment from the time the runtime was created.
62 char** envp = (Runtime::Current() == nullptr) ? nullptr : Runtime::Current()->GetEnvSnapshot();
63 if (envp == nullptr) {
64 execv(program, &args[0]);
65 } else {
66 execve(program, &args[0], envp);
67 }
Orion Hodsondd732cc2021-01-15 16:31:30 +000068 PLOG(ERROR) << "Failed to execve(" << ToCommandLine(arg_vector) << ")";
David Sehr97c381e2017-02-01 15:09:58 -080069 // _exit to avoid atexit handlers in child.
70 _exit(1);
71 } else {
Orion Hodsondd732cc2021-01-15 16:31:30 +000072 return pid;
David Sehr97c381e2017-02-01 15:09:58 -080073 }
74}
75
Orion Hodsondd732cc2021-01-15 16:31:30 +000076} // namespace
77
78int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) {
79 pid_t pid = ExecWithoutWait(arg_vector);
80 if (pid == -1) {
81 *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
82 ToCommandLine(arg_vector).c_str(), strerror(errno));
83 return -1;
84 }
85
86 // wait for subprocess to finish
87 int status = -1;
88 pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
89 if (got_pid != pid) {
90 *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
91 "wanted %d, got %d: %s",
92 ToCommandLine(arg_vector).c_str(), pid, got_pid, strerror(errno));
93 return -1;
94 }
95 if (WIFEXITED(status)) {
96 return WEXITSTATUS(status);
97 }
98 return -1;
99}
100
101int ExecAndReturnCode(std::vector<std::string>& arg_vector,
102 time_t timeout_secs,
103 bool* timed_out,
104 std::string* error_msg) {
105 *timed_out = false;
106
107 // Start subprocess.
108 pid_t pid = ExecWithoutWait(arg_vector);
109 if (pid == -1) {
110 *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
111 ToCommandLine(arg_vector).c_str(), strerror(errno));
112 return -1;
113 }
114
115 // Add SIGCHLD to the signal set.
116 sigset_t child_mask, original_mask;
117 sigemptyset(&child_mask);
118 sigaddset(&child_mask, SIGCHLD);
119 if (sigprocmask(SIG_BLOCK, &child_mask, &original_mask) == -1) {
120 *error_msg = StringPrintf("Failed to set sigprocmask(): %s", strerror(errno));
121 return -1;
122 }
123
124 // Wait for a SIGCHLD notification.
125 errno = 0;
126 timespec ts = {timeout_secs, 0};
127 int wait_result = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
128 int wait_errno = errno;
129
130 // Restore the original signal set.
131 if (sigprocmask(SIG_SETMASK, &original_mask, nullptr) == -1) {
132 *error_msg = StringPrintf("Fail to restore sigprocmask(): %s", strerror(errno));
133 if (wait_result == 0) {
134 return -1;
135 }
136 }
137
138 // Having restored the signal set, see if we need to terminate the subprocess.
139 if (wait_result == -1) {
140 if (wait_errno == EAGAIN) {
141 *error_msg = "Timed out.";
142 *timed_out = true;
143 } else {
144 *error_msg = StringPrintf("Failed to sigtimedwait(): %s", strerror(errno));
145 }
146 if (kill(pid, SIGKILL) != 0) {
147 PLOG(ERROR) << "Failed to kill() subprocess: ";
148 }
149 }
150
151 // Wait for subprocess to finish.
152 int status = -1;
153 pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
154 if (got_pid != pid) {
155 *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
156 "wanted %d, got %d: %s",
157 ToCommandLine(arg_vector).c_str(), pid, got_pid, strerror(errno));
158 return -1;
159 }
160 if (WIFEXITED(status)) {
161 return WEXITSTATUS(status);
162 }
163 return -1;
164}
165
166
David Sehr97c381e2017-02-01 15:09:58 -0800167bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) {
168 int status = ExecAndReturnCode(arg_vector, error_msg);
169 if (status != 0) {
David Sehr97c381e2017-02-01 15:09:58 -0800170 *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
Orion Hodsondd732cc2021-01-15 16:31:30 +0000171 ToCommandLine(arg_vector).c_str());
David Sehr97c381e2017-02-01 15:09:58 -0800172 return false;
173 }
174 return true;
175}
176
177} // namespace art