1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #ifdef GPR_POSIX_SUBPROCESS
22
23 #include <errno.h>
24 #include <grpc/support/alloc.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29
30 #include <iostream>
31
32 #include "absl/log/check.h"
33 #include "absl/log/log.h"
34 #include "absl/strings/substitute.h"
35 #include "src/core/util/memory.h"
36 #include "src/core/util/strerror.h"
37 #include "src/core/util/subprocess.h"
38
39 struct gpr_subprocess {
40 int pid;
41 bool joined;
42 int child_stdin_;
43 int child_stdout_;
44 };
45
gpr_subprocess_binary_extension()46 const char* gpr_subprocess_binary_extension() { return ""; }
47
gpr_subprocess_create(int argc,const char ** argv)48 gpr_subprocess* gpr_subprocess_create(int argc, const char** argv) {
49 gpr_subprocess* r;
50 int pid;
51 char** exec_args;
52 pid = fork();
53 if (pid == -1) {
54 return nullptr;
55 } else if (pid == 0) {
56 exec_args = static_cast<char**>(
57 gpr_malloc((static_cast<size_t>(argc) + 1) * sizeof(char*)));
58 memcpy(exec_args, argv, static_cast<size_t>(argc) * sizeof(char*));
59 exec_args[argc] = nullptr;
60 execv(exec_args[0], exec_args);
61 // if we reach here, an error has occurred
62 LOG(ERROR) << "execv '" << exec_args[0]
63 << "' failed: " << grpc_core::StrError(errno);
64 _exit(1);
65 } else {
66 r = grpc_core::Zalloc<gpr_subprocess>();
67 r->pid = pid;
68 r->child_stdin_ = -1;
69 r->child_stdout_ = -1;
70 return r;
71 }
72 }
73
gpr_subprocess_create_with_envp(int argc,const char ** argv,int envc,const char ** envp)74 gpr_subprocess* gpr_subprocess_create_with_envp(int argc, const char** argv,
75 int envc, const char** envp) {
76 gpr_subprocess* r;
77 int pid;
78 char **exec_args, **envp_args;
79 int stdin_pipe[2];
80 int stdout_pipe[2];
81 int p0 = pipe(stdin_pipe);
82 int p1 = pipe(stdout_pipe);
83 CHECK_NE(p0, -1);
84 CHECK_NE(p1, -1);
85 pid = fork();
86 if (pid == -1) {
87 return nullptr;
88 } else if (pid == 0) {
89 dup2(stdin_pipe[0], STDIN_FILENO);
90 dup2(stdout_pipe[1], STDOUT_FILENO);
91 close(stdin_pipe[0]);
92 close(stdin_pipe[1]);
93 close(stdout_pipe[0]);
94 close(stdout_pipe[1]);
95 exec_args = static_cast<char**>(
96 gpr_malloc((static_cast<size_t>(argc) + 1) * sizeof(char*)));
97 memcpy(exec_args, argv, static_cast<size_t>(argc) * sizeof(char*));
98 exec_args[argc] = nullptr;
99 envp_args = static_cast<char**>(
100 gpr_malloc((static_cast<size_t>(envc) + 1) * sizeof(char*)));
101 memcpy(envp_args, envp, static_cast<size_t>(envc) * sizeof(char*));
102 envp_args[envc] = nullptr;
103 execve(exec_args[0], exec_args, envp_args);
104 // if we reach here, an error has occurred
105 LOG(ERROR) << "execvpe '" << exec_args[0]
106 << "' failed: " << grpc_core::StrError(errno);
107 _exit(1);
108 } else {
109 r = grpc_core::Zalloc<gpr_subprocess>();
110 r->pid = pid;
111 close(stdin_pipe[0]);
112 close(stdout_pipe[1]);
113 r->child_stdin_ = stdin_pipe[1];
114 r->child_stdout_ = stdout_pipe[0];
115 return r;
116 }
117 }
118
gpr_subprocess_communicate(gpr_subprocess * p,std::string & input_data,std::string * output_data,std::string * error)119 bool gpr_subprocess_communicate(gpr_subprocess* p, std::string& input_data,
120 std::string* output_data, std::string* error) {
121 typedef void SignalHandler(int);
122
123 // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
124 SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
125
126 int input_pos = 0;
127 int max_fd = std::max(p->child_stdin_, p->child_stdout_);
128
129 while (p->child_stdout_ != -1) {
130 fd_set read_fds;
131 fd_set write_fds;
132 FD_ZERO(&read_fds);
133 FD_ZERO(&write_fds);
134 if (p->child_stdout_ != -1) {
135 FD_SET(p->child_stdout_, &read_fds);
136 }
137 if (p->child_stdin_ != -1) {
138 FD_SET(p->child_stdin_, &write_fds);
139 }
140
141 if (select(max_fd + 1, &read_fds, &write_fds, nullptr, nullptr) < 0) {
142 if (errno == EINTR) {
143 // Interrupted by signal. Try again.
144 continue;
145 } else {
146 std::cerr << "select: " << strerror(errno) << std::endl;
147 CHECK(0);
148 }
149 }
150
151 if (p->child_stdin_ != -1 && FD_ISSET(p->child_stdin_, &write_fds)) {
152 int n = write(p->child_stdin_, input_data.data() + input_pos,
153 input_data.size() - input_pos);
154 if (n < 0) {
155 // Child closed pipe. Presumably it will report an error later.
156 // Pretend we're done for now.
157 input_pos = input_data.size();
158 } else {
159 input_pos += n;
160 }
161
162 if (input_pos == static_cast<int>(input_data.size())) {
163 // We're done writing. Close.
164 close(p->child_stdin_);
165 p->child_stdin_ = -1;
166 }
167 }
168
169 if (p->child_stdout_ != -1 && FD_ISSET(p->child_stdout_, &read_fds)) {
170 char buffer[4096];
171 int n = read(p->child_stdout_, buffer, sizeof(buffer));
172
173 if (n > 0) {
174 output_data->append(buffer, static_cast<size_t>(n));
175 } else {
176 // We're done reading. Close.
177 close(p->child_stdout_);
178 p->child_stdout_ = -1;
179 }
180 }
181 }
182
183 if (p->child_stdin_ != -1) {
184 // Child did not finish reading input before it closed the output.
185 // Presumably it exited with an error.
186 close(p->child_stdin_);
187 p->child_stdin_ = -1;
188 }
189
190 int status;
191 while (waitpid(p->pid, &status, 0) == -1) {
192 if (errno != EINTR) {
193 std::cerr << "waitpid: " << strerror(errno) << std::endl;
194 CHECK(0);
195 }
196 }
197
198 // Restore SIGPIPE handling.
199 signal(SIGPIPE, old_pipe_handler);
200
201 if (WIFEXITED(status)) {
202 if (WEXITSTATUS(status) != 0) {
203 int error_code = WEXITSTATUS(status);
204 *error =
205 absl::Substitute("Plugin failed with status code $0.", error_code);
206 return false;
207 }
208 } else if (WIFSIGNALED(status)) {
209 int signal = WTERMSIG(status);
210 *error = absl::Substitute("Plugin killed by signal $0.", signal);
211 return false;
212 } else {
213 *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
214 return false;
215 }
216
217 return true;
218 }
219
gpr_subprocess_destroy(gpr_subprocess * p)220 void gpr_subprocess_destroy(gpr_subprocess* p) {
221 if (!p->joined) {
222 kill(p->pid, SIGKILL);
223 gpr_subprocess_join(p);
224 }
225 gpr_free(p);
226 }
227
gpr_subprocess_join(gpr_subprocess * p)228 int gpr_subprocess_join(gpr_subprocess* p) {
229 int status;
230 retry:
231 if (waitpid(p->pid, &status, 0) == -1) {
232 if (errno == EINTR) {
233 goto retry;
234 }
235 LOG(ERROR) << "waitpid failed for pid " << p->pid << ": "
236 << grpc_core::StrError(errno);
237 return -1;
238 }
239 p->joined = true;
240 return status;
241 }
242
gpr_subprocess_interrupt(gpr_subprocess * p)243 void gpr_subprocess_interrupt(gpr_subprocess* p) {
244 if (!p->joined) {
245 kill(p->pid, SIGINT);
246 }
247 }
248
gpr_subprocess_get_process_id(gpr_subprocess * p)249 int gpr_subprocess_get_process_id(gpr_subprocess* p) { return p->pid; }
250
251 #endif // GPR_POSIX_SUBPROCESS
252