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