summaryrefslogtreecommitdiff
path: root/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp')
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp292
1 files changed, 175 insertions, 117 deletions
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
index 8be9dafe0..83ba405c9 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
@@ -1,4 +1,4 @@
-/* $Id: VBoxServiceControlExec.cpp 37816 2011-07-07 11:52:16Z vboxsync $ */
+/* $Id: VBoxServiceControlExec.cpp 38395 2011-08-10 11:48:29Z vboxsync $ */
/** @file
* VBoxServiceControlExec - Utility functions for process execution.
*/
@@ -46,8 +46,8 @@
using namespace guestControl;
-extern RTLISTNODE g_GuestControlExecThreads;
-extern RTCRITSECT g_GuestControlExecThreadsCritSect;
+extern RTLISTNODE g_GuestControlThreads;
+extern RTCRITSECT g_GuestControlThreadsCritSect;
/**
@@ -190,7 +190,7 @@ static int VBoxServiceControlExecProcHandleStdInWritableEvent(RTPOLLSET hPollSe
/**
- * Handle pending output data/error on standard out or standard error.
+ * Handle pending output data/error on stdout or stderr.
*
* @return IPRT status code.
* @param hPollSet The polling set.
@@ -205,11 +205,6 @@ static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint3
AssertPtrReturn(phPipeR, VERR_INVALID_POINTER);
AssertPtrReturn(pBuf, VERR_INVALID_POINTER);
-#ifdef DEBUG
- VBoxServiceVerbose(4, "ControlExec: HandleOutputEvent: fPollEvt=%#x, uHandle=%u\n",
- fPollEvt, uHandleId);
-#endif
-
/*
* Try drain the pipe before acting on any errors.
*/
@@ -223,6 +218,10 @@ static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint3
uint32_t cbWritten;
rc = VBoxServicePipeBufWriteToBuf(pBuf, abBuf,
cbRead, false /* Pending close */, &cbWritten);
+#ifdef DEBUG_andy
+ VBoxServiceVerbose(4, "ControlExec: Written output event [%u %u], cbRead=%u, cbWritten=%u, rc=%Rrc, uHandleId=%u, fPollEvt=%#x\n",
+ pBuf->uPID, pBuf->uPipeId, cbRead, cbWritten, rc, uHandleId, fPollEvt);
+#endif
if (RT_SUCCESS(rc))
{
Assert(cbRead == cbWritten);
@@ -256,7 +255,7 @@ static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint3
int VBoxServiceControlExecProcHandleStdInputNotify(RTPOLLSET hPollSet,
PRTPIPE phNotificationPipeR, PRTPIPE phInputPipeW)
{
-#ifdef DEBUG
+#ifdef DEBUG_andy
VBoxServiceVerbose(4, "ControlExec: HandleStdInputNotify\n");
#endif
/* Drain the notification pipe. */
@@ -316,14 +315,23 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
AssertPtr(pData);
- /* Assign PID to thread data. */
- pData->uPID = hProcess;
+ /*
+ * Assign PID to thread data.
+ * Also check if there already was a thread with the same PID and shut it down -- otherwise
+ * the first (stale) entry will be found and we get really weird results!
+ */
+ rc = VBoxServiceControlExecThreadAssignPID(pData, hProcess);
+ if (RT_FAILURE(rc))
+ {
+ VBoxServiceError("ControlExec: Unable to assign PID to new thread, rc=%Rrc\n", rc);
+ return rc;
+ }
/*
* Before entering the loop, tell the host that we've started the guest
* and that it's now OK to send input to the process.
*/
- VBoxServiceVerbose(3, "ControlExec: Process started: PID=%u, CID=%u, User=%s\n",
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Process started, CID=%u, User=%s\n",
pData->uPID, pThread->uContextID, pData->pszUser);
rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
pData->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
@@ -348,7 +356,8 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
if (RT_SUCCESS(rc2))
{
- VBoxServiceVerbose(4, "ControlExec: RTPollNoResume idPollHnd=%u\n", idPollHnd);
+ /*VBoxServiceVerbose(4, "ControlExec: [PID %u}: RTPollNoResume idPollHnd=%u\n",
+ pData->uPID, idPollHnd);*/
switch (idPollHnd)
{
case VBOXSERVICECTRLPIPEID_STDIN_ERROR:
@@ -369,17 +378,26 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
}
case VBOXSERVICECTRLPIPEID_STDOUT:
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: StdOut fPollEvt=%#x\n",
+ pData->uPID, fPollEvt);
+#endif
rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, phStdOutR,
VBOXSERVICECTRLPIPEID_STDOUT, &pData->stdOut);
break;
case VBOXSERVICECTRLPIPEID_STDERR:
+#ifdef DEBUG
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: StdErr: fPollEvt=%#x\n",
+ pData->uPID, fPollEvt);
+#endif
rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, phStdErrR,
VBOXSERVICECTRLPIPEID_STDERR, &pData->stdErr);
break;
default:
- AssertMsgFailed(("idPollHnd=%u fPollEvt=%#x\n", idPollHnd, fPollEvt));
+ AssertMsgFailed(("PID=%u idPollHnd=%u fPollEvt=%#x\n",
+ pData->uPID, idPollHnd, fPollEvt));
break;
}
if (RT_FAILURE(rc) || rc == VINF_EOF)
@@ -427,7 +445,8 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
uint64_t cMsElapsed = u64Now - MsStart;
if (cMsElapsed >= cMsTimeout)
{
- VBoxServiceVerbose(3, "ControlExec: Process timed out (%ums elapsed > %ums timeout), killing ...", cMsElapsed, cMsTimeout);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...",
+ pData->uPID, cMsElapsed, cMsTimeout);
fProcessTimedOut = true;
if ( MsProcessKilled == UINT64_MAX
@@ -462,7 +481,7 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
{
if (MsProcessKilled == UINT64_MAX)
{
- VBoxServiceVerbose(3, "ControlExec: Process (PID=%u) is still alive and not killed yet\n",
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Is still alive and not killed yet\n",
pData->uPID);
MsProcessKilled = RTTimeMilliTS();
@@ -472,106 +491,105 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
for (size_t i = 0; i < 10; i++)
{
- VBoxServiceVerbose(4, "ControlExec: Kill attempt %d/10: Waiting for process (PID=%u) exit ...\n",
- i + 1, pData->uPID);
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: Kill attempt %d/10: Waiting to exit ...\n",
+ pData->uPID, i + 1);
rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
if (RT_SUCCESS(rc2))
{
- VBoxServiceVerbose(4, "ControlExec: Kill attempt %d/10: Process (PID=%u) exited\n",
- i + 1, pData->uPID);
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: Kill attempt %d/10: Exited\n",
+ pData->uPID, i + 1);
fProcessAlive = false;
break;
}
if (i >= 5)
{
- VBoxServiceVerbose(4, "ControlExec: Kill attempt %d/10: Try to terminate (PID=%u) ...\n",
- i + 1, pData->uPID);
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: Kill attempt %d/10: Trying to terminate ...\n",
+ pData->uPID, i + 1);
RTProcTerminate(hProcess);
}
RTThreadSleep(i >= 5 ? 2000 : 500);
}
if (fProcessAlive)
- VBoxServiceVerbose(3, "ControlExec: Process (PID=%u) could not be killed\n", pData->uPID);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Could not be killed\n", pData->uPID);
}
/*
- * If we don't have a client problem (RT_FAILURE(rc) we'll reply to the
+ * If we don't have a client problem (RT_FAILURE(rc)) we'll reply to the
* clients exec packet now.
*/
if (RT_SUCCESS(rc))
{
- VBoxServicePipeBufSetStatus(&pData->stdIn, false /* Disabled */);
- VBoxServicePipeBufSetStatus(&pData->stdOut, false /* Disabled */);
- VBoxServicePipeBufSetStatus(&pData->stdErr, false /* Disabled */);
-
- /* Since the process is not alive anymore, destroy its local
- * stdin pipe buffer - it's not used anymore and can eat up quite
- * a bit of memory. */
- VBoxServicePipeBufDestroy(&pData->stdIn);
+ /* Mark this thread as stopped and do some action required for stopping ... */
+ VBoxServiceControlExecThreadStop(pThread);
uint32_t uStatus = PROC_STS_UNDEFINED;
uint32_t uFlags = 0;
if ( fProcessTimedOut && !fProcessAlive && MsProcessKilled != UINT64_MAX)
{
- VBoxServiceVerbose(3, "ControlExec: Process timed out and got killed\n");
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Timed out and got killed\n",
+ pData->uPID);
uStatus = PROC_STS_TOK;
}
else if (fProcessTimedOut && fProcessAlive && MsProcessKilled != UINT64_MAX)
{
- VBoxServiceVerbose(3, "ControlExec: Process timed out and did *not* get killed\n");
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Timed out and did *not* get killed\n",
+ pData->uPID);
uStatus = PROC_STS_TOA;
}
else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
{
- VBoxServiceVerbose(3, "ControlExec: Process got terminated because system/service is about to shutdown\n");
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Got terminated because system/service is about to shutdown\n",
+ pData->uPID);
uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
uFlags = pData->uFlags; /* Return handed-in execution flags back to the host. */
}
else if (fProcessAlive)
{
- VBoxServiceError("ControlExec: Process is alive when it should not!\n");
+ VBoxServiceError("ControlExec: [PID %u]: Is alive when it should not!\n",
+ pData->uPID);
}
else if (MsProcessKilled != UINT64_MAX)
{
- VBoxServiceError("ControlExec: Process has been killed when it should not!\n");
+ VBoxServiceError("ControlExec: [PID %u]: Has been killed when it should not!\n",
+ pData->uPID);
}
else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
{
- VBoxServiceVerbose(3, "ControlExec: Process ended with RTPROCEXITREASON_NORMAL (%u)\n",
- ProcessStatus.iStatus);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n",
+ pData->uPID, ProcessStatus.iStatus);
uStatus = PROC_STS_TEN;
uFlags = ProcessStatus.iStatus;
}
else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
{
- VBoxServiceVerbose(3, "ControlExec: Process ended with RTPROCEXITREASON_SIGNAL (%u)\n",
- ProcessStatus.iStatus);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n",
+ pData->uPID, ProcessStatus.iStatus);
uStatus = PROC_STS_TES;
uFlags = ProcessStatus.iStatus;
}
else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND)
{
- VBoxServiceVerbose(3, "ControlExec: Process ended with RTPROCEXITREASON_ABEND (%u)\n",
- ProcessStatus.iStatus);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n",
+ pData->uPID, ProcessStatus.iStatus);
uStatus = PROC_STS_TEA;
uFlags = ProcessStatus.iStatus;
}
else
- {
- VBoxServiceError("ControlExec: Process has reached an undefined status!\n");
- }
+ VBoxServiceError("ControlExec: [PID %u]: Reached an undefined state!\n",
+ pData->uPID);
- VBoxServiceVerbose(3, "ControlExec: Process ended: PID=%u, CID=%u, Status=%u, Flags=%u\n",
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Ended, CID=%u, Status=%u, Flags=%u\n",
pData->uPID, pThread->uContextID, uStatus, uFlags);
rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID,
pData->uPID, uStatus, uFlags,
NULL /* pvData */, 0 /* cbData */);
- VBoxServiceVerbose(3, "ControlExec: Process loop ended with rc=%Rrc\n", rc);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Process loop ended with rc=%Rrc\n",
+ pData->uPID, rc);
/*
* Dump stdout for debugging purposes.
@@ -579,7 +597,7 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
*/
if (g_cVerbosity >= 5)
{
- VBoxServiceVerbose(5, "StdOut of process (PID %u):\n", pData->uPID);
+ VBoxServiceVerbose(5, "[PID %u]: StdOut:\n", pData->uPID);
uint8_t szBuf[_64K];
uint32_t cbOffset = 0;
@@ -588,7 +606,6 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
cbOffset, &cbRead, &cbLeft))
&& cbRead)
{
- RTStrmWrite(g_pStdOut, szBuf, cbRead);
cbOffset += cbRead;
if (!cbLeft)
break;
@@ -598,7 +615,8 @@ static int VBoxServiceControlExecProcLoop(PVBOXSERVICECTRLTHREAD pThread,
}
}
else
- VBoxServiceError("ControlExec: Process loop failed with rc=%Rrc\n", rc);
+ VBoxServiceError("ControlExec: [PID %u]: Loop failed with rc=%Rrc\n",
+ pData->uPID, rc);
return rc;
}
@@ -882,9 +900,9 @@ static int VBoxServiceControlExecCreateProcess(const char *pszExec, const char *
if (*pszAsUser)
uProcFlags |= RTPROC_FLAGS_SERVICE;
#ifdef DEBUG
- VBoxServiceVerbose(3, "Command: %s\n", szExecExp);
+ VBoxServiceVerbose(3, "ControlExec: Command: %s\n", szExecExp);
for (size_t i = 0; papszArgsExp[i]; i++)
- VBoxServiceVerbose(3, "\targv[%ld]: %s\n", i, papszArgsExp[i]);
+ VBoxServiceVerbose(3, "ControlExec:\targv[%ld]: %s\n", i, papszArgsExp[i]);
#endif
/* Do normal execution. */
rc = RTProcCreateEx(szExecExp, papszArgsExp, hEnv, uProcFlags,
@@ -1019,11 +1037,13 @@ static DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHR
* the guest from getting stuck accessing them.
* So, NIL the handles to avoid closing them again.
*/
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 0 /* stdin */, NULL)))
+ if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_WRITABLE, NULL)))
pData->pipeStdInW = NIL_RTPIPE;
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 1 /* stdout */, NULL)))
+ if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_INPUT_NOTIFY, NULL)))
+ pData->stdIn.hNotificationPipeR = NIL_RTPIPE;
+ if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDOUT, NULL)))
hStdOutR = NIL_RTPIPE;
- if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 2 /* stderr */, NULL)))
+ if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDERR, NULL)))
hStdErrR = NIL_RTPIPE;
}
else /* Something went wrong; report error! */
@@ -1040,6 +1060,7 @@ static DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHR
}
}
RTPollSetDestroy(hPollSet);
+ RTPipeClose(pData->stdIn.hNotificationPipeR);
}
RTPipeClose(hStdErrR);
RTHandleClose(phStdErr);
@@ -1055,8 +1076,8 @@ static DECLCALLBACK(int) VBoxServiceControlExecProcessWorker(PVBOXSERVICECTRLTHR
}
VbglR3GuestCtrlDisconnect(pThread->uClientID);
- VBoxServiceVerbose(3, "ControlExec: Thread of process \"%s\" (PID: %u) ended with rc=%Rrc\n",
- pData->pszCmd, pData->uPID, rc);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
+ pData->uPID, pData->pszCmd, rc);
/*
* If something went wrong signal the user event so that others don't wait
@@ -1089,6 +1110,7 @@ static DECLCALLBACK(int) VBoxServiceControlExecThread(RTTHREAD ThreadSelf, void
* so that this function will not block the overall program execution.
*
* @return IPRT status code.
+ * @param uClientID Client ID for accessing host service.
* @param uContextID Context ID to associate the process to start with.
* @param pszCmd Full qualified path of process to start (without arguments).
* @param uFlags Process execution flags.
@@ -1102,59 +1124,83 @@ static DECLCALLBACK(int) VBoxServiceControlExecThread(RTTHREAD ThreadSelf, void
* @param pszPassword Password of specified user name (account).
* @param uTimeLimitMS Time limit (in ms) of the process' life time.
*/
-int VBoxServiceControlExecProcess(uint32_t uContextID, const char *pszCmd, uint32_t uFlags,
+int VBoxServiceControlExecProcess(uint32_t uClientID, uint32_t uContextID,
+ const char *pszCmd, uint32_t uFlags,
const char *pszArgs, uint32_t uNumArgs,
const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS)
{
- int rc;
+ bool fAllowed = false;
+ int rc = VBoxServiceControlExecThreadStartAllowed(&fAllowed);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("ControlExec: Error determining whether process can be started or not, rc=%Rrc\n", rc);
- PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
- if (pThread)
+ if (fAllowed)
{
- rc = VBoxServiceControlExecThreadAlloc(pThread,
- uContextID,
- pszCmd, uFlags,
- pszArgs, uNumArgs,
- pszEnv, cbEnv, uNumEnvVars,
- pszUser, pszPassword,
- uTimeLimitMS);
- if (RT_SUCCESS(rc))
+ /*
+ * Allocate new thread data and assign it to our thread list.
+ */
+ PVBOXSERVICECTRLTHREAD pThread = (PVBOXSERVICECTRLTHREAD)RTMemAlloc(sizeof(VBOXSERVICECTRLTHREAD));
+ if (pThread)
{
- rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
- (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
- RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "Exec");
- if (RT_FAILURE(rc))
- {
- VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
- rc, pThread);
- }
- else
+ rc = VBoxServiceControlExecThreadAlloc(pThread,
+ uContextID,
+ pszCmd, uFlags,
+ pszArgs, uNumArgs,
+ pszEnv, cbEnv, uNumEnvVars,
+ pszUser, pszPassword,
+ uTimeLimitMS);
+ if (RT_SUCCESS(rc))
{
- VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n");
-
- /* Wait for the thread to initialize. */
- RTThreadUserWait(pThread->Thread, 60 * 1000);
- if (pThread->fShutdown)
+ static uint32_t uCtrlExecThread = 0;
+ char szThreadName[32];
+ if (!RTStrPrintf(szThreadName, sizeof(szThreadName), "controlexec%ld", uCtrlExecThread++))
+ AssertMsgFailed(("Unable to create unique control exec thread name!\n"));
+
+ rc = RTThreadCreate(&pThread->Thread, VBoxServiceControlExecThread,
+ (void *)(PVBOXSERVICECTRLTHREAD*)pThread, 0,
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, szThreadName);
+ if (RT_FAILURE(rc))
{
- VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);
- rc = VERR_GENERAL_FAILURE;
+ VBoxServiceError("ControlExec: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",
+ rc, pThread);
}
else
{
- pThread->fStarted = true;
- /*rc =*/ RTListAppend(&g_GuestControlExecThreads, &pThread->Node);
+ VBoxServiceVerbose(4, "ControlExec: Waiting for thread to initialize ...\n");
+
+ /* Wait for the thread to initialize. */
+ RTThreadUserWait(pThread->Thread, 60 * 1000 /* 60 seconds max. */);
+ if (pThread->fShutdown)
+ {
+ VBoxServiceError("ControlExec: Thread for process \"%s\" failed to start!\n", pszCmd);
+ rc = VERR_GENERAL_FAILURE;
+ }
+ else
+ {
+ pThread->fStarted = true;
+ /*rc =*/ RTListAppend(&g_GuestControlThreads, &pThread->Node);
+ }
}
- }
+ if (RT_FAILURE(rc))
+ VBoxServiceControlExecThreadDataDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData);
+ }
if (RT_FAILURE(rc))
- VBoxServiceControlExecThreadDestroy((PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData);
+ RTMemFree(pThread);
}
- if (RT_FAILURE(rc))
- RTMemFree(pThread);
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ else /* Process start is not allowed due to policy settings. */
+ {
+ VBoxServiceVerbose(3, "ControlExec: Guest process limit is reached!\n");
+
+ /* Tell the host. */
+ rc = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID, 0 /* PID */,
+ PROC_STS_ERROR, VERR_MAX_PROCS_REACHED,
+ NULL /* pvData */, 0 /* cbData */);
}
- else
- rc = VERR_NO_MEMORY;
return rc;
}
@@ -1213,13 +1259,14 @@ int VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t u
#endif
if (RT_SUCCESS(rc))
{
- rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
+ /** @todo Put the following params into a struct! */
+ rc = VBoxServiceControlExecProcess(u32ClientId, uContextID,
+ szCmd, uFlags, szArgs, uNumArgs,
szEnv, cbEnv, uNumEnvVars,
szUser, szPassword, uTimeLimitMS);
}
else
VBoxServiceError("ControlExec: Failed to retrieve exec start command! Error: %Rrc\n", rc);
- VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdStartProcess returned with %Rrc\n", rc);
return rc;
}
@@ -1255,12 +1302,13 @@ int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumP
pabBuffer, cbMaxBufSize, &cbSize);
if (RT_FAILURE(rc))
{
- VBoxServiceError("ControlExec: Failed to retrieve exec input command! Error: %Rrc\n", rc);
+ VBoxServiceError("ControlExec: [PID %u]: Failed to retrieve exec input command! Error: %Rrc\n",
+ uPID, rc);
}
else if (cbSize > cbMaxBufSize)
{
- VBoxServiceError("ControlExec: Maximum input buffer size is too small! cbSize=%u, cbMaxBufSize=%u\n",
- cbSize, cbMaxBufSize);
+ VBoxServiceError("ControlExec: [PID %u]: Maximum input buffer size is too small! cbSize=%u, cbMaxBufSize=%u\n",
+ uPID, cbSize, cbMaxBufSize);
rc = VERR_INVALID_PARAMETER;
}
else
@@ -1272,12 +1320,13 @@ int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumP
if (uFlags & INPUT_FLAG_EOF)
{
fPendingClose = true;
- VBoxServiceVerbose(4, "ControlExec: Got last input block (PID %u) of size %u ...\n", uPID, cbSize);
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: Got last input block of size %u ...\n",
+ uPID, cbSize);
}
rc = VBoxServiceControlExecThreadSetInput(uPID, fPendingClose, pabBuffer,
cbSize, &cbWritten);
- VBoxServiceVerbose(4, "ControlExec: Written input (PID %u): rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
+ VBoxServiceVerbose(4, "ControlExec: [PID %u]: Written input, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
uPID, rc, uFlags, fPendingClose, cbSize, cbWritten);
if (RT_SUCCESS(rc))
{
@@ -1309,8 +1358,8 @@ int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumP
}
Assert(uStatus > INPUT_STS_UNDEFINED);
- VBoxServiceVerbose(3, "ControlExec: Input processed (PID %u), Status=%u, Flags=0x%x, cbWritten=%u\n",
- uPID, uStatus, uFlags, cbWritten);
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n",
+ uPID, uContextID, uStatus, uFlags, cbWritten);
/* Note: Since the context ID is unique the request *has* to be completed here,
* regardless whether we got data or not! Otherwise the progress object
@@ -1318,7 +1367,9 @@ int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumP
rc = VbglR3GuestCtrlExecReportStatusIn(u32ClientId, uContextID, uPID,
uStatus, uFlags, (uint32_t)cbWritten);
- VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdSetInput returned with %Rrc\n", rc);
+ if (RT_FAILURE(rc))
+ VBoxServiceError("ControlExec: [PID %u]: Failed to report input status! Error: %Rrc\n",
+ uPID, rc);
return rc;
}
@@ -1342,29 +1393,36 @@ int VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNum
&uContextID, &uPID, &uHandleID, &uFlags);
if (RT_SUCCESS(rc))
{
- uint32_t cbRead;
+ uint32_t cbRead = 0;
uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);
if (pBuf)
{
rc = VBoxServiceControlExecThreadGetOutput(uPID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
pBuf, _64K /* cbSize */, &cbRead);
if (RT_SUCCESS(rc))
- {
- /* Note: Since the context ID is unique the request *has* to be completed here,
- * regardless whether we got data or not! Otherwise the progress object
- * on the host never will get completed! */
- /* cbRead now contains actual size. */
- rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, uHandleID, uFlags,
- pBuf, cbRead);
- }
+ VBoxServiceVerbose(3, "ControlExec: [PID %u]: Got output, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
+ uPID, uContextID, cbRead, uHandleID, uFlags);
+ else
+ VBoxServiceError("ControlExec: [PID %u]: Failed to retrieve output, CID=%u, uHandle=%u, rc=%Rrc\n",
+ uPID, uContextID, uHandleID, rc);
+
+ /* Note: Since the context ID is unique the request *has* to be completed here,
+ * regardless whether we got data or not! Otherwise the progress object
+ * on the host never will get completed! */
+ /* cbRead now contains actual size. */
+ int rc2 = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, uHandleID, uFlags,
+ pBuf, cbRead);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
RTMemFree(pBuf);
}
else
rc = VERR_NO_MEMORY;
}
- else
- VBoxServiceError("ControlExec: Failed to retrieve exec output command! Error: %Rrc\n", rc);
- VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdGetOutput returned with %Rrc\n", rc);
+
+ if (RT_FAILURE(rc))
+ VBoxServiceError("ControlExec: [PID %u]: Failed to handle output command! Error: %Rrc\n",
+ uPID, rc);
return rc;
}