734
785
/* Handle process map. This needs to be done first in order to have a valid
735
786
* map in case some callback gets notified a bit below. */
788
uint32_t uHostPID = 0;
737
790
/* Note: PIDs never get removed here in case the guest process signalled its
738
791
* end; instead the next call of GetProcessStatus() will remove the PID
739
792
* from the process map after we got the process' final (exit) status.
740
793
* See waitpid() for an example. */
741
794
if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
796
uHostPID = callbackGetHostPID(uContextID);
743
799
switch (pData->u32Status)
745
801
/* Just reach through flags. */
746
802
case PROC_STS_TES:
747
803
case PROC_STS_TOK:
748
vrc = processSetStatus(pData->u32PID,
804
vrc = processSetStatus(uHostPID, pData->u32PID,
749
805
(ExecuteProcessStatus_T)pData->u32Status,
750
0 /* Exit code. */, pData->u32Flags);
806
0 /* Exit code */, pData->u32Flags);
752
808
/* Interprete u32Flags as the guest process' exit code. */
754
vrc = processSetStatus(pData->u32PID,
810
vrc = processSetStatus(uHostPID, pData->u32PID,
755
811
(ExecuteProcessStatus_T)pData->u32Status,
756
pData->u32Flags /* Exit code. */, 0 /* Flags. */);
812
pData->u32Flags /* Exit code */, 0 /* Flags */);
762
/* Do progress handling. */
763
switch (pData->u32Status)
765
case PROC_STS_STARTED:
766
vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
767
LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
770
case PROC_STS_TEN: /* Terminated normally. */
771
vrc = callbackNotifyComplete(uContextID);
772
LogRel(("Guest process (PID %u) exited normally\n", pData->u32PID)); /** @todo Add process name */
775
case PROC_STS_TEA: /* Terminated abnormally. */
776
LogRel(("Guest process (PID %u) terminated abnormally with exit code = %u\n",
777
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
778
errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
780
rcCallback = VERR_GENERAL_FAILURE; /** @todo */
783
case PROC_STS_TES: /* Terminated through signal. */
784
LogRel(("Guest process (PID %u) terminated through signal with exit code = %u\n",
785
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
786
errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
788
rcCallback = VERR_GENERAL_FAILURE; /** @todo */
792
LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
793
errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
794
rcCallback = VERR_TIMEOUT;
798
LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
799
errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
800
rcCallback = VERR_TIMEOUT;
804
LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
806
* If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
807
* our progress object. This is helpful for waiters which rely on the success of our progress object
808
* even if the executed process was killed because the system/VBoxService is shutting down.
810
* In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
812
if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
819
/* Do progress handling. */
820
switch (pData->u32Status)
822
case PROC_STS_STARTED:
823
vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
824
LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
827
case PROC_STS_TEN: /* Terminated normally. */
814
828
vrc = callbackNotifyComplete(uContextID);
818
errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
819
rcCallback = VERR_CANCELLED;
826
LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n",
827
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
831
switch (pData->u32Flags)
833
case VERR_MAX_PROCS_REACHED:
834
LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n"));
838
LogRel(("Guest process could not be started because of rc=%Rrc\n",
843
errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pData->u32Flags);
844
rcCallback = pData->u32Flags; /* Report back rc. */
848
vrc = VERR_INVALID_PARAMETER;
829
LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n",
830
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
833
case PROC_STS_TEA: /* Terminated abnormally. */
834
LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n",
835
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
836
errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
838
rcCallback = VERR_GENERAL_FAILURE; /** @todo */
841
case PROC_STS_TES: /* Terminated through signal. */
842
LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n",
843
pData->u32PID, pData->u32Flags)); /** @todo Add process name */
844
errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
846
rcCallback = VERR_GENERAL_FAILURE; /** @todo */
850
LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
851
errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
852
rcCallback = VERR_TIMEOUT;
856
LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
857
errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
858
rcCallback = VERR_TIMEOUT;
862
LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
864
* If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
865
* our progress object. This is helpful for waiters which rely on the success of our progress object
866
* even if the executed process was killed because the system/VBoxService is shutting down.
868
* In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
870
if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
872
vrc = callbackNotifyComplete(uContextID);
876
errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
877
rcCallback = VERR_CANCELLED;
886
errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"),
887
pData->u32PID, pData->u32Flags);
891
switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */
893
case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
894
errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest"));
897
case VERR_PATH_NOT_FOUND:
898
errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest"));
901
case VERR_BAD_EXE_FORMAT:
902
errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest"));
905
case VERR_AUTHENTICATION_FAILURE:
906
errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest"));
910
errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time"));
914
errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled"));
917
case VERR_PERMISSION_DENIED:
918
errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials"));
921
case VERR_MAX_PROCS_REACHED:
922
errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached"));
926
errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags);
931
errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail;
932
rcCallback = pData->u32Flags; /* Report back guest rc. */
934
LogRel((errMsg.c_str()));
940
vrc = VERR_INVALID_PARAMETER;
861
954
AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n"));
863
/* Notify all callbacks which are still waiting on something
864
* which is related to the current PID. */
867
int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
958
/* Notify all callbacks which are still waiting on something
959
* which is related to the current PID. */
962
int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
965
LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
972
/* Let the caller know what went wrong ... */
973
int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
868
974
if (RT_FAILURE(rc2))
870
LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
976
LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
977
uContextID, pData->u32PID));
872
978
if (RT_SUCCESS(vrc))
877
/* Let the caller know what went wrong ... */
878
int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
881
LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
882
uContextID, pData->u32PID));
984
/* Since we don't know which context exactly failed all we can do is to shutdown
985
* all contexts ... */
986
errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"),
989
/* Cancel all callbacks. */
991
for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
993
int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
886
999
LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
887
1000
uContextID, pData->u32Status, errMsg.c_str()));
1000
1113
Guest::tr("Client disconnected"));
1116
uint32_t Guest::processGetGuestPID(uint32_t uHostPID)
1118
AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
1120
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1122
GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
1123
if (it == mGuestProcessMap.end())
1126
return it->second.mGuestPID;
1004
1130
* Gets guest process information. Removes the process from the map
1005
1131
* after the process was marked as exited/terminated.
1007
1133
* @return IPRT status code.
1008
* @param u32PID PID of process to get status for.
1134
* @param uHostPID Host PID of guest process to get status for.
1009
1135
* @param pProcess Where to store the process information. Optional.
1010
1136
* @param fRemove Flag indicating whether to remove the
1011
1137
* process from the map when process marked a
1012
1138
* exited/terminated.
1014
int Guest::processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess,
1140
int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess,
1017
AssertReturn(u32PID, VERR_INVALID_PARAMETER);
1143
AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
1019
1145
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1021
GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
1147
GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
1022
1148
if (it != mGuestProcessMap.end())
1152
pProcess->mGuestPID = it->second.mGuestPID;
1026
1153
pProcess->mStatus = it->second.mStatus;
1027
1154
pProcess->mExitCode = it->second.mExitCode;
1028
1155
pProcess->mFlags = it->second.mFlags;
1031
/* If the is marked as stopped/terminated
1032
* remove it from the map. */
1158
/* Only remove processes from our map when they signalled their final
1034
&& it->second.mStatus != ExecuteProcessStatus_Started)
1161
&& ( it->second.mStatus != ExecuteProcessStatus_Undefined
1162
&& it->second.mStatus != ExecuteProcessStatus_Started))
1036
1164
mGuestProcessMap.erase(it);
1042
1170
return VERR_NOT_FOUND;
1045
int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
1174
* Sets the current status of a guest process.
1176
* @return IPRT status code.
1177
* @param uHostPID Host PID of guest process to set status (and guest PID) for.
1178
* @param uGuestPID Guest PID to assign to the host PID.
1179
* @param enmStatus Current status to set.
1180
* @param uExitCode Exit code (if any).
1181
* @param uFlags Additional flags.
1183
int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
1184
ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
1047
AssertReturn(u32PID, VERR_INVALID_PARAMETER);
1186
AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
1187
/* Assigning a guest PID is optional. */
1049
1189
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1051
GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
1191
GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
1052
1192
if (it != mGuestProcessMap.end())
1054
it->second.mStatus = enmStatus;
1194
it->second.mGuestPID = uGuestPID;
1195
it->second.mStatus = enmStatus;
1055
1196
it->second.mExitCode = uExitCode;
1056
it->second.mFlags = uFlags;
1197
it->second.mFlags = uFlags;
1060
1201
VBOXGUESTCTRL_PROCESS process;
1062
process.mStatus = enmStatus;
1203
/* uGuestPID is optional -- the caller could call this function
1204
* before the guest process actually was started and a (valid) guest PID
1206
process.mGuestPID = uGuestPID;
1207
process.mStatus = enmStatus;
1063
1208
process.mExitCode = uExitCode;
1064
process.mFlags = uFlags;
1209
process.mFlags = uFlags;
1066
mGuestProcessMap[u32PID] = process;
1211
mGuestProcessMap[uHostPID] = process;
1069
1214
return VINF_SUCCESS;
1072
HRESULT Guest::handleErrorCompletion(int rc)
1217
HRESULT Guest::setErrorCompletion(int rc)
1075
1220
if (rc == VERR_NOT_FOUND)
1157
1346
GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
1158
1347
IProgress **aProgress, ULONG *aPID)
1160
ComPtr<IProgress> progressTool;
1349
ComPtr<IProgress> pProgress;
1162
1351
ULONG uFlags = ExecuteProcessFlag_Hidden;
1163
1352
if (uFlagsToAdd)
1164
1353
uFlags |= uFlagsToAdd;
1166
bool fWaitForOutput = false;
1355
bool fParseOutput = false;
1167
1356
if ( ( (uFlags & ExecuteProcessFlag_WaitForStdOut)
1169
1358
|| ( (uFlags & ExecuteProcessFlag_WaitForStdErr)
1170
1359
&& pObjStdErr))
1172
fWaitForOutput = true;
1361
fParseOutput = true;
1175
HRESULT rc = ExecuteProcess(aTool,
1364
HRESULT hr = ExecuteProcess(aTool,
1177
1366
ComSafeArrayInArg(aArguments),
1178
1367
ComSafeArrayInArg(aEnvironment),
1179
1368
aUsername, aPassword,
1180
0 /* No timeout. */,
1181
&uPID, progressTool.asOutParam());
1186
while ( SUCCEEDED(progressTool->COMGETTER(Completed)(&fCompleted))
1190
rc = progressTool->COMGETTER(Canceled)(&fCanceled);
1194
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1195
tr("%s was cancelled"), Utf8Str(aDescription).c_str());
1199
if ( (uFlags & ExecuteProcessFlag_WaitForStdOut)
1202
rc = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
1205
if ( (uFlags & ExecuteProcessFlag_WaitForStdErr)
1208
rc = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
1370
&uPID, pProgress.asOutParam());
1373
/* Wait for tool being started. */
1374
hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */,
1375
-1 /* No timeout */);
1379
&& !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly))
1383
if ( !(uFlags & ExecuteProcessFlag_WaitForStdOut)
1384
&& !(uFlags & ExecuteProcessFlag_WaitForStdErr))
1386
hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */);
1392
while ( SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted))
1396
hr = pProgress->COMGETTER(Canceled)(&fCanceled);
1400
hr = setErrorNoLog(VBOX_E_IPRT_ERROR,
1401
tr("%s was cancelled"), Utf8Str(aDescription).c_str());
1405
if ( (uFlags & ExecuteProcessFlag_WaitForStdOut)
1408
hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
1411
if ( (uFlags & ExecuteProcessFlag_WaitForStdErr)
1414
hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
1220
1427
/* Return the progress to the caller. */
1221
progressTool.queryInterfaceTo(aProgress);
1428
pProgress.queryInterfaceTo(aProgress);
1430
else if (!pProgress.isNull())
1431
pProgress.setNull();
1231
HRESULT Guest::executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout,
1232
PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID)
1234
AssertPtrReturn(pExecStatus, E_INVALIDARG);
1235
AssertPtrReturn(puPID, E_INVALIDARG);
1239
/* Did we get some status? */
1240
switch (pExecStatus->u32Status)
1242
case PROC_STS_STARTED:
1243
/* Process is (still) running; get PID. */
1244
*puPID = pExecStatus->u32PID;
1247
/* In any other case the process either already
1248
* terminated or something else went wrong, so no PID ... */
1249
case PROC_STS_TEN: /* Terminated normally. */
1250
case PROC_STS_TEA: /* Terminated abnormally. */
1251
case PROC_STS_TES: /* Terminated through signal. */
1256
* Process (already) ended, but we want to get the
1257
* PID anyway to retrieve the output in a later call.
1259
*puPID = pExecStatus->u32PID;
1262
case PROC_STS_ERROR:
1264
int vrc = pExecStatus->u32Flags; /* u32Flags member contains IPRT error code. */
1265
if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
1266
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1267
tr("The file '%s' was not found on guest"), pszCommand);
1268
else if (vrc == VERR_PATH_NOT_FOUND)
1269
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1270
tr("The path to file '%s' was not found on guest"), pszCommand);
1271
else if (vrc == VERR_BAD_EXE_FORMAT)
1272
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1273
tr("The file '%s' is not an executable format on guest"), pszCommand);
1274
else if (vrc == VERR_AUTHENTICATION_FAILURE)
1275
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1276
tr("The specified user '%s' was not able to logon on guest"), pszUser);
1277
else if (vrc == VERR_TIMEOUT)
1278
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1279
tr("The guest did not respond within time (%ums)"), ulTimeout);
1280
else if (vrc == VERR_CANCELLED)
1281
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1282
tr("The execution operation was canceled"));
1283
else if (vrc == VERR_PERMISSION_DENIED)
1284
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1285
tr("Invalid user/password credentials"));
1286
else if (vrc == VERR_MAX_PROCS_REACHED)
1287
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1288
tr("Concurrent guest process limit is reached"));
1291
if (pExecStatus && pExecStatus->u32Status == PROC_STS_ERROR)
1292
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1293
tr("Process could not be started: %Rrc"), pExecStatus->u32Flags);
1295
rc = setErrorNoLog(E_UNEXPECTED,
1296
tr("The service call failed with error %Rrc"), vrc);
1301
case PROC_STS_UNDEFINED: /* . */
1302
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1303
tr("The operation did not complete within time"));
1307
AssertReleaseMsgFailed(("Process (PID %u) reported back an undefined state!\n",
1308
pExecStatus->u32PID));
1785
1899
if (RT_SUCCESS(vrc))
1787
LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
1790
* Wait for the HGCM low level callback until the process
1791
* has been started (or something went wrong). This is necessary to
1795
PCALLBACKDATAEXECSTATUS pExecStatus = NULL;
1798
* Wait for the first stage (=0) to complete (that is starting the process).
1800
vrc = callbackWaitForCompletion(uContextID, 0 /* Stage */, aTimeoutMS);
1801
if (RT_SUCCESS(vrc))
1901
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1904
* Generate a host-driven PID so that we immediately can return to the caller and
1905
* don't need to wait until the guest started the desired process to return the
1906
* PID generated by the guest OS.
1908
* The guest PID will later be mapped to the host PID for later lookup.
1910
vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */
1912
uint32_t uTries = 0;
1803
vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
1804
(void**)&pExecStatus, NULL /* Don't need the size. */);
1805
if (RT_SUCCESS(vrc))
1807
rc = executeProcessResult(Utf8Command.c_str(), Utf8UserName.c_str(), aTimeoutMS,
1809
callbackFreeUserData(pExecStatus);
1813
rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
1814
tr("Unable to retrieve process execution status data"));
1915
/* Create a new context ID ... */
1916
uHostPID = ASMAtomicIncU32(&mNextHostPID);
1917
if (uHostPID == UINT32_MAX)
1918
ASMAtomicUoWriteU32(&mNextHostPID, 1000);
1919
/* Is the host PID already used? Try next PID ... */
1920
GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
1921
if (it == mGuestProcessMap.end())
1923
/* Host PID not used (anymore), we're done here ... */
1928
if (++uTries == UINT32_MAX)
1929
break; /* Don't try too hard. */
1818
rc = handleErrorCompletion(vrc);
1821
* Do *not* remove the callback yet - we might wait with the IProgress object on something
1822
* else (like end of process) ...
1932
if (RT_SUCCESS(vrc))
1933
vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */,
1934
ExecuteProcessStatus_Undefined /* Process not started yet */,
1935
0 /* uExitCode */, 0 /* uFlags */);
1937
if (RT_SUCCESS(vrc))
1938
vrc = callbackAssignHostPID(uContextID, uHostPID);
1826
rc = handleErrorHGCM(vrc);
1941
rc = setErrorHGCM(vrc);
1828
1943
for (unsigned i = 0; i < uNumArgs; i++)
1829
1944
RTMemFree(papszArgv[i]);
1830
1945
RTMemFree(papszArgv);
1947
if (RT_FAILURE(vrc))
1948
rc = VBOX_E_IPRT_ERROR;
1833
1951
if (SUCCEEDED(rc))
1953
/* Return host PID. */
1835
1956
/* Return the progress to the caller. */
1836
1957
pProgress.queryInterfaceTo(aProgress);