1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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 #include <algorithm> 36 #include <iostream> 37 38 #ifndef _WIN32 39 #include <errno.h> 40 #include <sys/select.h> 41 #include <sys/wait.h> 42 #include <signal.h> 43 #endif 44 45 #include <google/protobuf/stubs/logging.h> 46 #include <google/protobuf/stubs/common.h> 47 #include <google/protobuf/message.h> 48 #include <google/protobuf/stubs/substitute.h> 49 50 51 namespace google { 52 namespace protobuf { 53 namespace compiler { 54 55 #ifdef _WIN32 56 57 static void CloseHandleOrDie(HANDLE handle) { 58 if (!CloseHandle(handle)) { 59 GOOGLE_LOG(FATAL) << "CloseHandle: " 60 << Subprocess::Win32ErrorMessage(GetLastError()); 61 } 62 } 63 64 Subprocess::Subprocess() 65 : process_start_error_(ERROR_SUCCESS), 66 child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {} 67 68 Subprocess::~Subprocess() { 69 if (child_stdin_ != NULL) { 70 CloseHandleOrDie(child_stdin_); 71 } 72 if (child_stdout_ != NULL) { 73 CloseHandleOrDie(child_stdout_); 74 } 75 } 76 77 void Subprocess::Start(const string& program, SearchMode search_mode) { 78 // Create the pipes. 79 HANDLE stdin_pipe_read; 80 HANDLE stdin_pipe_write; 81 HANDLE stdout_pipe_read; 82 HANDLE stdout_pipe_write; 83 84 if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) { 85 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); 86 } 87 if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) { 88 GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); 89 } 90 91 // Make child side of the pipes inheritable. 92 if (!SetHandleInformation(stdin_pipe_read, 93 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { 94 GOOGLE_LOG(FATAL) << "SetHandleInformation: " 95 << Win32ErrorMessage(GetLastError()); 96 } 97 if (!SetHandleInformation(stdout_pipe_write, 98 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { 99 GOOGLE_LOG(FATAL) << "SetHandleInformation: " 100 << Win32ErrorMessage(GetLastError()); 101 } 102 103 // Setup STARTUPINFO to redirect handles. 104 STARTUPINFOA startup_info; 105 ZeroMemory(&startup_info, sizeof(startup_info)); 106 startup_info.cb = sizeof(startup_info); 107 startup_info.dwFlags = STARTF_USESTDHANDLES; 108 startup_info.hStdInput = stdin_pipe_read; 109 startup_info.hStdOutput = stdout_pipe_write; 110 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); 111 112 if (startup_info.hStdError == INVALID_HANDLE_VALUE) { 113 GOOGLE_LOG(FATAL) << "GetStdHandle: " 114 << Win32ErrorMessage(GetLastError()); 115 } 116 117 // CreateProcess() mutates its second parameter. WTF? 118 char* name_copy = strdup(program.c_str()); 119 120 // Create the process. 121 PROCESS_INFORMATION process_info; 122 123 if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(), 124 (search_mode == SEARCH_PATH) ? name_copy : NULL, 125 NULL, // process security attributes 126 NULL, // thread security attributes 127 TRUE, // inherit handles? 128 0, // obscure creation flags 129 NULL, // environment (inherit from parent) 130 NULL, // current directory (inherit from parent) 131 &startup_info, 132 &process_info)) { 133 child_handle_ = process_info.hProcess; 134 CloseHandleOrDie(process_info.hThread); 135 child_stdin_ = stdin_pipe_write; 136 child_stdout_ = stdout_pipe_read; 137 } else { 138 process_start_error_ = GetLastError(); 139 CloseHandleOrDie(stdin_pipe_write); 140 CloseHandleOrDie(stdout_pipe_read); 141 } 142 143 CloseHandleOrDie(stdin_pipe_read); 144 CloseHandleOrDie(stdout_pipe_write); 145 free(name_copy); 146 } 147 148 bool Subprocess::Communicate(const Message& input, Message* output, 149 string* error) { 150 if (process_start_error_ != ERROR_SUCCESS) { 151 *error = Win32ErrorMessage(process_start_error_); 152 return false; 153 } 154 155 GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first."; 156 157 string input_data = input.SerializeAsString(); 158 string output_data; 159 160 int input_pos = 0; 161 162 while (child_stdout_ != NULL) { 163 HANDLE handles[2]; 164 int handle_count = 0; 165 166 if (child_stdin_ != NULL) { 167 handles[handle_count++] = child_stdin_; 168 } 169 if (child_stdout_ != NULL) { 170 handles[handle_count++] = child_stdout_; 171 } 172 173 DWORD wait_result = 174 WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); 175 176 HANDLE signaled_handle = NULL; 177 if (wait_result >= WAIT_OBJECT_0 && 178 wait_result < WAIT_OBJECT_0 + handle_count) { 179 signaled_handle = handles[wait_result - WAIT_OBJECT_0]; 180 } else if (wait_result == WAIT_FAILED) { 181 GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: " 182 << Win32ErrorMessage(GetLastError()); 183 } else { 184 GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: " 185 << wait_result; 186 } 187 188 if (signaled_handle == child_stdin_) { 189 DWORD n; 190 if (!WriteFile(child_stdin_, 191 input_data.data() + input_pos, 192 input_data.size() - input_pos, 193 &n, NULL)) { 194 // Child closed pipe. Presumably it will report an error later. 195 // Pretend we're done for now. 196 input_pos = input_data.size(); 197 } else { 198 input_pos += n; 199 } 200 201 if (input_pos == input_data.size()) { 202 // We're done writing. Close. 203 CloseHandleOrDie(child_stdin_); 204 child_stdin_ = NULL; 205 } 206 } else if (signaled_handle == child_stdout_) { 207 char buffer[4096]; 208 DWORD n; 209 210 if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) { 211 // We're done reading. Close. 212 CloseHandleOrDie(child_stdout_); 213 child_stdout_ = NULL; 214 } else { 215 output_data.append(buffer, n); 216 } 217 } 218 } 219 220 if (child_stdin_ != NULL) { 221 // Child did not finish reading input before it closed the output. 222 // Presumably it exited with an error. 223 CloseHandleOrDie(child_stdin_); 224 child_stdin_ = NULL; 225 } 226 227 DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE); 228 229 if (wait_result == WAIT_FAILED) { 230 GOOGLE_LOG(FATAL) << "WaitForSingleObject: " 231 << Win32ErrorMessage(GetLastError()); 232 } else if (wait_result != WAIT_OBJECT_0) { 233 GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: " 234 << wait_result; 235 } 236 237 DWORD exit_code; 238 if (!GetExitCodeProcess(child_handle_, &exit_code)) { 239 GOOGLE_LOG(FATAL) << "GetExitCodeProcess: " 240 << Win32ErrorMessage(GetLastError()); 241 } 242 243 CloseHandleOrDie(child_handle_); 244 child_handle_ = NULL; 245 246 if (exit_code != 0) { 247 *error = strings::Substitute( 248 "Plugin failed with status code $0.", exit_code); 249 return false; 250 } 251 252 if (!output->ParseFromString(output_data)) { 253 *error = "Plugin output is unparseable: " + CEscape(output_data); 254 return false; 255 } 256 257 return true; 258 } 259 260 string Subprocess::Win32ErrorMessage(DWORD error_code) { 261 char* message; 262 263 // WTF? 264 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 265 FORMAT_MESSAGE_FROM_SYSTEM | 266 FORMAT_MESSAGE_IGNORE_INSERTS, 267 NULL, error_code, 0, 268 (LPTSTR)&message, // NOT A BUG! 269 0, NULL); 270 271 string result = message; 272 LocalFree(message); 273 return result; 274 } 275 276 // =================================================================== 277 278 #else // _WIN32 279 280 Subprocess::Subprocess() 281 : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {} 282 283 Subprocess::~Subprocess() { 284 if (child_stdin_ != -1) { 285 close(child_stdin_); 286 } 287 if (child_stdout_ != -1) { 288 close(child_stdout_); 289 } 290 } 291 292 void Subprocess::Start(const string& program, SearchMode search_mode) { 293 // Note that we assume that there are no other threads, thus we don't have to 294 // do crazy stuff like using socket pairs or avoiding libc locks. 295 296 // [0] is read end, [1] is write end. 297 int stdin_pipe[2]; 298 int stdout_pipe[2]; 299 300 GOOGLE_CHECK(pipe(stdin_pipe) != -1); 301 GOOGLE_CHECK(pipe(stdout_pipe) != -1); 302 303 char* argv[2] = { strdup(program.c_str()), NULL }; 304 305 child_pid_ = fork(); 306 if (child_pid_ == -1) { 307 GOOGLE_LOG(FATAL) << "fork: " << strerror(errno); 308 } else if (child_pid_ == 0) { 309 // We are the child. 310 dup2(stdin_pipe[0], STDIN_FILENO); 311 dup2(stdout_pipe[1], STDOUT_FILENO); 312 313 close(stdin_pipe[0]); 314 close(stdin_pipe[1]); 315 close(stdout_pipe[0]); 316 close(stdout_pipe[1]); 317 318 switch (search_mode) { 319 case SEARCH_PATH: 320 execvp(argv[0], argv); 321 break; 322 case EXACT_NAME: 323 execv(argv[0], argv); 324 break; 325 } 326 327 // Write directly to STDERR_FILENO to avoid stdio code paths that may do 328 // stuff that is unsafe here. 329 int ignored; 330 ignored = write(STDERR_FILENO, argv[0], strlen(argv[0])); 331 const char* message = ": program not found or is not executable\n"; 332 ignored = write(STDERR_FILENO, message, strlen(message)); 333 (void) ignored; 334 335 // Must use _exit() rather than exit() to avoid flushing output buffers 336 // that will also be flushed by the parent. 337 _exit(1); 338 } else { 339 free(argv[0]); 340 341 close(stdin_pipe[0]); 342 close(stdout_pipe[1]); 343 344 child_stdin_ = stdin_pipe[1]; 345 child_stdout_ = stdout_pipe[0]; 346 } 347 } 348 349 bool Subprocess::Communicate(const Message& input, Message* output, 350 string* error) { 351 352 GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first."; 353 354 // The "sighandler_t" typedef is GNU-specific, so define our own. 355 typedef void SignalHandler(int); 356 357 // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us. 358 SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN); 359 360 string input_data = input.SerializeAsString(); 361 string output_data; 362 363 int input_pos = 0; 364 int max_fd = std::max(child_stdin_, child_stdout_); 365 366 while (child_stdout_ != -1) { 367 fd_set read_fds; 368 fd_set write_fds; 369 FD_ZERO(&read_fds); 370 FD_ZERO(&write_fds); 371 if (child_stdout_ != -1) { 372 FD_SET(child_stdout_, &read_fds); 373 } 374 if (child_stdin_ != -1) { 375 FD_SET(child_stdin_, &write_fds); 376 } 377 378 if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) { 379 if (errno == EINTR) { 380 // Interrupted by signal. Try again. 381 continue; 382 } else { 383 GOOGLE_LOG(FATAL) << "select: " << strerror(errno); 384 } 385 } 386 387 if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) { 388 int n = write(child_stdin_, input_data.data() + input_pos, 389 input_data.size() - input_pos); 390 if (n < 0) { 391 // Child closed pipe. Presumably it will report an error later. 392 // Pretend we're done for now. 393 input_pos = input_data.size(); 394 } else { 395 input_pos += n; 396 } 397 398 if (input_pos == input_data.size()) { 399 // We're done writing. Close. 400 close(child_stdin_); 401 child_stdin_ = -1; 402 } 403 } 404 405 if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) { 406 char buffer[4096]; 407 int n = read(child_stdout_, buffer, sizeof(buffer)); 408 409 if (n > 0) { 410 output_data.append(buffer, n); 411 } else { 412 // We're done reading. Close. 413 close(child_stdout_); 414 child_stdout_ = -1; 415 } 416 } 417 } 418 419 if (child_stdin_ != -1) { 420 // Child did not finish reading input before it closed the output. 421 // Presumably it exited with an error. 422 close(child_stdin_); 423 child_stdin_ = -1; 424 } 425 426 int status; 427 while (waitpid(child_pid_, &status, 0) == -1) { 428 if (errno != EINTR) { 429 GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno); 430 } 431 } 432 433 // Restore SIGPIPE handling. 434 signal(SIGPIPE, old_pipe_handler); 435 436 if (WIFEXITED(status)) { 437 if (WEXITSTATUS(status) != 0) { 438 int error_code = WEXITSTATUS(status); 439 *error = strings::Substitute( 440 "Plugin failed with status code $0.", error_code); 441 return false; 442 } 443 } else if (WIFSIGNALED(status)) { 444 int signal = WTERMSIG(status); 445 *error = strings::Substitute( 446 "Plugin killed by signal $0.", signal); 447 return false; 448 } else { 449 *error = "Neither WEXITSTATUS nor WTERMSIG is true?"; 450 return false; 451 } 452 453 if (!output->ParseFromString(output_data)) { 454 *error = "Plugin output is unparseable: " + CEscape(output_data); 455 return false; 456 } 457 458 return true; 459 } 460 461 #endif // !_WIN32 462 463 } // namespace compiler 464 } // namespace protobuf 465 } // namespace google 466