diff options
author | Doug Schaefer | 2007-09-05 14:17:42 +0000 |
---|---|---|
committer | Doug Schaefer | 2007-09-05 14:17:42 +0000 |
commit | 2d980092d91c85ddbfc21c07fd556ecff6596bdd (patch) | |
tree | 16f5f1fd5a8e408ed5ed3934b2b80a3f0231d112 /core/org.eclipse.cdt.core.win32 | |
parent | 1c52fecbad7d544aa53a6572cd2e7bfe148e1737 (diff) | |
download | org.eclipse.cdt-2d980092d91c85ddbfc21c07fd556ecff6596bdd.tar.gz org.eclipse.cdt-2d980092d91c85ddbfc21c07fd556ecff6596bdd.tar.xz org.eclipse.cdt-2d980092d91c85ddbfc21c07fd556ecff6596bdd.zip |
This isn't a binary.
Diffstat (limited to 'core/org.eclipse.cdt.core.win32')
-rw-r--r-- | core/org.eclipse.cdt.core.win32/library/starter/starter.cpp | 962 |
1 files changed, 481 insertions, 481 deletions
diff --git a/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp b/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp index 29de0b5ced4..8cdcbcc840d 100644 --- a/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp +++ b/core/org.eclipse.cdt.core.win32/library/starter/starter.cpp @@ -1,481 +1,481 @@ -/*******************************************************************************
- * Copyright (c) 2002, 2007 QNX Software Systems and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * QNX Software Systems - initial API and implementation
- * Wind River Systems, Inc.
- *
- * starter.cpp
- *
- * This is a small utility for windows spawner
- *******************************************************************************/
-
-#define STRICT
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#include <process.h>
-#include <tchar.h>
-#include <stdio.h>
-#include <psapi.h>
-
-//#define DEBUG_MONITOR
-#define MAX_CMD_LINE_LENGTH (2049)
-#define PIPE_NAME_LENGTH 100
-
-int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
- int availSpace);
-void DisplayErrorMessage();
-
-//BOOL KillProcessEx(DWORD dwProcessId); // Handle of the process
-
-///////////////////////////////////////////////////////////////////////////////
-BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
-{
- BOOL ret = TRUE;
- switch(dwCtrlType)
- {
- case CTRL_C_EVENT:
- break;
- case CTRL_BREAK_EVENT:
- break;
- case CTRL_CLOSE_EVENT:
- ret = FALSE;
- break;
- case CTRL_LOGOFF_EVENT:
- ret = FALSE;
- break;
- case CTRL_SHUTDOWN_EVENT:
- ret = FALSE;
- break;
- default:
- break;
- }
- return ret;
-}
-
-// The default here means we haven't checked yet
-// i.e. cygwin is true but the bin dir hasn't been captured
-wchar_t * cygwinBin = NULL;
-bool _isCygwin = true;
-
-bool isCygwin(HANDLE process) {
- // Have we checked before?
- if (cygwinBin != NULL || !_isCygwin)
- return _isCygwin;
-
- // See if this process loaded cygwin, need a different SIGINT for them
- HMODULE mods[1024];
- DWORD needed;
- if (EnumProcessModules(process, mods, sizeof(mods), &needed)) {
- int i;
- needed /= sizeof(HMODULE);
- for (i = 0; i < needed; ++i ) {
- wchar_t modName[MAX_PATH];
- if (GetModuleFileNameEx(process, mods[i], modName, MAX_PATH)) {
- wchar_t * p = wcsrchr(modName, L'\\');
- if (p) {
- *p = 0; // Null terminate there for future reference
- if (!wcscmp(++p, L"cygwin1.dll")) {
- _isCygwin = true;
- // Store away the bind dir
- cygwinBin = wcsdup(modName);
- return _isCygwin;
- }
- }
- }
- }
- }
-
- _isCygwin = false;
- return _isCygwin;
-}
-
-bool runCygwinCommand(wchar_t * command) {
- wchar_t cygcmd[1024];
- swprintf(cygcmd, L"%s\\%s", cygwinBin, command);
-
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
- if (CreateProcess(NULL, cygcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return true;
- } else if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
- WaitForSingleObject(pi.hProcess, INFINITE);
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- return true;
- }
- return false;
-}
-
-void ensureSize(wchar_t** ptr, int* psize, int requiredLength) {
- int size= *psize;
- if (requiredLength > size) {
- size= 2*size;
- if (size < requiredLength) {
- size= requiredLength;
- }
- *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
- if (NULL == *ptr) {
- *psize= 0;
- } else {
- *psize= size;
- }
- }
-}
-
-int main() {
-
- int argc;
- wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc);
-
- // Make sure that we've been passed the right number of arguments
- if (argc < 7) {
- _tprintf(_T("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
- argv[0]);
- return(0);
- }
-
- // Construct the full command line
- int nCmdLineLength= MAX_CMD_LINE_LENGTH;
- wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
- szCmdLine[0]= 0;
- int nPos = 0;
-
- for(int i = 6; i < argc; ++i)
- {
- int nCpyLen;
- int len= wcslen(argv[i]);
- int requiredSize= nPos+len+2;
- if (requiredSize > 32*1024) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Command line too long!\n"));
-#endif
- return 0;
- }
- ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
- if (NULL == szCmdLine) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Not enough memory to build cmd line!\n"));
-#endif
- return 0;
- }
- if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos)))
- {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Not enough space to build command line\n"));
-#endif
- return 0;
- }
- nPos += nCpyLen;
- szCmdLine[nPos] = _T(' ');
- ++nPos;
- }
- szCmdLine[nPos] = _T('\0');
-
- STARTUPINFOW si = {sizeof(si)};
- PROCESS_INFORMATION pi = {0};
- DWORD dwExitCode = 0;
-#ifdef DEBUG_MONITOR
- int currentPID = GetCurrentProcessId();
- wchar_t buffer[MAX_CMD_LINE_LENGTH];
-#endif
-
- BOOL exitProc = FALSE;
- HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]);
- HANDLE h[3];
- h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]);
- h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event
- SetConsoleCtrlHandler(HandlerRoutine, TRUE);
-
- int parentPid = wcstol(argv[1], NULL, 10);
- int nCounter = wcstol(argv[2], NULL, 10);
- wchar_t inPipeName[PIPE_NAME_LENGTH];
- wchar_t outPipeName[PIPE_NAME_LENGTH];
- wchar_t errPipeName[PIPE_NAME_LENGTH];
-
- swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
- swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
- swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
- OutputDebugStringW(buffer);
-#endif
-
- HANDLE stdHandles[3];
-
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
- {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
- OutputDebugStringW(buffer);
-#endif
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- return -1;;
- }
- SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
-
- if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) ||
- !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
- !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError());
- OutputDebugStringW(buffer);
-#endif
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- return -1;;
- }
-
-#ifdef DEBUG_MONITOR
- wchar_t * lpvEnv = GetEnvironmentStringsW();
-
- // If the returned pointer is NULL, exit.
- if (lpvEnv == NULL)
- OutputDebugStringW(_T("Cannot Read Environment\n"));
- else {
- // Variable strings are separated by NULL byte, and the block is
- // terminated by a NULL byte.
-
- OutputDebugStringW(_T("Starter: Environment\n"));
- for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) {
- swprintf(buffer, _T("%s\n"), lpszVariable);
- OutputDebugStringW(buffer);
- }
-
- FreeEnvironmentStringsW(lpvEnv);
- }
-#endif
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Starting: %s\n"), szCmdLine);
- OutputDebugStringW(buffer);
-#endif
- // Create job object
- HANDLE hJob = CreateJobObject(NULL, NULL);
-
- // Spawn the other processes as part of this Process Group
- BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE,
- 0, NULL, NULL, &si, &pi);
-
- // We don't need them any more
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
-
- if (f) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId);
- OutputDebugStringW(buffer);
-#endif
- SetEvent(waitEvent); // Means thar process has been spawned
- CloseHandle(pi.hThread);
- h[1] = pi.hProcess;
-
- if(NULL != hJob) {
- if(!AssignProcessToJobObject(hJob, pi.hProcess)) {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId);
- OutputDebugStringW(buffer);
- DisplayErrorMessage();
-#endif
- }
- }
-
- while(!exitProc)
- {
- // Wait for the spawned-process to die or for the event
- // indicating that the processes should be forcibly killed.
- switch (WaitForMultipleObjects(3, h, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0 + 0: // Send Ctrl-C
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID);
- OutputDebugStringW(buffer);
-#endif
- if (isCygwin(h[1])) {
- // Need to issue a kill command
- wchar_t kill[1024];
- swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId);
- if (!runCygwinCommand(kill)) {
- // fall back to console event
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
- } else {
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
-
- SetEvent(waitEvent);
- break;
-
- case WAIT_OBJECT_0 + 1: // App terminated normally
- // Make it's exit code our exit code
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"),
- pi.dwProcessId);
- OutputDebugStringW(buffer);
-#endif
- GetExitCodeProcess(pi.hProcess, &dwExitCode);
- exitProc = TRUE;
- break;
-
- case WAIT_OBJECT_0 + 2: // Kill
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("starter received KILL event (PID %i)\n"), currentPID);
- OutputDebugStringW(buffer);
-#endif
- if (isCygwin(h[1])) {
- // Need to issue a kill command
- wchar_t kill[1024];
- swprintf(kill, L"kill -SIGTERM %d", pi.dwProcessId);
- if (!runCygwinCommand(kill)) {
- // fall back to console event
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
- } else {
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
- }
-
- SetEvent(waitEvent);
-
- if(NULL != hJob) {
- if(!TerminateJobObject(hJob, (DWORD)-1)) {
-#ifdef DEBUG_MONITOR
- OutputDebugStringW(_T("Cannot terminate job\n"));
- DisplayErrorMessage();
-#endif
- }
- } else
- exitProc = TRUE;
- break;
- default:
- // Unexpected code
-#ifdef DEBUG_MONITOR
- DisplayErrorMessage();
-#endif
- exitProc = TRUE;
- break;
- }
-
- }
- CloseHandle(pi.hProcess);
- } else {
-#ifdef DEBUG_MONITOR
- swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine);
- OutputDebugStringW(buffer);
-
- DisplayErrorMessage();
-#endif
- }
-
- if (NULL != szCmdLine)
- {
- free(szCmdLine);
- }
-
- CloseHandle(waitEvent);
- CloseHandle(h[0]);
- CloseHandle(h[1]);
- CloseHandle(h[2]);
-
- return(dwExitCode);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Use this utility program to process correctly quotation marks in the command line
-// Arguments:
-// target - string to copy to
-// source - string to copy from
-// cpyLength - copy length
-// availSpace - size of the target buffer
-// Return :number of bytes used in target, or -1 in case of error
-/////////////////////////////////////////////////////////////////////////////////////
-int copyTo(wchar_t * target, const wchar_t * source, int cpyLength,
- int availSpace) {
- BOOL bSlash = FALSE;
- int i = 0, j = 0;
- int totCpyLength = cpyLength;
-
-#define QUOTATION_DO 0
-#define QUOTATION_DONE 1
-#define QUOTATION_NONE 2
-
- int nQuotationMode = 0;
- if (availSpace <= cpyLength) // = to reserve space for '\0'
- return -1;
-
- if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
- // Already done
- nQuotationMode = QUOTATION_DONE;
- } else if (wcschr(source, _T(' '))== NULL) {
- // No reason to quotate term becase it doesn't have embedded spaces
- nQuotationMode = QUOTATION_NONE;
- } else {
- // Needs to be quotated
- nQuotationMode = QUOTATION_DO;
- *target = _T('\"');
- ++j;
- }
-
- for (; i < cpyLength; ++i, ++j) {
- if (source[i] == _T('\\'))
- bSlash = TRUE;
- else
- // Don't escape embracing quotation marks
- if ((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) )) {
- if (!bSlash) {
- if (j == availSpace)
- return -1;
- target[j] = _T('\\');
- ++j;
- }
- bSlash = FALSE;
- } else
- bSlash = FALSE;
-
- if (j == availSpace)
- return -1;
- target[j] = source[i];
- }
-
- if (nQuotationMode == QUOTATION_DO) {
- if (j == availSpace)
- return -1;
- target[j] = _T('\"');
- ++j;
- }
- return j;
-}
-
-void DisplayErrorMessage() {
- wchar_t * lpMsgBuf;
- FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (wchar_t *) &lpMsgBuf, 0, NULL);
- OutputDebugStringW(lpMsgBuf);
- // Free the buffer.
- LocalFree(lpMsgBuf);
-}
-
-//////////////////////////////// End of File //////////////////////////////////
+/******************************************************************************* + * Copyright (c) 2002, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + * Wind River Systems, Inc. + * + * starter.cpp + * + * This is a small utility for windows spawner + *******************************************************************************/ + +#define STRICT +#define _WIN32_WINNT 0x0500 +#include <windows.h> +#include <process.h> +#include <tchar.h> +#include <stdio.h> +#include <psapi.h> + +//#define DEBUG_MONITOR +#define MAX_CMD_LINE_LENGTH (2049) +#define PIPE_NAME_LENGTH 100 + +int copyTo(wchar_t * target, const wchar_t * source, int cpyLength, + int availSpace); +void DisplayErrorMessage(); + +//BOOL KillProcessEx(DWORD dwProcessId); // Handle of the process + +/////////////////////////////////////////////////////////////////////////////// +BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type +{ + BOOL ret = TRUE; + switch(dwCtrlType) + { + case CTRL_C_EVENT: + break; + case CTRL_BREAK_EVENT: + break; + case CTRL_CLOSE_EVENT: + ret = FALSE; + break; + case CTRL_LOGOFF_EVENT: + ret = FALSE; + break; + case CTRL_SHUTDOWN_EVENT: + ret = FALSE; + break; + default: + break; + } + return ret; +} + +// The default here means we haven't checked yet +// i.e. cygwin is true but the bin dir hasn't been captured +wchar_t * cygwinBin = NULL; +bool _isCygwin = true; + +bool isCygwin(HANDLE process) { + // Have we checked before? + if (cygwinBin != NULL || !_isCygwin) + return _isCygwin; + + // See if this process loaded cygwin, need a different SIGINT for them + HMODULE mods[1024]; + DWORD needed; + if (EnumProcessModules(process, mods, sizeof(mods), &needed)) { + int i; + needed /= sizeof(HMODULE); + for (i = 0; i < needed; ++i ) { + wchar_t modName[MAX_PATH]; + if (GetModuleFileNameEx(process, mods[i], modName, MAX_PATH)) { + wchar_t * p = wcsrchr(modName, L'\\'); + if (p) { + *p = 0; // Null terminate there for future reference + if (!wcscmp(++p, L"cygwin1.dll")) { + _isCygwin = true; + // Store away the bind dir + cygwinBin = wcsdup(modName); + return _isCygwin; + } + } + } + } + } + + _isCygwin = false; + return _isCygwin; +} + +bool runCygwinCommand(wchar_t * command) { + wchar_t cygcmd[1024]; + swprintf(cygcmd, L"%s\\%s", cygwinBin, command); + + STARTUPINFO si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + if (CreateProcess(NULL, cygcmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return true; + } else if (CreateProcess(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return true; + } + return false; +} + +void ensureSize(wchar_t** ptr, int* psize, int requiredLength) { + int size= *psize; + if (requiredLength > size) { + size= 2*size; + if (size < requiredLength) { + size= requiredLength; + } + *ptr= (wchar_t *)realloc(*ptr, size * sizeof(wchar_t)); + if (NULL == *ptr) { + *psize= 0; + } else { + *psize= size; + } + } +} + +int main() { + + int argc; + wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc); + + // Make sure that we've been passed the right number of arguments + if (argc < 7) { + _tprintf(_T("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"), + argv[0]); + return(0); + } + + // Construct the full command line + int nCmdLineLength= MAX_CMD_LINE_LENGTH; + wchar_t * szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t)); + szCmdLine[0]= 0; + int nPos = 0; + + for(int i = 6; i < argc; ++i) + { + int nCpyLen; + int len= wcslen(argv[i]); + int requiredSize= nPos+len+2; + if (requiredSize > 32*1024) { +#ifdef DEBUG_MONITOR + OutputDebugStringW(_T("Command line too long!\n")); +#endif + return 0; + } + ensureSize(&szCmdLine, &nCmdLineLength, requiredSize); + if (NULL == szCmdLine) { +#ifdef DEBUG_MONITOR + OutputDebugStringW(_T("Not enough memory to build cmd line!\n")); +#endif + return 0; + } + if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos))) + { +#ifdef DEBUG_MONITOR + OutputDebugStringW(_T("Not enough space to build command line\n")); +#endif + return 0; + } + nPos += nCpyLen; + szCmdLine[nPos] = _T(' '); + ++nPos; + } + szCmdLine[nPos] = _T('\0'); + + STARTUPINFOW si = {sizeof(si)}; + PROCESS_INFORMATION pi = {0}; + DWORD dwExitCode = 0; +#ifdef DEBUG_MONITOR + int currentPID = GetCurrentProcessId(); + wchar_t buffer[MAX_CMD_LINE_LENGTH]; +#endif + + BOOL exitProc = FALSE; + HANDLE waitEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[4]); + HANDLE h[3]; + h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]); + h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event + SetConsoleCtrlHandler(HandlerRoutine, TRUE); + + int parentPid = wcstol(argv[1], NULL, 10); + int nCounter = wcstol(argv[2], NULL, 10); + wchar_t inPipeName[PIPE_NAME_LENGTH]; + wchar_t outPipeName[PIPE_NAME_LENGTH]; + wchar_t errPipeName[PIPE_NAME_LENGTH]; + + swprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter); + swprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter); + swprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter); +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName); + OutputDebugStringW(buffer); +#endif + + HANDLE stdHandles[3]; + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) || + (INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) || + (INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa)))) + { +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Failed to open pipe %i, %i, %i: %i\n"), stdHandles[0], stdHandles[1], stdHandles[2], GetLastError()); + OutputDebugStringW(buffer); +#endif + CloseHandle(stdHandles[0]); + CloseHandle(stdHandles[1]); + CloseHandle(stdHandles[2]); + return -1;; + } + SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE); + SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE); + SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE); + + if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) || + !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) || + !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) { +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Failed to reassign standard streams: %i\n"), GetLastError()); + OutputDebugStringW(buffer); +#endif + CloseHandle(stdHandles[0]); + CloseHandle(stdHandles[1]); + CloseHandle(stdHandles[2]); + return -1;; + } + +#ifdef DEBUG_MONITOR + wchar_t * lpvEnv = GetEnvironmentStringsW(); + + // If the returned pointer is NULL, exit. + if (lpvEnv == NULL) + OutputDebugStringW(_T("Cannot Read Environment\n")); + else { + // Variable strings are separated by NULL byte, and the block is + // terminated by a NULL byte. + + OutputDebugStringW(_T("Starter: Environment\n")); + for (wchar_t * lpszVariable = (wchar_t *) lpvEnv; *lpszVariable; lpszVariable+=wcslen(lpszVariable) + 1) { + swprintf(buffer, _T("%s\n"), lpszVariable); + OutputDebugStringW(buffer); + } + + FreeEnvironmentStringsW(lpvEnv); + } +#endif +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Starting: %s\n"), szCmdLine); + OutputDebugStringW(buffer); +#endif + // Create job object + HANDLE hJob = CreateJobObject(NULL, NULL); + + // Spawn the other processes as part of this Process Group + BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE, + 0, NULL, NULL, &si, &pi); + + // We don't need them any more + CloseHandle(stdHandles[0]); + CloseHandle(stdHandles[1]); + CloseHandle(stdHandles[2]); + + if (f) { +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Process %i started\n"), pi.dwProcessId); + OutputDebugStringW(buffer); +#endif + SetEvent(waitEvent); // Means thar process has been spawned + CloseHandle(pi.hThread); + h[1] = pi.hProcess; + + if(NULL != hJob) { + if(!AssignProcessToJobObject(hJob, pi.hProcess)) { +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Cannot assign process %i to a job\n"), pi.dwProcessId); + OutputDebugStringW(buffer); + DisplayErrorMessage(); +#endif + } + } + + while(!exitProc) + { + // Wait for the spawned-process to die or for the event + // indicating that the processes should be forcibly killed. + switch (WaitForMultipleObjects(3, h, FALSE, INFINITE)) + { + case WAIT_OBJECT_0 + 0: // Send Ctrl-C +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID); + OutputDebugStringW(buffer); +#endif + if (isCygwin(h[1])) { + // Need to issue a kill command + wchar_t kill[1024]; + swprintf(kill, L"kill -SIGINT %d", pi.dwProcessId); + if (!runCygwinCommand(kill)) { + // fall back to console event + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + } + } else { + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + } + + SetEvent(waitEvent); + break; + + case WAIT_OBJECT_0 + 1: // App terminated normally + // Make it's exit code our exit code +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("starter: launched process has been terminated(PID %i)\n"), + pi.dwProcessId); + OutputDebugStringW(buffer); +#endif + GetExitCodeProcess(pi.hProcess, &dwExitCode); + exitProc = TRUE; + break; + + case WAIT_OBJECT_0 + 2: // Kill +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("starter received KILL event (PID %i)\n"), currentPID); + OutputDebugStringW(buffer); +#endif + if (isCygwin(h[1])) { + // Need to issue a kill command + wchar_t kill[1024]; + swprintf(kill, L"kill -SIGTERM %d", pi.dwProcessId); + if (!runCygwinCommand(kill)) { + // fall back to console event + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + } + } else { + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + } + + SetEvent(waitEvent); + + if(NULL != hJob) { + if(!TerminateJobObject(hJob, (DWORD)-1)) { +#ifdef DEBUG_MONITOR + OutputDebugStringW(_T("Cannot terminate job\n")); + DisplayErrorMessage(); +#endif + } + } else + exitProc = TRUE; + break; + default: + // Unexpected code +#ifdef DEBUG_MONITOR + DisplayErrorMessage(); +#endif + exitProc = TRUE; + break; + } + + } + CloseHandle(pi.hProcess); + } else { +#ifdef DEBUG_MONITOR + swprintf(buffer, _T("Cannot start: %s\n"), szCmdLine); + OutputDebugStringW(buffer); + + DisplayErrorMessage(); +#endif + } + + if (NULL != szCmdLine) + { + free(szCmdLine); + } + + CloseHandle(waitEvent); + CloseHandle(h[0]); + CloseHandle(h[1]); + CloseHandle(h[2]); + + return(dwExitCode); +} + +///////////////////////////////////////////////////////////////////////////////////// +// Use this utility program to process correctly quotation marks in the command line +// Arguments: +// target - string to copy to +// source - string to copy from +// cpyLength - copy length +// availSpace - size of the target buffer +// Return :number of bytes used in target, or -1 in case of error +///////////////////////////////////////////////////////////////////////////////////// +int copyTo(wchar_t * target, const wchar_t * source, int cpyLength, + int availSpace) { + BOOL bSlash = FALSE; + int i = 0, j = 0; + int totCpyLength = cpyLength; + +#define QUOTATION_DO 0 +#define QUOTATION_DONE 1 +#define QUOTATION_NONE 2 + + int nQuotationMode = 0; + if (availSpace <= cpyLength) // = to reserve space for '\0' + return -1; + + if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) { + // Already done + nQuotationMode = QUOTATION_DONE; + } else if (wcschr(source, _T(' '))== NULL) { + // No reason to quotate term becase it doesn't have embedded spaces + nQuotationMode = QUOTATION_NONE; + } else { + // Needs to be quotated + nQuotationMode = QUOTATION_DO; + *target = _T('\"'); + ++j; + } + + for (; i < cpyLength; ++i, ++j) { + if (source[i] == _T('\\')) + bSlash = TRUE; + else + // Don't escape embracing quotation marks + if ((source[i] == _T('\"')) && !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))) )) { + if (!bSlash) { + if (j == availSpace) + return -1; + target[j] = _T('\\'); + ++j; + } + bSlash = FALSE; + } else + bSlash = FALSE; + + if (j == availSpace) + return -1; + target[j] = source[i]; + } + + if (nQuotationMode == QUOTATION_DO) { + if (j == availSpace) + return -1; + target[j] = _T('\"'); + ++j; + } + return j; +} + +void DisplayErrorMessage() { + wchar_t * lpMsgBuf; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (wchar_t *) &lpMsgBuf, 0, NULL); + OutputDebugStringW(lpMsgBuf); + // Free the buffer. + LocalFree(lpMsgBuf); +} + +//////////////////////////////// End of File ////////////////////////////////// |