/thirdparty/breakpad/third_party/protobuf/protobuf/src/google/protobuf/compiler/subprocess.cc

http://github.com/tomahawk-player/tomahawk · C++ · 460 lines · 323 code · 76 blank · 61 comment · 97 complexity · 3dc87041bfdb724ed43e70a38ae193d4 MD5 · raw file

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