VirtualBox

Changeset 40685 in vbox


Ignore:
Timestamp:
Mar 28, 2012 2:48:00 PM (13 years ago)
Author:
vboxsync
Message:

Main/GuestCtrl: Introduced host<->guest PID mapping for immediate returns of executeProcess(); bugfixes.

Location:
trunk/src/VBox/Main
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestImpl.h

    r40084 r40685  
    175175    HRESULT getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
    176176                                     LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC);
    177     HRESULT executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);
     177    HRESULT executeSetResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);
    178178    int     executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs);
    179     int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream &stream);
     179    int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream *pStream);
    180180    int     executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
    181181    int     executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
    182182    HRESULT executeStreamParse(ULONG uPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects);
    183     HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS,
    184                                ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode);
     183    HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS);
    185184    // Internal guest file functions
    186185    HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
     
    211210        /** Size of user-supplied data. */
    212211        uint32_t                    cbData;
     212        /** The host PID. Needed for translating to
     213         *  a guest PID. */
     214        uint32_t                    uHostPID;
    213215        /** Pointer to user-supplied IProgress. */
    214216        ComObjPtr<Progress>         pProgress;
     
    219221
    220222    int callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallbackData, uint32_t *puContextID);
     223    int callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID);
    221224    void callbackDestroy(uint32_t uContextID);
    222225    void callbackRemove(uint32_t uContextID);
    223226    bool callbackExists(uint32_t uContextID);
    224227    void callbackFreeUserData(void *pvData);
     228    uint32_t callbackGetHostPID(uint32_t uContextID);
    225229    int callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType, void **ppvData, size_t *pcbData);
    226230    void* callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData);
     
    231235    int callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage);
    232236    int callbackNotifyComplete(uint32_t uContextID);
    233     int callbackNotifyAllForPID(uint32_t uPID, int iRC, const char *pszMessage);
     237    int callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage);
    234238    int callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout);
    235239
     
    242246    typedef struct VBOXGUESTCTRL_PROCESS
    243247    {
     248        /** The guest PID -- needed for controlling the actual guest
     249         *  process which has its own PID (generated by the guest OS). */
     250        uint32_t                    mGuestPID;
     251        /** The last reported process status. */
    244252        ExecuteProcessStatus_T      mStatus;
     253        /** The process execution flags. */
    245254        uint32_t                    mFlags;
     255        /** The process' exit code. */
    246256        uint32_t                    mExitCode;
    247257    } VBOXGUESTCTRL_PROCESS, *PVBOXGUESTCTRL_PROCESS;
     
    250260    typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst;
    251261
    252     int  processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove);
    253     int  processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
     262    uint32_t processGetGuestPID(uint32_t uHostPID);
     263    int  processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove);
     264    int  processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
     265                          ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
    254266
    255267    // Internal guest directory representation.
     
    259271        Bstr                        mFilter;
    260272        ULONG                       mFlags;
    261         /** Associated PID of started vbox_ls tool. */
     273        /** Associated host PID of started vbox_ls tool. */
    262274        ULONG                       mPID;
    263275        GuestProcessStream          mStream;
    264 #if 0
    265         /** Next enetry in our stream objects vector
    266          *  to process. */
    267         uint32_t                    mNextEntry;
    268         /** The guest stream object containing all */
    269         GuestCtrlStreamObjects      mStream;
    270 #endif
    271276    } VBOXGUESTCTRL_DIRECTORY, *PVBOXGUESTCTRL_DIRECTORY;
    272277    typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY > GuestDirectoryMap;
     
    280285     * Handler for guest execution control notifications.
    281286     */
    282     HRESULT handleErrorCompletion(int rc);
    283     HRESULT handleErrorHGCM(int rc);
     287    HRESULT setErrorCompletion(int rc);
     288    HRESULT setErrorFromProgress(ComPtr<IProgress> pProgress);
     289    HRESULT setErrorHGCM(int rc);
    284290# endif
    285291
     
    319325    /** Next upcoming context ID. */
    320326    volatile uint32_t mNextContextID;
     327    /** Next upcoming host PID */
     328    volatile uint32_t mNextHostPID;
    321329    /** Next upcoming directory handle ID. */
    322330    volatile uint32_t mNextDirectoryID;
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r40574 r40685  
    158158
    159159/**
     160 * Assigns a host PID to a specified context.
     161 * Does not do locking!
     162 *
     163 * @param   uContextID
     164 * @param   uHostPID
     165 */
     166int Guest::callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID)
     167{
     168    AssertReturn(uContextID, VERR_INVALID_PARAMETER);
     169    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
     170
     171    int rc = VINF_SUCCESS;
     172
     173    CallbackMapIter it = mCallbackMap.find(uContextID);
     174    if (it == mCallbackMap.end())
     175        return VERR_NOT_FOUND;
     176
     177    it->second.uHostPID = uHostPID;
     178
     179    return VINF_SUCCESS;
     180}
     181
     182/**
    160183 * Destroys the formerly allocated callback data. The callback then
    161184 * needs to get removed from the callback map via callbackRemove().
     
    211234}
    212235
     236/**
     237 * Frees the user data (actual context data) of a callback.
     238 * Does not do locking!
     239 *
     240 * @param   pvData              Data to free.
     241 */
    213242void Guest::callbackFreeUserData(void *pvData)
    214243{
     
    218247        pvData = NULL;
    219248    }
     249}
     250
     251/**
     252 * Retrieves the (generated) host PID of a given callback.
     253 *
     254 * @return  The host PID, if found, 0 otherwise.
     255 * @param   uContextID              Context ID to lookup host PID for.
     256 * @param   puHostPID               Where to store the host PID.
     257 */
     258uint32_t Guest::callbackGetHostPID(uint32_t uContextID)
     259{
     260    AssertReturn(uContextID, VERR_INVALID_PARAMETER);
     261
     262    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     263
     264    CallbackMapIterConst it = mCallbackMap.find(uContextID);
     265    if (it == mCallbackMap.end())
     266        return 0;
     267
     268    return it->second.uHostPID;
    220269}
    221270
     
    256305void* Guest::callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData)
    257306{
    258     AssertReturn(uContextID, NULL);
     307    /* uContextID can be 0. */
    259308    /* pcbData is optional. */
    260309
     
    326375bool Guest::callbackIsCanceled(uint32_t uContextID)
    327376{
    328     AssertReturn(uContextID, true);
     377    if (!uContextID)
     378        return true; /* If no context ID given then take a shortcut. */
    329379
    330380    ComPtr<IProgress> pProgress;
     
    468518            else
    469519            {
    470 
    471520                hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */,
    472521                                                COM_IIDOF(IGuest),
     
    492541
    493542/**
    494  * TODO
     543 * Notifies all callbacks which are assigned to a certain guest PID to set a certain
     544 * return/error code and an optional (error) message.
    495545 *
    496546 * @return  IPRT status code.
    497  * @param   uPID
    498  * @param   iRC
    499  * @param   pszMessage
     547 * @param   uGuestPID               Guest PID to find all callbacks for.
     548 * @param   iRC                     Return (error) code to set for the found callbacks.
     549 * @param   pszMessage              Optional (error) message to set.
    500550 */
    501 int Guest::callbackNotifyAllForPID(uint32_t uPID, int iRC, const char *pszMessage)
    502 {
    503     AssertReturn(uPID, VERR_INVALID_PARAMETER);
     551int Guest::callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage)
     552{
     553    AssertReturn(uGuestPID, VERR_INVALID_PARAMETER);
    504554
    505555    int vrc = VINF_SUCCESS;
     
    522572                PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it->second.pvData;
    523573                AssertPtr(pItData);
    524                 if (pItData->u32PID == uPID)
     574                if (pItData->u32PID == uGuestPID)
    525575                    vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    526576                break;
     
    534584                PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData;
    535585                AssertPtr(pItData);
    536                 if (pItData->u32PID == uPID)
     586                if (pItData->u32PID == uGuestPID)
    537587                    vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    538588                break;
     
    712762
    713763    uint32_t uContextID = pData->hdr.u32ContextID;
    714     Assert(uContextID);
     764    /* The context ID might be 0 in case the guest was not able to fetch
     765     * actual command. So we can't do much now but report an error. */
    715766
    716767    /* Scope write locks as much as possible. */
     
    744795        /* Handle process map. This needs to be done first in order to have a valid
    745796         * map in case some callback gets notified a bit below. */
     797
     798        uint32_t uHostPID = 0;
    746799
    747800        /* Note: PIDs never get removed here in case the guest process signalled its
     
    751804        if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
    752805        {
     806            uHostPID = callbackGetHostPID(uContextID);
     807            Assert(uHostPID);
     808
    753809            switch (pData->u32Status)
    754810            {
     
    756812                case PROC_STS_TES:
    757813                case PROC_STS_TOK:
    758                     vrc = processSetStatus(pData->u32PID,
     814                    vrc = processSetStatus(uHostPID, pData->u32PID,
    759815                                           (ExecuteProcessStatus_T)pData->u32Status,
    760                                            0 /* Exit code. */, pData->u32Flags);
     816                                           0 /* Exit code */, pData->u32Flags);
    761817                    break;
    762818                /* Interprete u32Flags as the guest process' exit code. */
    763819                default:
    764                     vrc = processSetStatus(pData->u32PID,
     820                    vrc = processSetStatus(uHostPID, pData->u32PID,
    765821                                           (ExecuteProcessStatus_T)pData->u32Status,
    766                                            pData->u32Flags /* Exit code. */, 0 /* Flags. */);
    767 
     822                                           pData->u32Flags /* Exit code */, 0 /* Flags */);
    768823                    break;
    769824            }
    770825        }
    771826
    772         /* Do progress handling. */
    773         switch (pData->u32Status)
    774         {
    775             case PROC_STS_STARTED:
    776                 vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
    777                 LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
    778                 break;
    779 
    780             case PROC_STS_TEN: /* Terminated normally. */
    781                 vrc = callbackNotifyComplete(uContextID);
    782                 LogRel(("Guest process (PID %u) exited normally\n", pData->u32PID)); /** @todo Add process name */
    783                 break;
    784 
    785             case PROC_STS_TEA: /* Terminated abnormally. */
    786                 LogRel(("Guest process (PID %u) terminated abnormally with exit code = %u\n",
    787                         pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    788                 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
    789                                     pData->u32Flags);
    790                 rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    791                 break;
    792 
    793             case PROC_STS_TES: /* Terminated through signal. */
    794                 LogRel(("Guest process (PID %u) terminated through signal with exit code = %u\n",
    795                         pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    796                 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
    797                                     pData->u32Flags);
    798                 rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    799                 break;
    800 
    801             case PROC_STS_TOK:
    802                 LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
    803                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
    804                 rcCallback = VERR_TIMEOUT;
    805                 break;
    806 
    807             case PROC_STS_TOA:
    808                 LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
    809                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
    810                 rcCallback = VERR_TIMEOUT;
    811                 break;
    812 
    813             case PROC_STS_DWN:
    814                 LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
    815                 /*
    816                  * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
    817                  * our progress object. This is helpful for waiters which rely on the success of our progress object
    818                  * even if the executed process was killed because the system/VBoxService is shutting down.
    819                  *
    820                  * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
    821                  */
    822                 if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
     827        if (RT_SUCCESS(vrc))
     828        {
     829            /* Do progress handling. */
     830            switch (pData->u32Status)
     831            {
     832                case PROC_STS_STARTED:
     833                    vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
     834                    LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
     835                    break;
     836
     837                case PROC_STS_TEN: /* Terminated normally. */
     838                    vrc = callbackNotifyComplete(uContextID);
     839                    LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n",
     840                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
     841                    break;
     842
     843                case PROC_STS_TEA: /* Terminated abnormally. */
     844                    LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n",
     845                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
     846                    errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
     847                                        pData->u32Flags);
     848                    rcCallback = VERR_GENERAL_FAILURE; /** @todo */
     849                    break;
     850
     851                case PROC_STS_TES: /* Terminated through signal. */
     852                    LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n",
     853                            pData->u32PID, pData->u32Flags)); /** @todo Add process name */
     854                    errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
     855                                        pData->u32Flags);
     856                    rcCallback = VERR_GENERAL_FAILURE; /** @todo */
     857                    break;
     858
     859                case PROC_STS_TOK:
     860                    LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
     861                    errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
     862                    rcCallback = VERR_TIMEOUT;
     863                    break;
     864
     865                case PROC_STS_TOA:
     866                    LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
     867                    errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
     868                    rcCallback = VERR_TIMEOUT;
     869                    break;
     870
     871                case PROC_STS_DWN:
     872                    LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
     873                    /*
     874                     * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
     875                     * our progress object. This is helpful for waiters which rely on the success of our progress object
     876                     * even if the executed process was killed because the system/VBoxService is shutting down.
     877                     *
     878                     * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
     879                     */
     880                    if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
     881                    {
     882                        vrc = callbackNotifyComplete(uContextID);
     883                    }
     884                    else
     885                    {
     886                        errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
     887                        rcCallback = VERR_CANCELLED;
     888                    }
     889                    break;
     890
     891                case PROC_STS_ERROR:
    823892                {
    824                     vrc = callbackNotifyComplete(uContextID);
     893                    Utf8Str errDetail;
     894                    if (pData->u32PID)
     895                    {
     896                        errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"),
     897                                               pData->u32PID, pData->u32Flags);
     898                    }
     899                    else
     900                    {
     901                        switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */
     902                        {
     903                            case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
     904                                errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest"));
     905                                break;
     906
     907                            case VERR_PATH_NOT_FOUND:
     908                                errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest"));
     909                                break;
     910
     911                            case VERR_BAD_EXE_FORMAT:
     912                                errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest"));
     913                                break;
     914
     915                            case VERR_AUTHENTICATION_FAILURE:
     916                                errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest"));
     917                                break;
     918
     919                            case VERR_TIMEOUT:
     920                                errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time"));
     921                                break;
     922
     923                            case VERR_CANCELLED:
     924                                errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled"));
     925                                break;
     926
     927                            case VERR_PERMISSION_DENIED:
     928                                errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials"));
     929                                break;
     930
     931                            case VERR_MAX_PROCS_REACHED:
     932                                errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached"));
     933                                break;
     934
     935                            default:
     936                                errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags);
     937                                break;
     938                        }
     939                    }
     940
     941                    errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail;
     942                    rcCallback = pData->u32Flags; /* Report back guest rc. */
     943
     944                    LogRel((errMsg.c_str()));
     945
     946                    break;
    825947                }
    826                 else
    827                 {
    828                     errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
    829                     rcCallback = VERR_CANCELLED;
    830                 }
    831                 break;
    832 
    833             case PROC_STS_ERROR:
    834                 if (pData->u32PID)
    835                 {
    836                     LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n",
    837                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    838                 }
    839                 else
    840                 {
    841                     switch (pData->u32Flags)
    842                     {
    843                         case VERR_MAX_PROCS_REACHED:
    844                             LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n"));
    845                             break;
    846 
    847                         default:
    848                             LogRel(("Guest process could not be started because of rc=%Rrc\n",
    849                                     pData->u32Flags));
    850                     }
    851 
    852                 }
    853                 errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pData->u32Flags);
    854                 rcCallback = pData->u32Flags; /* Report back rc. */
    855                 break;
    856 
    857             default:
    858                 vrc = VERR_INVALID_PARAMETER;
    859                 break;
     948
     949                default:
     950                    vrc = VERR_INVALID_PARAMETER;
     951                    break;
     952            }
    860953        }
    861954    }
     
    871964        AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n"));
    872965
    873         /* Notify all callbacks which are still waiting on something
    874          * which is related to the current PID. */
    875         if (pData->u32PID)
    876         {
    877             int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
     966        if (uContextID)
     967        {
     968            /* Notify all callbacks which are still waiting on something
     969             * which is related to the current PID. */
     970            if (pData->u32PID)
     971            {
     972                int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
     973                if (RT_FAILURE(rc2))
     974                {
     975                    LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
     976                                 pData->u32PID));
     977                    if (RT_SUCCESS(vrc))
     978                        vrc = rc2;
     979                }
     980            }
     981
     982            /* Let the caller know what went wrong ... */
     983            int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
    878984            if (RT_FAILURE(rc2))
    879985            {
    880                 LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
    881                              pData->u32PID));
     986                LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
     987                             uContextID, pData->u32PID));
    882988                if (RT_SUCCESS(vrc))
    883989                    vrc = rc2;
    884990            }
    885991        }
    886 
    887         /* Let the caller know what went wrong ... */
    888         int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
    889         if (RT_FAILURE(rc2))
    890         {
    891             LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
    892                          uContextID, pData->u32PID));
    893             if (RT_SUCCESS(vrc))
    894                 vrc = rc2;
    895         }
     992        else
     993        {
     994            /* Since we don't know which context exactly failed all we can do is to shutdown
     995             * all contexts ... */
     996            errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"),
     997                                pData->u32Flags);
     998
     999            /* Cancel all callbacks. */
     1000            CallbackMapIter it;
     1001            for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
     1002            {
     1003                int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
     1004                                           errMsg.c_str());
     1005                AssertRC(rc2);
     1006            }
     1007        }
     1008
    8961009        LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
    8971010                     uContextID, pData->u32Status, errMsg.c_str()));
     
    10111124}
    10121125
     1126uint32_t Guest::processGetGuestPID(uint32_t uHostPID)
     1127{
     1128    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
     1129
     1130    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1131
     1132    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
     1133    if (it == mGuestProcessMap.end())
     1134        return 0;
     1135
     1136    return it->second.mGuestPID;
     1137}
     1138
    10131139/**
    10141140 * Gets guest process information. Removes the process from the map
     
    10161142 *
    10171143 * @return  IPRT status code.
    1018  * @param   u32PID                  PID of process to get status for.
     1144 * @param   uHostPID                Host PID of guest process to get status for.
    10191145 * @param   pProcess                Where to store the process information. Optional.
    10201146 * @param   fRemove                 Flag indicating whether to remove the
     
    10221148 *                                  exited/terminated.
    10231149 */
    1024 int Guest::processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess,
     1150int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess,
    10251151                            bool fRemove)
    10261152{
    1027     AssertReturn(u32PID, VERR_INVALID_PARAMETER);
     1153    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    10281154
    10291155    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    10301156
    1031     GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
     1157    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    10321158    if (it != mGuestProcessMap.end())
    10331159    {
    10341160        if (pProcess)
    10351161        {
     1162            pProcess->mGuestPID = it->second.mGuestPID;
    10361163            pProcess->mStatus   = it->second.mStatus;
    10371164            pProcess->mExitCode = it->second.mExitCode;
     
    10391166        }
    10401167
    1041         /* If the is marked as stopped/terminated
    1042          * remove it from the map. */
     1168        /* Only remove processes from our map when they signalled their final
     1169         * status. */
    10431170        if (   fRemove
    1044             && it->second.mStatus != ExecuteProcessStatus_Started)
     1171            && (   it->second.mStatus != ExecuteProcessStatus_Undefined
     1172                && it->second.mStatus != ExecuteProcessStatus_Started))
    10451173        {
    10461174            mGuestProcessMap.erase(it);
     
    10531181}
    10541182
    1055 int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
    1056 {
    1057     AssertReturn(u32PID, VERR_INVALID_PARAMETER);
     1183/**
     1184 * Sets the current status of a guest process.
     1185 *
     1186 * @return  IPRT status code.
     1187 * @param   uHostPID                Host PID of guest process to set status (and guest PID) for.
     1188 * @param   uGuestPID               Guest PID to assign to the host PID.
     1189 * @param   enmStatus               Current status to set.
     1190 * @param   uExitCode               Exit code (if any).
     1191 * @param   uFlags                  Additional flags.
     1192 */
     1193int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
     1194                            ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
     1195{
     1196    AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
     1197    /* Assigning a guest PID is optional. */
    10581198
    10591199    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    10601200
    1061     GuestProcessMapIter it = mGuestProcessMap.find(u32PID);
     1201    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    10621202    if (it != mGuestProcessMap.end())
    10631203    {
    1064         it->second.mStatus = enmStatus;
     1204        it->second.mGuestPID = uGuestPID;
     1205        it->second.mStatus   = enmStatus;
    10651206        it->second.mExitCode = uExitCode;
    1066         it->second.mFlags = uFlags;
     1207        it->second.mFlags    = uFlags;
    10671208    }
    10681209    else
     
    10701211        VBOXGUESTCTRL_PROCESS process;
    10711212
    1072         process.mStatus = enmStatus;
     1213        /* uGuestPID is optional -- the caller could call this function
     1214         * before the guest process actually was started and a (valid) guest PID
     1215         * was returned. */
     1216        process.mGuestPID = uGuestPID;
     1217        process.mStatus   = enmStatus;
    10731218        process.mExitCode = uExitCode;
    1074         process.mFlags = uFlags;
    1075 
    1076         mGuestProcessMap[u32PID] = process;
     1219        process.mFlags    = uFlags;
     1220
     1221        mGuestProcessMap[uHostPID] = process;
    10771222    }
    10781223
     
    10801225}
    10811226
    1082 HRESULT Guest::handleErrorCompletion(int rc)
     1227HRESULT Guest::setErrorCompletion(int rc)
    10831228{
    10841229    HRESULT hRC;
     
    10981243}
    10991244
    1100 HRESULT Guest::handleErrorHGCM(int rc)
     1245HRESULT Guest::setErrorFromProgress(ComPtr<IProgress> pProgress)
     1246{
     1247    BOOL fCompleted;
     1248    HRESULT rc = pProgress->COMGETTER(Completed)(&fCompleted);
     1249    ComAssertComRC(rc);
     1250
     1251    HRESULT rcProc = S_OK;
     1252    Utf8Str strError;
     1253
     1254    if (!fCompleted)
     1255    {
     1256        BOOL fCanceled;
     1257        rc = pProgress->COMGETTER(Canceled)(&fCanceled);
     1258        ComAssertComRC(rc);
     1259
     1260        strError = fCanceled ? Utf8StrFmt(Guest::tr("Process execution was canceled"))
     1261                             : Utf8StrFmt(Guest::tr("Process neither completed nor canceled; this shouldn't happen"));
     1262    }
     1263    else
     1264    {
     1265        rc = pProgress->COMGETTER(ResultCode)(&rcProc);
     1266        ComAssertComRC(rc);
     1267
     1268        if (FAILED(rcProc))
     1269        {
     1270            ProgressErrorInfo info(pProgress);
     1271            strError = info.getText();
     1272        }
     1273    }
     1274
     1275    if (FAILED(rcProc))
     1276    {
     1277        AssertMsg(!strError.isEmpty(), ("Error message must not be empty!\n"));
     1278        return setErrorInternal(rcProc,
     1279                                this->getClassIID(),
     1280                                this->getComponentName(),
     1281                                strError,
     1282                                false /* aWarning */,
     1283                                false /* aLogIt */);
     1284    }
     1285
     1286    return S_OK;
     1287}
     1288
     1289HRESULT Guest::setErrorHGCM(int rc)
    11011290{
    11021291    HRESULT hRC;
     
    11681357                                     IProgress **aProgress, ULONG *aPID)
    11691358{
    1170     ComPtr<IProgress> progressTool;
     1359    ComPtr<IProgress> pProgress;
    11711360    ULONG uPID;
    11721361    ULONG uFlags = ExecuteProcessFlag_Hidden;
     
    11741363        uFlags |= uFlagsToAdd;
    11751364
    1176     bool fWaitForOutput = false;
     1365    bool fParseOutput = false;
    11771366    if (   (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    11781367            && pObjStdOut)
     
    11801369            && pObjStdErr))
    11811370    {
    1182         fWaitForOutput = true;
    1183     }
    1184 
    1185     HRESULT rc = ExecuteProcess(aTool,
     1371        fParseOutput = true;
     1372    }
     1373
     1374    HRESULT hr = ExecuteProcess(aTool,
    11861375                                uFlags,
    11871376                                ComSafeArrayInArg(aArguments),
    11881377                                ComSafeArrayInArg(aEnvironment),
    11891378                                aUsername, aPassword,
    1190                                 0 /* No timeout. */,
    1191                                 &uPID, progressTool.asOutParam());
    1192     if (   SUCCEEDED(rc)
    1193         && fWaitForOutput)
    1194     {
    1195         BOOL fCompleted;
    1196         while (   SUCCEEDED(progressTool->COMGETTER(Completed)(&fCompleted))
    1197                && !fCompleted)
    1198         {
    1199             BOOL fCanceled;
    1200             rc = progressTool->COMGETTER(Canceled)(&fCanceled);
    1201             AssertComRC(rc);
    1202             if (fCanceled)
    1203             {
    1204                 rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1205                                    tr("%s was cancelled"), Utf8Str(aDescription).c_str());
    1206                 break;
    1207             }
    1208 
    1209             if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    1210                 && pObjStdOut)
    1211             {
    1212                 rc = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
    1213             }
    1214 
    1215             if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
    1216                 && pObjStdErr)
    1217             {
    1218                 rc = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
    1219             }
    1220 
    1221             if (FAILED(rc))
    1222                 break;
    1223         }
    1224     }
    1225 
    1226     if (SUCCEEDED(rc))
     1379                                0 /* No timeout */,
     1380                                &uPID, pProgress.asOutParam());
     1381    if (SUCCEEDED(hr))
     1382    {
     1383        /* Wait for tool being started. */
     1384        hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */,
     1385                                                   -1 /* No timeout */);
     1386    }
     1387
     1388    if (   SUCCEEDED(hr)
     1389        && !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly))
     1390    {
     1391        if (!fParseOutput)
     1392        {
     1393            if (   !(uFlags & ExecuteProcessFlag_WaitForStdOut)
     1394                && !(uFlags & ExecuteProcessFlag_WaitForStdErr))
     1395            {
     1396                hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */);
     1397            }
     1398        }
     1399        else
     1400        {
     1401            BOOL fCompleted;
     1402            while (   SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted))
     1403                   && !fCompleted)
     1404            {
     1405                BOOL fCanceled;
     1406                hr = pProgress->COMGETTER(Canceled)(&fCanceled);
     1407                AssertComRC(hr);
     1408                if (fCanceled)
     1409                {
     1410                    hr = setErrorNoLog(VBOX_E_IPRT_ERROR,
     1411                                       tr("%s was cancelled"), Utf8Str(aDescription).c_str());
     1412                    break;
     1413                }
     1414
     1415                if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
     1416                    && pObjStdOut)
     1417                {
     1418                    hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
     1419                }
     1420
     1421                if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
     1422                    && pObjStdErr)
     1423                {
     1424                    hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
     1425                }
     1426
     1427                if (FAILED(hr))
     1428                    break;
     1429            }
     1430        }
     1431    }
     1432
     1433    if (SUCCEEDED(hr))
    12271434    {
    12281435        if (aProgress)
    12291436        {
    12301437            /* Return the progress to the caller. */
    1231             progressTool.queryInterfaceTo(aProgress);
    1232         }
     1438            pProgress.queryInterfaceTo(aProgress);
     1439        }
     1440        else if (!pProgress.isNull())
     1441            pProgress.setNull();
    12331442
    12341443        if (aPID)
     
    12361445    }
    12371446
    1238     return rc;
    1239 }
    1240 
    1241 HRESULT Guest::executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout,
    1242                                     PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID)
    1243 {
    1244     AssertPtrReturn(pExecStatus, E_INVALIDARG);
    1245     AssertPtrReturn(puPID, E_INVALIDARG);
    1246 
    1247     HRESULT rc = S_OK;
    1248 
    1249     /* Did we get some status? */
    1250     switch (pExecStatus->u32Status)
    1251     {
    1252         case PROC_STS_STARTED:
    1253             /* Process is (still) running; get PID. */
    1254             *puPID = pExecStatus->u32PID;
    1255             break;
    1256 
    1257         /* In any other case the process either already
    1258          * terminated or something else went wrong, so no PID ... */
    1259         case PROC_STS_TEN: /* Terminated normally. */
    1260         case PROC_STS_TEA: /* Terminated abnormally. */
    1261         case PROC_STS_TES: /* Terminated through signal. */
    1262         case PROC_STS_TOK:
    1263         case PROC_STS_TOA:
    1264         case PROC_STS_DWN:
    1265             /*
    1266              * Process (already) ended, but we want to get the
    1267              * PID anyway to retrieve the output in a later call.
    1268              */
    1269             *puPID = pExecStatus->u32PID;
    1270             break;
    1271 
    1272         case PROC_STS_ERROR:
    1273             {
    1274                 int vrc = pExecStatus->u32Flags; /* u32Flags member contains IPRT error code. */
    1275                 if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
    1276                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1277                                        tr("The file '%s' was not found on guest"), pszCommand);
    1278                 else if (vrc == VERR_PATH_NOT_FOUND)
    1279                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1280                                        tr("The path to file '%s' was not found on guest"), pszCommand);
    1281                 else if (vrc == VERR_BAD_EXE_FORMAT)
    1282                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1283                                        tr("The file '%s' is not an executable format on guest"), pszCommand);
    1284                 else if (vrc == VERR_AUTHENTICATION_FAILURE)
    1285                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1286                                        tr("The specified user '%s' was not able to logon on guest"), pszUser);
    1287                 else if (vrc == VERR_TIMEOUT)
    1288                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1289                                        tr("The guest did not respond within time (%ums)"), ulTimeout);
    1290                 else if (vrc == VERR_CANCELLED)
    1291                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1292                                        tr("The execution operation was canceled"));
    1293                 else if (vrc == VERR_PERMISSION_DENIED)
    1294                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1295                                        tr("Invalid user/password credentials"));
    1296                 else if (vrc == VERR_MAX_PROCS_REACHED)
    1297                     rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1298                                        tr("Concurrent guest process limit is reached"));
    1299                 else
    1300                 {
    1301                     if (pExecStatus && pExecStatus->u32Status == PROC_STS_ERROR)
    1302                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1303                                            tr("Process could not be started: %Rrc"), pExecStatus->u32Flags);
    1304                     else
    1305                         rc = setErrorNoLog(E_UNEXPECTED,
    1306                                            tr("The service call failed with error %Rrc"), vrc);
    1307                 }
    1308             }
    1309             break;
    1310 
    1311         case PROC_STS_UNDEFINED: /* . */
    1312             rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1313                                tr("The operation did not complete within time"));
    1314             break;
    1315 
    1316         default:
    1317             AssertReleaseMsgFailed(("Process (PID %u) reported back an undefined state!\n",
    1318                                     pExecStatus->u32PID));
    1319             rc = E_UNEXPECTED;
    1320             break;
    1321     }
    1322 
    1323     return rc;
     1447    return hr;
    13241448}
    13251449
     
    13551479 * @param   aPID                    PID of process to get the output from.
    13561480 * @param   aFlags                  Which stream to drain (stdout or stderr).
    1357  * @param   stream                  Reference to guest process stream to fill.
     1481 * @param   pStream                 Pointer to guest process stream to fill. If NULL,
     1482 *                                  data goes to /dev/null.
    13581483 */
    1359 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream &stream)
     1484int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream *pStream)
    13601485{
    13611486    AssertReturn(aPID, VERR_INVALID_PARAMETER);
     1487    /* pStream is optional. */
    13621488
    13631489    int rc = VINF_SUCCESS;
     
    13701496        if (RT_SUCCESS(rc))
    13711497        {
    1372             if (aData.size())
    1373             {
    1374                 rc = stream.AddData(aData.raw(), aData.size());
     1498            if (   pStream
     1499                && aData.size())
     1500            {
     1501                rc = pStream->AddData(aData.raw(), aData.size());
    13751502                if (RT_UNLIKELY(RT_FAILURE(rc)))
    13761503                    break;
     
    13871514            }
    13881515
    1389             /* In any case remove the (terminated/broken) process from
    1390              * the process table. */
    1391             int rc2 = processGetStatus(aPID, NULL /* PVBOXGUESTCTRL_PROCESS */,
    1392                                        true /* Remove from table */);
    1393             AssertRC(rc2);
    13941516            break;
    13951517        }
     
    14431565                    LogFlowFunc(("Got %ld bytes of additional data\n", aData.size()));
    14441566
     1567                    if (RT_FAILURE(rc))
     1568                    {
     1569                        if (rc == VERR_BROKEN_PIPE)
     1570                             rc = VINF_SUCCESS; /* No more data because process already ended. */
     1571                        break;
     1572                    }
     1573
    14451574                    if (aData.size())
    14461575                    {
     
    15331662{
    15341663    GuestProcessStream stream;
    1535     int rc = executeStreamDrain(ulPID, ulFlags, stream);
     1664    int rc = executeStreamDrain(ulPID, ulFlags, &stream);
    15361665    if (RT_SUCCESS(rc))
    15371666    {
     
    15711700 *                                  exit code. Optional.
    15721701 */
    1573 HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS,
    1574                                   ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode)
     1702HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS)
    15751703{
    15761704    HRESULT rc = S_OK;
     
    15921720        if (FAILED(rc))
    15931721            rc = setError(VBOX_E_IPRT_ERROR,
    1594                           tr("Waiting for guest process to end failed (%Rhrc)"),
    1595                           rc);
    1596     }
    1597 
    1598     if (SUCCEEDED(rc))
    1599     {
    1600         ULONG uExitCode, uRetFlags;
    1601         ExecuteProcessStatus_T enmStatus;
    1602         HRESULT hRC = GetProcessStatus(uPID, &uExitCode, &uRetFlags, &enmStatus);
    1603         if (FAILED(hRC))
    1604             return hRC;
    1605 
    1606         if (pRetStatus)
    1607             *pRetStatus = enmStatus;
    1608         if (puRetExitCode)
    1609             *puRetExitCode = uExitCode;
    1610         /** @todo Flags? */
     1722                          tr("Waiting for guest process to end failed (%Rhrc)"), rc);
    16111723    }
    16121724
     
    17071819        Utf8Str Utf8UserName(aUsername);
    17081820        Utf8Str Utf8Password(aPassword);
     1821        uint32_t uHostPID = 0;
     1822
    17091823        if (RT_SUCCESS(vrc))
    17101824        {
     
    17951909            if (RT_SUCCESS(vrc))
    17961910            {
    1797                 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
     1911                AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    17981912
    17991913                /*
    1800                  * Wait for the HGCM low level callback until the process
    1801                  * has been started (or something went wrong). This is necessary to
    1802                  * get the PID.
     1914                 * Generate a host-driven PID so that we immediately can return to the caller and
     1915                 * don't need to wait until the guest started the desired process to return the
     1916                 * PID generated by the guest OS.
     1917                 *
     1918                 * The guest PID will later be mapped to the host PID for later lookup.
    18031919                 */
    1804 
    1805                 PCALLBACKDATAEXECSTATUS pExecStatus = NULL;
    1806 
    1807                 /*
    1808                  * Wait for the first stage (=0) to complete (that is starting the process).
    1809                  */
    1810                 vrc = callbackWaitForCompletion(uContextID, 0 /* Stage */, aTimeoutMS);
     1920                vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */
     1921
     1922                uint32_t uTries = 0;
     1923                for (;;)
     1924                {
     1925                    /* Create a new context ID ... */
     1926                    uHostPID = ASMAtomicIncU32(&mNextHostPID);
     1927                    if (uHostPID == UINT32_MAX)
     1928                        ASMAtomicUoWriteU32(&mNextHostPID, 1000);
     1929                    /* Is the host PID already used? Try next PID ... */
     1930                    GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
     1931                    if (it == mGuestProcessMap.end())
     1932                    {
     1933                        /* Host PID not used (anymore), we're done here ... */
     1934                        vrc = VINF_SUCCESS;
     1935                        break;
     1936                    }
     1937
     1938                    if (++uTries == UINT32_MAX)
     1939                        break; /* Don't try too hard. */
     1940                }
     1941
    18111942                if (RT_SUCCESS(vrc))
    1812                 {
    1813                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
    1814                                               (void**)&pExecStatus, NULL /* Don't need the size. */);
    1815                     if (RT_SUCCESS(vrc))
    1816                     {
    1817                         rc = executeProcessResult(Utf8Command.c_str(), Utf8UserName.c_str(), aTimeoutMS,
    1818                                                   pExecStatus, aPID);
    1819                         callbackFreeUserData(pExecStatus);
    1820                     }
    1821                     else
    1822                     {
    1823                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1824                                            tr("Unable to retrieve process execution status data"));
    1825                     }
    1826                 }
    1827                 else
    1828                     rc = handleErrorCompletion(vrc);
    1829 
    1830                 /*
    1831                  * Do *not* remove the callback yet - we might wait with the IProgress object on something
    1832                  * else (like end of process) ...
    1833                  */
     1943                    vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */,
     1944                                           ExecuteProcessStatus_Undefined /* Process not started yet */,
     1945                                           0 /* uExitCode */, 0 /* uFlags */);
     1946
     1947                if (RT_SUCCESS(vrc))
     1948                    vrc = callbackAssignHostPID(uContextID, uHostPID);
    18341949            }
    18351950            else
    1836                 rc = handleErrorHGCM(vrc);
     1951                rc = setErrorHGCM(vrc);
    18371952
    18381953            for (unsigned i = 0; i < uNumArgs; i++)
    18391954                RTMemFree(papszArgv[i]);
    18401955            RTMemFree(papszArgv);
     1956
     1957            if (RT_FAILURE(vrc))
     1958                rc = VBOX_E_IPRT_ERROR;
    18411959        }
    18421960
    18431961        if (SUCCEEDED(rc))
    18441962        {
     1963            /* Return host PID. */
     1964            *aPID = uHostPID;
     1965
    18451966            /* Return the progress to the caller. */
    18461967            pProgress.queryInterfaceTo(aProgress);
     
    18972018            if (process.mStatus != ExecuteProcessStatus_Started)
    18982019                rc = setError(VBOX_E_IPRT_ERROR,
    1899                               Guest::tr("Cannot inject input to not running process (PID %u)"), aPID);
     2020                              Guest::tr("Cannot inject input to a not running process (PID %u)"), aPID);
    19002021        }
    19012022        else
    19022023            rc = setError(VBOX_E_IPRT_ERROR,
    1903                           Guest::tr("Cannot inject input to non-existent process (PID %u)"), aPID);
     2024                          Guest::tr("Cannot inject input to a non-existent process (PID %u)"), aPID);
    19042025
    19052026        if (RT_SUCCESS(vrc))
    19062027        {
    19072028            uint32_t uContextID = 0;
     2029
     2030            uint32_t uGuestPID = processGetGuestPID(aPID);
     2031            Assert(uGuestPID);
    19082032
    19092033            /*
     
    19352059
    19362060                /* Save PID + output flags for later use. */
    1937                 pData->u32PID = aPID;
     2061                pData->u32PID   = uGuestPID;
    19382062                pData->u32Flags = aFlags;
    19392063            }
     
    19502074                int i = 0;
    19512075                paParms[i++].setUInt32(uContextID);
    1952                 paParms[i++].setUInt32(aPID);
     2076                paParms[i++].setUInt32(uGuestPID);
    19532077                paParms[i++].setUInt32(aFlags);
    19542078                paParms[i++].setPointer(sfaData.raw(), cbSize);
     
    19742098                                                   i, paParms);
    19752099                        if (RT_FAILURE(vrc))
    1976                             rc = handleErrorHGCM(vrc);
     2100                            rc = setErrorHGCM(vrc);
    19772101                    }
    19782102                }
     
    20322156                }
    20332157                else
    2034                     rc = handleErrorCompletion(vrc);
     2158                    rc = setErrorCompletion(vrc);
    20352159            }
    20362160
     
    21072231        else if (proc.mStatus != ExecuteProcessStatus_Started)
    21082232        {
    2109             /* If the process is still in the process table but does not run anymore
    2110              * don't remove it but report back an appropriate error. */
     2233            /* If the process is already or still in the process table but does not run yet
     2234             * (or anymore) don't remove it but report back an appropriate error. */
    21112235            vrc = VERR_BROKEN_PIPE;
    21122236            /* Not getting any output is fine, so don't report an API error (rc)
     
    21442268                uHandleID = OUTPUT_HANDLE_ID_STDERR;
    21452269
     2270            uint32_t uGuestPID = processGetGuestPID(aPID);
     2271            Assert(uGuestPID);
     2272
    21462273            /** @todo Use a buffer for next iteration if returned data is too big
    21472274             *        for current read.
     
    21542281
    21552282                /* Save PID + output flags for later use. */
    2156                 pData->u32PID = aPID;
     2283                pData->u32PID   = uGuestPID;
    21572284                pData->u32Flags = aFlags;
    21582285            }
     
    21662293                int i = 0;
    21672294                paParms[i++].setUInt32(uContextID);
    2168                 paParms[i++].setUInt32(aPID);
     2295                paParms[i++].setUInt32(uGuestPID);
    21692296                paParms[i++].setUInt32(uHandleID);
    21702297                paParms[i++].setUInt32(0 /* Flags, none set yet */);
     
    22492376                }
    22502377                else
    2251                     rc = handleErrorCompletion(vrc);
     2378                    rc = setErrorCompletion(vrc);
    22522379            }
    22532380            else
    2254                 rc = handleErrorHGCM(vrc);
     2381                rc = setErrorHGCM(vrc);
    22552382
    22562383            {
     
    24272554    HRESULT rc = S_OK;
    24282555
    2429     ComObjPtr<Progress> progress;
     2556    ComObjPtr<Progress> pProgress;
    24302557    try
    24312558    {
    24322559        /* Create the progress object. */
    2433         progress.createObject();
    2434 
    2435         rc = progress->init(static_cast<IGuest*>(this),
    2436                             Bstr(tr("Copying file from host to guest")).raw(),
    2437                             TRUE /* aCancelable */);
     2560        pProgress.createObject();
     2561
     2562        rc = pProgress->init(static_cast<IGuest*>(this),
     2563                             Bstr(tr("Copying file from host to guest")).raw(),
     2564                             TRUE /* aCancelable */);
    24382565        if (FAILED(rc)) throw rc;
    24392566
    24402567        /* Initialize our worker task. */
    2441         GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, progress);
     2568        GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, pProgress);
    24422569        AssertPtr(pTask);
    24432570        std::auto_ptr<GuestTask> task(pTask);
     
    24652592    {
    24662593        /* Return progress to the caller. */
    2467         progress.queryInterfaceTo(aProgress);
     2594        pProgress.queryInterfaceTo(aProgress);
    24682595    }
    24692596    return rc;
  • trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp

    r39905 r40685  
    9999    }
    100100
    101     HRESULT rc = S_OK;
     101    HRESULT hr;
    102102    try
    103103    {
     
    122122        args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
    123123
    124         rc = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(),
     124        ULONG uPID;
     125        ComPtr<IProgress> pProgress;
     126        hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(),
    125127                                   ComSafeArrayAsInParam(args),
    126128                                   ComSafeArrayAsInParam(env),
     
    128130                                   ExecuteProcessFlag_None,
    129131                                   NULL, NULL,
    130                                    NULL /* Progress */, NULL /* PID */);
     132                                   pProgress.asOutParam(), &uPID);
     133        if (SUCCEEDED(hr))
     134        {
     135            hr = setErrorFromProgress(pProgress);
     136            pProgress.setNull();
     137        }
    131138    }
    132139    catch (std::bad_alloc &)
    133140    {
    134         rc = E_OUTOFMEMORY;
    135     }
    136     return rc;
     141        hr = E_OUTOFMEMORY;
     142    }
     143    return hr;
    137144}
    138145
     
    299306    {
    300307#ifdef DEBUG
    301         it->second.mStream.Dump("/tmp/stream.txt");
     308        it->second.mStream.Dump("c:\\temp\\stream.txt");
    302309#endif
    303310        return executeStreamGetNextBlock(it->second.mPID,
     
    482489         */
    483490        ULONG uPID;
     491        ComPtr<IProgress> pProgress;
    484492        GuestCtrlStreamObjects stdOut;
    485493        hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(),
     
    489497                                   ExecuteProcessFlag_WaitForStdOut,
    490498                                   &stdOut, NULL /* stdErr */,
    491                                    NULL /* Progress */, &uPID);
     499                                   pProgress.asOutParam(), &uPID);
    492500        if (SUCCEEDED(hr))
    493501        {
    494             int rc = VINF_SUCCESS;
    495             if (stdOut.size())
     502            hr = setErrorFromProgress(pProgress);
     503            if (SUCCEEDED(hr))
    496504            {
    497                 const char *pszFsType = stdOut[0].GetString("ftype");
    498                 if (!pszFsType) /* Attribute missing? */
    499                      rc = VERR_PATH_NOT_FOUND;
    500                 if (   RT_SUCCESS(rc)
    501                     && strcmp(pszFsType, "d")) /* Directory? */
     505                int rc = VINF_SUCCESS;
     506                if (stdOut.size())
    502507                {
    503                      rc = VERR_PATH_NOT_FOUND;
    504                      /* This is not critical for Main, so don't set hr --
    505                       * we will take care of rc then. */
     508                    const char *pszFsType = stdOut[0].GetString("ftype");
     509                    if (!pszFsType) /* Attribute missing? */
     510                         rc = VERR_PATH_NOT_FOUND;
     511                    if (   RT_SUCCESS(rc)
     512                        && strcmp(pszFsType, "d")) /* Directory? */
     513                    {
     514                         rc = VERR_PATH_NOT_FOUND;
     515                         /* This is not critical for Main, so don't set hr --
     516                          * we will take care of rc then. */
     517                    }
     518                    if (   RT_SUCCESS(rc)
     519                        && aObjInfo) /* Do we want object details? */
     520                    {
     521                        rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0],
     522                                                         aObjInfo, enmAddAttribs);
     523                    }
    506524                }
    507                 if (   RT_SUCCESS(rc)
    508                     && aObjInfo) /* Do we want object details? */
    509                 {
    510                     rc = executeStreamQueryFsObjInfo(aDirectory, stdOut[0],
    511                                                      aObjInfo, enmAddAttribs);
    512                 }
     525                else
     526                    rc = VERR_NO_DATA;
     527
     528                if (pRC)
     529                    *pRC = rc;
    513530            }
    514             else
    515                 rc = VERR_NO_DATA;
    516 
    517             if (pRC)
    518                 *pRC = rc;
     531
     532            pProgress.setNull();
    519533        }
    520534    }
  • trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp

    r39850 r40685  
    132132        ULONG uPID;
    133133        GuestCtrlStreamObjects stdOut;
     134        ComPtr<IProgress> pProgress;
    134135        hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying file information").raw(),
    135136                                   ComSafeArrayAsInParam(args),
     
    138139                                   ExecuteProcessFlag_WaitForStdOut,
    139140                                   &stdOut, NULL,
    140                                    NULL /* Progress */, &uPID);
     141                                   pProgress.asOutParam(), &uPID);
    141142        if (SUCCEEDED(hr))
    142143        {
    143             int rc = VINF_SUCCESS;
    144             if (stdOut.size())
     144            hr = setErrorFromProgress(pProgress);
     145            if (SUCCEEDED(hr))
    145146            {
     147                int rc = VINF_SUCCESS;
     148                if (stdOut.size())
     149                {
    146150#if 0
    147                 /* Dump the parsed stream contents to Log(). */
    148                 stdOut[0].Dump();
    149 #endif
    150                 const char *pszFsType = stdOut[0].GetString("ftype");
    151                 if (!pszFsType) /* Was an object found at all? */
    152                     rc = VERR_FILE_NOT_FOUND;
    153                 if (   RT_SUCCESS(rc)
    154                     && strcmp(pszFsType, "-")) /* Regular file? */
    155                 {
    156                     rc = VERR_FILE_NOT_FOUND;
    157                     /* This is not critical for Main, so don't set hr --
    158                      * we will take care of rc then. */
     151                    /* Dump the parsed stream contents to Log(). */
     152                    stdOut[0].Dump();
     153#endif
     154                    const char *pszFsType = stdOut[0].GetString("ftype");
     155                    if (!pszFsType) /* Was an object found at all? */
     156                        rc = VERR_FILE_NOT_FOUND;
     157                    if (   RT_SUCCESS(rc)
     158                        && strcmp(pszFsType, "-")) /* Regular file? */
     159                    {
     160                        rc = VERR_FILE_NOT_FOUND;
     161                        /* This is not critical for Main, so don't set hr --
     162                         * we will take care of rc then. */
     163                    }
     164                    if (   RT_SUCCESS(rc)
     165                        && aObjInfo) /* Do we want object details? */
     166                    {
     167                        rc = executeStreamQueryFsObjInfo(aFile, stdOut[0],
     168                                                         aObjInfo, enmAddAttribs);
     169                    }
    159170                }
    160                 if (   RT_SUCCESS(rc)
    161                     && aObjInfo) /* Do we want object details? */
    162                 {
    163                     rc = executeStreamQueryFsObjInfo(aFile, stdOut[0],
    164                                                      aObjInfo, enmAddAttribs);
    165                 }
     171                else
     172                    rc = VERR_NO_DATA;
     173
     174                if (pRC)
     175                    *pRC = rc;
    166176            }
    167             else
    168                 rc = VERR_NO_DATA;
    169 
    170             if (pRC)
    171                 *pRC = rc;
     177
     178            pProgress.setNull();
    172179        }
    173180    }
  • trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp

    r40579 r40685  
    279279                        BOOL fCompleted = FALSE;
    280280                        BOOL fCanceled = FALSE;
     281
    281282                        uint64_t cbTransferedTotal = 0;
     283                        uint64_t cbToRead = cbSize;
    282284
    283285                        SafeArray<BYTE> aInputData(_64K);
     
    285287                               && !fCompleted)
    286288                        {
    287                             size_t cbToRead = cbSize;
    288289                            size_t cbRead = 0;
    289290                            if (cbSize) /* If we have nothing to read, take a shortcut. */
     
    334335                            }
    335336
    336                             ULONG uBytesWritten = 0;
     337                            ULONG cbBytesWritten = 0;
    337338                            rc = pGuest->SetProcessInput(uPID, uFlags,
    338339                                                         0 /* Infinite timeout */,
    339                                                          ComSafeArrayAsInParam(aInputData), &uBytesWritten);
     340                                                         ComSafeArrayAsInParam(aInputData), &cbBytesWritten);
    340341                            if (FAILED(rc))
    341342                            {
     
    346347                            Assert(cbRead <= cbToRead);
    347348                            Assert(cbToRead >= cbRead);
    348                             cbToRead -= cbRead;
    349 
    350                             cbTransferedTotal += uBytesWritten;
     349                            /* Only subtract bytes reported written by the guest. */
     350                            cbToRead -= cbBytesWritten;
     351
     352                            cbTransferedTotal += cbBytesWritten;
    351353                            Assert(cbTransferedTotal <= cbSize);
    352354                            aTask->pProgress->SetCurrentOperationProgress((ULONG)(cbTransferedTotal * 100 / cbSize));
     
    377379                             * canceled or we simply got all stuff transferred.
    378380                             */
    379                             ExecuteProcessStatus_T retStatus;
    380                             ULONG uRetExitCode;
    381 
    382                             rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */,
    383                                                     &retStatus, &uRetExitCode);
     381                            rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */);
    384382                            if (FAILED(rc))
    385383                            {
     
    388386                            else
    389387                            {
    390                                 if (   uRetExitCode != 0
    391                                     || retStatus    != ExecuteProcessStatus_TerminatedNormally)
     388                                VBOXGUESTCTRL_PROCESS proc;
     389                                vrc = processGetStatus(uPID, &proc, true /* Remove from PID list. */);
     390                                if (RT_SUCCESS(vrc))
    392391                                {
    393                                     rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress,
    394                                                                         Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""),
    395                                                                         uRetExitCode, retStatus, aTask->strSource.c_str(), aTask->strDest.c_str());
     392
     393                                    if (   proc.mExitCode != 0
     394                                        || proc.mStatus   != ExecuteProcessStatus_TerminatedNormally)
     395                                    {
     396                                        rc = GuestTask::setProgressErrorMsg(VBOX_E_IPRT_ERROR, aTask->pProgress,
     397                                                                            Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""),
     398                                                                            proc.mExitCode, proc.mStatus, aTask->strSource.c_str(), aTask->strDest.c_str());
     399                                    }
    396400                                }
    397401                            }
  • trunk/src/VBox/Main/src-client/GuestImpl.cpp

    r40288 r40685  
    111111    /* Init the context ID counter at 1000. */
    112112    mNextContextID = 1000;
     113    /* Init the host PID counter. */
     114    mNextHostPID = 0;
    113115#endif
    114116
     
    211213     */
    212214    uFreeTotal      = 0;
    213     uAllocTotal     = 0; 
    214     uBalloonedTotal = 0; 
     215    uAllocTotal     = 0;
     216    uBalloonedTotal = 0;
    215217    uSharedTotal    = 0;
    216218    uTotalMem       = 0;
     
    253255    mParent->reportGuestStatistics(validStats,
    254256                                   aGuestStats[GUESTSTATTYPE_CPUUSER],
    255                                    aGuestStats[GUESTSTATTYPE_CPUKERNEL], 
     257                                   aGuestStats[GUESTSTATTYPE_CPUKERNEL],
    256258                                   aGuestStats[GUESTSTATTYPE_CPUIDLE],
    257259                                   /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette