示例#1
0
// get a "universal" path -- friendly to cygwin and non-cygwin
// no-op outside of cygwin
static std::string unipath(const std::string path)
{
  if(!isCygwin())
    return path;

  std::vector<std::string> args;
  std::string result;

  args.push_back("cygpath");
  args.push_back("-at");
  args.push_back("mixed");
  args.push_back(path);
  runCmd(&result, args);

  size_t len = result.length();
  const char *rdata = result.data() + len - 1;

  while(len && *rdata == '\n')
  {
    len--;
    rdata--;
  }
  result.resize(len);
  return result;
}
示例#2
0
int main() {

	int argc;
	wchar_t ** argv = CommandLineToArgvW(GetCommandLine(), &argc);

	// Make sure that we've been passed the right number of arguments
	if (argc < 8) {
		_tprintf(_T("Usage: %s (four inheritable event handles) (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 = 8; 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[5];
	h[0] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[3]);	// simulated SIGINT (CTRL-C or Cygwin 'kill -SIGINT')
//  h[1] we reserve for the process handle
	h[2] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[5]); // simulated SIGTERM
	h[3] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[6]); // simulated SIGKILL
	h[4] = OpenEventW(EVENT_ALL_ACCESS, TRUE, argv[7]); // CTRL-C, in all cases
	
	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.
			DWORD event = WaitForMultipleObjects(5, h, FALSE, INFINITE);
			switch (event)
			{
			case WAIT_OBJECT_0 + 0: // SIGINT
			case WAIT_OBJECT_0 + 4: // CTRL-C
#ifdef DEBUG_MONITOR
				swprintf(buffer, _T("starter (PID %i) received CTRL-C event\n"), currentPID);
				OutputDebugStringW(buffer);
#endif
				if ((event == (WAIT_OBJECT_0 + 0)) && 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;

			// Terminate and Kill behavior differ only for cygwin processes, where
			// we use the cygwin 'kill' command. We send a SIGKILL in one case,
			// SIGTERM in the other. For non-cygwin processes, both requests
			// are treated exactly the same
			case WAIT_OBJECT_0 + 2:	// TERM
			case WAIT_OBJECT_0 + 3:	// KILL
			{
				const wchar_t* signal = (event == WAIT_OBJECT_0 + 2) ? L"TERM" : L"KILL";
#ifdef DEBUG_MONITOR
				swprintf(buffer, _T("starter received %s event (PID %i)\n"), signal, currentPID);
				OutputDebugStringW(buffer);
#endif
				if (isCygwin(h[1])) {
					// Need to issue a kill command
					wchar_t kill[1024];
					swprintf(kill, L"kill -%s %d", signal, 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
					}
				}

				// Note that we keep trucking until the child process terminates (case WAIT_OBJECT_0 + 1)
				break;
			}

			default:
				// Unexpected code
#ifdef DEBUG_MONITOR
				DisplayErrorMessage();
#endif
				exitProc = TRUE;
				break;
			}

		}
	} 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]);
	CloseHandle(h[3]);
	CloseHandle(h[4]);

	return(dwExitCode);
}