|
@@ -2976,18 +2976,107 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
|
|
|
* and stderr, respectively, output of the child program can be read, and the
|
|
|
* stdin of the child process shall be set to /dev/null. Otherwise returns
|
|
|
* -1. Some parts of this code are based on the POSIX subprocess module from
|
|
|
- * Python.
|
|
|
+ * Python, and example code from
|
|
|
+ * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx.
|
|
|
*/
|
|
|
process_handle_t
|
|
|
tor_spawn_background(const char *const filename, const char **argv)
|
|
|
{
|
|
|
process_handle_t process_handle;
|
|
|
#ifdef MS_WINDOWS
|
|
|
- (void) filename; (void) argv;
|
|
|
- log_warn(LD_BUG, "not yet implemented on Windows.");
|
|
|
+ HANDLE stdout_pipe_read = NULL;
|
|
|
+ HANDLE stdout_pipe_write = NULL;
|
|
|
+ HANDLE stderr_pipe_read = NULL;
|
|
|
+ HANDLE stderr_pipe_write = NULL;
|
|
|
+
|
|
|
+ SECURITY_ATTRIBUTES saAttr;
|
|
|
+ smartlist_t *argv_list;
|
|
|
+ char *joined_argv;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
|
+ saAttr.bInheritHandle = TRUE;
|
|
|
+ saAttr.lpSecurityDescriptor = NULL;
|
|
|
+
|
|
|
process_handle.status = -1;
|
|
|
+
|
|
|
+ /* Set up pipe for stdout */
|
|
|
+ if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to create pipe for stdout communication with child process: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ return process_handle;
|
|
|
+ }
|
|
|
+ if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to configure pipe for stdout communication with child process: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Set up pipe for stderr */
|
|
|
+ if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to create pipe for stderr communication with child process: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ return process_handle;
|
|
|
+ }
|
|
|
+ if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to configure pipe for stderr communication with child process: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Create the child process */
|
|
|
+
|
|
|
+ /* Windows expects argv to be a whitespace delimited string, so join argv up */
|
|
|
+ argv_list = smartlist_create();
|
|
|
+ for (i=0; argv[i] != NULL; i++) {
|
|
|
+ smartlist_add(argv_list, (void *)argv[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL);
|
|
|
+
|
|
|
+ STARTUPINFO siStartInfo;
|
|
|
+ BOOL retval = FALSE;
|
|
|
+
|
|
|
+ ZeroMemory(&process_handle.pid, sizeof(PROCESS_INFORMATION));
|
|
|
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
|
|
+ siStartInfo.cb = sizeof(STARTUPINFO);
|
|
|
+ siStartInfo.hStdError = stderr_pipe_write;
|
|
|
+ siStartInfo.hStdOutput = stdout_pipe_write;
|
|
|
+ siStartInfo.hStdInput = NULL;
|
|
|
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
+
|
|
|
+ /* Create the child process */
|
|
|
+
|
|
|
+ retval = CreateProcess(filename, // module name
|
|
|
+ joined_argv, // command line
|
|
|
+ NULL, // process security attributes
|
|
|
+ NULL, // primary thread security attributes
|
|
|
+ TRUE, // handles are inherited
|
|
|
+ 0, // creation flags (TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() work?)
|
|
|
+ NULL, // use parent's environment
|
|
|
+ NULL, // use parent's current directory
|
|
|
+ &siStartInfo, // STARTUPINFO pointer
|
|
|
+ &process_handle.pid); // receives PROCESS_INFORMATION
|
|
|
+
|
|
|
+ tor_free(joined_argv);
|
|
|
+
|
|
|
+ if (!retval) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to create child process %s: %s", filename,
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ } else {
|
|
|
+ // TODO: Close hProcess and hThread in process_handle.pid?
|
|
|
+ process_handle.stdout_pipe = stdout_pipe_read;
|
|
|
+ process_handle.stderr_pipe = stderr_pipe_read;
|
|
|
+ process_handle.status = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: Close pipes on exit
|
|
|
+
|
|
|
return process_handle;
|
|
|
-#else
|
|
|
+#else // MS_WINDOWS
|
|
|
pid_t pid;
|
|
|
int stdout_pipe[2];
|
|
|
int stderr_pipe[2];
|
|
@@ -3154,15 +3243,25 @@ tor_spawn_background(const char *const filename, const char **argv)
|
|
|
process_handle.status = 0;
|
|
|
process_handle.pid = pid;
|
|
|
return process_handle;
|
|
|
-#endif
|
|
|
+#endif // MS_WINDOWS
|
|
|
}
|
|
|
|
|
|
int
|
|
|
tor_get_exit_code(const process_handle_t process_handle)
|
|
|
{
|
|
|
#ifdef MS_WINDOWS
|
|
|
- log_warn(LD_BUG, "not yet implemented on Windows.");
|
|
|
- return -1;
|
|
|
+ DWORD exit_code;
|
|
|
+ BOOL retval;
|
|
|
+ WaitForSingleObject(process_handle.pid.hProcess, INFINITE);
|
|
|
+ retval = GetExitCodeProcess(process_handle.pid.hProcess, &exit_code);
|
|
|
+
|
|
|
+ if (!retval) {
|
|
|
+ log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ return exit_code;
|
|
|
+ }
|
|
|
#else
|
|
|
int stat_loc;
|
|
|
|
|
@@ -3183,13 +3282,23 @@ tor_get_exit_code(const process_handle_t process_handle)
|
|
|
}
|
|
|
|
|
|
ssize_t
|
|
|
-tor_read_all_from_process_stdin(const process_handle_t process_handle,
|
|
|
+tor_read_all_from_process_stdout(const process_handle_t process_handle,
|
|
|
char *buf, size_t count)
|
|
|
{
|
|
|
#ifdef MS_WINDOWS
|
|
|
- return -1;
|
|
|
+ BOOL retval;
|
|
|
+ DWORD bytes_read;
|
|
|
+ retval = ReadFile(process_handle.stdout_pipe, buf, count, &bytes_read, NULL);
|
|
|
+ if (!retval) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to read from stdin pipe: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ return bytes_read;
|
|
|
+ }
|
|
|
#else
|
|
|
- return read_all(process_handle.stdin_pipe, buf, count, 0);
|
|
|
+ return read_all(process_handle.stdout_pipe, buf, count, 0);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
@@ -3198,7 +3307,17 @@ tor_read_all_from_process_stderr(const process_handle_t process_handle,
|
|
|
char *buf, size_t count)
|
|
|
{
|
|
|
#ifdef MS_WINDOWS
|
|
|
- return -1;
|
|
|
+ BOOL retval;
|
|
|
+ DWORD bytes_read;
|
|
|
+ retval = ReadFile(process_handle.stderr_pipe, buf, count, &bytes_read, NULL);
|
|
|
+ if (!retval) {
|
|
|
+ log_warn(LD_GENERAL,
|
|
|
+ "Failed to read from stderr pipe: %s",
|
|
|
+ format_win32_error(GetLastError()));
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ return bytes_read;
|
|
|
+ }
|
|
|
#else
|
|
|
return read_all(process_handle.stderr_pipe, buf, count, 0);
|
|
|
#endif
|