From 8d142eb85f64446f01a66515bc2b26ae6b8c19e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 22 Sep 2013 17:23:00 -0400 Subject: [PATCH] libwinpr-thread: initial CreateProcess() implementation --- winpr/libwinpr/handle/handle.c | 9 +++ winpr/libwinpr/handle/handle.h | 15 ++--- winpr/libwinpr/synch/wait.c | 13 +++++ winpr/libwinpr/thread/argv.c | 21 +++---- winpr/libwinpr/thread/process.c | 57 +++++++++++++++++-- winpr/libwinpr/thread/test/CMakeLists.txt | 3 +- .../thread/test/TestThreadCommandLineToArgv.c | 31 ++++++---- .../thread/test/TestThreadCreateProcess.c | 52 +++++++++++++++++ winpr/libwinpr/thread/thread.h | 10 ++++ 9 files changed, 177 insertions(+), 34 deletions(-) create mode 100644 winpr/libwinpr/thread/test/TestThreadCreateProcess.c diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index 31ac5641b..7830be31d 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -52,6 +52,15 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } + else if (Type == HANDLE_TYPE_PROCESS) + { + WINPR_PROCESS* process; + + process = (WINPR_PROCESS*) Object; + free(process); + + return TRUE; + } else if (Type == HANDLE_TYPE_MUTEX) { WINPR_MUTEX* mutex; diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 75faae4ea..9ba8982b5 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -23,13 +23,14 @@ #include #define HANDLE_TYPE_NONE 0 -#define HANDLE_TYPE_THREAD 1 -#define HANDLE_TYPE_EVENT 2 -#define HANDLE_TYPE_MUTEX 3 -#define HANDLE_TYPE_SEMAPHORE 4 -#define HANDLE_TYPE_TIMER 5 -#define HANDLE_TYPE_NAMED_PIPE 6 -#define HANDLE_TYPE_ANONYMOUS_PIPE 7 +#define HANDLE_TYPE_PROCESS 1 +#define HANDLE_TYPE_THREAD 2 +#define HANDLE_TYPE_EVENT 3 +#define HANDLE_TYPE_MUTEX 4 +#define HANDLE_TYPE_SEMAPHORE 5 +#define HANDLE_TYPE_TIMER 6 +#define HANDLE_TYPE_NAMED_PIPE 7 +#define HANDLE_TYPE_ANONYMOUS_PIPE 8 #define WINPR_HANDLE_DEF() \ ULONG Type diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 8fab17203..8727831e2 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -43,6 +43,8 @@ #ifndef _WIN32 +#include + #include "../handle/handle.h" #include "../pipe/pipe.h" @@ -102,6 +104,17 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) thread->dwExitCode = ((DWORD) (size_t) thread_status); } } + else if (Type == HANDLE_TYPE_PROCESS) + { + WINPR_PROCESS* process; + + process = (WINPR_PROCESS*) Object; + + if (waitpid(process->pid, &(process->status), 0) != -1) + { + return WAIT_FAILED; + } + } else if (Type == HANDLE_TYPE_MUTEX) { WINPR_MUTEX* mutex; diff --git a/winpr/libwinpr/thread/argv.c b/winpr/libwinpr/thread/argv.c index 1369742d1..041216131 100644 --- a/winpr/libwinpr/thread/argv.c +++ b/winpr/libwinpr/thread/argv.c @@ -101,7 +101,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) int maxBufferSize; int currentIndex; int cmdLineLength; - LPSTR lpEscapedChars; + BOOL* lpEscapedChars; LPSTR lpEscapedCmdLine; if (!lpCmdLine) @@ -116,15 +116,15 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) lpEscapedCmdLine = NULL; cmdLineLength = strlen(lpCmdLine); - lpEscapedChars = (char*) malloc(cmdLineLength + 1); - ZeroMemory(lpEscapedChars, cmdLineLength + 1); + lpEscapedChars = (BOOL*) malloc((cmdLineLength + 1) * sizeof(BOOL)); + ZeroMemory(lpEscapedChars, (cmdLineLength + 1) * sizeof(BOOL)); if (strstr(lpCmdLine, "\\\"")) { int i, n; char* pLastEnd = NULL; - lpEscapedCmdLine = (char*) malloc(cmdLineLength + 1); + lpEscapedCmdLine = (char*) malloc((cmdLineLength + 1) * sizeof(char)); p = (char*) lpCmdLine; pLastEnd = (char*) lpCmdLine; @@ -173,7 +173,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) p += n + 1; if ((n % 2) != 0) - lpEscapedChars[pOutput - lpEscapedCmdLine] = '\\'; + lpEscapedChars[pOutput - lpEscapedCmdLine] = TRUE; *pOutput = '"'; pOutput++; @@ -188,7 +188,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) cmdLineLength = strlen(lpCmdLine); } - maxNumArgs = 1; + maxNumArgs = 2; currentIndex = 0; p = (char*) lpCmdLine; @@ -240,7 +240,7 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) /* no whitespace escaped with double quotes */ p = &p[index + 1]; - pEnd = p; + pEnd = p - 1; length = (pEnd - pBeg); @@ -274,14 +274,14 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) if (p[index] == '\0') { p = &p[index + 1]; - pEnd = p; + pEnd = p - 1; } else { p = &p[index + 1]; index = strcspn(p, " \t\0"); p = &p[index + 1]; - pEnd = p; + pEnd = p - 1; } length = 0; @@ -312,7 +312,8 @@ LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs) if (lpEscapedCmdLine) free(lpEscapedCmdLine); - free(lpEscapedChars); + if (lpEscapedChars) + free(lpEscapedChars); *pNumArgs = numArgs; diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index 3d5c977df..347b2aca9 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -55,20 +55,69 @@ #include #endif +#include + +#include +#include +#include + #include -typedef void *(*pthread_start_routine)(void*); +#include "thread.h" + +#include "../handle/handle.h" BOOL CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { - int status = 0; + pid_t pid; + char* envp; + int status; + int numArgs; + LPSTR* pArgs; + WINPR_THREAD* thread; + WINPR_PROCESS* process; - if (!lpApplicationName) + pid = 0; + numArgs = 0; + + pArgs = CommandLineToArgvA(lpCommandLine, &numArgs); + + envp = NULL; + + status = posix_spawnp(&pid, pArgs[0], NULL, NULL, pArgs, &envp); + + if (status != 0) return FALSE; - status = execve(lpApplicationName, NULL, NULL); + process = (WINPR_PROCESS*) malloc(sizeof(WINPR_PROCESS)); + + if (!process) + return FALSE; + + ZeroMemory(process, sizeof(WINPR_PROCESS)); + + WINPR_HANDLE_SET_TYPE(process, HANDLE_TYPE_PROCESS); + + process->pid = pid; + process->status = 0; + + thread = (WINPR_THREAD*) malloc(sizeof(WINPR_THREAD)); + + ZeroMemory(thread, sizeof(WINPR_THREAD)); + + if (!thread) + return FALSE; + + WINPR_HANDLE_SET_TYPE(thread, HANDLE_TYPE_THREAD); + + thread->mainProcess = TRUE; + + lpProcessInformation->hProcess = (HANDLE) process; + lpProcessInformation->hThread = (HANDLE) thread; + lpProcessInformation->dwProcessId = (DWORD) pid; + lpProcessInformation->dwThreadId = (DWORD) pid; return TRUE; } diff --git a/winpr/libwinpr/thread/test/CMakeLists.txt b/winpr/libwinpr/thread/test/CMakeLists.txt index f05e033ed..1f6de6f2b 100644 --- a/winpr/libwinpr/thread/test/CMakeLists.txt +++ b/winpr/libwinpr/thread/test/CMakeLists.txt @@ -5,7 +5,8 @@ set(MODULE_PREFIX "TEST_THREAD") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS - TestThreadCommandLineToArgv.c) + TestThreadCommandLineToArgv.c + TestThreadCreateProcess.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} diff --git a/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c b/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c index e4573d91f..d863ba59b 100644 --- a/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c +++ b/winpr/libwinpr/thread/test/TestThreadCommandLineToArgv.c @@ -3,69 +3,76 @@ #include #include -const char* test_args_line_1 = "abc d e"; +const char* test_args_line_1 = "app.exe abc d e"; const char* test_args_list_1[] = { + "app.exe", "abc", "d", "e", NULL }; -const char* test_args_line_2 = "abc \t def"; +const char* test_args_line_2 = "app.exe abc \t def"; const char* test_args_list_2[] = { + "app.exe", "abc", "def", NULL }; -const char* test_args_line_3 = "\"abc\" d e"; +const char* test_args_line_3 = "app.exe \"abc\" d e"; const char* test_args_list_3[] = { + "app.exe", "abc", "d", "e", NULL }; -const char* test_args_line_4 = "a\\\\b d\"e f\"g h"; +const char* test_args_line_4 = "app.exe a\\\\b d\"e f\"g h"; const char* test_args_list_4[] = { + "app.exe", "a\\\\b", "de fg", "h", NULL }; -const char* test_args_line_5 = "a\\\\\\\"b c d"; +const char* test_args_line_5 = "app.exe a\\\\\\\"b c d"; const char* test_args_list_5[] = { + "app.exe", "a\\\"b", "c", "d", NULL }; -const char* test_args_line_6 = "a\\\\\\\\\"b c\" d e"; +const char* test_args_line_6 = "app.exe a\\\\\\\\\"b c\" d e"; const char* test_args_list_6[] = { + "app.exe", "a\\\\b c", "d", "e", NULL }; -const char* test_args_line_7 = "a\\\\\\\\\"b c\" d e f\\\\\\\\\"g h\" i j"; +const char* test_args_line_7 = "app.exe a\\\\\\\\\"b c\" d e f\\\\\\\\\"g h\" i j"; const char* test_args_list_7[] = { + "app.exe", "a\\\\b c", "d", "e", @@ -79,18 +86,18 @@ static int test_command_line_parsing_case(const char* line, const char** list) { int i; LPSTR* pArgs; - int pNumArgs; + int numArgs; pArgs = NULL; - pNumArgs = 0; + numArgs = 0; printf("Parsing: %s\n", line); - pArgs = CommandLineToArgvA(line, &pNumArgs); + pArgs = CommandLineToArgvA(line, &numArgs); - printf("pNumArgs: %d\n", pNumArgs); + printf("pNumArgs: %d\n", numArgs); - for (i = 0; i < pNumArgs; i++) + for (i = 0; i < numArgs; i++) { printf("argv[%d] = %s\n", i, pArgs[i]); } diff --git a/winpr/libwinpr/thread/test/TestThreadCreateProcess.c b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c new file mode 100644 index 000000000..889fb5cb4 --- /dev/null +++ b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c @@ -0,0 +1,52 @@ + +#include +#include +#include +#include +#include + +int TestThreadCreateProcess(int argc, char* argv[]) +{ + BOOL status; + LPCTSTR lpApplicationName; + LPTSTR lpCommandLine; + LPSECURITY_ATTRIBUTES lpProcessAttributes; + LPSECURITY_ATTRIBUTES lpThreadAttributes; + BOOL bInheritHandles; + DWORD dwCreationFlags; + LPVOID lpEnvironment; + LPCTSTR lpCurrentDirectory; + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInformation; + + lpApplicationName = NULL; + lpCommandLine = _T("ls -l /"); + lpProcessAttributes = NULL; + lpThreadAttributes = NULL; + bInheritHandles = FALSE; + dwCreationFlags = 0; + lpEnvironment = NULL; + lpCurrentDirectory = NULL; + ZeroMemory(&StartupInfo, sizeof(STARTUPINFO)); + StartupInfo.cb = sizeof(STARTUPINFO); + ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION)); + + status = CreateProcess(lpApplicationName, + lpCommandLine, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + &StartupInfo, + &ProcessInformation); + + WaitForSingleObject(ProcessInformation.hProcess, INFINITE); + + CloseHandle(ProcessInformation.hProcess); + CloseHandle(ProcessInformation.hThread); + + return 0; +} + diff --git a/winpr/libwinpr/thread/thread.h b/winpr/libwinpr/thread/thread.h index c13ff5278..6652ed310 100644 --- a/winpr/libwinpr/thread/thread.h +++ b/winpr/libwinpr/thread/thread.h @@ -35,6 +35,7 @@ struct winpr_thread WINPR_HANDLE_DEF(); BOOL started; + BOOL mainProcess; DWORD dwExitCode; pthread_t thread; SIZE_T dwStackSize; @@ -45,6 +46,15 @@ struct winpr_thread }; typedef struct winpr_thread WINPR_THREAD; +struct winpr_process +{ + WINPR_HANDLE_DEF(); + + pid_t pid; + int status; +}; +typedef struct winpr_process WINPR_PROCESS; + #endif #endif /* WINPR_THREAD_PRIVATE_H */