33 #include <google/protobuf/compiler/subprocess.h>
42 #include <sys/select.h>
46 #include <google/protobuf/stubs/logging.h>
47 #include <google/protobuf/stubs/common.h>
48 #include <google/protobuf/message.h>
49 #include <google/protobuf/stubs/substitute.h>
56 char* portable_strdup(
const char* s) {
57 char*
ns = (
char*)malloc(strlen(s) + 1);
67 static void CloseHandleOrDie(HANDLE
handle) {
68 if (!CloseHandle(
handle)) {
70 << Subprocess::Win32ErrorMessage(GetLastError());
75 : process_start_error_(ERROR_SUCCESS),
78 child_stdout_(NULL) {}
91 HANDLE stdin_pipe_read;
92 HANDLE stdin_pipe_write;
93 HANDLE stdout_pipe_read;
94 HANDLE stdout_pipe_write;
96 if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
97 GOOGLE_LOG(
FATAL) <<
"CreatePipe: " << Win32ErrorMessage(GetLastError());
99 if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
100 GOOGLE_LOG(
FATAL) <<
"CreatePipe: " << Win32ErrorMessage(GetLastError());
104 if (!SetHandleInformation(stdin_pipe_read, HANDLE_FLAG_INHERIT,
105 HANDLE_FLAG_INHERIT)) {
107 << Win32ErrorMessage(GetLastError());
109 if (!SetHandleInformation(stdout_pipe_write, HANDLE_FLAG_INHERIT,
110 HANDLE_FLAG_INHERIT)) {
112 << Win32ErrorMessage(GetLastError());
116 STARTUPINFOA startup_info;
117 ZeroMemory(&startup_info,
sizeof(startup_info));
118 startup_info.cb =
sizeof(startup_info);
119 startup_info.dwFlags = STARTF_USESTDHANDLES;
120 startup_info.hStdInput = stdin_pipe_read;
121 startup_info.hStdOutput = stdout_pipe_write;
122 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
125 GOOGLE_LOG(
FATAL) <<
"GetStdHandle: " << Win32ErrorMessage(GetLastError());
132 portable_strdup((
"cmd.exe /c \"" + program +
"\"").
c_str());
135 PROCESS_INFORMATION process_info;
137 if (CreateProcessA((search_mode ==
SEARCH_PATH) ? NULL : program.c_str(),
138 (search_mode ==
SEARCH_PATH) ? command_line : NULL,
145 &startup_info, &process_info)) {
146 child_handle_ = process_info.hProcess;
147 CloseHandleOrDie(process_info.hThread);
151 process_start_error_ = GetLastError();
152 CloseHandleOrDie(stdin_pipe_write);
153 CloseHandleOrDie(stdout_pipe_read);
156 CloseHandleOrDie(stdin_pipe_read);
157 CloseHandleOrDie(stdout_pipe_write);
163 if (process_start_error_ != ERROR_SUCCESS) {
164 *
error = Win32ErrorMessage(process_start_error_);
168 GOOGLE_CHECK(child_handle_ != NULL) <<
"Must call Start() first.";
177 int handle_count = 0;
187 WaitForMultipleObjects(handle_count,
handles, FALSE, INFINITE);
189 HANDLE signaled_handle = NULL;
190 if (wait_result >= WAIT_OBJECT_0 &&
191 wait_result < WAIT_OBJECT_0 + handle_count) {
192 signaled_handle =
handles[wait_result - WAIT_OBJECT_0];
193 }
else if (wait_result == WAIT_FAILED) {
195 << Win32ErrorMessage(GetLastError());
197 GOOGLE_LOG(
FATAL) <<
"WaitForMultipleObjects: Unexpected return code: "
203 if (!WriteFile(
child_stdin_, input_data.data() + input_pos,
204 input_data.size() - input_pos, &n, NULL)) {
207 input_pos = input_data.size();
212 if (input_pos == input_data.size()) {
226 output_data.append(
buffer, n);
238 DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
240 if (wait_result == WAIT_FAILED) {
242 << Win32ErrorMessage(GetLastError());
243 }
else if (wait_result != WAIT_OBJECT_0) {
249 if (!GetExitCodeProcess(child_handle_, &
exit_code)) {
251 << Win32ErrorMessage(GetLastError());
254 CloseHandleOrDie(child_handle_);
255 child_handle_ = NULL;
262 if (!
output->ParseFromString(output_data)) {
263 *
error =
"Plugin output is unparseable: " +
CEscape(output_data);
270 std::string Subprocess::Win32ErrorMessage(DWORD error_code) {
274 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
275 FORMAT_MESSAGE_IGNORE_INSERTS,
276 NULL, error_code, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
290 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
312 char* argv[2] = {portable_strdup(program.c_str()), NULL};
327 switch (search_mode) {
329 execvp(argv[0], argv);
332 execv(argv[0], argv);
339 ignored =
write(STDERR_FILENO, argv[0], strlen(argv[0]));
341 ": program not found or is not executable\n"
342 "Please specify a program using absolute path or make sure "
343 "the program is available in your PATH system variable\n";
366 typedef void SignalHandler(
int);
369 SignalHandler* old_pipe_handler =
signal(SIGPIPE, SIG_IGN);
389 if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
390 if (errno == EINTR) {
400 input_data.size() - input_pos);
404 input_pos = input_data.size();
409 if (input_pos == input_data.size()) {
421 output_data.append(
buffer, n);
439 if (errno != EINTR) {
445 signal(SIGPIPE, old_pipe_handler);
448 if (WEXITSTATUS(
status) != 0) {
449 int error_code = WEXITSTATUS(
status);
454 }
else if (WIFSIGNALED(
status)) {
459 *
error =
"Neither WEXITSTATUS nor WTERMSIG is true?";
463 if (!
output->ParseFromString(output_data)) {
464 *
error =
"Plugin output is unparseable: " +
CEscape(output_data);