1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // Author: kenton@google.com (Kenton Varda)
32
33 #include <google/protobuf/compiler/subprocess.h>
34
35 #include <algorithm>
36 #include <iostream>
37
38 #ifndef _WIN32
39 #include <errno.h>
40 #include <sys/select.h>
41 #include <sys/wait.h>
42 #include <signal.h>
43 #endif
44
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/message.h>
47 #include <google/protobuf/stubs/substitute.h>
48
49 namespace google {
50 namespace protobuf {
51 namespace compiler {
52
53 #ifdef _WIN32
54
CloseHandleOrDie(HANDLE handle)55 static void CloseHandleOrDie(HANDLE handle) {
56 if (!CloseHandle(handle)) {
57 GOOGLE_LOG(FATAL) << "CloseHandle: "
58 << Subprocess::Win32ErrorMessage(GetLastError());
59 }
60 }
61
Subprocess()62 Subprocess::Subprocess()
63 : process_start_error_(ERROR_SUCCESS),
64 child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
65
~Subprocess()66 Subprocess::~Subprocess() {
67 if (child_stdin_ != NULL) {
68 CloseHandleOrDie(child_stdin_);
69 }
70 if (child_stdout_ != NULL) {
71 CloseHandleOrDie(child_stdout_);
72 }
73 }
74
Start(const string & program,SearchMode search_mode)75 void Subprocess::Start(const string& program, SearchMode search_mode) {
76 // Create the pipes.
77 HANDLE stdin_pipe_read;
78 HANDLE stdin_pipe_write;
79 HANDLE stdout_pipe_read;
80 HANDLE stdout_pipe_write;
81
82 if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
83 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
84 }
85 if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
86 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
87 }
88
89 // Make child side of the pipes inheritable.
90 if (!SetHandleInformation(stdin_pipe_read,
91 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
92 GOOGLE_LOG(FATAL) << "SetHandleInformation: "
93 << Win32ErrorMessage(GetLastError());
94 }
95 if (!SetHandleInformation(stdout_pipe_write,
96 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
97 GOOGLE_LOG(FATAL) << "SetHandleInformation: "
98 << Win32ErrorMessage(GetLastError());
99 }
100
101 // Setup STARTUPINFO to redirect handles.
102 STARTUPINFOA startup_info;
103 ZeroMemory(&startup_info, sizeof(startup_info));
104 startup_info.cb = sizeof(startup_info);
105 startup_info.dwFlags = STARTF_USESTDHANDLES;
106 startup_info.hStdInput = stdin_pipe_read;
107 startup_info.hStdOutput = stdout_pipe_write;
108 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
109
110 if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
111 GOOGLE_LOG(FATAL) << "GetStdHandle: "
112 << Win32ErrorMessage(GetLastError());
113 }
114
115 // CreateProcess() mutates its second parameter. WTF?
116 char* name_copy = strdup(program.c_str());
117
118 // Create the process.
119 PROCESS_INFORMATION process_info;
120
121 if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
122 (search_mode == SEARCH_PATH) ? name_copy : NULL,
123 NULL, // process security attributes
124 NULL, // thread security attributes
125 TRUE, // inherit handles?
126 0, // obscure creation flags
127 NULL, // environment (inherit from parent)
128 NULL, // current directory (inherit from parent)
129 &startup_info,
130 &process_info)) {
131 child_handle_ = process_info.hProcess;
132 CloseHandleOrDie(process_info.hThread);
133 child_stdin_ = stdin_pipe_write;
134 child_stdout_ = stdout_pipe_read;
135 } else {
136 process_start_error_ = GetLastError();
137 CloseHandleOrDie(stdin_pipe_write);
138 CloseHandleOrDie(stdout_pipe_read);
139 }
140
141 CloseHandleOrDie(stdin_pipe_read);
142 CloseHandleOrDie(stdout_pipe_write);
143 free(name_copy);
144 }
145
Communicate(const Message & input,Message * output,string * error)146 bool Subprocess::Communicate(const Message& input, Message* output,
147 string* error) {
148 if (process_start_error_ != ERROR_SUCCESS) {
149 *error = Win32ErrorMessage(process_start_error_);
150 return false;
151 }
152
153 GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";
154
155 string input_data = input.SerializeAsString();
156 string output_data;
157
158 int input_pos = 0;
159
160 while (child_stdout_ != NULL) {
161 HANDLE handles[2];
162 int handle_count = 0;
163
164 if (child_stdin_ != NULL) {
165 handles[handle_count++] = child_stdin_;
166 }
167 if (child_stdout_ != NULL) {
168 handles[handle_count++] = child_stdout_;
169 }
170
171 DWORD wait_result =
172 WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
173
174 HANDLE signaled_handle;
175 if (wait_result >= WAIT_OBJECT_0 &&
176 wait_result < WAIT_OBJECT_0 + handle_count) {
177 signaled_handle = handles[wait_result - WAIT_OBJECT_0];
178 } else if (wait_result == WAIT_FAILED) {
179 GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
180 << Win32ErrorMessage(GetLastError());
181 } else {
182 GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
183 << wait_result;
184 }
185
186 if (signaled_handle == child_stdin_) {
187 DWORD n;
188 if (!WriteFile(child_stdin_,
189 input_data.data() + input_pos,
190 input_data.size() - input_pos,
191 &n, NULL)) {
192 // Child closed pipe. Presumably it will report an error later.
193 // Pretend we're done for now.
194 input_pos = input_data.size();
195 } else {
196 input_pos += n;
197 }
198
199 if (input_pos == input_data.size()) {
200 // We're done writing. Close.
201 CloseHandleOrDie(child_stdin_);
202 child_stdin_ = NULL;
203 }
204 } else if (signaled_handle == child_stdout_) {
205 char buffer[4096];
206 DWORD n;
207
208 if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
209 // We're done reading. Close.
210 CloseHandleOrDie(child_stdout_);
211 child_stdout_ = NULL;
212 } else {
213 output_data.append(buffer, n);
214 }
215 }
216 }
217
218 if (child_stdin_ != NULL) {
219 // Child did not finish reading input before it closed the output.
220 // Presumably it exited with an error.
221 CloseHandleOrDie(child_stdin_);
222 child_stdin_ = NULL;
223 }
224
225 DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
226
227 if (wait_result == WAIT_FAILED) {
228 GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
229 << Win32ErrorMessage(GetLastError());
230 } else if (wait_result != WAIT_OBJECT_0) {
231 GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
232 << wait_result;
233 }
234
235 DWORD exit_code;
236 if (!GetExitCodeProcess(child_handle_, &exit_code)) {
237 GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
238 << Win32ErrorMessage(GetLastError());
239 }
240
241 CloseHandleOrDie(child_handle_);
242 child_handle_ = NULL;
243
244 if (exit_code != 0) {
245 *error = strings::Substitute(
246 "Plugin failed with status code $0.", exit_code);
247 return false;
248 }
249
250 if (!output->ParseFromString(output_data)) {
251 *error = "Plugin output is unparseable: " + CEscape(output_data);
252 return false;
253 }
254
255 return true;
256 }
257
Win32ErrorMessage(DWORD error_code)258 string Subprocess::Win32ErrorMessage(DWORD error_code) {
259 char* message;
260
261 // WTF?
262 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
263 FORMAT_MESSAGE_FROM_SYSTEM |
264 FORMAT_MESSAGE_IGNORE_INSERTS,
265 NULL, error_code, 0,
266 (LPTSTR)&message, // NOT A BUG!
267 0, NULL);
268
269 string result = message;
270 LocalFree(message);
271 return result;
272 }
273
274 // ===================================================================
275
276 #else // _WIN32
277
278 Subprocess::Subprocess()
279 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
280
281 Subprocess::~Subprocess() {
282 if (child_stdin_ != -1) {
283 close(child_stdin_);
284 }
285 if (child_stdout_ != -1) {
286 close(child_stdout_);
287 }
288 }
289
290 void Subprocess::Start(const string& program, SearchMode search_mode) {
291 // Note that we assume that there are no other threads, thus we don't have to
292 // do crazy stuff like using socket pairs or avoiding libc locks.
293
294 // [0] is read end, [1] is write end.
295 int stdin_pipe[2];
296 int stdout_pipe[2];
297
298 GOOGLE_CHECK(pipe(stdin_pipe) != -1);
299 GOOGLE_CHECK(pipe(stdout_pipe) != -1);
300
301 char* argv[2] = { strdup(program.c_str()), NULL };
302
303 child_pid_ = fork();
304 if (child_pid_ == -1) {
305 GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
306 } else if (child_pid_ == 0) {
307 // We are the child.
308 dup2(stdin_pipe[0], STDIN_FILENO);
309 dup2(stdout_pipe[1], STDOUT_FILENO);
310
311 close(stdin_pipe[0]);
312 close(stdin_pipe[1]);
313 close(stdout_pipe[0]);
314 close(stdout_pipe[1]);
315
316 switch (search_mode) {
317 case SEARCH_PATH:
318 execvp(argv[0], argv);
319 break;
320 case EXACT_NAME:
321 execv(argv[0], argv);
322 break;
323 }
324
325 // Write directly to STDERR_FILENO to avoid stdio code paths that may do
326 // stuff that is unsafe here.
327 int ignored;
328 ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
329 const char* message = ": program not found or is not executable\n";
330 ignored = write(STDERR_FILENO, message, strlen(message));
331 (void) ignored;
332
333 // Must use _exit() rather than exit() to avoid flushing output buffers
334 // that will also be flushed by the parent.
335 _exit(1);
336 } else {
337 free(argv[0]);
338
339 close(stdin_pipe[0]);
340 close(stdout_pipe[1]);
341
342 child_stdin_ = stdin_pipe[1];
343 child_stdout_ = stdout_pipe[0];
344 }
345 }
346
347 bool Subprocess::Communicate(const Message& input, Message* output,
348 string* error) {
349
350 GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";
351
352 // The "sighandler_t" typedef is GNU-specific, so define our own.
353 typedef void SignalHandler(int);
354
355 // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
356 SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
357
358 string input_data = input.SerializeAsString();
359 string output_data;
360
361 int input_pos = 0;
362 int max_fd = max(child_stdin_, child_stdout_);
363
364 while (child_stdout_ != -1) {
365 fd_set read_fds;
366 fd_set write_fds;
367 FD_ZERO(&read_fds);
368 FD_ZERO(&write_fds);
369 if (child_stdout_ != -1) {
370 FD_SET(child_stdout_, &read_fds);
371 }
372 if (child_stdin_ != -1) {
373 FD_SET(child_stdin_, &write_fds);
374 }
375
376 if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
377 if (errno == EINTR) {
378 // Interrupted by signal. Try again.
379 continue;
380 } else {
381 GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
382 }
383 }
384
385 if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
386 int n = write(child_stdin_, input_data.data() + input_pos,
387 input_data.size() - input_pos);
388 if (n < 0) {
389 // Child closed pipe. Presumably it will report an error later.
390 // Pretend we're done for now.
391 input_pos = input_data.size();
392 } else {
393 input_pos += n;
394 }
395
396 if (input_pos == input_data.size()) {
397 // We're done writing. Close.
398 close(child_stdin_);
399 child_stdin_ = -1;
400 }
401 }
402
403 if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
404 char buffer[4096];
405 int n = read(child_stdout_, buffer, sizeof(buffer));
406
407 if (n > 0) {
408 output_data.append(buffer, n);
409 } else {
410 // We're done reading. Close.
411 close(child_stdout_);
412 child_stdout_ = -1;
413 }
414 }
415 }
416
417 if (child_stdin_ != -1) {
418 // Child did not finish reading input before it closed the output.
419 // Presumably it exited with an error.
420 close(child_stdin_);
421 child_stdin_ = -1;
422 }
423
424 int status;
425 while (waitpid(child_pid_, &status, 0) == -1) {
426 if (errno != EINTR) {
427 GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
428 }
429 }
430
431 // Restore SIGPIPE handling.
432 signal(SIGPIPE, old_pipe_handler);
433
434 if (WIFEXITED(status)) {
435 if (WEXITSTATUS(status) != 0) {
436 int error_code = WEXITSTATUS(status);
437 *error = strings::Substitute(
438 "Plugin failed with status code $0.", error_code);
439 return false;
440 }
441 } else if (WIFSIGNALED(status)) {
442 int signal = WTERMSIG(status);
443 *error = strings::Substitute(
444 "Plugin killed by signal $0.", signal);
445 return false;
446 } else {
447 *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
448 return false;
449 }
450
451 if (!output->ParseFromString(output_data)) {
452 *error = "Plugin output is unparseable: " + CEscape(output_data);
453 return false;
454 }
455
456 return true;
457 }
458
459 #endif // !_WIN32
460
461 } // namespace compiler
462 } // namespace protobuf
463 } // namespace google
464