1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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
49namespace google {
50namespace protobuf {
51namespace compiler {
52
53#ifdef _WIN32
54
55static void CloseHandleOrDie(HANDLE handle) {
56  if (!CloseHandle(handle)) {
57    GOOGLE_LOG(FATAL) << "CloseHandle: "
58                      << Subprocess::Win32ErrorMessage(GetLastError());
59  }
60}
61
62Subprocess::Subprocess()
63    : process_start_error_(ERROR_SUCCESS),
64      child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
65
66Subprocess::~Subprocess() {
67  if (child_stdin_ != NULL) {
68    CloseHandleOrDie(child_stdin_);
69  }
70  if (child_stdout_ != NULL) {
71    CloseHandleOrDie(child_stdout_);
72  }
73}
74
75void 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
146bool 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
258string 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
278Subprocess::Subprocess()
279    : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
280
281Subprocess::~Subprocess() {
282  if (child_stdin_ != -1) {
283    close(child_stdin_);
284  }
285  if (child_stdout_ != -1) {
286    close(child_stdout_);
287  }
288}
289
290void 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
347bool 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.";
453    return false;
454  }
455
456  return true;
457}
458
459#endif  // !_WIN32
460
461}  // namespace compiler
462}  // namespace protobuf
463}  // namespace google
464