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
46 namespace google {
47 namespace protobuf {
48 namespace compiler {
49
50 #ifdef _WIN32
51
CloseHandleOrDie(HANDLE handle)52 static void CloseHandleOrDie(HANDLE handle) {
53 if (!CloseHandle(handle)) {
54 GOOGLE_LOG(FATAL) << "CloseHandle: "
55 << Subprocess::Win32ErrorMessage(GetLastError());
56 }
57 }
58
Subprocess()59 Subprocess::Subprocess()
60 : process_start_error_(ERROR_SUCCESS),
61 child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
62
~Subprocess()63 Subprocess::~Subprocess() {
64 if (child_stdin_ != NULL) {
65 CloseHandleOrDie(child_stdin_);
66 }
67 if (child_stdout_ != NULL) {
68 CloseHandleOrDie(child_stdout_);
69 }
70 }
71
Start(const string & program,SearchMode search_mode)72 void 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
Communicate(const Message & input,Message * output,string * error)143 bool 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
Win32ErrorMessage(DWORD error_code)255 string 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
275 Subprocess::Subprocess()
276 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
277
278 Subprocess::~Subprocess() {
279 if (child_stdin_ != -1) {
280 close(child_stdin_);
281 }
282 if (child_stdout_ != -1) {
283 close(child_stdout_);
284 }
285 }
286
287 void 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
342 bool 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