process-win.cpp revision 245f263e3e0dfdf44e37fb698ff1478be433eeeb
/* $Id$ */
/** @file
* IPRT - Process, Windows.
*/
/*
* Copyright (C) 2006-2010 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_PROCESS
#include <Userenv.h>
#include <Windows.h>
#include <process.h>
#include <errno.h>
#include <iprt/critsect.h>
#include <iprt/initterm.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Init once structure. */
/** Critical section protecting the process array. */
static RTCRITSECT g_CritSect;
/** The number of processes in the array. */
static uint32_t g_cProcesses;
/** The current allocation size. */
static uint32_t g_cProcessesAlloc;
/** Array containing the live or non-reaped child processes. */
static struct RTPROCWINENTRY
{
/** The process ID. */
/** The process handle. */
} *g_paProcesses;
/**
* Clean up the globals.
*
* @param enmReason Ignored.
* @param iStatus Ignored.
* @param pvUser Ignored.
*/
{
size_t i = g_cProcesses;
while (i-- > 0)
{
}
g_cProcesses = 0;
g_cProcessesAlloc = 0;
}
/**
* Initialize the globals.
*
* @returns IPRT status code.
* @param pvUser1 Ignored.
* @param pvUser2 Ignored.
*/
{
g_cProcesses = 0;
g_cProcessesAlloc = 0;
if (RT_SUCCESS(rc))
{
/** @todo init once, terminate once - this is a generic thing which should
* have some kind of static and simpler setup! */
if (RT_SUCCESS(rc))
return rc;
}
return rc;
}
/**
* Gets the process handle for a process from g_paProcesses.
*
* @returns Process handle if found, NULL if not.
* @param pid The process to remove (pid).
*/
{
uint32_t i = g_cProcesses;
while (i-- > 0)
{
break;
}
return hProcess;
}
/**
* Removes a process from g_paProcesses.
*
* @param pid The process to remove (pid).
*/
{
uint32_t i = g_cProcesses;
while (i-- > 0)
{
g_cProcesses--;
if (cToMove)
break;
}
}
/**
* Adds a process to g_paProcesses.
*
* @returns IPRT status code.
* @param pid The process id.
* @param hProcess The process handle.
*/
{
uint32_t i = g_cProcesses;
if (i >= g_cProcessesAlloc)
{
if (RT_UNLIKELY(!pvNew))
{
return VERR_NO_MEMORY;
}
g_cProcessesAlloc = i + 16;
}
g_cProcesses = i + 1;
return VINF_SUCCESS;
}
RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)
{
pProcess);
}
static int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
{
/*
* The following rights are needed in order to use LogonUserW and
* CreateProcessAsUserW, so the local policy has to be modified to:
* - SE_TCB_NAME = Act as part of the operating system
* - SE_INCREASE_QUOTA_NAME
*
* We may fail here with ERROR_PRIVILEGE_NOT_HELD.
*/
int rc;
NULL, /* lpDomain */
&hToken);
if (fRc)
{
NULL, /* pProcessAttributes */
NULL, /* pThreadAttributes */
TRUE, /* fInheritHandles */
CREATE_UNICODE_ENVIRONMENT, /* dwCreationFlags */
NULL, /* pCurrentDirectory */
if (!fRc)
dwErr = GetLastError();
}
else
dwErr = GetLastError();
#ifndef IPRT_TARGET_NT4
/*
* If we don't hold enough priviledges to spawn a new process with
* different credentials we have to use CreateProcessWithLogonW here. This
* API is W2K+ and uses a system service for spawning the process.
*/
/** @todo Use fFlags to either use this feature or just fail. */
if (dwErr == ERROR_PRIVILEGE_NOT_HELD)
{
if (RT_SUCCESS(rc))
{
/* This may fail on too old (NT4) platforms. */
if (RT_SUCCESS(rc))
{
NULL, /* lpDomain*/
1 /*LOGON_WITH_PROFILE*/, /* dwLogonFlags */
CREATE_UNICODE_ENVIRONMENT, /* dwCreationFlags */
NULL, /* pCurrentDirectory */
if (fRc)
else
dwErr = GetLastError();
}
}
}
#endif
else
rc = VINF_SUCCESS;
return rc;
}
RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
{
/*
* Input validation
*/
/** @todo search the PATH (add flag for this). */
/*
* Initialize the globals.
*/
/*
* Get the file descriptors for the handles we've been passed.
*
* It seems there is no point in trying to convince a child process's CRT
* that any of the standard file handles is non-TEXT. So, we don't...
*/
#if 1 /* The CRT should keep the standard handles up to date. */
#else
#endif
for (int i = 0; i < 3; i++)
{
if (paHandles[i])
{
{
case RTHANDLETYPE_FILE:
break;
case RTHANDLETYPE_PIPE:
break;
case RTHANDLETYPE_SOCKET:
break;
default:
}
/* Get the inheritability of the handle. */
if (*aphStds[i] != INVALID_HANDLE_VALUE)
{
{
}
}
}
}
/*
* Set the inheritability any handles we're handing the child.
*/
rc = VINF_SUCCESS;
for (int i = 0; i < 3; i++)
if ( (afInhStds[i] != 0xffffffff)
&& !(afInhStds[i] & HANDLE_FLAG_INHERIT))
{
{
}
}
/*
* Create the environment block, command line and convert the executable
* name.
*/
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/*
* Get going...
*/
{
if (CreateProcessW(pwszExec,
NULL, /* pProcessAttributes */
NULL, /* pThreadAttributes */
TRUE, /* fInheritHandles */
CREATE_UNICODE_ENVIRONMENT, /* dwCreationFlags */
NULL, /* pCurrentDirectory */
&ProcInfo))
rc = VINF_SUCCESS;
else
}
else
{
/*
* Convert the additional parameters and use a helper
* function to do the actual work.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
&StartupInfo, &ProcInfo);
}
}
}
if (RT_SUCCESS(rc))
{
if (phProcess)
{
/*
* Add the process to the child process list so
* RTProcWait can reuse and close the process handle.
*/
}
else
rc = VINF_SUCCESS;
}
}
}
}
/* Undo any handle inherit changes. */
for (int i = 0; i < 3; i++)
if ( (afInhStds[i] != 0xffffffff)
&& !(afInhStds[i] & HANDLE_FLAG_INHERIT))
{
}
return rc;
}
{
AssertReturn(!(fFlags & ~(RTPROCWAIT_FLAGS_BLOCK | RTPROCWAIT_FLAGS_NOBLOCK)), VERR_INVALID_PARAMETER);
/*
* Try find the process among the ones we've spawned, otherwise, attempt
* opening the specified process.
*/
{
/*
* Wait for it to terminate.
*/
while (WaitRc == WAIT_IO_COMPLETION)
switch (WaitRc)
{
/*
* It has terminated.
*/
case WAIT_OBJECT_0:
{
{
/** @todo the exit code can be special statuses. */
if (pProcStatus)
{
}
return VINF_SUCCESS;
}
break;
}
/*
* It hasn't terminated just yet.
*/
case WAIT_TIMEOUT:
return VERR_PROCESS_RUNNING;
/*
* Something went wrong...
*/
case WAIT_FAILED:
break;
case WAIT_ABANDONED:
AssertFailed();
return VERR_GENERAL_FAILURE;
default:
return VERR_GENERAL_FAILURE;
}
}
if (dwErr == ERROR_INVALID_PARAMETER)
return VERR_PROCESS_NOT_FOUND;
return RTErrConvertFromWin32(dwErr);
}
{
/** @todo this isn't quite right. */
}
{
{
if (fRc)
return VINF_SUCCESS;
}
return RTErrConvertFromWin32(dwErr);
}
{
BOOL fRc = GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
return dwProcessAffinityMask;
}