void limitMem( size_t limit )
{
    static HANDLE hJob = NULL;
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;

    jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
    jobInfo.ProcessMemoryLimit = limit? limit*MByte : 2*MByte*1024;
    if (NULL == hJob) {
        if (NULL == (hJob = CreateJobObject(NULL, NULL))) {
            REPORT("Can't assign create job object: %ld\n", GetLastError());
            exit(1);
        }
        if (0 == AssignProcessToJobObject(hJob, GetCurrentProcess())) {
            REPORT("Can't assign process to job object: %ld\n", GetLastError());
            exit(1);
        }
    }
    if (0 == SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
                                     &jobInfo, sizeof(jobInfo))) {
        REPORT("Can't set limits: %ld\n", GetLastError());
        exit(1);
    }
}
Example #2
0
/* This could be interesting to expose in public API */
static void
_g_test_watcher_add_pid (GPid pid)
{
  static gsize started = 0;
  HANDLE job;

  if (g_once_init_enter (&started))
    {
      JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;

      job = CreateJobObjectW (NULL, NULL);
      memset (&info, 0, sizeof (info));
      info.BasicLimitInformation.LimitFlags = 0x2000 /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE */;

      if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof (info)))
	g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError()));

      g_once_init_leave (&started,(gsize)job);
    }

  job = (HANDLE)started;

  if (!AssignProcessToJobObject(job, pid))
    g_warning ("Can't assign process to job: %s", g_win32_error_message (GetLastError()));
}
Example #3
0
void CJobObject::AssignProcess(CProcess& Process) {
   BOOL bRet;
   CMutex::CEnter MutexEnter(m_Mutex);

   bRet = AssignProcessToJobObject(GetHandle(), Process.GetHandle());   
   if (bRet == 0) {
      throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__);
   }
}
Example #4
0
/// <summary>
///	Creates a console object and starts the child process </summary>
///
/// <param name="ac">
/// Uninitialized console object </param>
/// <param name="tzClientPath">
/// Path to client, in an inject environment this should not be relative </param>
///
/// <returns>
/// If child could be created </returns>
BOOL ImAllocConsole(OUT IM_CONSOLE* ac, IN const TCHAR* tzClientPath) {
       
    SecureZeroMemory(ac->tzClientPipe, MAX_NAME);

    // generate a random name (tmpnam has a forward slash and is not necessarily alphanumeric)
    for (register size_t i = 0; i < rand() % MAX_NAME; ++i) {
        ac->tzClientPipe[i] = rand() % 26 + 'A'; // make random letter
        ac->tzClientPipe[i] ^= rand() % 1 << 5;  // randomly toggle 0x20 (upper/lowercase)
    }
        
    { // create job object and set information
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION joELI;

        ac->hJob = CreateJobObject(NULL, ac->tzClientPipe);
        if (ac->hJob == NULL)
            return FALSE;

	    joELI.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
	    if(!SetInformationJobObject(ac->hJob, JobObjectExtendedLimitInformation, &joELI, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) {
            CloseHandle(ac->hJob), ac->hJob = NULL;
            return FALSE;
        }
    }

    { // create child process
        SECURITY_ATTRIBUTES sa = {0};

        sa.nLength = sizeof(sa);
        sa.bInheritHandle = TRUE;
        //  sa.lpSecurityDescriptor = NULL;

        if (!CreatePipe(&ac->hRead, &ac->hWrite, &sa, BUFSIZ)) {
            CloseHandle(ac->hJob), ac->hJob = NULL;
            return FALSE;
        }

        STARTUPINFO siCon = {0};
        PROCESS_INFORMATION piCon = {0};

        siCon.cb = sizeof(siCon);
        siCon.hStdInput = ac->hRead;
        siCon.dwFlags |= STARTF_USESTDHANDLES;

        if (!CreateProcess(tzClientPath, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &siCon, &piCon)) {
            CloseHandle(ac->hJob), ac->hJob = NULL;
            return FALSE;
        }

        DuplicateHandle(GetCurrentProcess(), piCon.hProcess, GetCurrentProcess(), &ac->hChildProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
        CloseHandle(piCon.hThread);
        CloseHandle(piCon.hProcess);
    }

    return AssignProcessToJobObject(ac->hJob, ac->hChildProcess);
}
Example #5
0
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	AttachConsole(ATTACH_PARENT_PROCESS);

	// Create a named pipe that we can be signaled on for early termination
	wchar_t buf[512];
	wsprintf(buf, L"\\\\.\\pipe\\jobber-%d", GetCurrentProcessId());

	HANDLE hPipe = CreateNamedPipe(buf, 
		PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 
		PIPE_READMODE_BYTE | PIPE_WAIT, 
		1, 256, 256, 100000, NULL);

	OVERLAPPED io = { 0 };
	io.hEvent = CreateEvent(NULL, true, true, NULL);
	if (!ConnectNamedPipe(hPipe, &io) && GetLastError() != ERROR_IO_PENDING) {
		DWORD dwLastError = GetLastError();
		return -1;
	}

	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	si.cb = sizeof(STARTUPINFO);
	si.wShowWindow = nCmdShow;

	if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, true, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
		DWORD dwLastError = GetLastError();
		return -1;
	}

	HANDLE hJob = CreateJobObject(NULL, NULL);
	AssignProcessToJobObject(hJob, pi.hProcess);

	ResumeThread(pi.hThread);

	HANDLE handles[2];
	handles[0] = io.hEvent;
	handles[1] = pi.hProcess;

	int result = WaitForMultipleObjects(2, handles, false, INFINITE);
	TerminateJobObject(hJob, -1);

	if (result == WAIT_OBJECT_0) {
		return -1;
	} else {
		DWORD dwExit;

		GetExitCodeProcess(pi.hProcess, &dwExit);
		return dwExit;
	}

}
int ActivePet::launch(std::wstring exePath, std::wstring originalDocPath){

	wchar_t commandLine[4096] = { '\0' };
	if (originalDocPath != L"") {

		// Build the command line.
	    std::wstring editableDocPath = edit(originalDocPath);
		wcscat(commandLine, L"\"");
		wcscat(commandLine, exePath.c_str());
		wcscat(commandLine, L"\" \"");
		wcscat(commandLine, editableDocPath.c_str());
		wcscat(commandLine, L"\"");
	}
    auto_close<void*, &::DestroyEnvironmentBlock> environment(NULL);
	if (!CreateEnvironmentBlock(&environment, m_session.get(), FALSE)) {
        printf("CreateEnvironmentBlock() failed: %d", GetLastError());
		return -30;
	}
    STARTUPINFO si = { sizeof(STARTUPINFO) };
    PROCESS_INFORMATION pi = {};
	if (!CreateProcessAsUser(m_session.get(),
							 exePath.c_str(),
							 commandLine,
							 NULL,
							 NULL,
							 FALSE,
							 CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE,
							 environment.get(),
							 NULL, // lpCurrentDirectory,
							 &si,
							 &pi)) {
        printf("CreateProcessAsUser() failed: %d", GetLastError());
		return -30;
	}
	if (!AssignProcessToJobObject(m_job.get(), pi.hProcess)) {
        printf("AssignProcessToJobObject() failed: %d", GetLastError());
		return -30;
	}
	if (!ResumeThread(pi.hThread)) {
        printf("ResumeThread() failed: %d", GetLastError());
		return -30;
	}
    if (WaitForInputIdle(pi.hProcess, INFINITE) != ERROR_SUCCESS) {
        printf("WaitForInputIdle() failed: %d", GetLastError());
		return -30;
	}
    InjectAndCall(pi.hProcess, "ApplyHooks", 10000);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);

    return 0;
}
Example #7
0
File: Job.cpp Project: stden/IJE
void Job::assignMainProcess(const Process &process)
{
    hMainProcess = process.processHandle();
    tryApi(_T("AssignProcessToJobObject"),
        AssignProcessToJobObject(hJob,hMainProcess) != 0);
    gatherInfo();
    initialElapsedTimeCounter = elapsedTimeCounter.getLargeValue();
    millisecondsIdle = 0;
    prevJobTime = -1;
    prevElapsedTime = -1;
    res = JobResult();
    jobactive = true;
}
Example #8
0
int main( int argc , char* argv[] )
{
#if defined(WIN32) && defined(MAX_MEMORY_GB)
    if( MAX_MEMORY_GB>0 )
    {
        SIZE_T peakMemory = 1;
        peakMemory <<= 30;
        peakMemory *= MAX_MEMORY_GB;
        printf( "Limiting memory usage to %.2f GB\n" , float( peakMemory>>30 ) );
        HANDLE h = CreateJobObject( NULL , NULL );
        AssignProcessToJobObject( h , GetCurrentProcess() );

        JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
        jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_JOB_MEMORY;
        jeli.JobMemoryLimit = peakMemory;
        if( !SetInformationJobObject( h , JobObjectExtendedLimitInformation , &jeli , sizeof( jeli ) ) )
            fprintf( stderr , "Failed to set memory limit\n" );
    }
Example #9
0
File: apby.cpp Project: yngccc/apby
void mpk_import_create_process(mpk_import_command_line *cmdl, HANDLE process_group, memory_arena *memory_arena) {
  m_memory_arena_undo_allocations_at_scope_exit(memory_arena);
  STARTUPINFO su_info = { sizeof(su_info) };
  su_info.dwFlags = STARTF_USESHOWWINDOW;
  su_info.wShowWindow = SW_HIDE;
  PROCESS_INFORMATION ps_info;
  int n = snprintf(nullptr, 0, m_mpk_import_command_line_parse_str, m_mpk_import_command_line_snprintf_unpack(cmdl));
  char *cmdl_str = memory_arena_allocate<char>(memory_arena, n + 1);
  snprintf(cmdl_str, n + 1, m_mpk_import_command_line_parse_str, m_mpk_import_command_line_snprintf_unpack(cmdl));
  if (!CreateProcessA("mpk_import.exe", cmdl_str, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &su_info, &ps_info)) {
    m_last_error_str(err);
    m_die("cannot create new mpk import process, %s", err);
  }
  if (!AssignProcessToJobObject(process_group, ps_info.hProcess)) {
    m_last_error_str(err);
    m_die("cannot assign new mpk import process to process group, %s", err);
  }
  CloseHandle(ps_info.hProcess);
}
Example #10
0
void runner::set_allow_breakaway(bool allow) {
    if (allow_breakaway == allow) {
        return;
    }
    if (main_job_object == handle_default_value) {
        main_job_object = CreateJobObject(NULL, NULL);
        AssignProcessToJobObject(main_job_object, GetCurrentProcess());
    }
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION extended_limit_information;
    memset(&extended_limit_information, 0, sizeof(extended_limit_information));
    if (allow) {
        extended_limit_information.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    }

    if (!SetInformationJobObject(main_job_object, JobObjectExtendedLimitInformation, &extended_limit_information, sizeof(extended_limit_information))) {
        DWORD le = GetLastError();
        return;
    }
    allow_breakaway = allow;
}
Example #11
0
HANDLE create_child_process(const char *cmd)
{
	PROCESS_INFORMATION pi = {0};
	STARTUPINFO si = {sizeof(si)};

	hJOB = CreateJobObject(NULL, NULL);
	if(!hJOB) {
		return NULL;
	}

	/*JOBOBJECT_SECURITY_LIMIT_INFORMATION security_info = {0};
	security_info.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN;
	if(!SetInformationJobObject(hJOB, JobObjectSecurityLimitInformation, &security_info, sizeof security_info)) {
		CloseHandle(hJOB);
		return NULL;
	}*/
	freopen("err.out", "w", stderr);
	freopen("cmpr.out", "w", stdout);

	BOOL bSuccess = CreateProcess(NULL, (LPSTR)(void*)cmd, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
	if(!bSuccess) {
		CloseHandle(hJOB);
		return NULL;
	}
	if(!AssignProcessToJobObject(hJOB, pi.hProcess)) {
		CloseHandle(hJOB);
		CloseHandle(pi.hThread);
		TerminateProcess(pi.hProcess, 0);
		CloseHandle(pi.hProcess);
		return NULL;
	}
	if(-1 == ResumeThread(pi.hThread)) {
		CloseHandle(hJOB);
		CloseHandle(pi.hThread);
		TerminateProcess(pi.hProcess, 0);
		CloseHandle(pi.hProcess);
		return NULL;
	}
	CloseHandle(pi.hThread);
	return pi.hProcess;
}
Example #12
0
/* 结束进程方案2 TerminateJobObject */
BOOL KillProcessMethod_2(DWORD dwProcessID)
{
    BOOL bRet;
    HANDLE hProcess, hJob;

    hProcess = OpenProcess(PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessID);
    if (hProcess == NULL)
    {
        return FALSE;
    }

    hJob = CreateJobObject(NULL, _T("TestJob"));

    if (!AssignProcessToJobObject(hJob, hProcess))
    {
        return FALSE;
    }

    bRet = TerminateJobObject(hJob, 0);
    CloseHandle(hProcess);
    CloseHandle(hJob);
    return bRet;
}
Example #13
0
bool JobObject::addProcessToJob(const QProcess *proc)
{
	if(!m_hJobObject)
	{
		qWarning("Cannot assign process to job: No job bject available!");
		return false;
	}

	if(Q_PID pid = proc->pid())
	{
		DWORD exitCode;
		if(!GetExitCodeProcess(pid->hProcess, &exitCode))
		{
			qWarning("Cannot assign process to job: Failed to query process status!");
			return false;
		}

		if(exitCode != STILL_ACTIVE)
		{
			qWarning("Cannot assign process to job: Process is not running anymore!");
			return false;
		}

		if(!AssignProcessToJobObject(m_hJobObject, pid->hProcess))
		{
			qWarning("Failed to assign process to job object!");
			return false;
		}

		return true;
	}
	else
	{
		qWarning("Cannot assign process to job: Process handle not available!");
		return false;
	}
}
bool WindowsJob::assinProcess(HANDLE handel)
{
	return !!AssignProcessToJobObject(jobHandle_, handel);
}
Example #15
0
void EngineProcess::start(const QString& program,
			  const QStringList& arguments,
			  OpenMode mode)
{
	if (m_started)
		close();

	m_started = false;
	m_finished = false;
	m_exitCode = 0;
	m_exitStatus = NormalExit;
	m_errRead = createFile(m_stdErrFile, m_stdErrFileMode);

	// Temporary handles for the child process' end of the pipes
	HANDLE outWrite;
	HANDLE inRead;

	// Security attributes. Use the same one for both pipes.
	SECURITY_ATTRIBUTES saAttr;
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saAttr.bInheritHandle = TRUE;
	saAttr.lpSecurityDescriptor = NULL;

	CreatePipe(&m_outRead, &outWrite, &saAttr, 0);
	CreatePipe(&inRead, &m_inWrite, &saAttr, 0);

	STARTUPINFO startupInfo;
	ZeroMemory(&startupInfo, sizeof(startupInfo));
	startupInfo.cb = sizeof(startupInfo);
	startupInfo.hStdError = m_errRead;
	startupInfo.hStdOutput = outWrite;
	startupInfo.hStdInput = inRead;
	startupInfo.dwFlags |= STARTF_USESTDHANDLES;

	// Call DuplicateHandle with a NULL target to get non-inheritable
	// handles for the parent process' ends of the pipes
	DuplicateHandle(GetCurrentProcess(),
			m_outRead,		// child's stdout read end
			GetCurrentProcess(),
			NULL,			// no target
			0,			// flags
			FALSE,			// not inheritable
			DUPLICATE_SAME_ACCESS);	// same handle access
	DuplicateHandle(GetCurrentProcess(),
			m_inWrite,		// child's stdin write end
			GetCurrentProcess(),
			NULL,			// no target
			0,			// flags
			FALSE,			// not inheritable
			DUPLICATE_SAME_ACCESS);	// same handle access

	BOOL ok = FALSE;
	QString cmd = cmdLine(m_workDir, program, arguments);
	QString wdir = QDir::toNativeSeparators(m_workDir);
	ZeroMemory(&m_processInfo, sizeof(m_processInfo));

#ifdef UNICODE
	ok = CreateProcessW(NULL,
			    (WCHAR*)cmd.utf16(),
			    NULL,	// process attributes
			    NULL,	// thread attributes
			    TRUE,	// inherit handles
			    CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, // creation flags
			    NULL,	// environment
			    wdir.isEmpty() ? NULL : (WCHAR*)wdir.utf16(),
			    &startupInfo,
			    &m_processInfo);
#else // not UNICODE
	ok = CreateProcessA(NULL,
			    cmd.toLocal8Bit().data(),
			    NULL,	// process attributes
			    NULL,	// thread attributes
			    TRUE,	// inherit handles
			    CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, // creation flags
			    NULL,	// environment
			    wdir.isEmpty() ? NULL : wdir.toLocal8Bit().data(),
			    &startupInfo,
			    &m_processInfo);
#endif // not UNICODE

	m_started = (bool)ok;
	if (ok)
	{
		// Assign the engine process to the main job to make sure it's
		// terminated when CuteChess terminates.
		AssignProcessToJobObject(mainJob(), m_processInfo.hProcess);

		// Close the child process' ends of the pipes to make sure
		// that ReadFile and WriteFile will return when the child
		// terminates and closes its pipes
		killHandle(&outWrite);
		killHandle(&inRead);
		killHandle(&m_processInfo.hThread);

		// Start reading input from the child
		m_reader = new PipeReader(m_outRead, this);
		connect(m_reader, SIGNAL(finished()), this, SLOT(onFinished()));
		connect(m_reader, SIGNAL(finished()), this, SIGNAL(readChannelFinished()));
		connect(m_reader, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
		m_reader->start();

		// Make QIODevice aware that the device is now open
		QIODevice::open(mode);
	}
	else
		cleanup();
}
Example #16
0
static intptr_t do_spawnv(rktio_t *rktio,
                          const char *command, int argc, const char * const *argv,
			  int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid,
			  int new_process_group, int chain_termination_here_to_child,
                          void *env, const char *wd)
{
  intptr_t i, l, len = 0;
  int use_jo;
  intptr_t cr_flag;
  char *cmdline;
  wchar_t *cmdline_w, *wd_w, *command_w;
  STARTUPINFOW startup;
  PROCESS_INFORMATION info;

  if (exact_cmdline) {
    cmdline = (char *)argv[1];
  } else {
    for (i = 0; i < argc; i++) {
      len += strlen(argv[i]) + 1;
    }

    cmdline = malloc(len);

    len = 0;
    for (i = 0; i < argc; i++) {
      l = strlen(argv[i]);
      memcpy(cmdline + len, argv[i], l);
      cmdline[len + l] = ' ';
      len += l + 1;
    }
    --len;
    cmdline[len] = 0;
  }

  memset(&startup, 0, sizeof(startup));
  startup.cb = sizeof(startup);
  startup.dwFlags = STARTF_USESTDHANDLES;
  startup.hStdInput = (HANDLE)sin;
  startup.hStdOutput = (HANDLE)sout;
  startup.hStdError = (HANDLE)serr;

  /* If none of the stdio handles are consoles, specifically
     create the subprocess without a console: */
  if (!rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdInput)
      && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdOutput)
      && !rktio_system_fd_is_terminal(rktio, (intptr_t)startup.hStdError))
    cr_flag = CREATE_NO_WINDOW;
  else
    cr_flag = 0;
  if (new_process_group)
    cr_flag |= CREATE_NEW_PROCESS_GROUP;
  cr_flag |= CREATE_UNICODE_ENVIRONMENT;

  use_jo = chain_termination_here_to_child;
  if (use_jo) {
    /* Use a job object to ensure that the new process will be terminated
       if this process ends for any reason (including a crash) */
    if (!rktio->process_job_object) {
      JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;

      rktio->process_job_object = CreateJobObject(NULL, NULL);

      memset(&jeli, 0, sizeof(jeli));
      jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
      SetInformationJobObject(rktio->process_job_object,
			      JobObjectExtendedLimitInformation,
			      &jeli,
			      sizeof(jeli));
    }
  }

  
  cmdline_w = WIDE_PATH_copy(cmdline);
  if (!exact_cmdline)
    free(cmdline);
  wd_w = WIDE_PATH_copy(wd);
  command_w = WIDE_PATH_temp(command);

  if (cmdline_w
      && wd_w
      && command_w
      && CreateProcessW(command_w, cmdline_w, 
                        NULL, NULL, 1 /*inherit*/,
                        cr_flag, env, wd_w,
                        &startup, &info)) {
    if (use_jo)
      AssignProcessToJobObject(rktio->process_job_object, info.hProcess);
    CloseHandle(info.hThread);
    *pid = info.dwProcessId;
    free(cmdline_w);
    free(wd_w);
    return (intptr_t)info.hProcess;
  } else {
    if (cmdline_w) free(cmdline_w);
    if (wd_w) free(wd_w);
    return -1;
  }
}
Example #17
0
BOOL CreateBuilderProcess(HANDLE job, PCTSTR appName, 
						  PTSTR cmdLine, PCTSTR workDir,
						  H2BOperation& op)
{
	BOOL ret = TRUE;
	DWORD err = ERROR_SUCCESS;
	STARTUPINFO si = { sizeof(si) };
	PROCESS_INFORMATION pi;

	if( CreateProcess(appName, cmdLine, NULL, NULL, FALSE, 
		CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB , NULL, workDir, &si, &pi) )
	{
		HANDLE openProc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pi.dwProcessId);

		if( openProc )
		{
			if( AssignProcessToJobObject(job, openProc) )
			{
				if( (int) ResumeThread(pi.hThread) != -1 )
				{
					DWORD wait = ERROR_TIMEOUT;
					const DWORD waitStep = 200;

					op.SetStatusMessageDescription(_T("Esse processo pode demorar vários ")
						_T("minutos, dependendo da velocidade de seu computador."));

					for( DWORD i = 0; i * waitStep < BAB_BUILD_TIMEOUT; ++i )
					{
						wait = WaitForSingleObject(openProc, waitStep);

						if( wait == WAIT_OBJECT_0 )
							break;
						else if( op.Cancel() )
						{
							err = ERROR_CANCELLED;
							break;
						}
					}

					if( err == ERROR_CANCELLED )
					{
						Log("Babylon builder process cancellation.");
					}
					else if( wait == WAIT_OBJECT_0 )
					{
						GetExitCodeProcess(openProc, &err);
						Log("Babylon builder process return: %d", err);
					}
					else
					{
						err = ERROR_TIMEOUT;
						Log("Babylon builder timeout");
					}
				}
				else 
				{
					err = GetLastError();
					Log("Error resuming builder process");
				}
			}
			else 
			{
				err = GetLastError();
				Log("Error assigning builder process to job");
				TerminateProcess(openProc, -1);
			}

			CloseHandle(openProc);
		}

		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}
	else 
	{
		err = GetLastError();
		Log("Error creating Babylon Builder process");
	}

	if( err != ERROR_SUCCESS )
	{
		SetLastError(err);
		ret = FALSE;
	}

	return ret;
}
Example #18
0
BOOL Go(const char *commandLine)
{
	HANDLE stdInRead, stdInWrite;

	if (!CreatePipes(&stdInRead, &stdInWrite)) return FALSE;


	PROCESS_INFORMATION piProcInfo; 
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE; 

	
	ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

	ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
	siStartInfo.cb = sizeof(STARTUPINFO); 
	siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	siStartInfo.hStdInput = stdInRead;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

	siStartInfo.wShowWindow = SW_HIDE;
	siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
	// Create the child process. 

	if (!CreateProcess(NULL, 
		const_cast<char *>(commandLine),   // command line 
		NULL,          // process security attributes 
		NULL,          // primary thread security attributes 
		TRUE,          // handles are inherited 
		CREATE_BREAKAWAY_FROM_JOB,             // creation flags 
		NULL,          // use parent's environment 
		NULL,          // use parent's current directory 
		&siStartInfo,  // STARTUPINFO pointer 
		&piProcInfo))  // receives PROCESS_INFORMATION 
	{
		return FALSE;
	}

	HANDLE ghJob = CreateJobObject( NULL, NULL);

	JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
	jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
	if( ghJob == NULL || SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == FALSE) {
		std::cerr << "Error initializing close-process job";
		return 1;
	}

	if (!AssignProcessToJobObject( ghJob, piProcInfo.hProcess)) {
		DWORD error = GetLastError();
		std::cerr << "AssignProcessToJobObject failed: " << error << std::endl;
		return FALSE;
	}

	// Close handles to the child process and its primary thread.
	// Some applications might keep these handles to monitor the status
	// of the child process, for example. 

	CloseHandle(piProcInfo.hThread);
	MonitorProcessClose(piProcInfo.hProcess);

	WriteToPipe(stdInWrite, piProcInfo.hProcess);
	
	CloseHandle(piProcInfo.hProcess);
	CloseHandle(stdInRead);
	CloseHandle(stdInWrite);


	return 0;
}
Example #19
0
int main(){
  DWORD exit_code, terminated;

  STARTUPINFO child_1_si;
  STARTUPINFO child_2_si;

  PROCESS_INFORMATION child_1_pi;
  PROCESS_INFORMATION child_2_pi;

  HANDLE job_handle = CreateJobObject(NULL, "job");

  memset(&child_1_si, 0, sizeof(STARTUPINFO));
  child_1_si.cb=sizeof(child_1_si);

  memset(&child_2_si, 0, sizeof(STARTUPINFO));
  child_2_si.cb=sizeof(child_2_si);

  get_warning_alert("\nTrying to create the first child process...");
  DWORD child_1_created = CreateProcess(NULL, "child.exe ChildOne GrandChildOne", NULL, NULL, FALSE,
                  NORMAL_PRIORITY_CLASS, NULL, NULL, &child_1_si, &child_1_pi);

  if(!child_1_created){
    get_error_alert("\nError on creating process / code #%ld", GetLastError());
    exit(1);
  }
  get_success_alert("\nProcess created!");

  get_warning_alert("\nTrying to create the second child process...");
  DWORD child_2_created = CreateProcess(NULL, "child.exe ChildTwo GrandChildTwo", NULL, NULL, FALSE,
                  NORMAL_PRIORITY_CLASS, NULL, NULL, &child_2_si, &child_2_pi);

  if(!child_2_created){
    get_error_alert("\nError on creating process / code #%ld", GetLastError());
    exit(1);
  }
  get_success_alert("\nProcess created!");

  AssignProcessToJobObject(job_handle, child_2_pi.hProcess);


  for(int i = 0; i <= 20; i++){
    get_error_alert("Parent: ");
    printf("on step %d\n", i);

    if(i == 7)
    {
      GetExitCodeProcess(child_1_pi.hProcess, &exit_code);
      terminated = TerminateProcess(child_1_pi.hProcess, (UINT) exit_code);

      if(!terminated)
      {
        get_error_alert("\nTerminating error %d\n", GetLastError());
      }
      else
      {
        get_success_alert("\nThe first child process terminated\n");
      }
    }

    if(i == 10)
    {
      GetExitCodeProcess(job_handle, &exit_code);
      terminated = TerminateJobObject(job_handle, (UINT) exit_code);

      if(!terminated)
      {
        get_error_alert("\nJob terminating error %d\n", GetLastError());
      }
      else
      {
        get_success_alert("\nJob terminated\n");
      }
    }

    Sleep(3000);
  }

  return 0;
}
Example #20
0
int uv_spawn(uv_loop_t* loop,
             uv_process_t* process,
             const uv_process_options_t* options) {
  int i;
  int err = 0;
  WCHAR* path = NULL, *alloc_path = NULL;
  BOOL result;
  WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
         *env = NULL, *cwd = NULL;
  STARTUPINFOW startup;
  PROCESS_INFORMATION info;
  DWORD process_flags;

  uv_process_init(loop, process);
  process->exit_cb = options->exit_cb;

  if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
    return UV_ENOTSUP;
  }

  if (options->file == NULL ||
      options->args == NULL) {
    return UV_EINVAL;
  }

  if (options->cpumask != NULL) {
    if (options->cpumask_size < (size_t)uv_cpumask_size()) {
      return UV_EINVAL;
    }
  }

  assert(options->file != NULL);
  assert(!(options->flags & ~(UV_PROCESS_DETACHED |
                              UV_PROCESS_SETGID |
                              UV_PROCESS_SETUID |
                              UV_PROCESS_WINDOWS_HIDE |
                              UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));

  err = uv_utf8_to_utf16_alloc(options->file, &application);
  if (err)
    goto done;

  err = make_program_args(
      options->args,
      options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
      &arguments);
  if (err)
    goto done;

  if (options->env) {
     err = make_program_env(options->env, &env);
     if (err)
       goto done;
  }

  if (options->cwd) {
    /* Explicit cwd */
    err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
    if (err)
      goto done;

  } else {
    /* Inherit cwd */
    DWORD cwd_len, r;

    cwd_len = GetCurrentDirectoryW(0, NULL);
    if (!cwd_len) {
      err = GetLastError();
      goto done;
    }

    cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
    if (cwd == NULL) {
      err = ERROR_OUTOFMEMORY;
      goto done;
    }

    r = GetCurrentDirectoryW(cwd_len, cwd);
    if (r == 0 || r >= cwd_len) {
      err = GetLastError();
      goto done;
    }
  }

  /* Get PATH environment variable. */
  path = find_path(env);
  if (path == NULL) {
    DWORD path_len, r;

    path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
    if (path_len == 0) {
      err = GetLastError();
      goto done;
    }

    alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
    if (alloc_path == NULL) {
      err = ERROR_OUTOFMEMORY;
      goto done;
    }
    path = alloc_path;

    r = GetEnvironmentVariableW(L"PATH", path, path_len);
    if (r == 0 || r >= path_len) {
      err = GetLastError();
      goto done;
    }
  }

  err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
  if (err)
    goto done;

  application_path = search_path(application,
                                 cwd,
                                 path);
  if (application_path == NULL) {
    /* Not found. */
    err = ERROR_FILE_NOT_FOUND;
    goto done;
  }

  startup.cb = sizeof(startup);
  startup.lpReserved = NULL;
  startup.lpDesktop = NULL;
  startup.lpTitle = NULL;
  startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

  startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
  startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;

  startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
  startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
  startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);

  process_flags = CREATE_UNICODE_ENVIRONMENT;

  if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
    /* Avoid creating console window if stdio is not inherited. */
    for (i = 0; i < options->stdio_count; i++) {
      if (options->stdio[i].flags & UV_INHERIT_FD)
        break;
      if (i == options->stdio_count - 1)
        process_flags |= CREATE_NO_WINDOW;
    }

    /* Use SW_HIDE to avoid any potential process window. */
    startup.wShowWindow = SW_HIDE;
  } else {
    startup.wShowWindow = SW_SHOWDEFAULT;
  }

  if (options->flags & UV_PROCESS_DETACHED) {
    /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
     * means that libuv might not let you create a fully daemonized process
     * when run under job control. However the type of job control that libuv
     * itself creates doesn't trickle down to subprocesses so they can still
     * daemonize.
     *
     * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
     * CreateProcess call fail if we're under job control that doesn't allow
     * breakaway.
     */
    process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
  }

  if (options->cpumask != NULL) {
    /* Create the child in a suspended state so we have a chance to set
       its process affinity before it runs.  */
    process_flags |= CREATE_SUSPENDED;
  }

  if (!CreateProcessW(application_path,
                     arguments,
                     NULL,
                     NULL,
                     1,
                     process_flags,
                     env,
                     cwd,
                     &startup,
                     &info)) {
    /* CreateProcessW failed. */
    err = GetLastError();
    goto done;
  }

  if (options->cpumask != NULL) {
    /* The child is currently suspended.  Set its process affinity
       or terminate it if we can't.  */
    int i;
    int cpumasksize;
    DWORD_PTR sysmask;
    DWORD_PTR oldmask;
    DWORD_PTR newmask;

    cpumasksize = uv_cpumask_size();

    if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) {
      err = GetLastError();
      TerminateProcess(info.hProcess, 1);
      goto done;
    }

    newmask = 0;
    for (i = 0; i < cpumasksize; i++) {
      if (options->cpumask[i]) {
        if (oldmask & (((DWORD_PTR)1) << i)) {
          newmask |= ((DWORD_PTR)1) << i;
        } else {
          err = UV_EINVAL;
          TerminateProcess(info.hProcess, 1);
          goto done;
        }
      }
    }

    if (!SetProcessAffinityMask(info.hProcess, newmask)) {
      err = GetLastError();
      TerminateProcess(info.hProcess, 1);
      goto done;
    }

    /* The process affinity of the child is set.  Let it run.  */
    if (ResumeThread(info.hThread) == ((DWORD)-1)) {
      err = GetLastError();
      TerminateProcess(info.hProcess, 1);
      goto done;
    }
  }

  /* Spawn succeeded */
  /* Beyond this point, failure is reported asynchronously. */

  process->process_handle = info.hProcess;
  process->pid = info.dwProcessId;

  /* If the process isn't spawned as detached, assign to the global job */
  /* object so windows will kill it when the parent process dies. */
  if (!(options->flags & UV_PROCESS_DETACHED)) {
    uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);

    if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
      /* AssignProcessToJobObject might fail if this process is under job
       * control and the job doesn't have the
       * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
       * that doesn't support nested jobs.
       *
       * When that happens we just swallow the error and continue without
       * establishing a kill-child-on-parent-exit relationship, otherwise
       * there would be no way for libuv applications run under job control
       * to spawn processes at all.
       */
      DWORD err = GetLastError();
      if (err != ERROR_ACCESS_DENIED)
        uv_fatal_error(err, "AssignProcessToJobObject");
    }
  }

  /* Set IPC pid to all IPC pipes. */
  for (i = 0; i < options->stdio_count; i++) {
    const uv_stdio_container_t* fdopt = &options->stdio[i];
    if (fdopt->flags & UV_CREATE_PIPE &&
        fdopt->data.stream->type == UV_NAMED_PIPE &&
        ((uv_pipe_t*) fdopt->data.stream)->ipc) {
      ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
    }
  }

  /* Setup notifications for when the child process exits. */
  result = RegisterWaitForSingleObject(&process->wait_handle,
      process->process_handle, exit_wait_callback, (void*)process, INFINITE,
      WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
  if (!result) {
    uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
  }

  CloseHandle(info.hThread);

  assert(!err);

  /* Make the handle active. It will remain active until the exit callback */
  /* is made or the handle is closed, whichever happens first. */
  uv__handle_start(process);

  /* Cleanup, whether we succeeded or failed. */
 done:
  uv__free(application);
  uv__free(application_path);
  uv__free(arguments);
  uv__free(cwd);
  uv__free(env);
  uv__free(alloc_path);

  if (process->child_stdio_buffer != NULL) {
    /* Clean up child stdio handles. */
    uv__stdio_destroy(process->child_stdio_buffer);
    process->child_stdio_buffer = NULL;
  }

  return uv_translate_sys_error(err);
}
Example #21
0
apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo,
                                fcgid_procnode *procnode)
{
    HANDLE *finish_event, listen_handle;
    SECURITY_ATTRIBUTES SecurityAttributes;
    fcgid_server_conf *sconf;
    apr_procattr_t *proc_attr;
    apr_status_t rv;
    apr_file_t *file;
    const char * const *proc_environ;
    char sock_path[FCGID_PATH_MAX];
    int argc;
    char const * wargv[APACHE_ARG_MAX + 1], *word; /* For wrapper */
    const char *tmp;

    /* Build wrapper args */
    argc = 0;
    tmp = cmdline;
    while (1) {
        word = ap_getword_white(procnode->proc_pool, &tmp);
        if (word == NULL || *word == '\0')
            break;
        if (argc >= APACHE_ARG_MAX)
            break;
        wargv[argc++] = word;
    }
    wargv[argc] = NULL;

    memset(&SecurityAttributes, 0, sizeof(SecurityAttributes));

    /* Prepare finish event */
    finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE));
    *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (*finish_event == NULL
        || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE))
    {
        ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(),
                     procinfo->main_server,
                     "mod_fcgid: can't create mutex for subprocess");
        return APR_ENOLOCK;
    }
    apr_pool_cleanup_register(procnode->proc_pool, finish_event,
                              close_finish_event, apr_pool_cleanup_null);

    /* For proc_kill_gracefully() */
    apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME,
                          NULL, procnode->proc_pool);

    /* Pass the finish event id to subprocess */
    apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME,
                   apr_ltoa(procnode->proc_pool, (long) *finish_event));

    /* Prepare the listen namedpipe file name (no check for truncation) */
    apr_snprintf(sock_path, sizeof sock_path,
                 "\\\\.\\pipe\\fcgidpipe-%lu.%d",
                 GetCurrentProcessId(), g_process_counter++);

    /* Prepare the listen namedpipe handle */
    SecurityAttributes.bInheritHandle = TRUE;
    SecurityAttributes.nLength = sizeof(SecurityAttributes);
    SecurityAttributes.lpSecurityDescriptor = NULL;
    listen_handle = CreateNamedPipe(sock_path,
                                    PIPE_ACCESS_DUPLEX,
                                    PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
                                    PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
                                    8192, 8192, 0, &SecurityAttributes);
    if (listen_handle == INVALID_HANDLE_VALUE) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(),
                     procinfo->main_server,
                     "mod_fcgid: can't create namedpipe for subprocess");
        return APR_ENOSOCKET;
    }
    apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path));
    apr_cpystrn(procnode->executable_path, wargv[0],
                sizeof(procnode->executable_path));

    /* Build environment variables */
    proc_environ = (const char * const *)
                   ap_create_environment(procnode->proc_pool,
                                         procinfo->proc_environ);
    if (!proc_environ) {
        ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(),
                     procinfo->main_server,
                     "mod_fcgid: can't build environment variables");
        return APR_ENOMEM;
    }

    /* Create process now */
    if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool))
               != APR_SUCCESS
        || (rv = apr_procattr_dir_set(proc_attr,
                     ap_make_dirstr_parent(procnode->proc_pool,
                                           wargv[0]))) != APR_SUCCESS
        || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM))
               != APR_SUCCESS
        || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS
        || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE,
                                     APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS
        || (rv = apr_os_file_put(&file, &listen_handle, 0,
                                 procnode->proc_pool)) != APR_SUCCESS
        || (rv = apr_procattr_child_in_set(proc_attr, file, NULL))
               != APR_SUCCESS)
    {
        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server,
                     "mod_fcgid: can't create FastCGI process attribute");
        CloseHandle(listen_handle);
        return APR_ENOPROC;
    }

    /* fork and exec now */
    rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv,
                         proc_environ,
                         proc_attr, procnode->proc_pool);

    /* OK, I created the process, now put it back to idle list */
    CloseHandle(listen_handle);

    if (rv != APR_SUCCESS) {
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server,
                     "mod_fcgid: can't run %s", wargv[0]);
        return rv;
    }

    /* FcgidWin32PreventOrphans feature */
    sconf = ap_get_module_config(procinfo->main_server->module_config,
                                 &fcgid_module);

    if (sconf->hJobObjectForAutoCleanup != NULL) {
        /* Associate cgi process to current process */
        if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup,
                                     procnode->proc_id.hproc) == 0) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(),
                         procinfo->main_server,
                         "mod_fcgid: unable to assign child process to "
                         "job object");
        }
    }

    return APR_SUCCESS;
}
Example #22
0
File: lib.c Project: pfmoore/shimmy
static void
run_child(wchar_t * cmdline)
{
    HANDLE job;
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
    DWORD rc;
    BOOL ok;
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;

#if defined(_WINDOWS)
    // When explorer launches a Windows (GUI) application, it displays
    // the "app starting" (the "pointer + hourglass") cursor for a number
    // of seconds, or until the app does something UI-ish (eg, creating a
    // window, or fetching a message).  As this launcher doesn't do this
    // directly, that cursor remains even after the child process does these
    // things.  We avoid that by doing a simple post+get message.
    // See http://bugs.python.org/issue17290 and
    // https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running
    MSG msg;

    PostMessage(0, 0, 0, 0);
    GetMessage(&msg, 0, 0, 0);
#endif

    job = CreateJobObject(NULL, NULL);
    ok = QueryInformationJobObject(job, JobObjectExtendedLimitInformation,
                                  &info, sizeof(info), &rc);
    if (!ok || (rc != sizeof(info)) || !job)
        error(RC_CREATE_PROCESS, L"Job information querying failed");
    info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
                                             JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    ok = SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info,
                                 sizeof(info));
    if (!ok)
        error(RC_CREATE_PROCESS, L"Job information setting failed");
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    ok = safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stdin duplication failed");
    ok = safe_duplicate_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stdout duplication failed");
    ok = safe_duplicate_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stderr duplication failed");

    ok = SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
    if (!ok)
        error(RC_CREATE_PROCESS, L"control handler setting failed");

    si.dwFlags = STARTF_USESTDHANDLES;
    ok = CreateProcessW(NULL, cmdline, NULL, NULL, TRUE,
                        0, NULL, NULL, &si, &pi);
    if (!ok)
        error(RC_CREATE_PROCESS, L"Unable to create process using '%ls'", cmdline);
    AssignProcessToJobObject(job, pi.hProcess);
    CloseHandle(pi.hThread);
    WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);
    ok = GetExitCodeProcess(pi.hProcess, &rc);
    if (!ok)
        error(RC_CREATE_PROCESS, L"Failed to get exit code of process");
    exit(rc);
}
Example #23
0
    bool LaunchProcess(const string16& cmdline,
        const LaunchOptions& options,
        ProcessHandle* process_handle)
    {
        STARTUPINFO startup_info = {};
        startup_info.cb = sizeof(startup_info);
        if(options.empty_desktop_name)
        {
            startup_info.lpDesktop = L"";
        }
        startup_info.dwFlags = STARTF_USESHOWWINDOW;
        startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
        PROCESS_INFORMATION process_info;

        DWORD flags = 0;

        if(options.job_handle)
        {
            flags |= CREATE_SUSPENDED;

            // If this code is run under a debugger, the launched process is
            // automatically associated with a job object created by the debugger.
            // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
            flags |= CREATE_BREAKAWAY_FROM_JOB;
        }

        if(options.as_user)
        {
            flags |= CREATE_UNICODE_ENVIRONMENT;
            void* enviroment_block = NULL;

            if(!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE))
            {
                return false;
            }

            BOOL launched = CreateProcessAsUser(options.as_user, NULL,
                const_cast<wchar_t*>(cmdline.c_str()),
                NULL, NULL, options.inherit_handles, flags,
                enviroment_block, NULL, &startup_info,
                &process_info);
            DestroyEnvironmentBlock(enviroment_block);
            if(!launched)
            {
                return false;
            }
        }
        else
        {
            if(!CreateProcess(NULL,
                const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
                options.inherit_handles, flags, NULL, NULL,
                &startup_info, &process_info))
            {
                return false;
            }
        }

        if(options.job_handle)
        {
            if(0 == AssignProcessToJobObject(options.job_handle, process_info.hProcess))
            {
                LOG(ERROR) << "Could not AssignProcessToObject.";
                KillProcess(process_info.hProcess, kProcessKilledExitCode, true);
                return false;
            }

            ResumeThread(process_info.hThread);
        }

        // Handles must be closed or they will leak.
        CloseHandle(process_info.hThread);

        if(options.wait)
        {
            WaitForSingleObject(process_info.hProcess, INFINITE);
        }

        // If the caller wants the process handle, we won't close it.
        if(process_handle)
        {
            *process_handle = process_info.hProcess;
        }
        else
        {
            CloseHandle(process_info.hProcess);
        }
        return true;
    }
Example #24
0
bool AI::init(int engine)
{
	bool engine_started = false;
	bool b64bit = isOS64Bit();
	bool jobSuccess = false;

	m_engine = engine;
	memset(m_engine_path, 0, sizeof(m_engine_path));

	// set up the security attributes
	m_sa.bInheritHandle = true;
	m_sa.lpSecurityDescriptor = NULL;
	m_sa.nLength = sizeof(SECURITY_ATTRIBUTES);

	// setup job to kill the child process when calling process terminates
	m_hJob = CreateJobObject(NULL, NULL);
	if(m_hJob != NULL){
		m_jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

		jobSuccess = SetInformationJobObject(m_hJob, JobObjectExtendedLimitInformation, &m_jeli, sizeof(m_jeli));
	}

	// open a pipe to the AI engine
	if(!CreatePipe(&m_child_stdin, &m_hWrite, &m_sa, 0)){
		throw std::runtime_error("CreatePipe - stdin");
		return false;
	}

	if(!CreatePipe(&m_hRead, &m_child_stdout, &m_sa, 0)){
		throw std::runtime_error("CreatePipe - stdout");
		cleanup();
		return false;
	}

	// prepare to launch the process
	GetStartupInfo(&m_si);
	m_si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	m_si.wShowWindow = SW_HIDE;
	m_si.hStdOutput = m_child_stdout;
	m_si.hStdError = m_child_stdout;
	m_si.hStdInput = m_child_stdin;

	for(;!engine_started;){
		switch(m_engine){
			case ENGINE_HOUDINI:
				if(b64bit){
					strcpy(m_engine_path, "Data/Engines/Houdini_x64.exe");
					checkProcess("Houdini_x64.exe");
				}
				else{
					strcpy(m_engine_path, "Data/Engines/Houdini_x86.exe");
					checkProcess("Houdini_x86.exe");
				}
				break;

			case ENGINE_STOCKFISH:
				if(b64bit){
					strcpy(m_engine_path, "Data/Engines/Stockfish_x64.exe");
					checkProcess("Stockfish_x64.exe");
				}
				else{
					strcpy(m_engine_path, "Data/Engines/Stockfish_x86.exe");
					checkProcess("Stockfish_x86.exe");
				}
				break;

			case ENGINE_CRITTER:
				if(b64bit){
					strcpy(m_engine_path, "Data/Engines/Critter_x64.exe");
					checkProcess("Critter_x64.exe");
				}
				else{
					strcpy(m_engine_path, "Data/Engines/Critter_x86.exe");
					checkProcess("Critter_x86.exe");
				}
				break;

			case ENGINE_CUSTOM:
				strcpy(m_engine_path, "Data/Engines/Custom.exe");
				break;

			default:
				throw std::runtime_error("No valid engine found");
				cleanup();
				return false;
		}

		// attempt to launch the process
		engine_started =
			CreateProcess(m_engine_path, 
						  NULL,
						  NULL,
						  NULL,
						  TRUE,
						  0,
						  NULL,
						  NULL,
						  &m_si,
						  &m_pi);

		if(!engine_started){
			if(engine > 0)
				engine = 0;
			else
				++engine;

			continue;
		}

		break;
	}

	// assign the job to the process
	if(jobSuccess){
		jobSuccess = AssignProcessToJobObject(m_hJob, m_pi.hProcess);
	}

	// change states
	//m_active = true;
	//m_thinking = true;
	
	// set process priority to below normal to prevent destruction of the CPU
	SetPriorityClass(m_pi.hProcess, BELOW_NORMAL_PRIORITY_CLASS);

	// set AI to active
	if(engine_started){
		m_active = true;

		// start the state machine thread
		(void)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&InitThread, this, 0, 0);
	}

	return true;
}
Example #25
0
int main(int argc, char** argv) {
	enum {
		 envbufsize = 1024*32
		,exebufsize = 1024
		,cmdbufsize = envbufsize
	};

	char *envbuf, *sep, *resbuf, *cmdbuf;
	DWORD len, exitCode;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	DIE_IF_FALSE(
		(envbuf = malloc(envbufsize))
	);
	DIE_IF_FALSE(
		(cmdbuf = malloc(cmdbufsize))
	);
	*cmdbuf = 0;

	DIE_IF_FALSE(
		GetEnvironmentVariable("PATH", envbuf, envbufsize)
	);
    dbg_printf("env: %s\n", envbuf);

	DIE_IF_FALSE(
		GetModuleFileName(0, cmdbuf, exebufsize)
	);
    dbg_printf("curdir: %s\n", cmdbuf);

	DIE_IF_FALSE(
		(sep = strrchr(cmdbuf, '\\'))
	);
	*(sep+1) = 0;
	strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR);
	dbg_printf("sep: %s\n", cmdbuf);

	len = strlen(envbuf)+strlen(cmdbuf)
		+1  /* for envronment separator */
		+1; /* for zero-terminator */
	
	DIE_IF_FALSE(
		(resbuf = malloc(len))
	);

	DIE_IF_FALSE(
		(snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0)
	);
    dbg_printf("PATH: %s\n", resbuf);

	DIE_IF_FALSE(
		SetEnvironmentVariable("PATH", resbuf)
	);

	*(sep+1) = 0;
	strcat(cmdbuf, PYTHONHOME_REL_DIR);
	dbg_printf("PYTHONHOME: %s\n", cmdbuf);
	DIE_IF_FALSE(
		SetEnvironmentVariable("PYTHONHOME", cmdbuf)
	);
	
	*(sep+1) = 0;
	strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" ");
	
	if ( argc > 1 ) {
		for ( ++argv; *argv; ++argv ) {
			len = strlen(cmdbuf);
			snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv);
		}
	}
	dbg_printf("cmd: %s\n", cmdbuf);

	HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/);
	if ( ghJob == NULL ) {
		dbg_printf("Could not create job object\n");
	} else {
		JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
		// Configure all child processes associated with the job to terminate when the last handle to the job is closed
		jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
		if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) {
			dbg_printf("Could not SetInformationJobObject\n");
		}
	}

	memset(&si, 0, sizeof(si));
	si.cb = sizeof(si);
	si.dwFlags |= STARTF_USESTDHANDLES;
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

	memset(&pi, 0, sizeof(pi));

	DIE_IF_FALSE(
		CreateProcess(
			 0			// exe name
			,cmdbuf	// command line
			,0			// process security attributes
			,0			// primary thread security attributes
			,TRUE		// handles are inherited
			,0			// creation flags
			,0			// use parent's environment
			,0			// use parent's current directory
			,&si		// STARTUPINFO pointer
			,&pi		// receives PROCESS_INFORMATION
		)
	);

	if ( ghJob != NULL && AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) {
		dbg_printf("Could not AssignProcessToObject\n");
	}

	// Do not handle Ctrl-C in the wrapper
	SetConsoleCtrlHandler(NULL, TRUE);

	WaitForSingleObject(pi.hProcess, INFINITE);
	
	DIE_IF_FALSE(
		GetExitCodeProcess(pi.hProcess, &exitCode)
	);

	if ( ghJob != NULL )
		CloseHandle(ghJob);
	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );

	free(envbuf);
	free(resbuf);
	free(cmdbuf);
	
	dbg_printf("exiting with exitCode %d", exitCode);

	return exitCode;
}
Example #26
0
/******************************************************************************
 *                                                                            *
 * Function: zbx_waitpid                                                      *
 *                                                                            *
 * Purpose: this function waits for process to change state                   *
 *                                                                            *
 * Parameters: pid     - [IN] child process PID                               *
 *                                                                            *
 * Return value: on success, PID is returned. On error,                       *
 *               -1 is returned, and errno is set appropriately               *
 *                                                                            *
 * Author: Alexander Vladishev                                                *
 *                                                                            *
 ******************************************************************************/
static int	zbx_waitpid(pid_t pid)
{
	const char	*__function_name = "zbx_waitpid";
	int		rc, status;

	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);

	do
	{
#ifdef WCONTINUED
		static int	wcontinued = WCONTINUED;
retry:
		if (-1 == (rc = waitpid(pid, &status, WUNTRACED | wcontinued)))
		{
			if (EINVAL == errno && 0 != wcontinued)
			{
				wcontinued = 0;
				goto retry;
			}
#else
		if (-1 == (rc = waitpid(pid, &status, WUNTRACED)))
		{
#endif
			zabbix_log(LOG_LEVEL_DEBUG, "%s() waitpid failure: %s", __function_name, zbx_strerror(errno));
			goto exit;
		}

		if (WIFEXITED(status))
			zabbix_log(LOG_LEVEL_DEBUG, "%s() exited, status:%d", __function_name, WEXITSTATUS(status));
		else if (WIFSIGNALED(status))
			zabbix_log(LOG_LEVEL_DEBUG, "%s() killed by signal %d", __function_name, WTERMSIG(status));
		else if (WIFSTOPPED(status))
			zabbix_log(LOG_LEVEL_DEBUG, "%s() stopped by signal %d", __function_name, WSTOPSIG(status));
#ifdef WIFCONTINUED
		else if (WIFCONTINUED(status))
			zabbix_log(LOG_LEVEL_DEBUG, "%s() continued", __function_name);
#endif
	}
	while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit:
	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc);

	return rc;
}

#endif	/* _WINDOWS */

/******************************************************************************
 *                                                                            *
 * Function: zbx_execute                                                      *
 *                                                                            *
 * Purpose: this function executes a script and returns result from stdout    *
 *                                                                            *
 * Parameters: command       - [IN] command for execution                     *
 *             buffer        - [OUT] buffer for output, if NULL - ignored     *
 *             error         - [OUT] error string if function fails           *
 *             max_error_len - [IN] length of error buffer                    *
 *                                                                            *
 * Return value: SUCCEED if processed successfully, TIMEOUT_ERROR if          *
 *               timeout occurred or FAIL otherwise                           *
 *                                                                            *
 * Author: Alexander Vladishev                                                *
 *                                                                            *
 ******************************************************************************/
int	zbx_execute(const char *command, char **buffer, char *error, size_t max_error_len, int timeout)
{
	size_t			buf_size = PIPE_BUFFER_SIZE, offset = 0;
	int			ret = FAIL;
#ifdef _WINDOWS
	STARTUPINFO		si;
	PROCESS_INFORMATION	pi;
	SECURITY_ATTRIBUTES	sa;
	HANDLE			job = NULL, hWrite = NULL, hRead = NULL;
	char			*cmd = NULL;
	wchar_t			*wcmd = NULL;
	struct _timeb		start_time, current_time;
#else
	pid_t			pid;
	int			fd;
#endif

	*error = '\0';

	if (NULL != buffer)
	{
		*buffer = zbx_realloc(*buffer, buf_size);
		**buffer = '\0';
	}

#ifdef _WINDOWS

	/* set the bInheritHandle flag so pipe handles are inherited */
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	/* create a pipe for the child process's STDOUT */
	if (0 == CreatePipe(&hRead, &hWrite, &sa, 0))
	{
		zbx_snprintf(error, max_error_len, "unable to create a pipe: %s", strerror_from_system(GetLastError()));
		goto close;
	}

	/* create a new job where the script will be executed */
	if (0 == (job = CreateJobObject(&sa, NULL)))
	{
		zbx_snprintf(error, max_error_len, "unable to create a job: %s", strerror_from_system(GetLastError()));
		goto close;
	}

	/* fill in process startup info structure */
	memset(&si, 0, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESTDHANDLES;
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = hWrite;
	si.hStdError = hWrite;

	/* use cmd command to support scripts */
	cmd = zbx_dsprintf(cmd, "cmd /C \"%s\"", command);
	wcmd = zbx_utf8_to_unicode(cmd);

	/* create the new process */
	if (0 == CreateProcess(NULL, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
	{
		zbx_snprintf(error, max_error_len, "unable to create process [%s]: %s",
				cmd, strerror_from_system(GetLastError()));
		goto close;
	}

	CloseHandle(hWrite);
	hWrite = NULL;

	/* assign the new process to the created job */
	if (0 == AssignProcessToJobObject(job, pi.hProcess))
	{
		zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s",
				cmd, strerror_from_system(GetLastError()));
		if (0 == TerminateProcess(pi.hProcess, 0))
		{
			zabbix_log(LOG_LEVEL_ERR, "failed to terminate [%s]: %s",
					cmd, strerror_from_system(GetLastError()));
		}
	}
	else if (-1 == ResumeThread(pi.hThread))
	{
		zbx_snprintf(error, max_error_len, "unable to assign process [%s] to a job: %s",
				cmd, strerror_from_system(GetLastError()));
	}
	else
		ret = SUCCEED;

	if (FAIL == ret)
		goto close;

	_ftime(&start_time);
	timeout *= 1000;

	ret = zbx_read_from_pipe(hRead, buffer, &buf_size, &offset, timeout);

	if (TIMEOUT_ERROR != ret)
	{
		_ftime(&current_time);
		if (0 < (timeout -= zbx_get_timediff_ms(&start_time, &current_time)) &&
				WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, timeout))
		{
			ret = TIMEOUT_ERROR;
		}
	}

	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
close:
	if (NULL != job)
	{
		/* terminate the child process and it's childs */
		if (0 == TerminateJobObject(job, 0))
			zabbix_log(LOG_LEVEL_ERR, "failed to terminate job [%s]: %s", cmd, strerror_from_system(GetLastError()));
		CloseHandle(job);
	}

	if (NULL != hWrite)
		CloseHandle(hWrite);

	if (NULL != hRead)
		CloseHandle(hRead);

	zbx_free(cmd);
	zbx_free(wcmd);

#else	/* not _WINDOWS */

	alarm(timeout);

	if (-1 != (fd = zbx_popen(&pid, command)))
	{
		int	rc;
		char	tmp_buf[PIPE_BUFFER_SIZE];

		while (0 < (rc = read(fd, tmp_buf, sizeof(tmp_buf) - 1)) && MAX_EXECUTE_OUTPUT_LEN > offset + rc)
		{
			if (NULL != buffer)
			{
				tmp_buf[rc] = '\0';
				zbx_strcpy_alloc(buffer, &buf_size, &offset, tmp_buf);
			}
		}

		close(fd);

		if (-1 == rc || -1 == zbx_waitpid(pid))
		{
			if (EINTR == errno)
				ret = TIMEOUT_ERROR;
			else
				zbx_snprintf(error, max_error_len, "zbx_waitpid() failed: %s", zbx_strerror(errno));

			/* kill the whole process group, pid must be the leader */
			if (-1 == kill(-pid, SIGTERM))
				zabbix_log(LOG_LEVEL_ERR, "failed to kill [%s]: %s", command, zbx_strerror(errno));

			zbx_waitpid(pid);
		}
		else if (MAX_EXECUTE_OUTPUT_LEN <= offset + rc)
		{
			zabbix_log(LOG_LEVEL_ERR, "command output exceeded limit of %d KB",
					MAX_EXECUTE_OUTPUT_LEN / ZBX_KIBIBYTE);
		}
		else
			ret = SUCCEED;
	}
	else
		zbx_strlcpy(error, zbx_strerror(errno), max_error_len);

	alarm(0);

#endif	/* _WINDOWS */

	if (TIMEOUT_ERROR == ret)
		zbx_strlcpy(error, "Timeout while executing a shell script.", max_error_len);
	else if ('\0' != *error)
		zabbix_log(LOG_LEVEL_WARNING, "%s", error);

	if (SUCCEED != ret && NULL != buffer)
		zbx_free(*buffer);

	return ret;
}
Example #27
0
void
CPCD::Process::do_exec() {
  unsigned i;

#ifdef _WIN32
  Vector<BaseString> saved;
  char *cwd = 0;
  save_environment(m_env.c_str(), saved);
#endif

  setup_environment(m_env.c_str());

  char **argv = BaseString::argify(m_path.c_str(), m_args.c_str());

  if(strlen(m_cwd.c_str()) > 0) {
#ifdef _WIN32
    cwd = getcwd(0, 0);
    if(!cwd)
    {
      logger.critical("Couldn't getcwd before spawn");
    }
#endif
    int err = chdir(m_cwd.c_str());
    if(err == -1) {
      BaseString err;
      logger.error("%s: %s\n", m_cwd.c_str(), strerror(errno));
      _exit(1);
    }
  }
#ifndef _WIN32
  Vector<BaseString> ulimit;
  m_ulimit.split(ulimit);
  for(i = 0; i<ulimit.size(); i++){
    if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){
      _exit(1);
    }
  }
#endif

  const char *nul = IF_WIN("nul:", "/dev/null");
  int fdnull = open(nul, O_RDWR, 0);
  if(fdnull == -1) {
    logger.error("Cannot open `%s': %s\n", nul, strerror(errno));
    _exit(1);
  }
  
  BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr };
  int fds[3];
#ifdef _WIN32
  int std_dups[3];
#endif
  for (i = 0; i < 3; i++) {
#ifdef _WIN32
    std_dups[i] = dup(i);
#endif
    if (redirects[i]->empty()) {
#ifndef DEBUG
      dup2(fdnull, i);
#endif
      continue;
    }
    
    if((* redirects[i]) == "2>&1" && i == 2){
      dup2(fds[1], 2);
      continue;
    }
    
    /**
     * Make file
     */
    int flags = 0;
    int mode = S_IRUSR | S_IWUSR ;
    if(i == 0){
      flags |= O_RDONLY;
    } else {
      flags |= O_WRONLY | O_CREAT | O_APPEND;
    }
    int f = fds[i]= open(redirects[i]->c_str(), flags, mode);
    if(f == -1){
      logger.error("Cannot redirect %u to/from '%s' : %s\n", i,
		   redirects[i]->c_str(), strerror(errno));
      _exit(1);
    }
    dup2(f, i);
#ifdef _WIN32
    close(f);
#endif
  }

#ifndef _WIN32
  /* Close all filedescriptors */
  for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++)
    close(i);

  execv(m_path.c_str(), argv);
  /* XXX If we reach this point, an error has occurred, but it's kind of hard
   * to report it, because we've closed all files... So we should probably
   * create a new logger here */
  logger.error("Exec failed: %s\n", strerror(errno));
  /* NOTREACHED */
#else

  // Get full path to cygwins shell
  FILE *fpipe = _popen("sh -c 'cygpath -w `which sh`'", "rt");
  char buf[MAX_PATH];

  require(fgets(buf, MAX_PATH - 1, fpipe));
  fclose(fpipe);

  BaseString sh;
  sh.assign(buf);
  sh.trim("\n");
  sh.append(".exe");

  BaseString shcmd;
  shcmd.assfmt("%s -c '%s %s'", sh.c_str(), m_path.c_str(), m_args.c_str());

  PROCESS_INFORMATION pi = {0};
  STARTUPINFO si = {sizeof(STARTUPINFO), 0};

  si.dwFlags   |=  STARTF_USESTDHANDLES;
  si.hStdInput  = (HANDLE)_get_osfhandle(0);
  si.hStdOutput = (HANDLE)_get_osfhandle(1);
  si.hStdError  = (HANDLE)_get_osfhandle(2);

  if(!CreateProcessA(sh.c_str(),
                     (LPSTR)shcmd.c_str(),
                     NULL,
                     NULL,
                     TRUE,
                     CREATE_SUSPENDED, // Resumed after assigned to Job
                     NULL,
                     NULL,
                     &si,
                     &pi))
  {
    char* message;
    DWORD err = GetLastError();

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                  FORMAT_MESSAGE_FROM_SYSTEM |
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  err,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&message,
                  0, NULL );

    logger.error("CreateProcess failed, error: %d, message: '%s'",
                 err, message);
    LocalFree(message);

  }

  HANDLE proc = pi.hProcess;
  require(proc);

  // Job control
  require(m_job = CreateJobObject(0, 0));
  require(AssignProcessToJobObject(m_job, proc));

  // Resum process after it has been added to Job
  ResumeThread(pi.hThread);
  CloseHandle(pi.hThread);


  // go back up to original cwd
  if(chdir(cwd))
  {
    logger.critical("Couldn't go back to saved cwd after spawn()");
    logger.critical("errno: %d, strerror: %s", errno, strerror(errno));
  }
  free(cwd);

  // get back to original std i/o
  for(i = 0; i < 3; i++) {
    dup2(std_dups[i], i);
    close(std_dups[i]);
  }

  for (i = 0; i < saved.size(); i++) {
    putenv(saved[i].c_str());
  }

  logger.debug("'%s' has been started", shcmd.c_str());

  DWORD exitcode;
  BOOL result = GetExitCodeProcess(proc, &exitcode);
  //maybe a short running process
  if (result && exitcode != 259) {
    m_status = STOPPED;
    logger.warning("Process terminated early");
  }

  int pid = GetProcessId(proc);
  if (!pid)
    logger.critical("GetProcessId failed, error: %d!", GetLastError());

  logger.debug("new pid %d", pid);

  CloseHandle(proc);
  m_status = RUNNING;
  writePid(pid);
#endif

  close(fdnull);
}
Example #28
0
/* Uninstall NSIS */
MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall )
{
	DWORD rv = ERROR_SUCCESS;
	// lookup the NSISUNINSTALL property value
	LPTSTR cNsisUninstall = _T("NSISUNINSTALL");
	HANDLE hIo = NULL;
	DWORD dwSize = 0;
	LPTSTR strPathUninst = NULL;
	HANDLE hJob = NULL;
	STARTUPINFO sInfo;
	PROCESS_INFORMATION pInfo;

	pInfo.hProcess = NULL;
	pInfo.hThread = NULL;

	rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize );
	if(rv != ERROR_MORE_DATA) goto _cleanup;

	strPathUninst = new TCHAR[ ++dwSize ];

	rv = MsiGetProperty( hInstall, cNsisUninstall, strPathUninst, &dwSize );
	if(rv != ERROR_SUCCESS) goto _cleanup;

	// Create a process for the uninstaller
	sInfo.cb = sizeof(sInfo);
	sInfo.lpReserved = NULL;
	sInfo.lpDesktop = _T("");
	sInfo.lpTitle = _T("Foo");
	sInfo.dwX = 0;
	sInfo.dwY = 0;
	sInfo.dwXSize = 0;
	sInfo.dwYSize = 0;
	sInfo.dwXCountChars = 0;
	sInfo.dwYCountChars = 0;
	sInfo.dwFillAttribute = 0;
	sInfo.dwFlags = 0;
	sInfo.wShowWindow = 0;
	sInfo.cbReserved2 = 0;
	sInfo.lpReserved2 = 0;
	sInfo.hStdInput = 0;
	sInfo.hStdOutput = 0;
	sInfo.hStdError = 0;

	if(!CreateProcess( 
		strPathUninst,
		_T("Uninstall /S"),
		NULL,
		NULL,
		FALSE,
		CREATE_SUSPENDED,
		NULL,
		NULL,
		&sInfo,
		&pInfo)) {
			pInfo.hProcess = NULL;
			pInfo.hThread = NULL;
			rv = 40;
			goto _cleanup;
		};

	// Create a job object to contain the NSIS uninstall process tree

	JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp;

	acp.CompletionKey = 0;

	hJob = CreateJobObject(NULL, _T("NSISUninstallObject"));
	if(!hJob) {
		rv = 41;
		goto _cleanup;
	}

	hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
	if(!hIo) {
		rv = 42;
		goto _cleanup;
	}

	acp.CompletionPort = hIo;

	SetInformationJobObject( hJob, JobObjectAssociateCompletionPortInformation, &acp, sizeof(acp));

	AssignProcessToJobObject( hJob, pInfo.hProcess );

	ResumeThread( pInfo.hThread );

	DWORD a,b,c;
	for(;;) {
		if(!GetQueuedCompletionStatus(hIo, &a, (PULONG_PTR) &b, (LPOVERLAPPED *) &c, INFINITE)) {
			Sleep(1000);
			continue;
		}
		if(a == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
			break;
		}
	}

	rv = ERROR_SUCCESS;
    
_cleanup:
	if(hIo) CloseHandle(hIo);
	if(pInfo.hProcess)	CloseHandle( pInfo.hProcess );
	if(pInfo.hThread) 	CloseHandle( pInfo.hThread );
	if(hJob) CloseHandle(hJob);
	if(strPathUninst) delete[] strPathUninst;

	if(rv != ERROR_SUCCESS) {
        ShowMsiError( hInstall, ERR_NSS_FAILED, rv );
	}
	return rv;
}
Example #29
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);
}
Example #30
0
int uv_spawn_jx(uv_loop_t* loop, uv_process_t* process,
                uv_process_options_t* options) {
#ifdef WINONECORE
  error_console("Error: WindowsOneCore does not support spawning a process.\n");
  return -1; // not supported
#else
  int i;
  uv_err_t err = uv_ok_;
  WCHAR* path = NULL;
  BOOL result;
  WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
         *env = NULL, *cwd = NULL;
  STARTUPINFOW startup;
  PROCESS_INFORMATION info;
  DWORD process_flags;

  if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
    uv__set_artificial_error(loop, UV_ENOTSUP);
    return -1;
  }

  if (options->file == NULL || options->args == NULL) {
    uv__set_artificial_error(loop, UV_EINVAL);
    return -1;
  }

  assert(options->file != NULL);
  assert(!(options->flags &
           ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID |
             UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));

  uv_process_init(loop, process);
  process->exit_cb = options->exit_cb;

  err = uv_utf8_to_utf16_alloc(options->file, &application);
  if (err.code != UV_OK) goto done;

  err = make_program_args(
      options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
      &arguments);
  if (err.code != UV_OK) goto done;

  if (options->env) {
    err = make_program_env(options->env, &env);
    if (err.code != UV_OK) goto done;
  }

  if (options->cwd) {
    /* Explicit cwd */
    err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
    if (err.code != UV_OK) goto done;

  } else {
    /* Inherit cwd */
    DWORD cwd_len, r;

    cwd_len = GetCurrentDirectoryW(0, NULL);
    if (!cwd_len) {
      err = uv__new_sys_error(GetLastError());
      goto done;
    }

    cwd = (WCHAR*)malloc(cwd_len * sizeof(WCHAR));
    if (cwd == NULL) {
      err = uv__new_artificial_error(UV_ENOMEM);
      goto done;
    }

    r = GetCurrentDirectoryW(cwd_len, cwd);
    if (r == 0 || r >= cwd_len) {
      err = uv__new_sys_error(GetLastError());
      goto done;
    }
  }

  /* Get PATH environment variable. */
  {
    DWORD path_len, r;

    path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
    if (path_len == 0) {
      err = uv__new_sys_error(GetLastError());
      goto done;
    }

    path = (WCHAR*)malloc(path_len * sizeof(WCHAR));
    if (path == NULL) {
      err = uv__new_artificial_error(UV_ENOMEM);
      goto done;
    }

    r = GetEnvironmentVariableW(L"PATH", path, path_len);
    if (r == 0 || r >= path_len) {
      err = uv__new_sys_error(GetLastError());
      goto done;
    }
  }

  application_path = search_path(application, cwd, path);
  if (application_path == NULL) {
    /* Not found. */
    err = uv__new_artificial_error(UV_ENOENT);
    goto done;
  }

  err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
  if (err.code != UV_OK) goto done;

  startup.cb = sizeof(startup);
  startup.lpReserved = NULL;
  startup.lpDesktop = NULL;
  startup.lpTitle = NULL;
  startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

  startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
  startup.lpReserved2 = (BYTE*)process->child_stdio_buffer;

  startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
  startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
  startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);

  if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
    /* Use SW_HIDE to avoid any potential process window. */
    startup.wShowWindow = SW_HIDE;
  } else {
    startup.wShowWindow = SW_SHOWDEFAULT;
  }

  process_flags = CREATE_UNICODE_ENVIRONMENT;

  if (options->flags & UV_PROCESS_DETACHED) {
    /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
     * means that libuv might not let you create a fully deamonized process
     * when run under job control. However the type of job control that libuv
     * itself creates doesn't trickle down to subprocesses so they can still
     * daemonize.
     *
     * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
     * CreateProcess call fail if we're under job control that doesn't allow
     * breakaway.
     */
    process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
  }

  if (CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags,
                     env, cwd, &startup, &info)) {
    /* Spawn succeeded */
    process->process_handle = info.hProcess;
    process->pid = info.dwProcessId;

    /* If the process isn't spawned as detached, assign to the global job */
    /* object so windows will kill it when the parent process dies. */
    if (!(options->flags & UV_PROCESS_DETACHED)) {
      uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);

      if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
        /* AssignProcessToJobObject might fail if this process is under job
         * control and the job doesn't have the
         * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
         * that doesn't support nested jobs.
         *
         * When that happens we just swallow the error and continue without
         * establishing a kill-child-on-parent-exit relationship, otherwise
         * there would be no way for libuv applications run under job control
         * to spawn processes at all.
         */
        DWORD err = GetLastError();
        if (err != ERROR_ACCESS_DENIED)
          uv_fatal_error(err, "AssignProcessToJobObject");
      }
    }

    /* Set IPC pid to all IPC pipes. */
    for (i = 0; i < options->stdio_count; i++) {
      const uv_stdio_container_t* fdopt = &options->stdio[i];
      if (fdopt->flags & UV_CREATE_PIPE &&
          fdopt->data.stream->type == UV_NAMED_PIPE &&
          ((uv_pipe_t*)fdopt->data.stream)->ipc) {
        ((uv_pipe_t*)fdopt->data.stream)->ipc_pid = info.dwProcessId;
      }
    }

    /* Setup notifications for when the child process exits. */
    result = RegisterWaitForSingleObject(
        &process->wait_handle, process->process_handle, exit_wait_callback,
        (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
    if (!result) {
      uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
    }

    CloseHandle(info.hThread);

  } else {
    /* CreateProcessW failed. */
    err = uv__new_sys_error(GetLastError());
  }

done:
  JX_FREE(process, application);
  JX_FREE(process, application_path);
  JX_FREE(process, arguments);
  JX_FREE(process, cwd);
  JX_FREE(process, env);
  JX_FREE(process, path);

  process->spawn_error = err;

  if (process->child_stdio_buffer != NULL) {
    /* Clean up child stdio handles. */
    uv__stdio_destroy(process->child_stdio_buffer);
    process->child_stdio_buffer = NULL;
  }

  /* Make the handle active. It will remain active until the exit callback */
  /* is made or the handle is closed, whichever happens first. */
  uv__handle_start(process);

  /* If an error happened, queue the exit req. */
  if (err.code != UV_OK) {
    process->exit_cb_pending = 1;
    uv_insert_pending_req(loop, (uv_req_t*)&process->exit_req);
  }

  return 0;
#endif
}