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