42 #include <sys/select.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) {}
80 Subprocess::~Subprocess() {
81 if (child_stdin_ !=
NULL) {
82 CloseHandleOrDie(child_stdin_);
84 if (child_stdout_ !=
NULL) {
85 CloseHandleOrDie(child_stdout_);
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);
124 if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
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);
148 child_stdin_ = stdin_pipe_write;
149 child_stdout_ = stdout_pipe_read;
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);
161 bool Subprocess::Communicate(
const Message&
input, Message*
output,
163 if (process_start_error_ != ERROR_SUCCESS) {
164 *
error = Win32ErrorMessage(process_start_error_);
175 while (child_stdout_ !=
NULL) {
177 int handle_count = 0;
179 if (child_stdin_ !=
NULL) {
180 handles[handle_count++] = child_stdin_;
182 if (child_stdout_ !=
NULL) {
183 handles[handle_count++] = child_stdout_;
187 WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
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: "
201 if (signaled_handle == child_stdin_) {
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()) {
214 CloseHandleOrDie(child_stdin_);
217 }
else if (signaled_handle == child_stdout_) {
223 CloseHandleOrDie(child_stdout_);
224 child_stdout_ =
NULL;
231 if (child_stdin_ !=
NULL) {
234 CloseHandleOrDie(child_stdin_);
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;
257 if (exit_code != 0) {
263 if (!
output->ParseFromString(output_data)) {
264 *
error =
"Plugin output is unparseable: " +
CEscape(output_data);
271 std::string Subprocess::Win32ErrorMessage(DWORD error_code) {
275 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
276 FORMAT_MESSAGE_IGNORE_INSERTS,
291 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
313 char* argv[2] = {portable_strdup(
program.c_str()),
NULL};
320 dup2(stdin_pipe[0], STDIN_FILENO);
321 dup2(stdout_pipe[1], STDOUT_FILENO);
323 close(stdin_pipe[0]);
324 close(stdin_pipe[1]);
325 close(stdout_pipe[0]);
326 close(stdout_pipe[1]);
328 switch (search_mode) {
330 execvp(argv[0], argv);
333 execv(argv[0], argv);
340 ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
342 ": program not found or is not executable\n"
343 "Please specify a program using absolute path or make sure "
344 "the program is available in your PATH system variable\n";
354 close(stdin_pipe[0]);
355 close(stdout_pipe[1]);
367 typedef void SignalHandler(
int);
370 SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
390 if (select(max_fd + 1, &read_fds, &write_fds,
NULL,
NULL) < 0) {
401 input_data.size() - input_pos);
405 input_pos = input_data.size();
410 if (input_pos == input_data.size()) {
439 while (waitpid(
child_pid_, &status, 0) == -1) {
446 signal(SIGPIPE, old_pipe_handler);
448 if (WIFEXITED(status)) {
449 if (WEXITSTATUS(status) != 0) {
450 int error_code = WEXITSTATUS(status);
455 }
else if (WIFSIGNALED(status)) {
456 int signal = WTERMSIG(status);
460 *
error =
"Neither WEXITSTATUS nor WTERMSIG is true?";
464 if (!
output->ParseFromString(output_data)) {
465 *
error =
"Plugin output is unparseable: " +
CEscape(output_data);