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 (at) 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 52 static void CloseHandleOrDie(HANDLE handle) { 53 if (!CloseHandle(handle)) { 54 GOOGLE_LOG(FATAL) << "CloseHandle: " 55 << Subprocess::Win32ErrorMessage(GetLastError()); 56 } 57 } 58 59 Subprocess::Subprocess() 60 : process_start_error_(ERROR_SUCCESS), 61 child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {} 62 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 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 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 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