1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
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
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.
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.
31 // Author: kenton@google.com (Kenton Varda)
33 #include <google/protobuf/compiler/subprocess.h>
40 #include <sys/select.h>
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/message.h>
47 #include <google/protobuf/stubs/substitute.h>
55 static void CloseHandleOrDie(HANDLE handle) {
56 if (!CloseHandle(handle)) {
57 GOOGLE_LOG(FATAL) << "CloseHandle: "
58 << Subprocess::Win32ErrorMessage(GetLastError());
62 Subprocess::Subprocess()
63 : process_start_error_(ERROR_SUCCESS),
64 child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
66 Subprocess::~Subprocess() {
67 if (child_stdin_ != NULL) {
68 CloseHandleOrDie(child_stdin_);
70 if (child_stdout_ != NULL) {
71 CloseHandleOrDie(child_stdout_);
75 void Subprocess::Start(const string& program, SearchMode search_mode) {
77 HANDLE stdin_pipe_read;
78 HANDLE stdin_pipe_write;
79 HANDLE stdout_pipe_read;
80 HANDLE stdout_pipe_write;
82 if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
83 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
85 if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
86 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
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());
95 if (!SetHandleInformation(stdout_pipe_write,
96 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
97 GOOGLE_LOG(FATAL) << "SetHandleInformation: "
98 << Win32ErrorMessage(GetLastError());
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);
110 if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
111 GOOGLE_LOG(FATAL) << "GetStdHandle: "
112 << Win32ErrorMessage(GetLastError());
115 // CreateProcess() mutates its second parameter. WTF?
116 char* name_copy = strdup(program.c_str());
118 // Create the process.
119 PROCESS_INFORMATION process_info;
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)
131 child_handle_ = process_info.hProcess;
132 CloseHandleOrDie(process_info.hThread);
133 child_stdin_ = stdin_pipe_write;
134 child_stdout_ = stdout_pipe_read;
136 process_start_error_ = GetLastError();
137 CloseHandleOrDie(stdin_pipe_write);
138 CloseHandleOrDie(stdout_pipe_read);
141 CloseHandleOrDie(stdin_pipe_read);
142 CloseHandleOrDie(stdout_pipe_write);
146 bool Subprocess::Communicate(const Message& input, Message* output,
148 if (process_start_error_ != ERROR_SUCCESS) {
149 *error = Win32ErrorMessage(process_start_error_);
153 GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";
155 string input_data = input.SerializeAsString();
160 while (child_stdout_ != NULL) {
162 int handle_count = 0;
164 if (child_stdin_ != NULL) {
165 handles[handle_count++] = child_stdin_;
167 if (child_stdout_ != NULL) {
168 handles[handle_count++] = child_stdout_;
172 WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
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());
182 GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
186 if (signaled_handle == child_stdin_) {
188 if (!WriteFile(child_stdin_,
189 input_data.data() + input_pos,
190 input_data.size() - input_pos,
192 // Child closed pipe. Presumably it will report an error later.
193 // Pretend we're done for now.
194 input_pos = input_data.size();
199 if (input_pos == input_data.size()) {
200 // We're done writing. Close.
201 CloseHandleOrDie(child_stdin_);
204 } else if (signaled_handle == child_stdout_) {
208 if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
209 // We're done reading. Close.
210 CloseHandleOrDie(child_stdout_);
211 child_stdout_ = NULL;
213 output_data.append(buffer, n);
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_);
225 DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
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: "
236 if (!GetExitCodeProcess(child_handle_, &exit_code)) {
237 GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
238 << Win32ErrorMessage(GetLastError());
241 CloseHandleOrDie(child_handle_);
242 child_handle_ = NULL;
244 if (exit_code != 0) {
245 *error = strings::Substitute(
246 "Plugin failed with status code $0.", exit_code);
250 if (!output->ParseFromString(output_data)) {
251 *error = "Plugin output is unparseable: " + CEscape(output_data);
258 string Subprocess::Win32ErrorMessage(DWORD error_code) {
262 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
263 FORMAT_MESSAGE_FROM_SYSTEM |
264 FORMAT_MESSAGE_IGNORE_INSERTS,
266 (LPTSTR)&message, // NOT A BUG!
269 string result = message;
274 // ===================================================================
278 Subprocess::Subprocess()
279 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
281 Subprocess::~Subprocess() {
282 if (child_stdin_ != -1) {
285 if (child_stdout_ != -1) {
286 close(child_stdout_);
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.
294 // [0] is read end, [1] is write end.
298 GOOGLE_CHECK(pipe(stdin_pipe) != -1);
299 GOOGLE_CHECK(pipe(stdout_pipe) != -1);
301 char* argv[2] = { strdup(program.c_str()), NULL };
304 if (child_pid_ == -1) {
305 GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
306 } else if (child_pid_ == 0) {
308 dup2(stdin_pipe[0], STDIN_FILENO);
309 dup2(stdout_pipe[1], STDOUT_FILENO);
311 close(stdin_pipe[0]);
312 close(stdin_pipe[1]);
313 close(stdout_pipe[0]);
314 close(stdout_pipe[1]);
316 switch (search_mode) {
318 execvp(argv[0], argv);
321 execv(argv[0], argv);
325 // Write directly to STDERR_FILENO to avoid stdio code paths that may do
326 // stuff that is unsafe here.
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));
333 // Must use _exit() rather than exit() to avoid flushing output buffers
334 // that will also be flushed by the parent.
339 close(stdin_pipe[0]);
340 close(stdout_pipe[1]);
342 child_stdin_ = stdin_pipe[1];
343 child_stdout_ = stdout_pipe[0];
347 bool Subprocess::Communicate(const Message& input, Message* output,
350 GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";
352 // The "sighandler_t" typedef is GNU-specific, so define our own.
353 typedef void SignalHandler(int);
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);
358 string input_data = input.SerializeAsString();
362 int max_fd = max(child_stdin_, child_stdout_);
364 while (child_stdout_ != -1) {
369 if (child_stdout_ != -1) {
370 FD_SET(child_stdout_, &read_fds);
372 if (child_stdin_ != -1) {
373 FD_SET(child_stdin_, &write_fds);
376 if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
377 if (errno == EINTR) {
378 // Interrupted by signal. Try again.
381 GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
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);
389 // Child closed pipe. Presumably it will report an error later.
390 // Pretend we're done for now.
391 input_pos = input_data.size();
396 if (input_pos == input_data.size()) {
397 // We're done writing. Close.
403 if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
405 int n = read(child_stdout_, buffer, sizeof(buffer));
408 output_data.append(buffer, n);
410 // We're done reading. Close.
411 close(child_stdout_);
417 if (child_stdin_ != -1) {
418 // Child did not finish reading input before it closed the output.
419 // Presumably it exited with an error.
425 while (waitpid(child_pid_, &status, 0) == -1) {
426 if (errno != EINTR) {
427 GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
431 // Restore SIGPIPE handling.
432 signal(SIGPIPE, old_pipe_handler);
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);
441 } else if (WIFSIGNALED(status)) {
442 int signal = WTERMSIG(status);
443 *error = strings::Substitute(
444 "Plugin killed by signal $0.", signal);
447 *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
451 if (!output->ParseFromString(output_data)) {
452 *error = "Plugin output is unparseable.";
461 } // namespace compiler
462 } // namespace protobuf
463 } // namespace google