VirtualBox

Changeset 42864 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Aug 17, 2012 1:36:01 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
80134
Message:

Main/Guest control: Removed old API.

Location:
trunk/src/VBox/Main/src-client
Files:
4 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r42758 r42864  
    4747#ifdef VBOX_WITH_GUEST_CONTROL
    4848/**
    49  * Appends environment variables to the environment block.
    50  *
    51  * Each var=value pair is separated by the null character ('\\0').  The whole
    52  * block will be stored in one blob and disassembled on the guest side later to
    53  * fit into the HGCM param structure.
    54  *
    55  * @returns VBox status code.
    56  *
    57  * @param   pszEnvVar       The environment variable=value to append to the
    58  *                          environment block.
    59  * @param   ppvList         This is actually a pointer to a char pointer
    60  *                          variable which keeps track of the environment block
    61  *                          that we're constructing.
    62  * @param   pcbList         Pointer to the variable holding the current size of
    63  *                          the environment block.  (List is a misnomer, go
    64  *                          ahead a be confused.)
    65  * @param   pcEnvVars       Pointer to the variable holding count of variables
    66  *                          stored in the environment block.
    67  */
    68 int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnvVars)
    69 {
    70     int rc = VINF_SUCCESS;
    71     uint32_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
    72     if (*ppvList)
    73     {
    74         uint32_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
    75         char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
    76         if (pvTmp == NULL)
    77             rc = VERR_NO_MEMORY;
    78         else
    79         {
    80             memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
    81             pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
    82             *ppvList = (void **)pvTmp;
    83         }
    84     }
    85     else
    86     {
    87         char *pszTmp;
    88         if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
    89         {
    90             *ppvList = (void **)pszTmp;
    91             /* Reset counters. */
    92             *pcEnvVars = 0;
    93             *pcbList = 0;
    94         }
    95     }
    96     if (RT_SUCCESS(rc))
    97     {
    98         *pcbList += cchEnv + 1; /* Include zero termination. */
    99         *pcEnvVars += 1;        /* Increase env variable count. */
    100     }
    101     return rc;
    102 }
    103 
    104 /**
    105  * Adds a callback with a user provided data block and an optional progress object
    106  * to the callback map. A callback is identified by a unique context ID which is used
    107  * to identify a callback from the guest side.
    108  *
    109  * @return  IPRT status code.
    110  * @param   pCallback
    111  * @param   puContextID
    112  */
    113 int Guest::callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallback, uint32_t *puContextID)
    114 {
    115     AssertPtrReturn(pCallback, VERR_INVALID_PARAMETER);
    116     /* puContextID is optional. */
    117 
    118     int rc = VERR_NOT_FOUND;
    119 
    120     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    121 
    122     /* Create a new context ID and assign it. */
    123     uint32_t uNewContextID = 0;
    124     uint32_t uTries = 0;
    125     for (;;)
    126     {
    127         /* Create a new context ID ... */
    128         uNewContextID = ASMAtomicIncU32(&mNextContextID);
    129         if (uNewContextID == UINT32_MAX)
    130             ASMAtomicUoWriteU32(&mNextContextID, 1000);
    131         /* Is the context ID already used?  Try next ID ... */
    132         if (!callbackExists(uNewContextID))
    133         {
    134             /* Callback with context ID was not found. This means
    135              * we can use this context ID for our new callback we want
    136              * to add below. */
    137             rc = VINF_SUCCESS;
    138             break;
    139         }
    140 
    141         if (++uTries == UINT32_MAX)
    142             break; /* Don't try too hard. */
    143     }
    144 
    145     if (RT_SUCCESS(rc))
    146     {
    147         /* Add callback with new context ID to our callback map. */
    148         mCallbackMap[uNewContextID] = *pCallback;
    149         Assert(mCallbackMap.size());
    150 
    151         /* Report back new context ID. */
    152         if (puContextID)
    153             *puContextID = uNewContextID;
    154     }
    155 
    156     return rc;
    157 }
    158 
    159 /**
    160  * Assigns a host PID to a specified context.
    161  * Does not do locking!
    162  *
    163  * @param   uContextID
    164  * @param   uHostPID
    165  */
    166 int 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 /**
    183  * Destroys the formerly allocated callback data. The callback then
    184  * needs to get removed from the callback map via callbackRemove().
    185  * Does not do locking!
    186  *
    187  * @param   uContextID
    188  */
    189 void Guest::callbackDestroy(uint32_t uContextID)
    190 {
    191     AssertReturnVoid(uContextID);
    192 
    193     CallbackMapIter it = mCallbackMap.find(uContextID);
    194     if (it != mCallbackMap.end())
    195     {
    196         LogFlowFunc(("Callback with CID=%u found\n", uContextID));
    197         if (it->second.pvData)
    198         {
    199             LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));
    200 
    201             callbackFreeUserData(it->second.pvData);
    202             it->second.cbData = 0;
    203         }
    204     }
    205 }
    206 
    207 /**
    208  * Removes a callback from the callback map.
    209  * Does not do locking!
    210  *
    211  * @param   uContextID
    212  */
    213 void Guest::callbackRemove(uint32_t uContextID)
    214 {
    215     callbackDestroy(uContextID);
    216 
    217     mCallbackMap.erase(uContextID);
    218 }
    219 
    220 /**
    221  * Checks whether a callback with the given context ID
    222  * exists or not.
    223  * Does not do locking!
    224  *
    225  * @return  bool                True, if callback exists, false if not.
    226  * @param   uContextID          Context ID to check.
    227  */
    228 bool Guest::callbackExists(uint32_t uContextID)
    229 {
    230     AssertReturn(uContextID, false);
    231 
    232     CallbackMapIter it = mCallbackMap.find(uContextID);
    233     return (it == mCallbackMap.end()) ? false : true;
    234 }
    235 
    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  */
    242 void Guest::callbackFreeUserData(void *pvData)
    243 {
    244     if (pvData)
    245     {
    246         RTMemFree(pvData);
    247         pvData = NULL;
    248     }
    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  */
    258 uint32_t Guest::callbackGetHostPID(uint32_t uContextID)
    259 {
    260     AssertReturn(uContextID, 0);
    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;
    269 }
    270 
    271 int Guest::callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType,
    272                                void **ppvData, size_t *pcbData)
    273 {
    274     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    275     /* pEnmType is optional. */
    276     /* ppvData is optional. */
    277     /* pcbData is optional. */
    278 
    279     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    280 
    281     CallbackMapIterConst it = mCallbackMap.find(uContextID);
    282     if (it == mCallbackMap.end())
    283         return VERR_NOT_FOUND;
    284 
    285     if (pEnmType)
    286         *pEnmType = it->second.mType;
    287 
    288     if (   ppvData
    289         && it->second.cbData)
    290     {
    291         void *pvData = RTMemAlloc(it->second.cbData);
    292         AssertPtrReturn(pvData, VERR_NO_MEMORY);
    293         memcpy(pvData, it->second.pvData, it->second.cbData);
    294         *ppvData = pvData;
    295     }
    296 
    297     if (pcbData)
    298         *pcbData = it->second.cbData;
    299 
    300     return VINF_SUCCESS;
    301 }
    302 
    303 /* Does not do locking! Caller has to take care of it because the caller needs to
    304  * modify the data ...*/
    305 void* Guest::callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData)
    306 {
    307     /* uContextID can be 0. */
    308     /* pcbData is optional. */
    309 
    310     CallbackMapIterConst it = mCallbackMap.find(uContextID);
    311     if (it != mCallbackMap.end())
    312     {
    313         if (pcbData)
    314             *pcbData = it->second.cbData;
    315         return it->second.pvData;
    316     }
    317 
    318     return NULL;
    319 }
    320 
    321 int Guest::callbackInit(PVBOXGUESTCTRL_CALLBACK pCallback, eVBoxGuestCtrlCallbackType enmType,
    322                         ComPtr<Progress> pProgress)
    323 {
    324     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
    325     /* Everything else is optional. */
    326 
    327     int vrc = VINF_SUCCESS;
    328     switch (enmType)
    329     {
    330         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
    331         {
    332             PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
    333             AssertPtrReturn(pData, VERR_NO_MEMORY);
    334             RT_BZERO(pData, sizeof(CALLBACKDATAEXECSTATUS));
    335             pCallback->cbData = sizeof(CALLBACKDATAEXECSTATUS);
    336             pCallback->pvData = pData;
    337             break;
    338         }
    339 
    340         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
    341         {
    342             PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
    343             AssertPtrReturn(pData, VERR_NO_MEMORY);
    344             RT_BZERO(pData, sizeof(CALLBACKDATAEXECOUT));
    345             pCallback->cbData = sizeof(CALLBACKDATAEXECOUT);
    346             pCallback->pvData = pData;
    347             break;
    348         }
    349 
    350         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
    351         {
    352             PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
    353             AssertPtrReturn(pData, VERR_NO_MEMORY);
    354             RT_BZERO(pData, sizeof(CALLBACKDATAEXECINSTATUS));
    355             pCallback->cbData = sizeof(CALLBACKDATAEXECINSTATUS);
    356             pCallback->pvData = pData;
    357             break;
    358         }
    359 
    360         default:
    361             vrc = VERR_INVALID_PARAMETER;
    362             break;
    363     }
    364 
    365     if (RT_SUCCESS(vrc))
    366     {
    367         /* Init/set common stuff. */
    368         pCallback->mType  = enmType;
    369         pCallback->pProgress = pProgress;
    370     }
    371 
    372     return vrc;
    373 }
    374 
    375 bool Guest::callbackIsCanceled(uint32_t uContextID)
    376 {
    377     if (!uContextID)
    378         return true; /* If no context ID given then take a shortcut. */
    379 
    380     ComPtr<IProgress> pProgress;
    381     {
    382         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    383 
    384         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    385         if (it != mCallbackMap.end())
    386             pProgress = it->second.pProgress;
    387     }
    388 
    389     if (pProgress)
    390     {
    391         BOOL fCanceled = FALSE;
    392         HRESULT hRC = pProgress->COMGETTER(Canceled)(&fCanceled);
    393         if (   SUCCEEDED(hRC)
    394             && !fCanceled)
    395         {
    396             return false;
    397         }
    398     }
    399 
    400     return true; /* No progress / error means canceled. */
    401 }
    402 
    403 bool Guest::callbackIsComplete(uint32_t uContextID)
    404 {
    405     AssertReturn(uContextID, true);
    406 
    407     ComPtr<IProgress> pProgress;
    408     {
    409         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    410 
    411         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    412         if (it != mCallbackMap.end())
    413             pProgress = it->second.pProgress;
    414     }
    415 
    416     if (pProgress)
    417     {
    418         BOOL fCompleted = FALSE;
    419         HRESULT hRC = pProgress->COMGETTER(Completed)(&fCompleted);
    420         if (   SUCCEEDED(hRC)
    421             && fCompleted)
    422         {
    423             return true;
    424         }
    425     }
    426 
    427     return false;
    428 }
    429 
    430 int Guest::callbackMoveForward(uint32_t uContextID, const char *pszMessage)
    431 {
    432     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    433     AssertPtrReturn(pszMessage, VERR_INVALID_PARAMETER);
    434 
    435     ComPtr<IProgress> pProgress;
    436     {
    437         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    438 
    439         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    440         if (it != mCallbackMap.end())
    441             pProgress = it->second.pProgress;
    442     }
    443 
    444     if (pProgress)
    445     {
    446         HRESULT hr = pProgress->SetNextOperation(Bstr(pszMessage).raw(), 1 /* Weight */);
    447         if (FAILED(hr))
    448             return VERR_CANCELLED;
    449 
    450         return VINF_SUCCESS;
    451     }
    452 
    453     return VERR_NOT_FOUND;
    454 }
    455 
    456 /**
    457  * Notifies a specified callback about its final status.
    458  *
    459  * @return  IPRT status code.
    460  * @param   uContextID
    461  * @param   iRC
    462  * @param   pszMessage
    463  */
    464 int Guest::callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage)
    465 {
    466     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    467     if (RT_FAILURE(iRC))
    468         AssertReturn(pszMessage, VERR_INVALID_PARAMETER);
    469 
    470     LogFlowFunc(("Checking whether callback (CID=%u) needs notification iRC=%Rrc, pszMsg=%s\n",
    471                  uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
    472 
    473     ComObjPtr<Progress> pProgress;
    474     {
    475         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    476 
    477         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    478         if (it != mCallbackMap.end())
    479             pProgress = it->second.pProgress;
    480     }
    481 
    482 #if 0
    483     BOOL fCanceled = FALSE;
    484     HRESULT hRC = pProgress->COMGETTER(Canceled)(&fCanceled);
    485     if (   SUCCEEDED(hRC)
    486         && fCanceled)
    487     {
    488         /* If progress already canceled do nothing here. */
    489         return VINF_SUCCESS;
    490     }
    491 #endif
    492 
    493     if (pProgress)
    494     {
    495         /*
    496          * Assume we didn't complete to make sure we clean up even if the
    497          * following call fails.
    498          */
    499         BOOL fCompleted = FALSE;
    500         HRESULT hRC = pProgress->COMGETTER(Completed)(&fCompleted);
    501         if (   SUCCEEDED(hRC)
    502             && !fCompleted)
    503         {
    504             LogFlowFunc(("Notifying callback with CID=%u, iRC=%Rrc, pszMsg=%s\n",
    505                          uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
    506 
    507             /*
    508              * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only
    509              * cancel won't work!). This could happen if the client thread (e.g. VBoxService, thread of a spawned process)
    510              * is disconnecting without having the chance to sending a status message before, so we
    511              * have to abort here to make sure the host never hangs/gets stuck while waiting for the
    512              * progress object to become signalled.
    513              */
    514             if (RT_SUCCESS(iRC))
    515             {
    516                 hRC = pProgress->notifyComplete(S_OK);
    517             }
    518             else
    519             {
    520                 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */,
    521                                                 COM_IIDOF(IGuest),
    522                                                 Guest::getStaticComponentName(),
    523                                                 pszMessage);
    524             }
    525 
    526             LogFlowFunc(("Notified callback with CID=%u returned %Rhrc (0x%x)\n",
    527                          uContextID, hRC, hRC));
    528         }
    529         else
    530             LogFlowFunc(("Callback with CID=%u already notified\n", uContextID));
    531 
    532         /*
    533          * Do *not* NULL pProgress here, because waiting function like executeProcess()
    534          * will still rely on this object for checking whether they have to give up!
    535          */
    536     }
    537     /* If pProgress is not found (anymore) that's fine.
    538      * Might be destroyed already. */
    539     return S_OK;
    540 }
    541 
    542 /**
    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.
    545  *
    546  * @return  IPRT status code.
    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.
    550  */
    551 int Guest::callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage)
    552 {
    553     AssertReturn(uGuestPID, VERR_INVALID_PARAMETER);
    554 
    555     int vrc = VINF_SUCCESS;
    556 
    557     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    558 
    559     CallbackMapIter it;
    560     for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    561     {
    562         switch (it->second.mType)
    563         {
    564             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
    565                 break;
    566 
    567             /* When waiting for process output while the process is destroyed,
    568              * make sure we also destroy the actual waiting operation (internal progress object)
    569              * in order to not block the caller. */
    570             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
    571             {
    572                 PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it->second.pvData;
    573                 AssertPtr(pItData);
    574                 if (pItData->u32PID == uGuestPID)
    575                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    576                 break;
    577             }
    578 
    579             /* When waiting for injecting process input while the process is destroyed,
    580              * make sure we also destroy the actual waiting operation (internal progress object)
    581              * in order to not block the caller. */
    582             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
    583             {
    584                 PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData;
    585                 AssertPtr(pItData);
    586                 if (pItData->u32PID == uGuestPID)
    587                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    588                 break;
    589             }
    590 
    591             default:
    592                 vrc = VERR_INVALID_PARAMETER;
    593                 AssertMsgFailed(("Unknown callback type %d, iRC=%d, message=%s\n",
    594                                  it->second.mType, iRC, pszMessage ? pszMessage : "<No message given>"));
    595                 break;
    596         }
    597 
    598         if (RT_FAILURE(vrc))
    599             break;
    600     }
    601 
    602     return vrc;
    603 }
    604 
    605 int Guest::callbackNotifyComplete(uint32_t uContextID)
    606 {
    607     return callbackNotifyEx(uContextID, S_OK, NULL /* No message */);
    608 }
    609 
    610 /**
    611  * Waits for a callback (using its context ID) to complete.
    612  *
    613  * @return  IPRT status code.
    614  * @param   uContextID              Context ID to wait for.
    615  * @param   lStage                  Stage to wait for. Specify -1 if no staging is present/required.
    616  *                                  Specifying a stage is only needed if there's a multi operation progress
    617  *                                  object to wait for.
    618  * @param   lTimeout                Timeout (in ms) to wait for.
    619  */
    620 int Guest::callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout)
    621 {
    622     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    623 
    624     /*
    625      * Wait for the HGCM low level callback until the process
    626      * has been started (or something went wrong). This is necessary to
    627      * get the PID.
    628      */
    629 
    630     int vrc = VINF_SUCCESS;
    631     ComPtr<IProgress> pProgress;
    632     {
    633         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    634 
    635         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    636         if (it != mCallbackMap.end())
    637             pProgress = it->second.pProgress;
    638         else
    639             vrc = VERR_NOT_FOUND;
    640     }
    641 
    642     if (RT_SUCCESS(vrc))
    643     {
    644         LogFlowFunc(("Waiting for callback completion (CID=%u, Stage=%RI32, timeout=%RI32ms) ...\n",
    645                      uContextID, lStage, lTimeout));
    646         HRESULT rc;
    647         if (lStage < 0)
    648             rc = pProgress->WaitForCompletion(lTimeout);
    649         else
    650             rc = pProgress->WaitForOperationCompletion((ULONG)lStage, lTimeout);
    651         if (SUCCEEDED(rc))
    652         {
    653             if (!callbackIsComplete(uContextID))
    654                 vrc = callbackIsCanceled(uContextID)
    655                     ? VERR_CANCELLED : VINF_SUCCESS;
    656         }
    657         else
    658             vrc = VERR_TIMEOUT;
    659     }
    660 
    661     LogFlowFunc(("Callback (CID=%u) completed with rc=%Rrc\n",
    662                  uContextID, vrc));
    663     return vrc;
    664 }
    665 
    666 /**
    66749 * Static callback function for receiving updates on guest control commands
    66850 * from the guest. Acts as a dispatcher for the actual class instance.
     
    67355 *
    67456 */
     57/* static */
    67558DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void    *pvExtension,
    67659                                              uint32_t u32Function,
     
    742125    }
    743126
    744 #ifdef DEBUG
    745     /* @todo Don't use legacy stuff in debug mode. Remove for final! */
    746     return rc;
    747 #endif
    748 
    749     /* Legacy handling. */
    750     switch (u32Function)
    751     {
    752         case GUEST_DISCONNECTED:
    753         {
    754             PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
    755             AssertPtr(pCBData);
    756             AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
    757             AssertReturn(CALLBACKDATAMAGIC_CLIENT_DISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    758 
    759             rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
    760             break;
    761         }
    762 
    763         case GUEST_EXEC_SEND_STATUS:
    764         {
    765             PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
    766             AssertPtr(pCBData);
    767             AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
    768             AssertReturn(CALLBACKDATAMAGIC_EXEC_STATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    769 
    770             rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
    771             break;
    772         }
    773 
    774         case GUEST_EXEC_SEND_OUTPUT:
    775         {
    776             PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
    777             AssertPtr(pCBData);
    778             AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
    779             AssertReturn(CALLBACKDATAMAGIC_EXEC_OUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    780 
    781             rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
    782             break;
    783         }
    784 
    785         case GUEST_EXEC_SEND_INPUT_STATUS:
    786         {
    787             PCALLBACKDATAEXECINSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECINSTATUS>(pvParms);
    788             AssertPtr(pCBData);
    789             AssertReturn(sizeof(CALLBACKDATAEXECINSTATUS) == cbParms, VERR_INVALID_PARAMETER);
    790             AssertReturn(CALLBACKDATAMAGIC_EXEC_IN_STATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    791 
    792             rc = pGuest->notifyCtrlExecInStatus(u32Function, pCBData);
    793             break;
    794         }
    795 
    796         default:
    797             /* Silently ignore not implemented functions. */
    798             rc = VERR_NOT_IMPLEMENTED;
    799             break;
    800     }
    801 
    802127    LogFlowFuncLeaveRC(rc);
    803128    return rc;
    804129}
    805 
    806 /* Function for handling the execution start/termination notification. */
    807 /* Callback can be called several times. */
    808 int Guest::notifyCtrlExecStatus(uint32_t                u32Function,
    809                                 PCALLBACKDATAEXECSTATUS pData)
    810 {
    811     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    812     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    813 
    814     uint32_t uContextID = pData->hdr.u32ContextID;
    815     /* The context ID might be 0 in case the guest was not able to fetch
    816      * actual command. So we can't do much now but report an error. */
    817 
    818     /* Scope write locks as much as possible. */
    819     {
    820         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    821 
    822         LogFlowFunc(("Execution status (CID=%u, pData=0x%p)\n",
    823                      uContextID, pData));
    824 
    825         PCALLBACKDATAEXECSTATUS pCallbackData =
    826             (PCALLBACKDATAEXECSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    827         if (pCallbackData)
    828         {
    829             pCallbackData->u32PID = pData->u32PID;
    830             pCallbackData->u32Status = pData->u32Status;
    831             pCallbackData->u32Flags = pData->u32Flags;
    832             /** @todo Copy void* buffer contents? */
    833         }
    834         /* If pCallbackData is NULL this might be an old request for which no user data
    835          * might exist anymore. */
    836     }
    837 
    838     int vrc = VINF_SUCCESS; /* Function result. */
    839     int rcCallback = VINF_SUCCESS; /* Callback result. */
    840     Utf8Str errMsg;
    841 
    842     /* Was progress canceled before? */
    843     bool fCanceled = callbackIsCanceled(uContextID);
    844     if (!fCanceled)
    845     {
    846         /* Handle process map. This needs to be done first in order to have a valid
    847          * map in case some callback gets notified a bit below. */
    848 
    849         uint32_t uHostPID = 0;
    850 
    851         /* Note: PIDs never get removed here in case the guest process signalled its
    852          *       end; instead the next call of GetProcessStatus() will remove the PID
    853          *       from the process map after we got the process' final (exit) status.
    854          *       See waitpid() for an example. */
    855         if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
    856         {
    857             uHostPID = callbackGetHostPID(uContextID);
    858             Assert(uHostPID);
    859 
    860             switch (pData->u32Status)
    861             {
    862                 /* Just reach through flags. */
    863                 case PROC_STS_TES:
    864                 case PROC_STS_TOK:
    865                     vrc = processSetStatus(uHostPID, pData->u32PID,
    866                                            (ExecuteProcessStatus_T)pData->u32Status,
    867                                            0 /* Exit code */, pData->u32Flags);
    868                     break;
    869                 /* Interprete u32Flags as the guest process' exit code. */
    870                 default:
    871                     vrc = processSetStatus(uHostPID, pData->u32PID,
    872                                            (ExecuteProcessStatus_T)pData->u32Status,
    873                                            pData->u32Flags /* Exit code */, 0 /* Flags */);
    874                     break;
    875             }
    876         }
    877 
    878         if (RT_SUCCESS(vrc))
    879         {
    880             /* Do progress handling. */
    881             switch (pData->u32Status)
    882             {
    883                 case PROC_STS_STARTED:
    884                     vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
    885                     LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
    886                     break;
    887 
    888                 case PROC_STS_TEN: /* Terminated normally. */
    889                     vrc = callbackNotifyComplete(uContextID);
    890                     LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n",
    891                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    892                     break;
    893 
    894                 case PROC_STS_TEA: /* Terminated abnormally. */
    895                     LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n",
    896                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    897                     errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
    898                                         pData->u32Flags);
    899                     rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    900                     break;
    901 
    902                 case PROC_STS_TES: /* Terminated through signal. */
    903                     LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n",
    904                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    905                     errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
    906                                         pData->u32Flags);
    907                     rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    908                     break;
    909 
    910                 case PROC_STS_TOK:
    911                     LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
    912                     errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
    913                     rcCallback = VERR_TIMEOUT;
    914                     break;
    915 
    916                 case PROC_STS_TOA:
    917                     LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
    918                     errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
    919                     rcCallback = VERR_TIMEOUT;
    920                     break;
    921 
    922                 case PROC_STS_DWN:
    923                     LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
    924                     /*
    925                      * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
    926                      * our progress object. This is helpful for waiters which rely on the success of our progress object
    927                      * even if the executed process was killed because the system/VBoxService is shutting down.
    928                      *
    929                      * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
    930                      */
    931                     if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
    932                     {
    933                         vrc = callbackNotifyComplete(uContextID);
    934                     }
    935                     else
    936                     {
    937                         errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
    938                         rcCallback = VERR_CANCELLED;
    939                     }
    940                     break;
    941 
    942                 case PROC_STS_ERROR:
    943                 {
    944                     Utf8Str errDetail;
    945                     if (pData->u32PID)
    946                     {
    947                         errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"),
    948                                                pData->u32PID, pData->u32Flags);
    949                     }
    950                     else
    951                     {
    952                         switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */
    953                         {
    954                             case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
    955                                 errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest"));
    956                                 break;
    957 
    958                             case VERR_PATH_NOT_FOUND:
    959                                 errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest"));
    960                                 break;
    961 
    962                             case VERR_BAD_EXE_FORMAT:
    963                                 errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest"));
    964                                 break;
    965 
    966                             case VERR_AUTHENTICATION_FAILURE:
    967                                 errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest"));
    968                                 break;
    969 
    970                             case VERR_TIMEOUT:
    971                                 errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time"));
    972                                 break;
    973 
    974                             case VERR_CANCELLED:
    975                                 errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled"));
    976                                 break;
    977 
    978                             case VERR_PERMISSION_DENIED:
    979                                 errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials"));
    980                                 break;
    981 
    982                             case VERR_MAX_PROCS_REACHED:
    983                                 errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached"));
    984                                 break;
    985 
    986                             default:
    987                                 errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags);
    988                                 break;
    989                         }
    990                     }
    991 
    992                     errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail;
    993                     rcCallback = pData->u32Flags; /* Report back guest rc. */
    994 
    995                     LogRel((errMsg.c_str()));
    996 
    997                     break;
    998                 }
    999 
    1000                 default:
    1001                     vrc = VERR_INVALID_PARAMETER;
    1002                     break;
    1003             }
    1004         }
    1005     }
    1006     else
    1007     {
    1008         errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
    1009         rcCallback = VERR_CANCELLED;
    1010     }
    1011 
    1012     /* Do we need to handle the callback error? */
    1013     if (RT_FAILURE(rcCallback))
    1014     {
    1015         AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n"));
    1016 
    1017         if (uContextID)
    1018         {
    1019             /* Notify all callbacks which are still waiting on something
    1020              * which is related to the current PID. */
    1021             if (pData->u32PID)
    1022             {
    1023                 int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
    1024                 if (RT_FAILURE(rc2))
    1025                 {
    1026                     LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
    1027                                  pData->u32PID));
    1028                     if (RT_SUCCESS(vrc))
    1029                         vrc = rc2;
    1030                 }
    1031             }
    1032 
    1033             /* Let the caller know what went wrong ... */
    1034             int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
    1035             if (RT_FAILURE(rc2))
    1036             {
    1037                 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
    1038                              uContextID, pData->u32PID));
    1039                 if (RT_SUCCESS(vrc))
    1040                     vrc = rc2;
    1041             }
    1042         }
    1043         else
    1044         {
    1045             /* Since we don't know which context exactly failed all we can do is to shutdown
    1046              * all contexts ... */
    1047             errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"),
    1048                                 pData->u32Flags);
    1049 
    1050             /* Cancel all callbacks. */
    1051             CallbackMapIter it;
    1052             for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    1053             {
    1054                 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
    1055                                            errMsg.c_str());
    1056                 AssertRC(rc2);
    1057             }
    1058         }
    1059 
    1060         LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
    1061                      uContextID, pData->u32Status, errMsg.c_str()));
    1062     }
    1063     LogFlowFunc(("Returned with rc=%Rrc, rcCallback=%Rrc\n",
    1064                  vrc, rcCallback));
    1065     return vrc;
    1066 }
    1067 
    1068 /* Function for handling the execution output notification. */
    1069 int Guest::notifyCtrlExecOut(uint32_t             u32Function,
    1070                              PCALLBACKDATAEXECOUT pData)
    1071 {
    1072     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    1073     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1074 
    1075     uint32_t uContextID = pData->hdr.u32ContextID;
    1076     Assert(uContextID);
    1077 
    1078     /* Scope write locks as much as possible. */
    1079     {
    1080         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1081 
    1082         LogFlowFunc(("Output status (CID=%u, pData=0x%p)\n",
    1083                      uContextID, pData));
    1084 
    1085         PCALLBACKDATAEXECOUT pCallbackData =
    1086             (PCALLBACKDATAEXECOUT)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    1087         if (pCallbackData)
    1088         {
    1089             pCallbackData->u32PID = pData->u32PID;
    1090             pCallbackData->u32HandleId = pData->u32HandleId;
    1091             pCallbackData->u32Flags = pData->u32Flags;
    1092 
    1093             /* Make sure we really got something! */
    1094             if (   pData->cbData
    1095                 && pData->pvData)
    1096             {
    1097                 callbackFreeUserData(pCallbackData->pvData);
    1098 
    1099                 /* Allocate data buffer and copy it */
    1100                 pCallbackData->pvData = RTMemAlloc(pData->cbData);
    1101                 pCallbackData->cbData = pData->cbData;
    1102 
    1103                 AssertReturn(pCallbackData->pvData, VERR_NO_MEMORY);
    1104                 memcpy(pCallbackData->pvData, pData->pvData, pData->cbData);
    1105             }
    1106             else /* Nothing received ... */
    1107             {
    1108                 pCallbackData->pvData = NULL;
    1109                 pCallbackData->cbData = 0;
    1110             }
    1111         }
    1112         /* If pCallbackData is NULL this might be an old request for which no user data
    1113          * might exist anymore. */
    1114     }
    1115 
    1116     int vrc;
    1117     if (callbackIsCanceled(pData->u32PID))
    1118     {
    1119         vrc = callbackNotifyEx(uContextID, VERR_CANCELLED,
    1120                                Guest::tr("The output operation was canceled"));
    1121     }
    1122     else
    1123         vrc = callbackNotifyComplete(uContextID);
    1124 
    1125     return vrc;
    1126 }
    1127 
    1128 /* Function for handling the execution input status notification. */
    1129 int Guest::notifyCtrlExecInStatus(uint32_t                  u32Function,
    1130                                   PCALLBACKDATAEXECINSTATUS pData)
    1131 {
    1132     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    1133     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1134 
    1135     uint32_t uContextID = pData->hdr.u32ContextID;
    1136     Assert(uContextID);
    1137 
    1138     /* Scope write locks as much as possible. */
    1139     {
    1140         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1141 
    1142         LogFlowFunc(("Input status (CID=%u, pData=0x%p)\n",
    1143                      uContextID, pData));
    1144 
    1145         PCALLBACKDATAEXECINSTATUS pCallbackData =
    1146             (PCALLBACKDATAEXECINSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    1147         if (pCallbackData)
    1148         {
    1149             /* Save bytes processed. */
    1150             pCallbackData->cbProcessed = pData->cbProcessed;
    1151             pCallbackData->u32Status   = pData->u32Status;
    1152             pCallbackData->u32Flags    = pData->u32Flags;
    1153             pCallbackData->u32PID      = pData->u32PID;
    1154         }
    1155         /* If pCallbackData is NULL this might be an old request for which no user data
    1156          * might exist anymore. */
    1157     }
    1158 
    1159     return callbackNotifyComplete(uContextID);
    1160 }
    1161 
    1162 int Guest::notifyCtrlClientDisconnected(uint32_t                        u32Function,
    1163                                         PCALLBACKDATACLIENTDISCONNECTED pData)
    1164 {
    1165     /* u32Function is 0. */
    1166     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1167 
    1168     uint32_t uContextID = pData->hdr.u32ContextID;
    1169     Assert(uContextID);
    1170 
    1171     LogFlowFunc(("Client disconnected (CID=%u)\n,", uContextID));
    1172 
    1173     return callbackNotifyEx(uContextID, VERR_CANCELLED,
    1174                             Guest::tr("Client disconnected"));
    1175 }
    1176 
    1177 uint32_t Guest::processGetGuestPID(uint32_t uHostPID)
    1178 {
    1179     AssertReturn(uHostPID, 0);
    1180 
    1181     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1182 
    1183     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1184     if (it == mGuestProcessMap.end())
    1185         return 0;
    1186 
    1187     return it->second.mGuestPID;
    1188 }
    1189 
    1190 /**
    1191  * Gets guest process information. Removes the process from the map
    1192  * after the process was marked as exited/terminated.
    1193  *
    1194  * @return  IPRT status code.
    1195  * @param   uHostPID                Host PID of guest process to get status for.
    1196  * @param   pProcess                Where to store the process information. Optional.
    1197  * @param   fRemove                 Flag indicating whether to remove the
    1198  *                                  process from the map when process marked a
    1199  *                                  exited/terminated.
    1200  */
    1201 int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess,
    1202                             bool fRemove)
    1203 {
    1204     AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    1205 
    1206     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1207 
    1208     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1209     if (it != mGuestProcessMap.end())
    1210     {
    1211         if (pProcess)
    1212         {
    1213             pProcess->mGuestPID = it->second.mGuestPID;
    1214             pProcess->mStatus   = it->second.mStatus;
    1215             pProcess->mExitCode = it->second.mExitCode;
    1216             pProcess->mFlags    = it->second.mFlags;
    1217         }
    1218 
    1219         /* Only remove processes from our map when they signalled their final
    1220          * status. */
    1221         if (   fRemove
    1222             && (   it->second.mStatus != ExecuteProcessStatus_Undefined
    1223                 && it->second.mStatus != ExecuteProcessStatus_Started))
    1224         {
    1225             mGuestProcessMap.erase(it);
    1226         }
    1227 
    1228         return VINF_SUCCESS;
    1229     }
    1230 
    1231     return VERR_NOT_FOUND;
    1232 }
    1233 
    1234 /**
    1235  * Sets the current status of a guest process.
    1236  *
    1237  * @return  IPRT status code.
    1238  * @param   uHostPID                Host PID of guest process to set status (and guest PID) for.
    1239  * @param   uGuestPID               Guest PID to assign to the host PID.
    1240  * @param   enmStatus               Current status to set.
    1241  * @param   uExitCode               Exit code (if any).
    1242  * @param   uFlags                  Additional flags.
    1243  */
    1244 int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
    1245                             ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
    1246 {
    1247     AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    1248     /* Assigning a guest PID is optional. */
    1249 
    1250     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1251 
    1252     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1253     if (it != mGuestProcessMap.end())
    1254     {
    1255         it->second.mGuestPID = uGuestPID;
    1256         it->second.mStatus   = enmStatus;
    1257         it->second.mExitCode = uExitCode;
    1258         it->second.mFlags    = uFlags;
    1259     }
    1260     else
    1261     {
    1262         VBOXGUESTCTRL_PROCESS process;
    1263 
    1264         /* uGuestPID is optional -- the caller could call this function
    1265          * before the guest process actually was started and a (valid) guest PID
    1266          * was returned. */
    1267         process.mGuestPID = uGuestPID;
    1268         process.mStatus   = enmStatus;
    1269         process.mExitCode = uExitCode;
    1270         process.mFlags    = uFlags;
    1271 
    1272         mGuestProcessMap[uHostPID] = process;
    1273     }
    1274 
    1275     return VINF_SUCCESS;
    1276 }
    1277 
    1278 HRESULT Guest::setErrorCompletion(int rc)
    1279 {
    1280     HRESULT hRC;
    1281     if (rc == VERR_NOT_FOUND)
    1282         hRC = setErrorNoLog(VBOX_E_VM_ERROR,
    1283                             tr("VMM device is not available (is the VM running?)"));
    1284     else if (rc == VERR_CANCELLED)
    1285         hRC = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1286                             tr("Process execution has been canceled"));
    1287     else if (rc == VERR_TIMEOUT)
    1288         hRC= setErrorNoLog(VBOX_E_IPRT_ERROR,
    1289                             tr("The guest did not respond within time"));
    1290     else
    1291         hRC = setErrorNoLog(E_UNEXPECTED,
    1292                             tr("Waiting for completion failed with error %Rrc"), rc);
    1293     return hRC;
    1294 }
    1295 
    1296 HRESULT Guest::setErrorFromProgress(ComPtr<IProgress> pProgress)
    1297 {
    1298     BOOL fCompleted;
    1299     HRESULT rc = pProgress->COMGETTER(Completed)(&fCompleted);
    1300     ComAssertComRC(rc);
    1301 
    1302     LONG rcProc = S_OK;
    1303     Utf8Str strError;
    1304 
    1305     if (!fCompleted)
    1306     {
    1307         BOOL fCanceled;
    1308         rc = pProgress->COMGETTER(Canceled)(&fCanceled);
    1309         ComAssertComRC(rc);
    1310 
    1311         strError = fCanceled ? Utf8StrFmt(Guest::tr("Process execution was canceled"))
    1312                              : Utf8StrFmt(Guest::tr("Process neither completed nor canceled; this shouldn't happen"));
    1313     }
    1314     else
    1315     {
    1316         rc = pProgress->COMGETTER(ResultCode)(&rcProc);
    1317         ComAssertComRC(rc);
    1318 
    1319         if (FAILED(rcProc))
    1320         {
    1321             ProgressErrorInfo info(pProgress);
    1322             strError = info.getText();
    1323         }
    1324     }
    1325 
    1326     if (FAILED(rcProc))
    1327     {
    1328         AssertMsg(!strError.isEmpty(), ("Error message must not be empty!\n"));
    1329         return setErrorInternal(rcProc,
    1330                                 this->getClassIID(),
    1331                                 this->getComponentName(),
    1332                                 strError,
    1333                                 false /* aWarning */,
    1334                                 false /* aLogIt */);
    1335     }
    1336 
    1337     return S_OK;
    1338 }
    1339 
    1340 HRESULT Guest::setErrorHGCM(int rc)
    1341 {
    1342     HRESULT hRC;
    1343     if (rc == VERR_INVALID_VM_HANDLE)
    1344         hRC = setErrorNoLog(VBOX_E_VM_ERROR,
    1345                             tr("VMM device is not available (is the VM running?)"));
    1346     else if (rc == VERR_NOT_FOUND)
    1347         hRC = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1348                             tr("The guest execution service is not ready (yet)"));
    1349     else if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
    1350         hRC= setErrorNoLog(VBOX_E_IPRT_ERROR,
    1351                             tr("The guest execution service is not available"));
    1352     else /* HGCM call went wrong. */
    1353         hRC = setErrorNoLog(E_UNEXPECTED,
    1354                             tr("The HGCM call failed with error %Rrc"), rc);
    1355     return hRC;
    1356 }
    1357130#endif /* VBOX_WITH_GUEST_CONTROL */
    1358 
    1359 STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags,
    1360                                    ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1361                                    IN_BSTR aUsername, IN_BSTR aPassword,
    1362                                    ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress)
    1363 {
    1364 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    1365  *        in the API and have the same way of specifying infinite waits!  */
    1366 #ifndef VBOX_WITH_GUEST_CONTROL
    1367     ReturnComNotImplemented();
    1368 #else  /* VBOX_WITH_GUEST_CONTROL */
    1369     using namespace guestControl;
    1370 
    1371     CheckComArgStrNotEmptyOrNull(aCommand);
    1372     CheckComArgOutPointerValid(aPID);
    1373     CheckComArgOutPointerValid(aProgress);
    1374 
    1375     /* Do not allow anonymous executions (with system rights). */
    1376     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    1377         return setError(E_INVALIDARG, tr("No user name specified"));
    1378 
    1379     LogRel(("Executing guest process \"%s\" as user \"%s\" ...\n",
    1380             Utf8Str(aCommand).c_str(), Utf8Str(aUsername).c_str()));
    1381 
    1382     return executeProcessInternal(aCommand, aFlags, ComSafeArrayInArg(aArguments),
    1383                                   ComSafeArrayInArg(aEnvironment),
    1384                                   aUsername, aPassword, aTimeoutMS, aPID, aProgress, NULL /* rc */);
    1385 #endif
    1386 }
    1387 
    1388 #ifdef VBOX_WITH_GUEST_CONTROL
    1389 /**
    1390  * Executes and waits for an internal tool (that is, a tool which is integrated into
    1391  * VBoxService, beginning with "vbox_" (e.g. "vbox_ls")) to finish its operation.
    1392  *
    1393  * @return  HRESULT
    1394  * @param   aTool                   Name of tool to execute.
    1395  * @param   aDescription            Friendly description of the operation.
    1396  * @param   aFlags                  Execution flags.
    1397  * @param   aUsername               Username to execute tool under.
    1398  * @param   aPassword               The user's password.
    1399  * @param   uFlagsToAdd             ExecuteProcessFlag flags to add to the execution operation.
    1400  * @param   aProgress               Pointer which receives the tool's progress object. Optional.
    1401  * @param   aPID                    Pointer which receives the tool's PID. Optional.
    1402  */
    1403 HRESULT Guest::executeAndWaitForTool(IN_BSTR aTool, IN_BSTR aDescription,
    1404                                      ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1405                                      IN_BSTR aUsername, IN_BSTR aPassword,
    1406                                      ULONG uFlagsToAdd,
    1407                                      GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
    1408                                      IProgress **aProgress, ULONG *aPID)
    1409 {
    1410     ComPtr<IProgress> pProgress;
    1411     ULONG uPID;
    1412     ULONG uFlags = ExecuteProcessFlag_Hidden;
    1413     if (uFlagsToAdd)
    1414         uFlags |= uFlagsToAdd;
    1415 
    1416     bool fParseOutput = false;
    1417     if (   (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    1418             && pObjStdOut)
    1419         || (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
    1420             && pObjStdErr))
    1421     {
    1422         fParseOutput = true;
    1423     }
    1424 
    1425     HRESULT hr = ExecuteProcess(aTool,
    1426                                 uFlags,
    1427                                 ComSafeArrayInArg(aArguments),
    1428                                 ComSafeArrayInArg(aEnvironment),
    1429                                 aUsername, aPassword,
    1430                                 0 /* No timeout */,
    1431                                 &uPID, pProgress.asOutParam());
    1432     if (SUCCEEDED(hr))
    1433     {
    1434         /* Wait for tool being started. */
    1435         hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */,
    1436                                                    -1 /* No timeout */);
    1437     }
    1438 
    1439     if (   SUCCEEDED(hr)
    1440         && !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly))
    1441     {
    1442         if (!fParseOutput)
    1443         {
    1444             if (   !(uFlags & ExecuteProcessFlag_WaitForStdOut)
    1445                 && !(uFlags & ExecuteProcessFlag_WaitForStdErr))
    1446             {
    1447                 hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */);
    1448             }
    1449         }
    1450         else
    1451         {
    1452             BOOL fCompleted;
    1453             while (   SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted))
    1454                    && !fCompleted)
    1455             {
    1456                 BOOL fCanceled;
    1457                 hr = pProgress->COMGETTER(Canceled)(&fCanceled);
    1458                 AssertComRC(hr);
    1459                 if (fCanceled)
    1460                 {
    1461                     hr = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1462                                        tr("%s was cancelled"), Utf8Str(aDescription).c_str());
    1463                     break;
    1464                 }
    1465 
    1466                 if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    1467                     && pObjStdOut)
    1468                 {
    1469                     hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
    1470                 }
    1471 
    1472                 if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
    1473                     && pObjStdErr)
    1474                 {
    1475                     hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
    1476                 }
    1477 
    1478                 if (FAILED(hr))
    1479                     break;
    1480             }
    1481         }
    1482     }
    1483 
    1484     if (SUCCEEDED(hr))
    1485     {
    1486         if (aProgress)
    1487         {
    1488             /* Return the progress to the caller. */
    1489             pProgress.queryInterfaceTo(aProgress);
    1490         }
    1491         else if (!pProgress.isNull())
    1492             pProgress.setNull();
    1493 
    1494         if (aPID)
    1495             *aPID = uPID;
    1496     }
    1497 
    1498     return hr;
    1499 }
    1500 
    1501 /**
    1502  * TODO
    1503  *
    1504  * @return  HRESULT
    1505  * @param   aObjName
    1506  * @param   pStreamBlock
    1507  * @param   pObjInfo
    1508  * @param   enmAddAttribs
    1509  */
    1510 int Guest::executeStreamQueryFsObjInfo(IN_BSTR aObjName,
    1511                                        GuestProcessStreamBlock &streamBlock,
    1512                                        PRTFSOBJINFO pObjInfo,
    1513                                        RTFSOBJATTRADD enmAddAttribs)
    1514 {
    1515     Utf8Str Utf8ObjName(aObjName);
    1516     int64_t iVal;
    1517     int rc = streamBlock.GetInt64Ex("st_size", &iVal);
    1518     if (RT_SUCCESS(rc))
    1519         pObjInfo->cbObject = iVal;
    1520     /** @todo Add more stuff! */
    1521     return rc;
    1522 }
    1523 
    1524 /**
    1525  * Tries to drain the guest's output and fill it into
    1526  * a guest process stream object for later usage.
    1527  *
    1528  * @todo    What's about specifying stderr?
    1529  * @return  IPRT status code.
    1530  * @param   aPID                    PID of process to get the output from.
    1531  * @param   aFlags                  Which stream to drain (stdout or stderr).
    1532  * @param   pStream                 Pointer to guest process stream to fill. If NULL,
    1533  *                                  data goes to /dev/null.
    1534  */
    1535 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream *pStream)
    1536 {
    1537     AssertReturn(aPID, VERR_INVALID_PARAMETER);
    1538     /* pStream is optional. */
    1539 
    1540     int rc = VINF_SUCCESS;
    1541     for (;;)
    1542     {
    1543         SafeArray<BYTE> aData;
    1544         HRESULT hr = getProcessOutputInternal(aPID, aFlags,
    1545                                               0 /* Infinite timeout */,
    1546                                               _64K, ComSafeArrayAsOutParam(aData), &rc);
    1547         if (RT_SUCCESS(rc))
    1548         {
    1549             if (   pStream
    1550                 && aData.size())
    1551             {
    1552                 rc = pStream->AddData(aData.raw(), aData.size());
    1553                 if (RT_UNLIKELY(RT_FAILURE(rc)))
    1554                     break;
    1555             }
    1556 
    1557             continue; /* Try one more time. */
    1558         }
    1559         else /* No more output and/or error! */
    1560         {
    1561             if (   rc == VERR_NOT_FOUND
    1562                 || rc == VERR_BROKEN_PIPE)
    1563             {
    1564                 rc = VINF_SUCCESS;
    1565             }
    1566 
    1567             break;
    1568         }
    1569     }
    1570 
    1571     return rc;
    1572 }
    1573 
    1574 /**
    1575  * Tries to retrieve the next stream block of a given stream and
    1576  * drains the process output only as much as needed to get this next
    1577  * stream block.
    1578  *
    1579  * @return  IPRT status code.
    1580  * @param   ulPID
    1581  * @param   ulFlags
    1582  * @param   stream
    1583  * @param   streamBlock
    1584  */
    1585 int Guest::executeStreamGetNextBlock(ULONG ulPID,
    1586                                      ULONG ulFlags,
    1587                                      GuestProcessStream &stream,
    1588                                      GuestProcessStreamBlock &streamBlock)
    1589 {
    1590     AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
    1591 
    1592     LogFlowFunc(("Getting next stream block of PID=%u, Flags=%u; cbStrmSize=%u, cbStrmOff=%u\n",
    1593                  ulPID, ulFlags, stream.GetSize(), stream.GetOffset()));
    1594 
    1595     int rc;
    1596 
    1597     uint32_t cPairs = 0;
    1598     bool fDrainStream = true;
    1599 
    1600     do
    1601     {
    1602         rc = stream.ParseBlock(streamBlock);
    1603         LogFlowFunc(("Parsing block rc=%Rrc, strmBlockCnt=%ld\n",
    1604                      rc, streamBlock.GetCount()));
    1605 
    1606         if (RT_FAILURE(rc)) /* More data needed or empty buffer? */
    1607         {
    1608             if (fDrainStream)
    1609             {
    1610                 SafeArray<BYTE> aData;
    1611                 HRESULT hr = getProcessOutputInternal(ulPID, ulFlags,
    1612                                                       0 /* Infinite timeout */,
    1613                                                       _64K, ComSafeArrayAsOutParam(aData), &rc);
    1614                 if (SUCCEEDED(hr))
    1615                 {
    1616                     LogFlowFunc(("Got %ld bytes of additional data\n", aData.size()));
    1617 
    1618                     if (RT_FAILURE(rc))
    1619                     {
    1620                         if (rc == VERR_BROKEN_PIPE)
    1621                              rc = VINF_SUCCESS; /* No more data because process already ended. */
    1622                         break;
    1623                     }
    1624 
    1625                     if (aData.size())
    1626                     {
    1627                         rc = stream.AddData(aData.raw(), aData.size());
    1628                         if (RT_UNLIKELY(RT_FAILURE(rc)))
    1629                             break;
    1630                     }
    1631 
    1632                     /* Reset found pairs to not break out too early and let all the new
    1633                      * data to be parsed as well. */
    1634                     cPairs = 0;
    1635                     continue; /* Try one more time. */
    1636                 }
    1637                 else
    1638                 {
    1639                     LogFlowFunc(("Getting output returned hr=%Rhrc\n", hr));
    1640 
    1641                     /* No more output to drain from stream. */
    1642                     if (rc == VERR_NOT_FOUND)
    1643                     {
    1644                         fDrainStream = false;
    1645                         continue;
    1646                     }
    1647 
    1648                     break;
    1649                 }
    1650             }
    1651             else
    1652             {
    1653                 /* We haved drained the stream as much as we can and reached the
    1654                  * end of our stream buffer -- that means that there simply is no
    1655                  * stream block anymore, which is ok. */
    1656                 if (rc == VERR_NO_DATA)
    1657                     rc = VINF_SUCCESS;
    1658                 break;
    1659             }
    1660         }
    1661         else
    1662             cPairs = streamBlock.GetCount();
    1663     }
    1664     while (!cPairs);
    1665 
    1666     LogFlowFunc(("Returned with strmBlockCnt=%ld, cPairs=%ld, rc=%Rrc\n",
    1667                  streamBlock.GetCount(), cPairs, rc));
    1668     return rc;
    1669 }
    1670 
    1671 /**
    1672  * Tries to get the next upcoming value block from a started guest process
    1673  * by first draining its output and then processing the received guest stream.
    1674  *
    1675  * @return  IPRT status code.
    1676  * @param   ulPID                   PID of process to get/parse the output from.
    1677  * @param   ulFlags                 ?
    1678  * @param   stream                  Reference to process stream object to use.
    1679  * @param   streamBlock             Reference that receives the next stream block data.
    1680  *
    1681  */
    1682 int Guest::executeStreamParseNextBlock(ULONG ulPID,
    1683                                        ULONG ulFlags,
    1684                                        GuestProcessStream &stream,
    1685                                        GuestProcessStreamBlock &streamBlock)
    1686 {
    1687     AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
    1688 
    1689     int rc;
    1690     do
    1691     {
    1692         rc = stream.ParseBlock(streamBlock);
    1693         if (RT_FAILURE(rc))
    1694             break;
    1695     }
    1696     while (!streamBlock.GetCount());
    1697 
    1698     return rc;
    1699 }
    1700 
    1701 /**
    1702  * Gets output from a formerly started guest process, tries to parse all of its guest
    1703  * stream (as long as data is available) and returns a stream object which can contain
    1704  * multiple stream blocks (which in turn then can contain key=value pairs).
    1705  *
    1706  * @return  HRESULT
    1707  * @param   ulPID                   PID of process to get/parse the output from.
    1708  * @param   ulFlags                 ?
    1709  * @param   streamObjects           Reference to a guest stream object structure for
    1710  *                                  storing the parsed data.
    1711  */
    1712 HRESULT Guest::executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects)
    1713 {
    1714     GuestProcessStream stream;
    1715     int rc = executeStreamDrain(ulPID, ulFlags, &stream);
    1716     if (RT_SUCCESS(rc))
    1717     {
    1718         do
    1719         {
    1720             /* Try to parse the stream output we gathered until now. If we still need more
    1721              * data the parsing routine will tell us and we just do another poll round. */
    1722             GuestProcessStreamBlock curBlock;
    1723             rc = executeStreamParseNextBlock(ulPID, ulFlags, stream, curBlock);
    1724             if (RT_SUCCESS(rc))
    1725                 streamObjects.push_back(curBlock);
    1726         } while (RT_SUCCESS(rc));
    1727 
    1728         if (rc == VERR_NO_DATA) /* End of data reached. */
    1729             rc = VINF_SUCCESS;
    1730     }
    1731 
    1732     if (RT_FAILURE(rc))
    1733         return setError(VBOX_E_IPRT_ERROR,
    1734                         tr("Error while parsing guest output (%Rrc)"), rc);
    1735     return rc;
    1736 }
    1737 
    1738 /**
    1739  * Waits for a fomerly started guest process to exit using its progress
    1740  * object and returns its final status. Returns E_ABORT if guest process
    1741  * was canceled.
    1742  *
    1743  * @return  IPRT status code.
    1744  * @param   uPID                    PID of guest process to wait for.
    1745  * @param   pProgress               Progress object to wait for.
    1746  * @param   uTimeoutMS              Timeout (in ms) for waiting; use 0 for
    1747  *                                  an indefinite timeout.
    1748  * @param   pRetStatus              Pointer where to store the final process
    1749  *                                  status. Optional.
    1750  * @param   puRetExitCode           Pointer where to store the final process
    1751  *                                  exit code. Optional.
    1752  */
    1753 HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS)
    1754 {
    1755     HRESULT rc = S_OK;
    1756 
    1757     BOOL fCanceled = FALSE;
    1758     if (   SUCCEEDED(pProgress->COMGETTER(Canceled(&fCanceled)))
    1759         && fCanceled)
    1760     {
    1761         return E_ABORT;
    1762     }
    1763 
    1764     BOOL fCompleted = FALSE;
    1765     if (   SUCCEEDED(pProgress->COMGETTER(Completed(&fCompleted)))
    1766         && !fCompleted)
    1767     {
    1768         rc = pProgress->WaitForCompletion(  !uTimeoutMS
    1769                                           ? -1 /* No timeout */
    1770                                           : uTimeoutMS);
    1771         if (FAILED(rc))
    1772             rc = setError(VBOX_E_IPRT_ERROR,
    1773                           tr("Waiting for guest process to end failed (%Rhrc)"), rc);
    1774     }
    1775 
    1776     return rc;
    1777 }
    1778 
    1779 /**
    1780  * Does the actual guest process execution, internal function.
    1781  *
    1782  * @return  HRESULT
    1783  * @param   aCommand                Command line to execute.
    1784  * @param   aFlags                  Execution flags.
    1785  * @param   Username                Username to execute the process with.
    1786  * @param   aPassword               The user's password.
    1787  * @param   aTimeoutMS              Timeout (in ms) to wait for the execution operation.
    1788  * @param   aPID                    Pointer that receives the guest process' PID.
    1789  * @param   aProgress               Pointer that receives the guest process' progress object.
    1790  * @param   pRC                     Pointer that receives the internal IPRT return code. Optional.
    1791  */
    1792 HRESULT Guest::executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
    1793                                       ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1794                                       IN_BSTR aUsername, IN_BSTR aPassword,
    1795                                       ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC)
    1796 {
    1797 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    1798  *        in the API and have the same way of specifying infinite waits!  */
    1799     using namespace guestControl;
    1800 
    1801     AutoCaller autoCaller(this);
    1802     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1803 
    1804     /* Validate flags. */
    1805     if (aFlags != ExecuteProcessFlag_None)
    1806     {
    1807         if (   !(aFlags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
    1808             && !(aFlags & ExecuteProcessFlag_WaitForProcessStartOnly)
    1809             && !(aFlags & ExecuteProcessFlag_Hidden)
    1810             && !(aFlags & ExecuteProcessFlag_NoProfile)
    1811             && !(aFlags & ExecuteProcessFlag_WaitForStdOut)
    1812             && !(aFlags & ExecuteProcessFlag_WaitForStdErr))
    1813         {
    1814             if (pRC)
    1815                 *pRC = VERR_INVALID_PARAMETER;
    1816             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    1817         }
    1818     }
    1819 
    1820     HRESULT rc = S_OK;
    1821 
    1822     try
    1823     {
    1824         /*
    1825          * Create progress object.  Note that this is a multi operation
    1826          * object to perform the following steps:
    1827          * - Operation 1 (0): Create/start process.
    1828          * - Operation 2 (1): Wait for process to exit.
    1829          * If this progress completed successfully (S_OK), the process
    1830          * started and exited normally. In any other case an error/exception
    1831          * occurred.
    1832          */
    1833         ComObjPtr <Progress> pProgress;
    1834         rc = pProgress.createObject();
    1835         if (SUCCEEDED(rc))
    1836         {
    1837             rc = pProgress->init(static_cast<IGuest*>(this),
    1838                                  Bstr(tr("Executing process")).raw(),
    1839                                  TRUE,
    1840                                  2,                                          /* Number of operations. */
    1841                                  Bstr(tr("Starting process ...")).raw());    /* Description of first stage. */
    1842         }
    1843         ComAssertComRC(rc);
    1844 
    1845         /*
    1846          * Prepare process execution.
    1847          */
    1848         int vrc = VINF_SUCCESS;
    1849         Utf8Str Utf8Command(aCommand);
    1850 
    1851         /* Adjust timeout. If set to 0, we define
    1852          * an infinite timeout. */
    1853         if (aTimeoutMS == 0)
    1854             aTimeoutMS = UINT32_MAX;
    1855 
    1856         /* Prepare arguments. */
    1857         char **papszArgv = NULL;
    1858         uint32_t uNumArgs = 0;
    1859         if (aArguments)
    1860         {
    1861             com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
    1862             uNumArgs = args.size();
    1863             papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
    1864             AssertReturn(papszArgv, E_OUTOFMEMORY);
    1865             for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
    1866                 vrc = RTUtf16ToUtf8(args[i], &papszArgv[i]);
    1867             papszArgv[uNumArgs] = NULL;
    1868         }
    1869 
    1870         Utf8Str Utf8UserName(aUsername);
    1871         Utf8Str Utf8Password(aPassword);
    1872         uint32_t uHostPID = 0;
    1873 
    1874         if (RT_SUCCESS(vrc))
    1875         {
    1876             uint32_t uContextID = 0;
    1877 
    1878             char *pszArgs = NULL;
    1879             if (uNumArgs > 0)
    1880                 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
    1881             if (RT_SUCCESS(vrc))
    1882             {
    1883                 uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
    1884 
    1885                 /* Prepare environment. */
    1886                 void *pvEnv = NULL;
    1887                 uint32_t uNumEnv = 0;
    1888                 uint32_t cbEnv = 0;
    1889                 if (aEnvironment)
    1890                 {
    1891                     com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
    1892 
    1893                     for (unsigned i = 0; i < env.size(); i++)
    1894                     {
    1895                         vrc = prepareExecuteEnv(Utf8Str(env[i]).c_str(), &pvEnv, &cbEnv, &uNumEnv);
    1896                         if (RT_FAILURE(vrc))
    1897                             break;
    1898                     }
    1899                 }
    1900 
    1901                 if (RT_SUCCESS(vrc))
    1902                 {
    1903                     VBOXGUESTCTRL_CALLBACK callback;
    1904                     vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, pProgress);
    1905                     if (RT_SUCCESS(vrc))
    1906                         vrc = callbackAdd(&callback, &uContextID);
    1907 
    1908                     if (RT_SUCCESS(vrc))
    1909                     {
    1910                         VBOXHGCMSVCPARM paParms[15];
    1911                         int i = 0;
    1912                         paParms[i++].setUInt32(uContextID);
    1913                         paParms[i++].setPointer((void*)Utf8Command.c_str(), (uint32_t)Utf8Command.length() + 1);
    1914                         paParms[i++].setUInt32(aFlags);
    1915                         paParms[i++].setUInt32(uNumArgs);
    1916                         paParms[i++].setPointer((void*)pszArgs, cbArgs);
    1917                         paParms[i++].setUInt32(uNumEnv);
    1918                         paParms[i++].setUInt32(cbEnv);
    1919                         paParms[i++].setPointer((void*)pvEnv, cbEnv);
    1920                         paParms[i++].setPointer((void*)Utf8UserName.c_str(), (uint32_t)Utf8UserName.length() + 1);
    1921                         paParms[i++].setPointer((void*)Utf8Password.c_str(), (uint32_t)Utf8Password.length() + 1);
    1922 
    1923                         /*
    1924                          * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
    1925                          * until the process was started - the process itself then gets an infinite timeout for execution.
    1926                          * This is handy when we want to start a process inside a worker thread within a certain timeout
    1927                          * but let the started process perform lengthly operations then.
    1928                          */
    1929                         if (aFlags & ExecuteProcessFlag_WaitForProcessStartOnly)
    1930                             paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
    1931                         else
    1932                             paParms[i++].setUInt32(aTimeoutMS);
    1933 
    1934                         VMMDev *pVMMDev = NULL;
    1935                         {
    1936                             /* Make sure mParent is valid, so set the read lock while using.
    1937                              * Do not keep this lock while doing the actual call, because in the meanwhile
    1938                              * another thread could request a write lock which would be a bad idea ... */
    1939                             AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1940 
    1941                             /* Forward the information to the VMM device. */
    1942                             AssertPtr(mParent);
    1943                             pVMMDev = mParent->getVMMDev();
    1944                         }
    1945 
    1946                         if (pVMMDev)
    1947                         {
    1948                             LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    1949                             vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
    1950                                                        i, paParms);
    1951                         }
    1952                         else
    1953                             vrc = VERR_INVALID_VM_HANDLE;
    1954                     }
    1955                     RTMemFree(pvEnv);
    1956                 }
    1957                 RTStrFree(pszArgs);
    1958             }
    1959 
    1960             if (RT_SUCCESS(vrc))
    1961             {
    1962                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1963 
    1964                 /*
    1965                  * Generate a host-driven PID so that we immediately can return to the caller and
    1966                  * don't need to wait until the guest started the desired process to return the
    1967                  * PID generated by the guest OS.
    1968                  *
    1969                  * The guest PID will later be mapped to the host PID for later lookup.
    1970                  */
    1971                 vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */
    1972 
    1973                 uint32_t uTries = 0;
    1974                 for (;;)
    1975                 {
    1976                     /* Create a new context ID ... */
    1977                     uHostPID = ASMAtomicIncU32(&mNextHostPID);
    1978                     if (uHostPID == UINT32_MAX)
    1979                         ASMAtomicUoWriteU32(&mNextHostPID, 1000);
    1980                     /* Is the host PID already used? Try next PID ... */
    1981                     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1982                     if (it == mGuestProcessMap.end())
    1983                     {
    1984                         /* Host PID not used (anymore), we're done here ... */
    1985                         vrc = VINF_SUCCESS;
    1986                         break;
    1987                     }
    1988 
    1989                     if (++uTries == UINT32_MAX)
    1990                         break; /* Don't try too hard. */
    1991                 }
    1992 
    1993                 if (RT_SUCCESS(vrc))
    1994                     vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */,
    1995                                            ExecuteProcessStatus_Undefined /* Process not started yet */,
    1996                                            0 /* uExitCode */, 0 /* uFlags */);
    1997 
    1998                 if (RT_SUCCESS(vrc))
    1999                     vrc = callbackAssignHostPID(uContextID, uHostPID);
    2000             }
    2001             else
    2002                 rc = setErrorHGCM(vrc);
    2003 
    2004             for (unsigned i = 0; i < uNumArgs; i++)
    2005                 RTMemFree(papszArgv[i]);
    2006             RTMemFree(papszArgv);
    2007 
    2008             if (RT_FAILURE(vrc))
    2009                 rc = VBOX_E_IPRT_ERROR;
    2010         }
    2011 
    2012         if (SUCCEEDED(rc))
    2013         {
    2014             /* Return host PID. */
    2015             *aPID = uHostPID;
    2016 
    2017             /* Return the progress to the caller. */
    2018             pProgress.queryInterfaceTo(aProgress);
    2019         }
    2020         else
    2021         {
    2022             if (!pRC) /* Skip logging internal calls. */
    2023                 LogRel(("Executing guest process \"%s\" as user \"%s\" failed with %Rrc\n",
    2024                         Utf8Command.c_str(), Utf8UserName.c_str(), vrc));
    2025         }
    2026 
    2027         if (pRC)
    2028             *pRC = vrc;
    2029     }
    2030     catch (std::bad_alloc &)
    2031     {
    2032         rc = E_OUTOFMEMORY;
    2033         if (pRC)
    2034             *pRC = VERR_NO_MEMORY;
    2035     }
    2036     return rc;
    2037 }
    2038 #endif /* VBOX_WITH_GUEST_CONTROL */
    2039 
    2040 STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
    2041 {
    2042 #ifndef VBOX_WITH_GUEST_CONTROL
    2043     ReturnComNotImplemented();
    2044 #else  /* VBOX_WITH_GUEST_CONTROL */
    2045     using namespace guestControl;
    2046 
    2047     CheckComArgExpr(aPID, aPID > 0);
    2048     CheckComArgOutPointerValid(aBytesWritten);
    2049 
    2050     /* Validate flags. */
    2051     if (aFlags)
    2052     {
    2053         if (!(aFlags & ProcessInputFlag_EndOfFile))
    2054             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2055     }
    2056 
    2057     AutoCaller autoCaller(this);
    2058     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2059 
    2060     HRESULT rc = S_OK;
    2061 
    2062     try
    2063     {
    2064         VBOXGUESTCTRL_PROCESS process;
    2065         int vrc = processGetStatus(aPID, &process, false /* Don't remove */);
    2066         if (RT_SUCCESS(vrc))
    2067         {
    2068             /* PID exists; check if process is still running. */
    2069             if (process.mStatus != ExecuteProcessStatus_Started)
    2070                 rc = setError(VBOX_E_IPRT_ERROR,
    2071                               Guest::tr("Cannot inject input to a not running process (PID %u)"), aPID);
    2072         }
    2073         else
    2074             rc = setError(VBOX_E_IPRT_ERROR,
    2075                           Guest::tr("Cannot inject input to a non-existent process (PID %u)"), aPID);
    2076 
    2077         if (RT_SUCCESS(vrc))
    2078         {
    2079             uint32_t uContextID = 0;
    2080 
    2081             uint32_t uGuestPID = processGetGuestPID(aPID);
    2082             Assert(uGuestPID);
    2083 
    2084             /*
    2085              * Create progress object.
    2086              * This progress object, compared to the one in executeProgress() above,
    2087              * is only single-stage local and is used to determine whether the operation
    2088              * finished or got canceled.
    2089              */
    2090             ComObjPtr <Progress> pProgress;
    2091             rc = pProgress.createObject();
    2092             if (SUCCEEDED(rc))
    2093             {
    2094                 rc = pProgress->init(static_cast<IGuest*>(this),
    2095                                      Bstr(tr("Setting input for process")).raw(),
    2096                                      TRUE /* Cancelable */);
    2097             }
    2098             if (FAILED(rc)) throw rc;
    2099             ComAssert(!pProgress.isNull());
    2100 
    2101             /* Adjust timeout. */
    2102             if (aTimeoutMS == 0)
    2103                 aTimeoutMS = UINT32_MAX;
    2104 
    2105             VBOXGUESTCTRL_CALLBACK callback;
    2106             vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS, pProgress);
    2107             if (RT_SUCCESS(vrc))
    2108             {
    2109                 PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)callback.pvData;
    2110 
    2111                 /* Save PID + output flags for later use. */
    2112                 pData->u32PID   = uGuestPID;
    2113                 pData->u32Flags = aFlags;
    2114             }
    2115 
    2116             if (RT_SUCCESS(vrc))
    2117                 vrc = callbackAdd(&callback, &uContextID);
    2118 
    2119             if (RT_SUCCESS(vrc))
    2120             {
    2121                 com::SafeArray<BYTE> sfaData(ComSafeArrayInArg(aData));
    2122                 uint32_t cbSize = sfaData.size();
    2123 
    2124                 VBOXHGCMSVCPARM paParms[6];
    2125                 int i = 0;
    2126                 paParms[i++].setUInt32(uContextID);
    2127                 paParms[i++].setUInt32(uGuestPID);
    2128                 paParms[i++].setUInt32(aFlags);
    2129                 paParms[i++].setPointer(sfaData.raw(), cbSize);
    2130                 paParms[i++].setUInt32(cbSize);
    2131 
    2132                 {
    2133                     VMMDev *pVMMDev = NULL;
    2134                     {
    2135                         /* Make sure mParent is valid, so set the read lock while using.
    2136                          * Do not keep this lock while doing the actual call, because in the meanwhile
    2137                          * another thread could request a write lock which would be a bad idea ... */
    2138                         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2139 
    2140                         /* Forward the information to the VMM device. */
    2141                         AssertPtr(mParent);
    2142                         pVMMDev = mParent->getVMMDev();
    2143                     }
    2144 
    2145                     if (pVMMDev)
    2146                     {
    2147                         LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    2148                         vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_SET_INPUT,
    2149                                                    i, paParms);
    2150                         if (RT_FAILURE(vrc))
    2151                             rc = setErrorHGCM(vrc);
    2152                     }
    2153                 }
    2154             }
    2155 
    2156             if (RT_SUCCESS(vrc))
    2157             {
    2158                 LogFlowFunc(("Waiting for HGCM callback ...\n"));
    2159 
    2160                  /*
    2161                  * Wait for getting back the input response from the guest.
    2162                  */
    2163                 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS);
    2164                 if (RT_SUCCESS(vrc))
    2165                 {
    2166                     PCALLBACKDATAEXECINSTATUS pExecStatusIn;
    2167                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
    2168                                               (void**)&pExecStatusIn, NULL /* Don't need the size. */);
    2169                     if (RT_SUCCESS(vrc))
    2170                     {
    2171                         AssertPtr(pExecStatusIn);
    2172                         switch (pExecStatusIn->u32Status)
    2173                         {
    2174                             case INPUT_STS_WRITTEN:
    2175                                 *aBytesWritten = pExecStatusIn->cbProcessed;
    2176                                 break;
    2177 
    2178                             case INPUT_STS_ERROR:
    2179                                 rc = setError(VBOX_E_IPRT_ERROR,
    2180                                               tr("Client reported error %Rrc while processing input data"),
    2181                                               pExecStatusIn->u32Flags);
    2182                                 break;
    2183 
    2184                             case INPUT_STS_TERMINATED:
    2185                                 rc = setError(VBOX_E_IPRT_ERROR,
    2186                                               tr("Client terminated while processing input data"));
    2187                                 break;
    2188 
    2189                             case INPUT_STS_OVERFLOW:
    2190                                 rc = setError(VBOX_E_IPRT_ERROR,
    2191                                               tr("Client reported buffer overflow while processing input data"));
    2192                                 break;
    2193 
    2194                             default:
    2195                                 /*AssertReleaseMsgFailed(("Client reported unknown input error, status=%u, flags=%u\n",
    2196                                                         pExecStatusIn->u32Status, pExecStatusIn->u32Flags));*/
    2197                                 break;
    2198                         }
    2199 
    2200                         callbackFreeUserData(pExecStatusIn);
    2201                     }
    2202                     else
    2203                     {
    2204                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    2205                                            tr("Unable to retrieve process input status data"));
    2206                     }
    2207                 }
    2208                 else
    2209                     rc = setErrorCompletion(vrc);
    2210             }
    2211 
    2212             {
    2213                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2214 
    2215                 /* The callback isn't needed anymore -- just was kept locally. */
    2216                 callbackRemove(uContextID);
    2217             }
    2218 
    2219             /* Cleanup. */
    2220             if (!pProgress.isNull())
    2221                 pProgress->uninit();
    2222             pProgress.setNull();
    2223         }
    2224     }
    2225     catch (std::bad_alloc &)
    2226     {
    2227         rc = E_OUTOFMEMORY;
    2228     }
    2229     return rc;
    2230 #endif
    2231 }
    2232 
    2233 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
    2234 {
    2235 #ifndef VBOX_WITH_GUEST_CONTROL
    2236     ReturnComNotImplemented();
    2237 #else  /* VBOX_WITH_GUEST_CONTROL */
    2238     using namespace guestControl;
    2239 
    2240     return getProcessOutputInternal(aPID, aFlags, aTimeoutMS,
    2241                                     aSize, ComSafeArrayOutArg(aData), NULL /* rc */);
    2242 #endif
    2243 }
    2244 
    2245 HRESULT Guest::getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
    2246                                         LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC)
    2247 {
    2248 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    2249  *        in the API and have the same way of specifying infinite waits!  */
    2250 #ifndef VBOX_WITH_GUEST_CONTROL
    2251     ReturnComNotImplemented();
    2252 #else  /* VBOX_WITH_GUEST_CONTROL */
    2253     using namespace guestControl;
    2254 
    2255     CheckComArgExpr(aPID, aPID > 0);
    2256     if (aSize < 0)
    2257         return setError(E_INVALIDARG, tr("The size argument (%lld) is negative"), aSize);
    2258     if (aSize == 0)
    2259         return setError(E_INVALIDARG, tr("The size (%lld) is zero"), aSize);
    2260     if (aFlags)
    2261     {
    2262         if (!(aFlags & ProcessOutputFlag_StdErr))
    2263         {
    2264             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2265         }
    2266     }
    2267 
    2268     AutoCaller autoCaller(this);
    2269     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2270 
    2271     HRESULT rc = S_OK;
    2272 
    2273     try
    2274     {
    2275         VBOXGUESTCTRL_PROCESS proc;
    2276         int vrc = processGetStatus(aPID, &proc, false /* Don't remove */);
    2277         if (RT_FAILURE(vrc))
    2278         {
    2279             rc = setError(VBOX_E_IPRT_ERROR,
    2280                           Guest::tr("Guest process (PID %u) does not exist"), aPID);
    2281         }
    2282         else if (proc.mStatus != ExecuteProcessStatus_Started)
    2283         {
    2284             /* If the process is already or still in the process table but does not run yet
    2285              * (or anymore) don't remove it but report back an appropriate error. */
    2286             vrc = VERR_BROKEN_PIPE;
    2287             /* Not getting any output is fine, so don't report an API error (rc)
    2288              * and only signal something through internal error code (vrc). */
    2289         }
    2290 
    2291         if (RT_SUCCESS(vrc))
    2292         {
    2293             uint32_t uContextID = 0;
    2294 
    2295             /*
    2296              * Create progress object.
    2297              * This progress object, compared to the one in executeProgress() above,
    2298              * is only single-stage local and is used to determine whether the operation
    2299              * finished or got canceled.
    2300              */
    2301             ComObjPtr <Progress> pProgress;
    2302             rc = pProgress.createObject();
    2303             if (SUCCEEDED(rc))
    2304             {
    2305                 rc = pProgress->init(static_cast<IGuest*>(this),
    2306                                      Bstr(tr("Getting output for guest process")).raw(),
    2307                                      TRUE /* Cancelable */);
    2308             }
    2309             if (FAILED(rc)) throw rc;
    2310             ComAssert(!pProgress.isNull());
    2311 
    2312             /* Adjust timeout. */
    2313             if (aTimeoutMS == 0)
    2314                 aTimeoutMS = UINT32_MAX;
    2315 
    2316             /* Set handle ID. */
    2317             uint32_t uHandleID = OUTPUT_HANDLE_ID_STDOUT; /* Default */
    2318             if (aFlags & ProcessOutputFlag_StdErr)
    2319                 uHandleID = OUTPUT_HANDLE_ID_STDERR;
    2320 
    2321             uint32_t uGuestPID = processGetGuestPID(aPID);
    2322             Assert(uGuestPID);
    2323 
    2324             /** @todo Use a buffer for next iteration if returned data is too big
    2325              *        for current read.
    2326              *        aSize is bogus -- will be ignored atm! */
    2327             VBOXGUESTCTRL_CALLBACK callback;
    2328             vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT, pProgress);
    2329             if (RT_SUCCESS(vrc))
    2330             {
    2331                 PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)callback.pvData;
    2332 
    2333                 /* Save PID + output flags for later use. */
    2334                 pData->u32PID   = uGuestPID;
    2335                 pData->u32Flags = aFlags;
    2336             }
    2337 
    2338             if (RT_SUCCESS(vrc))
    2339                 vrc = callbackAdd(&callback, &uContextID);
    2340 
    2341             if (RT_SUCCESS(vrc))
    2342             {
    2343                 VBOXHGCMSVCPARM paParms[5];
    2344                 int i = 0;
    2345                 paParms[i++].setUInt32(uContextID);
    2346                 paParms[i++].setUInt32(uGuestPID);
    2347                 paParms[i++].setUInt32(uHandleID);
    2348                 paParms[i++].setUInt32(0 /* Flags, none set yet */);
    2349 
    2350                 VMMDev *pVMMDev = NULL;
    2351                 {
    2352                     /* Make sure mParent is valid, so set the read lock while using.
    2353                      * Do not keep this lock while doing the actual call, because in the meanwhile
    2354                      * another thread could request a write lock which would be a bad idea ... */
    2355                     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2356 
    2357                     /* Forward the information to the VMM device. */
    2358                     AssertPtr(mParent);
    2359                     pVMMDev = mParent->getVMMDev();
    2360                 }
    2361 
    2362                 if (pVMMDev)
    2363                 {
    2364                     LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    2365                     vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_GET_OUTPUT,
    2366                                                i, paParms);
    2367                 }
    2368             }
    2369 
    2370             if (RT_SUCCESS(vrc))
    2371             {
    2372                 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
    2373 
    2374                 /*
    2375                  * Wait for the HGCM low level callback until the process
    2376                  * has been started (or something went wrong). This is necessary to
    2377                  * get the PID.
    2378                  */
    2379 
    2380                 /*
    2381                  * Wait for the first output callback notification to arrive.
    2382                  */
    2383                 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS);
    2384                 if (RT_SUCCESS(vrc))
    2385                 {
    2386                     PCALLBACKDATAEXECOUT pExecOut = NULL;
    2387                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
    2388                                               (void**)&pExecOut, NULL /* Don't need the size. */);
    2389                     if (RT_SUCCESS(vrc))
    2390                     {
    2391                         com::SafeArray<BYTE> outputData((size_t)aSize);
    2392 
    2393                         if (pExecOut->cbData)
    2394                         {
    2395                             bool fResize;
    2396 
    2397                             /* Do we need to resize the array? */
    2398                             if (pExecOut->cbData > aSize)
    2399                             {
    2400                                 fResize = outputData.resize(pExecOut->cbData);
    2401                                 Assert(fResize);
    2402                             }
    2403 
    2404                             /* Fill output in supplied out buffer. */
    2405                             Assert(outputData.size() >= pExecOut->cbData);
    2406                             memcpy(outputData.raw(), pExecOut->pvData, pExecOut->cbData);
    2407                             fResize = outputData.resize(pExecOut->cbData); /* Shrink to fit actual buffer size. */
    2408                             Assert(fResize);
    2409                         }
    2410                         else
    2411                         {
    2412                             /* No data within specified timeout available. */
    2413                             bool fResize = outputData.resize(0);
    2414                             Assert(fResize);
    2415                         }
    2416 
    2417                         /* Detach output buffer to output argument. */
    2418                         outputData.detachTo(ComSafeArrayOutArg(aData));
    2419 
    2420                         callbackFreeUserData(pExecOut);
    2421                     }
    2422                     else
    2423                     {
    2424                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    2425                                            tr("Unable to retrieve process output data (%Rrc)"), vrc);
    2426                     }
    2427                 }
    2428                 else
    2429                     rc = setErrorCompletion(vrc);
    2430             }
    2431             else
    2432                 rc = setErrorHGCM(vrc);
    2433 
    2434             {
    2435                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2436 
    2437                 /* The callback isn't needed anymore -- just was kept locally. */
    2438                 callbackRemove(uContextID);
    2439             }
    2440 
    2441             /* Cleanup. */
    2442             if (!pProgress.isNull())
    2443                 pProgress->uninit();
    2444             pProgress.setNull();
    2445         }
    2446 
    2447         if (pRC)
    2448             *pRC = vrc;
    2449     }
    2450     catch (std::bad_alloc &)
    2451     {
    2452         rc = E_OUTOFMEMORY;
    2453         if (pRC)
    2454             *pRC = VERR_NO_MEMORY;
    2455     }
    2456     return rc;
    2457 #endif
    2458 }
    2459 
    2460 STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ExecuteProcessStatus_T *aStatus)
    2461 {
    2462 #ifndef VBOX_WITH_GUEST_CONTROL
    2463     ReturnComNotImplemented();
    2464 #else  /* VBOX_WITH_GUEST_CONTROL */
    2465 
    2466     AutoCaller autoCaller(this);
    2467     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2468 
    2469     HRESULT rc = S_OK;
    2470 
    2471     try
    2472     {
    2473         VBOXGUESTCTRL_PROCESS process;
    2474         int vrc = processGetStatus(aPID, &process,
    2475                                    true /* Remove when terminated */);
    2476         if (RT_SUCCESS(vrc))
    2477         {
    2478             if (aExitCode)
    2479                 *aExitCode = process.mExitCode;
    2480             if (aFlags)
    2481                 *aFlags = process.mFlags;
    2482             if (aStatus)
    2483                 *aStatus = process.mStatus;
    2484         }
    2485         else
    2486             rc = setError(VBOX_E_IPRT_ERROR,
    2487                           tr("Process (PID %u) not found!"), aPID);
    2488     }
    2489     catch (std::bad_alloc &)
    2490     {
    2491         rc = E_OUTOFMEMORY;
    2492     }
    2493     return rc;
    2494 #endif
    2495 }
    2496 
    2497 STDMETHODIMP Guest::CopyFromGuest(IN_BSTR aSource, IN_BSTR aDest,
    2498                                   IN_BSTR aUsername, IN_BSTR aPassword,
    2499                                   ULONG aFlags, IProgress **aProgress)
    2500 {
    2501 #ifndef VBOX_WITH_GUEST_CONTROL
    2502     ReturnComNotImplemented();
    2503 #else /* VBOX_WITH_GUEST_CONTROL */
    2504     CheckComArgStrNotEmptyOrNull(aSource);
    2505     CheckComArgStrNotEmptyOrNull(aDest);
    2506     CheckComArgOutPointerValid(aProgress);
    2507 
    2508     /* Do not allow anonymous executions (with system rights). */
    2509     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    2510         return setError(E_INVALIDARG, tr("No user name specified"));
    2511 
    2512     AutoCaller autoCaller(this);
    2513     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2514 
    2515     /* Validate flags. */
    2516     if (aFlags != CopyFileFlag_None)
    2517     {
    2518         if (   !(aFlags & CopyFileFlag_Recursive)
    2519             && !(aFlags & CopyFileFlag_Update)
    2520             && !(aFlags & CopyFileFlag_FollowLinks))
    2521         {
    2522             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2523         }
    2524     }
    2525 
    2526     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2527 
    2528     HRESULT rc = S_OK;
    2529 
    2530     ComObjPtr<Progress> progress;
    2531     try
    2532     {
    2533         /* Create the progress object. */
    2534         progress.createObject();
    2535 
    2536         rc = progress->init(static_cast<IGuest*>(this),
    2537                             Bstr(tr("Copying file from guest to host")).raw(),
    2538                             TRUE /* aCancelable */);
    2539         if (FAILED(rc)) throw rc;
    2540 
    2541         /* Initialize our worker task. */
    2542         GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileFromGuest, this, progress);
    2543         AssertPtr(pTask);
    2544         std::auto_ptr<GuestTask> task(pTask);
    2545 
    2546         /* Assign data - aSource is the source file on the host,
    2547          * aDest reflects the full path on the guest. */
    2548         task->strSource   = (Utf8Str(aSource));
    2549         task->strDest     = (Utf8Str(aDest));
    2550         task->strUserName = (Utf8Str(aUsername));
    2551         task->strPassword = (Utf8Str(aPassword));
    2552         task->uFlags      = aFlags;
    2553 
    2554         rc = task->startThread();
    2555         if (FAILED(rc)) throw rc;
    2556 
    2557         /* Don't destruct on success. */
    2558         task.release();
    2559     }
    2560     catch (HRESULT aRC)
    2561     {
    2562         rc = aRC;
    2563     }
    2564 
    2565     if (SUCCEEDED(rc))
    2566     {
    2567         /* Return progress to the caller. */
    2568         progress.queryInterfaceTo(aProgress);
    2569     }
    2570     return rc;
    2571 #endif /* VBOX_WITH_GUEST_CONTROL */
    2572 }
    2573 
    2574 STDMETHODIMP Guest::CopyToGuest(IN_BSTR aSource, IN_BSTR aDest,
    2575                                 IN_BSTR aUsername, IN_BSTR aPassword,
    2576                                 ULONG aFlags, IProgress **aProgress)
    2577 {
    2578 #ifndef VBOX_WITH_GUEST_CONTROL
    2579     ReturnComNotImplemented();
    2580 #else /* VBOX_WITH_GUEST_CONTROL */
    2581     CheckComArgStrNotEmptyOrNull(aSource);
    2582     CheckComArgStrNotEmptyOrNull(aDest);
    2583     CheckComArgOutPointerValid(aProgress);
    2584 
    2585     /* Do not allow anonymous executions (with system rights). */
    2586     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    2587         return setError(E_INVALIDARG, tr("No user name specified"));
    2588 
    2589     AutoCaller autoCaller(this);
    2590     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2591 
    2592     /* Validate flags. */
    2593     if (aFlags != CopyFileFlag_None)
    2594     {
    2595         if (   !(aFlags & CopyFileFlag_Recursive)
    2596             && !(aFlags & CopyFileFlag_Update)
    2597             && !(aFlags & CopyFileFlag_FollowLinks))
    2598         {
    2599             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2600         }
    2601     }
    2602 
    2603     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2604 
    2605     HRESULT rc = S_OK;
    2606 
    2607     ComObjPtr<Progress> pProgress;
    2608     try
    2609     {
    2610         /* Create the progress object. */
    2611         pProgress.createObject();
    2612 
    2613         rc = pProgress->init(static_cast<IGuest*>(this),
    2614                              Bstr(tr("Copying file from host to guest")).raw(),
    2615                              TRUE /* aCancelable */);
    2616         if (FAILED(rc)) throw rc;
    2617 
    2618         /* Initialize our worker task. */
    2619         GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, pProgress);
    2620         AssertPtr(pTask);
    2621         std::auto_ptr<GuestTask> task(pTask);
    2622 
    2623         /* Assign data - aSource is the source file on the host,
    2624          * aDest reflects the full path on the guest. */
    2625         task->strSource   = (Utf8Str(aSource));
    2626         task->strDest     = (Utf8Str(aDest));
    2627         task->strUserName = (Utf8Str(aUsername));
    2628         task->strPassword = (Utf8Str(aPassword));
    2629         task->uFlags      = aFlags;
    2630 
    2631         rc = task->startThread();
    2632         if (FAILED(rc)) throw rc;
    2633 
    2634         /* Don't destruct on success. */
    2635         task.release();
    2636     }
    2637     catch (HRESULT aRC)
    2638     {
    2639         rc = aRC;
    2640     }
    2641 
    2642     if (SUCCEEDED(rc))
    2643     {
    2644         /* Return progress to the caller. */
    2645         pProgress.queryInterfaceTo(aProgress);
    2646     }
    2647     return rc;
    2648 #endif /* VBOX_WITH_GUEST_CONTROL */
    2649 }
    2650131
    2651132STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress)
     
    2676157
    2677158    HRESULT hr = S_OK;
    2678 #if 1
     159
    2679160    /* Create an anonymous session. This is required to run the Guest Additions
    2680161     * update process with administrative rights. */
     
    2724205    }
    2725206    return hr;
    2726 #else /* Legacy, can be removed later. */
    2727     ComObjPtr<Progress> progress;
    2728     try
    2729     {
    2730         /* Create the progress object. */
    2731         progress.createObject();
    2732 
    2733         rc = progress->init(static_cast<IGuest*>(this),
    2734                             Bstr(tr("Updating Guest Additions")).raw(),
    2735                             TRUE /* aCancelable */);
    2736         if (FAILED(rc)) throw rc;
    2737 
    2738         /* Initialize our worker task. */
    2739         GuestTask *pTask = new GuestTask(GuestTask::TaskType_UpdateGuestAdditions, this, progress);
    2740         AssertPtr(pTask);
    2741         std::auto_ptr<GuestTask> task(pTask);
    2742 
    2743         /* Assign data - in that case aSource is the full path
    2744          * to the Guest Additions .ISO we want to mount. */
    2745         task->strSource = (Utf8Str(aSource));
    2746         task->uFlags = aFlags;
    2747 
    2748         rc = task->startThread();
    2749         if (FAILED(rc)) throw rc;
    2750 
    2751         /* Don't destruct on success. */
    2752         task.release();
    2753     }
    2754     catch (HRESULT aRC)
    2755     {
    2756         rc = aRC;
    2757     }
    2758 
    2759     if (SUCCEEDED(rc))
    2760     {
    2761         /* Return progress to the caller. */
    2762         progress.queryInterfaceTo(aProgress);
    2763     }
    2764     return rc;
    2765 #endif
    2766207#endif /* VBOX_WITH_GUEST_CONTROL */
    2767208}
  • trunk/src/VBox/Main/src-client/GuestImpl.cpp

    r42817 r42864  
    3232
    3333#include <VBox/VMMDev.h>
    34 #ifdef VBOX_WITH_GUEST_CONTROL
    35 # include <VBox/com/array.h>
    36 # include <VBox/com/ErrorInfo.h>
    37 #endif
    3834#include <iprt/cpp/utils.h>
    3935#include <iprt/timer.h>
     
    108104    AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
    109105
    110 #ifdef VBOX_WITH_GUEST_CONTROL
    111     /* Init the context ID counter at 1000. */
    112     mNextContextID = 1000;
    113     /* Init the host PID counter. */
    114     mNextHostPID = 0;
    115 #endif
    116 
    117106#ifdef VBOX_WITH_DRAG_AND_DROP
    118107    m_pGuestDnD = new GuestDnD(this);
     
    134123    if (autoUninitSpan.uninitDone())
    135124        return;
    136 
    137 #ifdef VBOX_WITH_GUEST_CONTROL
    138     /* Scope write lock as much as possible. */
    139     {
    140         /*
    141          * Cleanup must be done *before* AutoUninitSpan to cancel all
    142          * all outstanding waits in API functions (which hold AutoCaller
    143          * ref counts).
    144          */
    145         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    146 
    147         /* Notify left over callbacks that we are about to shutdown ... */
    148         CallbackMapIter it;
    149         for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    150         {
    151             int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
    152                                        Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
    153             AssertRC(rc2);
    154         }
    155 
    156         /* Destroy left over callback data. */
    157         for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    158             callbackDestroy(it->first);
    159 
    160         /* Clear process map (remove all callbacks). */
    161         mGuestProcessMap.clear();
    162     }
    163 #endif
    164125
    165126    /* Destroy stat update timer */
  • trunk/src/VBox/Main/src-client/xpcom/module.cpp

    r42852 r42864  
    6767NS_DECL_CLASSINFO(GuestDirectory)
    6868NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestDirectory, IGuestDirectory, IDirectory)
    69 NS_DECL_CLASSINFO(GuestDirEntry)
    70 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestDirEntry, IGuestDirEntry)
    7169NS_DECL_CLASSINFO(GuestFile)
    7270NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestFile, IGuestFile, IFile)
Note: See TracChangeset for help on using the changeset viewer.

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