CreateProcess: add stdin/out/err redirection
authorBernhard Miklautz <bernhard.miklautz@thincast.com>
Fri, 28 Aug 2015 08:31:22 +0000 (10:31 +0200)
committerBernhard Miklautz <bernhard.miklautz@thincast.com>
Fri, 28 Aug 2015 08:41:23 +0000 (10:41 +0200)
When launching a new process stdin/stdout/stderr can be redirected by
passing the corresponding HANDLEs in the passed lpStartupInfo structure.
This is required for example if a pipe should be used as stdin/stdout.

If set in lpStartupInfo the file descriptor of the passed handle is
now used. The test was updated accordingly.

winpr/libwinpr/thread/process.c
winpr/libwinpr/thread/test/TestThreadCreateProcess.c

index 4dca0f4..52aac77 100644 (file)
@@ -168,7 +168,7 @@ char* FindApplicationPath(char* application)
        nSize = GetEnvironmentVariableA("PATH", NULL, 0);
 
        if (!nSize)
-               return application;
+               return _strdup(application);
 
        lpSystemPath = (LPSTR) malloc(nSize);
        if (!lpSystemPath)
@@ -288,16 +288,34 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags,
                sigfillset(&set);
                pthread_sigmask(SIG_UNBLOCK, &set, NULL);
 
+               if (lpStartupInfo)
+               {
+                       int handle_fd;
+
+                       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdOutput);
+                       if (handle_fd != -1)
+                               dup2(handle_fd, STDOUT_FILENO);
+
+                       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdError);
+                       if (handle_fd != -1)
+                               dup2(handle_fd, STDERR_FILENO);
+
+                       handle_fd = winpr_Handle_getFd(lpStartupInfo->hStdInput);
+                       if (handle_fd != -1)
+                               dup2(handle_fd, STDIN_FILENO);
+               }
+
+
 #ifdef __sun
-       closefrom(3);
+               closefrom(3);
 #else
 #ifdef F_MAXFD // on some BSD derivates
-       maxfd = fcntl(0, F_MAXFD);
+               maxfd = fcntl(0, F_MAXFD);
 #else
-       maxfd = sysconf(_SC_OPEN_MAX);
+               maxfd = sysconf(_SC_OPEN_MAX);
 #endif
-       for(fd=3; fd<maxfd; fd++)
-               close(fd);
+               for(fd=3; fd<maxfd; fd++)
+                       close(fd);
 #endif // __sun
 
                if (token)
index 0ccc405..b3c9f01 100644 (file)
@@ -5,6 +5,9 @@
 #include <winpr/synch.h>
 #include <winpr/thread.h>
 #include <winpr/environment.h>
+#include <winpr/pipe.h>
+
+#define TESTENV "TEST_PROCESS=oyeah"
 
 int TestThreadCreateProcess(int argc, char* argv[])
 {
@@ -21,6 +24,11 @@ int TestThreadCreateProcess(int argc, char* argv[])
        STARTUPINFO StartupInfo;
        PROCESS_INFORMATION ProcessInformation;
        LPTCH lpszEnvironmentBlock;
+       HANDLE pipe_read = NULL;
+       HANDLE pipe_write = NULL;
+       char buf[255];
+       DWORD read_bytes;
+       int ret = 0;
 
        lpszEnvironmentBlock = GetEnvironmentStrings();
 
@@ -61,10 +69,77 @@ int TestThreadCreateProcess(int argc, char* argv[])
                return 1;
        }
 
+
+       WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+
+       exitCode = 0;
+       status = GetExitCodeProcess(ProcessInformation.hProcess, &exitCode);
+
+       printf("GetExitCodeProcess status: %d\n", status);
+       printf("Process exited with code: 0x%08X\n", exitCode);
+
+       CloseHandle(ProcessInformation.hProcess);
+       CloseHandle(ProcessInformation.hThread);
        FreeEnvironmentStrings(lpszEnvironmentBlock);
 
+       /* Test stdin,stdout,stderr redirection */
+       ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
+       StartupInfo.cb = sizeof(STARTUPINFO);
+       ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
+
+       if (!CreatePipe(&pipe_read, &pipe_write, NULL, 0))
+       {
+               printf("Pipe creation failed. error=%d\n", GetLastError());
+               return 1;
+       }
+       StartupInfo.hStdOutput = pipe_write;
+       StartupInfo.hStdError = pipe_write;
+
+       lpEnvironment = calloc(1, sizeof(TESTENV) + 1);
+       strncpy(lpEnvironment, TESTENV, strlen(TESTENV));
+       lpCommandLine = _T("printenv");
+
+       status = CreateProcess(lpApplicationName,
+                                                  lpCommandLine,
+                                                  lpProcessAttributes,
+                                                  lpThreadAttributes,
+                                                  bInheritHandles,
+                                                  dwCreationFlags,
+                                                  lpEnvironment,
+                                                  lpCurrentDirectory,
+                                                  &StartupInfo,
+                                                  &ProcessInformation);
+
+       free(lpEnvironment);
+
+       if (!status)
+       {
+               CloseHandle(pipe_read);
+               CloseHandle(pipe_write);
+               printf("CreateProcess failed. error=%d\n", GetLastError());
+               return 1;
+       }
+
+       if (WaitForSingleObject(pipe_read, 200) != WAIT_OBJECT_0)
+       {
+               printf("pipe wait failed.\n");
+               ret = 1;
+       }
+       else
+       {
+               ReadFile(pipe_read, buf, 255, &read_bytes, NULL);
+               if (read_bytes < strlen(TESTENV))
+               {
+                       printf("pipe read problem?!\n");
+                       ret = 1;
+               }
+       }
+
        WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
 
+       CloseHandle(pipe_read);
+       CloseHandle(pipe_write);
+
        exitCode = 0;
        status = GetExitCodeProcess(ProcessInformation.hProcess, &exitCode);
 
@@ -74,6 +149,6 @@ int TestThreadCreateProcess(int argc, char* argv[])
        CloseHandle(ProcessInformation.hProcess);
        CloseHandle(ProcessInformation.hThread);
 
-       return 0;
+       return ret;
 }