VirtualBox

Changeset 33064 in vbox


Ignore:
Timestamp:
Oct 12, 2010 1:20:50 PM (14 years ago)
Author:
vboxsync
Message:

Guest Execution/Copy: Added support for input handling, added more code for data copying.

Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/GuestControlSvc.h

    r32852 r33064  
    108108    /** Optional data buffer. */
    109109    void *pvData;
    110     /** Size of optional data buffer. */
     110    /** Size (in bytes) of optional data buffer. */
    111111    uint32_t cbData;
    112112} CALLBACKDATAEXECOUT, *PCALLBACKDATAEXECOUT;
     113
     114typedef struct _VBoxGuestCtrlCallbackDataExecInStatus
     115{
     116    /** Callback data header. */
     117    CALLBACKHEADER hdr;
     118    /** The process ID (PID). */
     119    uint32_t u32PID;
     120    /** Optional flags (not used atm). */
     121    uint32_t u32Flags;
     122    /** Size (in bytes) of processed input data. */
     123    uint32_t cbProcessed;
     124} CALLBACKDATAEXECINSTATUS, *PCALLBACKDATAEXECINSTATUS;
    113125
    114126typedef struct _VBoxGuestCtrlCallbackDataClientDisconnected
     
    125137    CALLBACKDATAMAGICEXECSTATUS = 0x26011982,
    126138    /** Magic number for sanity checking the CALLBACKDATAEXECOUT structure. */
    127     CALLBACKDATAMAGICEXECOUT = 0x11061949
     139    CALLBACKDATAMAGICEXECOUT = 0x11061949,
     140    /** Magic number for sanity checking the CALLBACKDATAEXECIN structure. */
     141    CALLBACKDATAMAGICEXECINSTATUS = 0x19091951
    128142};
    129143
     
    132146    VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN = 0,
    133147    VBOXGUESTCTRLCALLBACKTYPE_EXEC_START = 1,
    134     VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT = 2
     148    VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT = 2,
     149    VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS = 3
    135150};
    136151
     
    140155enum eHostFn
    141156{
     157    /**
     158     * The host asks the client to cancel all pending waits and exit.
     159     */
     160    HOST_CANCEL_PENDING_WAITS = 0,
    142161    /**
    143162     * The host wants to execute something in the guest. This can be a command line
     
    179198    GUEST_DISCONNECTED = 3,
    180199    /**
    181      * TODO
     200     * Guests sends output from an executed process.
    182201     */
    183202    GUEST_EXEC_SEND_OUTPUT = 100,
    184203    /**
    185      * TODO
    186      */
    187     GUEST_EXEC_SEND_STATUS = 101
    188 };
    189 
    190 /**
    191  * Sub host commands.  These commands are stored as first (=0) parameter in a GUEST_GET_HOST_MSG
    192  * so that the guest can react dynamically to requests from the host.
    193  */
    194 enum eGetHostMsgFn
    195 {
    196     /**
    197      * Hosts wants the guest to stop waiting for new messages.
    198      */
    199     GETHOSTMSG_EXEC_HOST_CANCEL_WAIT = 0,
    200     /**
    201      * The host wants to execute something in the guest. This can be a command line
    202      * or starting a program.
    203      */
    204     GETHOSTMSG_EXEC_START_PROCESS = 100,
    205     /**
    206      * Sends input data for stdin to a running process executed by HOST_EXEC_CMD.
    207      */
    208     GETHOSTMSG_EXEC_SEND_INPUT = 101,
    209     /**
    210      * Host requests the so far collected stdout/stderr output
    211      * from a running process executed by HOST_EXEC_CMD.
    212      */
    213     GETHOSTMSG_EXEC_GET_OUTPUT = 102
     204     * Guest sends a status update of an executed process to the host.
     205     */
     206    GUEST_EXEC_SEND_STATUS = 101,
     207    /**
     208     * Guests sends an input status notification to the host.
     209     */
     210    GUEST_EXEC_SEND_INPUT_STATUS = 102
    214211};
    215212
     
    265262} VBoxGuestCtrlHGCMMsgExecCmd;
    266263
     264typedef struct _VBoxGuestCtrlHGCMMsgExecIn
     265{
     266    VBoxGuestHGCMCallInfo hdr;
     267    /** Context ID. */
     268    HGCMFunctionParameter context;
     269    /** The process ID (PID). */
     270    HGCMFunctionParameter pid;
     271    /** Optional flags. */
     272    HGCMFunctionParameter flags;
     273    /** Data buffer. */
     274    HGCMFunctionParameter data;
     275    /** Actual size of data. */
     276    HGCMFunctionParameter size;
     277
     278} VBoxGuestCtrlHGCMMsgExecIn;
     279
    267280typedef struct _VBoxGuestCtrlHGCMMsgExecOut
    268281{
     
    272285    /** The process ID (PID). */
    273286    HGCMFunctionParameter pid;
    274     /** The pipe handle ID. */
     287    /** The pipe handle ID (stdout/stderr). */
    275288    HGCMFunctionParameter handle;
    276289    /** Optional flags. */
     
    296309
    297310} VBoxGuestCtrlHGCMMsgExecStatus;
     311
     312typedef struct _VBoxGuestCtrlHGCMMsgExecStatusIn
     313{
     314    VBoxGuestHGCMCallInfo hdr;
     315    /** Context ID. */
     316    HGCMFunctionParameter context;
     317    /** The process ID (PID). */
     318    HGCMFunctionParameter pid;
     319    /** Optional flags. */
     320    HGCMFunctionParameter flags;
     321    /** Data written. */
     322    HGCMFunctionParameter written;
     323
     324} VBoxGuestCtrlHGCMMsgExecStatusIn;
    298325#pragma pack ()
    299326
  • trunk/include/VBox/VBoxGuestLib.h

    r32574 r33064  
    557557                                                  char     *pszPassword,    uint32_t  cbPassword,
    558558                                                  uint32_t *puTimeLimit);
    559 VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t  u32ClientId,    uint32_t  uNumParms,
    560                                                     uint32_t *puContext,      uint32_t *puPID,
    561                                                     uint32_t *puHandle,       uint32_t *puFlags);
     559VBGLR3DECL(int)     VbglR3GuestCtrlExecGetHostCmdInput(uint32_t  u32ClientId,    uint32_t   uNumParms,
     560                                                       uint32_t *puContext,      uint32_t  *puPID,
     561                                                       uint32_t *puFlags,        void      *pvData,
     562                                                       uint32_t  cbData,         uint32_t  *pcbSize);
     563VBGLR3DECL(int)     VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t  u32ClientId,    uint32_t  uNumParms,
     564                                                        uint32_t *puContext,      uint32_t *puPID,
     565                                                        uint32_t *puHandle,       uint32_t *puFlags);
    562566VBGLR3DECL(int)     VbglR3GuestCtrlExecReportStatus(uint32_t  u32ClientId,
    563567                                                    uint32_t  u32Context,
     
    574578                                               void        *pvData,
    575579                                               uint32_t     cbData);
     580VBGLR3DECL(int)     VbglR3GuestCtrlExecReportStatusIn(uint32_t     u32ClientId,
     581                                                      uint32_t     u32Context,
     582                                                      uint32_t     u32PID,
     583                                                      uint32_t     u32Flags,
     584                                                      uint32_t     cbWritten);
    576585/** @}  */
    577586# endif /* VBOX_WITH_GUEST_CONTROL defined */
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp

    r30013 r33064  
    105105VBGLR3DECL(int) VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms)
    106106{
    107     AssertPtr(puMsg);
    108     AssertPtr(puNumParms);
     107    AssertPtrReturn(puMsg, VERR_INVALID_PARAMETER);
     108    AssertPtrReturn(puNumParms, VERR_INVALID_PARAMETER);
    109109
    110110    VBoxGuestCtrlHGCMMsgType Msg;
     
    178178                                              uint32_t *puTimeLimit)
    179179{
    180     AssertPtr(puContext);
    181     AssertPtr(pszCmd);
    182     AssertPtr(puFlags);
    183     AssertPtr(pszArgs);
    184     AssertPtr(puNumArgs);
    185     AssertPtr(pszEnv);
    186     AssertPtr(pcbEnv);
    187     AssertPtr(puNumEnvVars);
    188     AssertPtr(pszUser);
    189     AssertPtr(pszPassword);
    190     AssertPtr(puTimeLimit);
     180    AssertPtrReturn(puContext, VERR_INVALID_PARAMETER);
     181    AssertPtrReturn(pszCmd, VERR_INVALID_PARAMETER);
     182    AssertPtrReturn(puFlags, VERR_INVALID_PARAMETER);
     183    AssertPtrReturn(pszArgs, VERR_INVALID_PARAMETER);
     184    AssertPtrReturn(puNumArgs, VERR_INVALID_PARAMETER);
     185    AssertPtrReturn(pszEnv, VERR_INVALID_PARAMETER);
     186    AssertPtrReturn(pcbEnv, VERR_INVALID_PARAMETER);
     187    AssertPtrReturn(puNumEnvVars, VERR_INVALID_PARAMETER);
     188    AssertPtrReturn(pszUser, VERR_INVALID_PARAMETER);
     189    AssertPtrReturn(pszPassword, VERR_INVALID_PARAMETER);
     190    AssertPtrReturn(puTimeLimit, VERR_INVALID_PARAMETER);
    191191
    192192    VBoxGuestCtrlHGCMMsgExecCmd Msg;
     
    197197    Msg.hdr.cParms = uNumParms;
    198198
    199     VbglHGCMParmUInt32Set(&Msg.context, 0); /** @todo Put this some header struct! */
     199    VbglHGCMParmUInt32Set(&Msg.context, 0);
    200200    VbglHGCMParmPtrSet(&Msg.cmd, pszCmd, cbCmd);
    201201    VbglHGCMParmUInt32Set(&Msg.flags, 0);
     
    245245                                                    uint32_t *puHandle,       uint32_t *puFlags)
    246246{
    247     AssertPtr(puContext);
    248     AssertPtr(puPID);
     247    AssertPtrReturn(puContext, VERR_INVALID_PARAMETER);
     248    AssertPtrReturn(puPID, VERR_INVALID_PARAMETER);
     249    AssertPtrReturn(puHandle, VERR_INVALID_PARAMETER);
     250    AssertPtrReturn(puFlags, VERR_INVALID_PARAMETER);
    249251
    250252    VBoxGuestCtrlHGCMMsgExecOut Msg;
     
    255257    Msg.hdr.cParms = uNumParms;
    256258
    257     VbglHGCMParmUInt32Set(&Msg.context, 0); /** @todo Put this some header struct! */
     259    VbglHGCMParmUInt32Set(&Msg.context, 0);
    258260    VbglHGCMParmUInt32Set(&Msg.pid, 0);
    259261    VbglHGCMParmUInt32Set(&Msg.handle, 0);
     
    274276            Msg.handle.GetUInt32(puHandle);
    275277            Msg.flags.GetUInt32(puFlags);
     278        }
     279    }
     280    return rc;
     281}
     282
     283
     284/**
     285 * Retrieves the input data from host which then gets sent to the
     286 * started process.
     287 *
     288 * This will block until data becomes available.
     289 *
     290 * @returns VBox status code.
     291 * @param   u32ClientId     The client id returned by VbglR3GuestCtrlConnect().
     292 * @param   uNumParms
     293 ** @todo Docs!
     294 */
     295VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdInput(uint32_t  u32ClientId,    uint32_t   uNumParms,
     296                                                   uint32_t *puContext,      uint32_t  *puPID,
     297                                                   uint32_t *puFlags,
     298                                                   void      *pvData,        uint32_t  cbData,
     299                                                   uint32_t *pcbSize)
     300{
     301    AssertPtrReturn(puContext, VERR_INVALID_PARAMETER);
     302    AssertPtrReturn(puPID, VERR_INVALID_PARAMETER);
     303    AssertPtrReturn(puFlags, VERR_INVALID_PARAMETER);
     304    AssertPtrReturn(pvData, VERR_INVALID_PARAMETER);
     305    AssertPtrReturn(pcbSize, VERR_INVALID_PARAMETER);
     306
     307    VBoxGuestCtrlHGCMMsgExecIn Msg;
     308
     309    Msg.hdr.result = VERR_WRONG_ORDER;
     310    Msg.hdr.u32ClientID = u32ClientId;
     311    Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
     312    Msg.hdr.cParms = uNumParms;
     313
     314    VbglHGCMParmUInt32Set(&Msg.context, 0);
     315    VbglHGCMParmUInt32Set(&Msg.pid, 0);
     316    VbglHGCMParmUInt32Set(&Msg.flags, 0);
     317    VbglHGCMParmPtrSet(&Msg.data, pvData, cbData);
     318    VbglHGCMParmUInt32Set(&Msg.size, 0);
     319
     320    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     321    if (RT_SUCCESS(rc))
     322    {
     323        int rc2 = Msg.hdr.result;
     324        if (RT_FAILURE(rc2))
     325        {
     326            rc = rc2;
     327        }
     328        else
     329        {
     330            Msg.context.GetUInt32(puContext);
     331            Msg.pid.GetUInt32(puPID);
     332            Msg.flags.GetUInt32(puFlags);
     333            Msg.size.GetUInt32(pcbSize);
    276334        }
    277335    }
     
    355413}
    356414
     415
     416/**
     417 * Reports back the input status to the host.
     418 *
     419 * @returns VBox status code.
     420 ** @todo Docs!
     421 */
     422VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatusIn(uint32_t     u32ClientId,
     423                                                  uint32_t     u32Context,
     424                                                  uint32_t     u32PID,
     425                                                  uint32_t     u32Flags,
     426                                                  uint32_t     cbWritten)
     427{
     428    VBoxGuestCtrlHGCMMsgExecStatusIn Msg;
     429
     430    Msg.hdr.result = VERR_WRONG_ORDER;
     431    Msg.hdr.u32ClientID = u32ClientId;
     432    Msg.hdr.u32Function = GUEST_EXEC_SEND_INPUT_STATUS;
     433    Msg.hdr.cParms = 4;
     434
     435    VbglHGCMParmUInt32Set(&Msg.context, u32Context);
     436    VbglHGCMParmUInt32Set(&Msg.pid, u32PID);
     437    VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);
     438    VbglHGCMParmUInt32Set(&Msg.written, cbWritten);
     439
     440    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     441    if (RT_SUCCESS(rc))
     442    {
     443        int rc2 = Msg.hdr.result;
     444        if (RT_FAILURE(rc2))
     445            rc = rc2;
     446    }
     447    return rc;
     448}
  • trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk

    r32991 r33064  
    3939ifdef VBOX_WITH_GUEST_PROPS
    4040 VBoxService_DEFS        += VBOX_WITH_GUEST_PROPS VBOXSERVICE_VMINFO
    41  if1of ($(KBUILD_TARGET), win)
    42   VBoxService_DEFS       += VBOXSERVICE_EXEC
    43  endif
    4441endif
    4542ifdef VBOX_WITH_GUEST_CONTROL
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r32431 r33064  
    105105
    106106
    107 static int VBoxServiceControlHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms)
    108 {
    109     uint32_t uContextID;
    110     char szCmd[_1K];
    111     uint32_t uFlags;
    112     char szArgs[_1K];
    113     uint32_t uNumArgs;
    114     char szEnv[_64K];
    115     uint32_t cbEnv = sizeof(szEnv);
    116     uint32_t uNumEnvVars;
    117     char szUser[128];
    118     char szPassword[128];
    119     uint32_t uTimeLimitMS;
    120 
    121 #if 0 /* for valgrind */
    122     RT_ZERO(szCmd);
    123     RT_ZERO(szArgs);
    124     RT_ZERO(szEnv);
    125     RT_ZERO(szUser);
    126     RT_ZERO(szPassword);
    127 #endif
    128 
    129     if (uNumParms != 11)
    130         return VERR_INVALID_PARAMETER;
    131 
    132     int rc = VbglR3GuestCtrlExecGetHostCmd(u32ClientId,
    133                                            uNumParms,
    134                                            &uContextID,
    135                                            /* Command */
    136                                            szCmd,      sizeof(szCmd),
    137                                            /* Flags */
    138                                            &uFlags,
    139                                            /* Arguments */
    140                                            szArgs,     sizeof(szArgs), &uNumArgs,
    141                                            /* Environment */
    142                                            szEnv, &cbEnv, &uNumEnvVars,
    143                                            /* Credentials */
    144                                            szUser,     sizeof(szUser),
    145                                            szPassword, sizeof(szPassword),
    146                                            /* Timelimit */
    147                                            &uTimeLimitMS);
    148     if (RT_FAILURE(rc))
    149     {
    150         VBoxServiceError("Control: Failed to retrieve exec start command! Error: %Rrc\n", rc);
    151     }
    152     else
    153     {
    154         rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
    155                                            szEnv, cbEnv, uNumEnvVars,
    156                                            szUser, szPassword, uTimeLimitMS);
    157     }
    158 
    159     VBoxServiceVerbose(3, "Control: VBoxServiceControlHandleCmdStartProcess returned with %Rrc\n", rc);
    160     return rc;
    161 }
    162 
    163 
    164 static int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms)
    165 {
    166     uint32_t uContextID;
    167     uint32_t uPID;
    168     uint32_t uHandleID;
    169     uint32_t uFlags;
    170 
    171     int rc = VbglR3GuestCtrlExecGetHostCmdOutput(u32ClientId, uNumParms,
    172                                                  &uContextID, &uPID, &uHandleID, &uFlags);
    173     if (RT_FAILURE(rc))
    174     {
    175         VBoxServiceError("Control: Failed to retrieve exec output command! Error: %Rrc\n", rc);
    176     }
    177     else
    178     {
    179         /* Let's have a look if we have a running process with PID = uPID ... */
    180         PVBOXSERVICECTRLTHREAD pNode;
    181         bool fFound = false;
    182         RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
    183         {
    184             if (   pNode->fStarted
    185                 && pNode->enmType == VBoxServiceCtrlThreadDataExec)
    186             {
    187                 PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
    188                 if (pData && pData->uPID == uPID)
    189                 {
    190                     fFound = true;
    191                     break;
    192                 }
    193             }
    194         }
    195 
    196         if (fFound)
    197         {
    198             PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
    199             AssertPtr(pData);
    200 
    201             const uint32_t cbSize = _4K;
    202             uint32_t cbRead = cbSize;
    203             uint8_t *pBuf = (uint8_t*)RTMemAlloc(cbSize);
    204             if (pBuf)
    205             {
    206                 rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbSize, &cbRead);
    207                 if (RT_SUCCESS(rc))
    208                 {
    209                     /* cbRead now contains actual size. */
    210                     rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* handle ID */, 0 /* flags */,
    211                                                     pBuf, cbRead);
    212                 }
    213                 RTMemFree(pBuf);
    214             }
    215             else
    216                 rc = VERR_NO_MEMORY;
    217         }
    218         else
    219             rc = VERR_NOT_FOUND; /* PID not found! */
    220     }
    221     VBoxServiceVerbose(3, "Control: VBoxServiceControlHandleCmdGetOutput returned with %Rrc\n", rc);
    222     return rc;
    223 }
    224 
    225 
    226107/** @copydoc VBOXSERVICE::pfnWorker */
    227108DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown)
     
    263144            switch(uMsg)
    264145            {
    265                 case GETHOSTMSG_EXEC_HOST_CANCEL_WAIT:
     146                case HOST_CANCEL_PENDING_WAITS:
    266147                    VBoxServiceVerbose(3, "Control: Host asked us to quit ...\n");
    267148                    break;
    268149
    269                 case GETHOSTMSG_EXEC_START_PROCESS:
    270                     rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
    271                     break;
    272 
    273                 case GETHOSTMSG_EXEC_GET_OUTPUT:
    274                     rc = VBoxServiceControlHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
     150                case HOST_EXEC_CMD:
     151                    rc = VBoxServiceControlExecHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
     152                    break;
     153
     154                case HOST_EXEC_SET_INPUT:
     155                    rc = VBoxServiceControlExecHandleCmdSetInput(g_GuestControlSvcClientID, uNumParms);
     156                    break;
     157
     158                case HOST_EXEC_GET_OUTPUT:
     159                    rc = VBoxServiceControlExecHandleCmdGetOutput(g_GuestControlSvcClientID, uNumParms);
    275160                    break;
    276161
     
    287172        /* Do we need to shutdown? */
    288173        if (   *pfShutdown
    289             || uMsg == GETHOSTMSG_EXEC_HOST_CANCEL_WAIT)
     174            || uMsg == HOST_CANCEL_PENDING_WAITS)
    290175        {
    291176            rc = VINF_SUCCESS;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp

    r32852 r33064  
    4747extern RTLISTNODE g_GuestControlExecThreads;
    4848
     49
    4950/**
    5051 * Handle an error event on standard input.
    5152 *
     53 * @returns IPRT status code.
    5254 * @param   hPollSet            The polling set.
    5355 * @param   fPollEvt            The event mask returned by RTPollNoResume.
     
    5557 * @param   pStdInBuf           The standard input buffer.
    5658 */
    57 static void VBoxServiceControlExecProcHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
    58                                                             PVBOXSERVICECTRLSTDINBUF pStdInBuf)
    59 {
    60     int rc2;
    61     if (pStdInBuf->off < pStdInBuf->cb)
    62     {
    63         rc2 = RTPollSetRemove(hPollSet, 4 /*TXSEXECHNDID_STDIN_WRITABLE*/);
     59static int VBoxServiceControlExecProcHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
     60                                                           PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf)
     61{
     62    int rc = RTCritSectEnter(&pStdInBuf->CritSect);
     63    if (RT_SUCCESS(rc))
     64    {
     65        int rc2;
     66        /* If no data is to be processed anymore, remove the writable pipe from
     67         * the poll set. */
     68        if (pStdInBuf->cbProcessed <= pStdInBuf->cbSize)
     69        {
     70            rc2 = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_WRITABLE);
     71            AssertRC(rc2);
     72
     73            rc2 = RTPipeClose(*phStdInW);
     74            AssertRC(rc2);
     75            *phStdInW = NIL_RTPIPE;
     76
     77            /* Mark the stdin buffer as dead; we're not using it anymore. */
     78            pStdInBuf->fAlive = false;
     79        }
     80
     81        rc2 = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_ERROR);
    6482        AssertRC(rc2);
    65     }
    66 
    67     rc2 = RTPollSetRemove(hPollSet, 0 /*TXSEXECHNDID_STDIN*/);
    68     AssertRC(rc2);
    69 
    70     rc2 = RTPipeClose(*phStdInW);
    71     AssertRC(rc2);
    72     *phStdInW = NIL_RTPIPE;
    73 
    74     RTMemFree(pStdInBuf->pch);
    75     pStdInBuf->pch          = NULL;
    76     pStdInBuf->off          = 0;
    77     pStdInBuf->cb           = 0;
    78     pStdInBuf->cbAllocated  = 0;
    79     pStdInBuf->fBitBucket   = true;
     83
     84        rc2 = RTCritSectLeave(&pStdInBuf->CritSect);
     85        if (RT_SUCCESS(rc))
     86            rc = rc2;
     87    }
     88    return rc;
    8089}
    8190
     
    8897 * @param   hStdInW             The standard input pipe.
    8998 */
    90 static int VBoxServiceControlExecProcWriteStdIn(PVBOXSERVICECTRLSTDINBUF pStdInBuf, RTPIPE hStdInW)
    91 {
    92     size_t  cbToWrite = pStdInBuf->cb - pStdInBuf->off;
    93     size_t  cbWritten;
    94     int     rc = RTPipeWrite(hStdInW, &pStdInBuf->pch[pStdInBuf->off], cbToWrite, &cbWritten);
     99static int VBoxServiceControlExecProcWriteStdIn(PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf, RTPIPE hStdInW, size_t *pcbWritten)
     100{
     101    AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER);
     102
     103    int rc = RTCritSectEnter(&pStdInBuf->CritSect);
    95104    if (RT_SUCCESS(rc))
    96105    {
    97         Assert(cbWritten == cbToWrite);
    98         pStdInBuf->off += cbWritten;
     106        size_t cbToWrite = pStdInBuf->cbSize - pStdInBuf->cbProcessed;
     107        int rc = VINF_SUCCESS;
     108        if (cbToWrite && pStdInBuf->fAlive)
     109        {
     110            rc = RTPipeWrite(hStdInW, &pStdInBuf->pbData[pStdInBuf->cbProcessed], cbToWrite, pcbWritten);
     111            if (RT_SUCCESS(rc))
     112            {
     113                Assert(*pcbWritten <= cbToWrite);
     114                pStdInBuf->cbProcessed += *pcbWritten;
     115            }
     116            else
     117                *pcbWritten = 0;
     118        }
     119        else
     120            rc = VERR_BAD_PIPE;
     121        int rc2 = RTCritSectLeave(&pStdInBuf->CritSect);
     122        if (RT_SUCCESS(rc))
     123            rc = rc2;
    99124    }
    100125    return rc;
     
    106131 * child process.
    107132 *
     133 * @returns IPRT status code.
    108134 * @param   hPollSet            The polling set.
    109135 * @param   fPollEvt            The event mask returned by RTPollNoResume.
     
    111137 * @param   pStdInBuf           The standard input buffer.
    112138 */
    113 static void VBoxServiceControlExecProcHandleStdInWritableEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
    114                                                                PVBOXSERVICECTRLSTDINBUF pStdInBuf)
    115 {
    116     int rc;
     139static int  VBoxServiceControlExecProcHandleStdInWritableEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
     140                                                               PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf)
     141{
     142    VBoxServiceVerbose(4, "ControlExec: HandleStdInWritableEvent: fPollEvt=%#x\n", fPollEvt);
     143
     144    int rc = VINF_SUCCESS;
    117145    if (!(fPollEvt & RTPOLL_EVT_ERROR))
    118146    {
    119         rc = VBoxServiceControlExecProcWriteStdIn(pStdInBuf, *phStdInW);
    120         if (RT_FAILURE(rc) && rc != VERR_BAD_PIPE)
    121         {
    122             /** @todo do we need to do something about this error condition? */
     147        size_t cbWritten;
     148        rc = VBoxServiceControlExecProcWriteStdIn(pStdInBuf, *phStdInW, &cbWritten);
     149        if (   RT_FAILURE(rc)
     150            && rc != VERR_BAD_PIPE)
     151        {
     152            /** @todo Do we need to do something about this error condition? */
    123153            AssertRC(rc);
    124154        }
    125155
    126         if (pStdInBuf->off < pStdInBuf->cb)
    127         {
    128             rc = RTPollSetRemove(hPollSet, 4 /*TXSEXECHNDID_STDIN_WRITABLE*/);
     156        /* No more data to write to stdin? Then remove stdin from poll set. */
     157        if (   cbWritten <= 0
     158            || rc == VERR_BAD_PIPE)
     159        {
     160            rc = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_WRITABLE);
    129161            AssertRC(rc);
    130162        }
    131163    }
    132164    else
    133         VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf);
     165        rc = VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf);
     166    return rc;
     167}
     168
     169
     170static int VBoxServiceControlExecProcHandleInputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW,
     171                                                      uint32_t uHandleId, PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf)
     172{
     173    VBoxServiceVerbose(4, "ControlExec: HandleInputEvent: fPollEvt=%#x\n", fPollEvt);
     174
     175    int rc = VINF_SUCCESS;
     176    if (fPollEvt & RTPOLL_EVT_ERROR)
     177        rc = VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf);
     178    return rc;
    134179}
    135180
     
    146191 * @param   pu32Crc             The current CRC-32 of the stream. (In/Out)
    147192 * @param   uHandleId           The handle ID.
    148  * @param   pszOpcode           The opcode for the data upload.
    149193 *
    150194 * @todo    Put the last 4 parameters into a struct!
    151195 */
    152 static int VBoxServiceControlExecProcHandleOutputEvent(PVBOXSERVICECTRLTHREAD pThread,
    153                                                        RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR,
    154                                                        uint32_t *puCrc32 , uint32_t uHandleId)
    155 {
    156     Log(("VBoxServiceControlExecProcHandleOutputEvent: fPollEvt=%#x\n",  fPollEvt));
     196static int VBoxServiceControlExecProcHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phPipeR,
     197                                                       uint32_t uHandleId, PVBOXSERVICECTRLEXECPIPEBUF pStdOutBuf)
     198{
     199    VBoxServiceVerbose(4, "ControlExec: HandleOutputEvent: fPollEvt=%#x\n", fPollEvt);
    157200
    158201    /*
     
    163206    uint8_t abBuf[_64K];
    164207
    165     AssertPtr(pThread);
    166     PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;
    167     AssertPtr(pData);
    168 
    169208    int rc2 = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead);
    170209    if (RT_SUCCESS(rc2) && cbRead)
     
    183222        {
    184223#endif
    185             rc = VBoxServiceControlExecWritePipeBuffer(&pData->stdOut, abBuf, cbRead);
     224            rc = VBoxServiceControlExecWritePipeBuffer(pStdOutBuf, abBuf, cbRead);
    186225            if (RT_SUCCESS(rc))
    187226            {
     
    229268 */
    230269static int VBoxServiceControlExecProcHandleTransportEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, uint32_t idPollHnd,
    231                                                           PRTPIPE phStdInW, PVBOXSERVICECTRLSTDINBUF pStdInBuf)
    232 {
    233 
    234     int rc = RTPollSetAddPipe(hPollSet, *phStdInW, RTPOLL_EVT_WRITE, 4 /*TXSEXECHNDID_STDIN_WRITABLE*/);
    235 
    236     return rc;
     270                                                          PRTPIPE phStdInW, PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf)
     271{
     272    return 0; //RTPollSetAddPipe(hPollSet, *phStdInW, RTPOLL_EVT_WRITE, 4 /*TXSEXECHNDID_STDIN_WRITABLE*/);
    237273}
    238274
     
    244280    int                         rc;
    245281    int                         rc2;
    246     VBOXSERVICECTRLSTDINBUF     StdInBuf            = { 0, 0, NULL, 0, hStdInW == NIL_RTPIPE, RTCrc32Start() };
    247     uint32_t                    uStdOutCrc32        = RTCrc32Start();
    248     uint32_t                    uStdErrCrc32        = uStdOutCrc32;
    249282    uint64_t const              MsStart             = RTTimeMilliTS();
    250283    RTPROCSTATUS                ProcessStatus       = { 254, RTPROCEXITREASON_ABEND };
     
    253286    uint64_t                    MsProcessKilled     = UINT64_MAX;
    254287    RTMSINTERVAL const          cMsPollBase         = hStdInW != NIL_RTPIPE
    255                                                       ? 100   /* need to poll for input */
    256                                                       : 1000; /* need only poll for process exit and aborts */
     288                                                      ? 100   /* Need to poll for input. */
     289                                                      : 1000; /* Need only poll for process exit and aborts. */
    257290    RTMSINTERVAL                cMsPollCur          = 0;
    258291
     
    290323            continue;
    291324
    292         cMsPollCur = 0;                 /* no rest until we've checked everything. */
     325        cMsPollCur = 0; /* No rest until we've checked everything. */
    293326
    294327        if (RT_SUCCESS(rc2))
    295328        {
     329            VBoxServiceVerbose(4, "ControlExec: RTPollNoResume idPollHnd=%u\n", idPollHnd);
    296330            switch (idPollHnd)
    297331            {
    298                 case 0 /* TXSEXECHNDID_STDIN */:
    299                     VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, &hStdInW, &StdInBuf);
     332                case VBOXSERVICECTRLPIPEID_STDIN_ERROR:
     333                    rc = VBoxServiceControlExecProcHandleInputEvent(hPollSet, fPollEvt, &hStdInW,
     334                                                                    VBOXSERVICECTRLPIPEID_STDIN_ERROR, &pData->stdIn);
    300335                    break;
    301336
    302                 case 1 /* TXSEXECHNDID_STDOUT */:
    303                     rc = VBoxServiceControlExecProcHandleOutputEvent(pThread, hPollSet, fPollEvt, &hStdOutR, &uStdOutCrc32, 1 /* TXSEXECHNDID_STDOUT */);
     337                case VBOXSERVICECTRLPIPEID_STDIN_WRITABLE:
     338                    rc = VBoxServiceControlExecProcHandleStdInWritableEvent(hPollSet, fPollEvt, &hStdInW, &pData->stdIn);
    304339                    break;
    305340
    306                 case 2 /*TXSEXECHNDID_STDERR */:
    307                     rc = VBoxServiceControlExecProcHandleOutputEvent(pThread, hPollSet, fPollEvt, &hStdErrR, &uStdErrCrc32, 2 /*TXSEXECHNDID_STDERR */);
     341                case VBOXSERVICECTRLPIPEID_STDOUT:
     342                    rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, &hStdOutR,
     343                                                                     VBOXSERVICECTRLPIPEID_STDOUT, &pData->stdOut);
    308344                    break;
    309345
    310                 case 4 /* TXSEXECHNDID_STDIN_WRITABLE */:
    311                     VBoxServiceControlExecProcHandleStdInWritableEvent(hPollSet, fPollEvt, &hStdInW, &StdInBuf);
     346                case VBOXSERVICECTRLPIPEID_STDERR:
     347                    rc = VBoxServiceControlExecProcHandleOutputEvent(hPollSet, fPollEvt, &hStdErrR,
     348                                                                     VBOXSERVICECTRLPIPEID_STDERR, &pData->stdOut);
    312349                    break;
    313350
    314351                default:
    315                     rc = VBoxServiceControlExecProcHandleTransportEvent(hPollSet, fPollEvt, idPollHnd, &hStdInW, &StdInBuf);
     352                    //rc = VBoxServiceControlExecProcHandleTransportEvent(hPollSet, fPollEvt, idPollHnd, &hStdInW, &pData->stdIn);
    316353                    break;
    317354            }
    318355            if (RT_FAILURE(rc) || rc == VINF_EOF)
    319                 break; /* abort command, or client dead or something */
     356                break; /* Abort command, or client dead or something. */
    320357            continue;
    321358        }
    322 
    323         /*
    324          * Check for incoming data.
    325          */
    326359
    327360        /*
     
    501534    else
    502535        VBoxServiceError("ControlExec: Process loop failed with rc=%Rrc\n", rc);
    503     RTMemFree(StdInBuf.pch);
    504536    return rc;
    505537}
     
    510542 *
    511543 * @returns IPRT status code.  No client replies made.
    512  * @param   pszHowTo            How to set up this standard handle.
    513544 * @param   fd                  Which standard handle it is (0 == stdin, 1 ==
    514545 *                              stdout, 2 == stderr).
     
    560591    AssertPtr(pBuf);
    561592
     593    /** @todo Add allocation size as function parameter! */
    562594    pBuf->pbData = (uint8_t*)RTMemAlloc(_64K); /* Start with a 64k buffer. */
    563595    AssertReturn(pBuf->pbData, VERR_NO_MEMORY);
     596    pBuf->cbAllocated = _64K;
    564597    pBuf->cbSize = 0;
    565     pBuf->cbOffset = 0;
    566     pBuf->cbRead = 0;
     598    pBuf->cbProcessed = 0;
     599    pBuf->fAlive = true;
    567600
    568601    return RTCritSectInit(&pBuf->CritSect);
     
    576609            RTMemFree(pBuf->pbData);
    577610        pBuf->pbData = NULL;
     611        pBuf->cbAllocated = 0;
    578612        pBuf->cbSize = 0;
    579         pBuf->cbOffset = 0;
    580         pBuf->cbRead = 0;
    581     }
     613        pBuf->cbProcessed = 0;
     614    }
     615    pBuf->fAlive = false;
    582616    return RTCritSectDelete(&pBuf->CritSect);
    583617}
     
    592626    if (RT_SUCCESS(rc))
    593627    {
    594         Assert(pBuf->cbOffset >= pBuf->cbRead);
    595         if (*pcbToRead > pBuf->cbOffset - pBuf->cbRead)
    596             *pcbToRead = pBuf->cbOffset - pBuf->cbRead;
     628        Assert(pBuf->cbSize >= pBuf->cbProcessed);
     629        if (*pcbToRead > pBuf->cbSize - pBuf->cbProcessed)
     630            *pcbToRead = pBuf->cbSize - pBuf->cbProcessed;
    597631
    598632        if (*pcbToRead > cbBuffer)
     
    601635        if (*pcbToRead > 0)
    602636        {
    603             memcpy(pbBuffer, pBuf->pbData + pBuf->cbRead, *pcbToRead);
    604             pBuf->cbRead += *pcbToRead;
     637            memcpy(pbBuffer, pBuf->pbData + pBuf->cbProcessed, *pcbToRead);
     638            pBuf->cbProcessed += *pcbToRead;
    605639        }
    606640        else
     
    622656    if (RT_SUCCESS(rc))
    623657    {
    624         /** @todo Use RTMemCache or RTMemObj here? */
    625         uint8_t *pNewBuf;
    626         while (pBuf->cbSize - pBuf->cbOffset < cbData)
    627         {
    628             pNewBuf = (uint8_t*)RTMemRealloc(pBuf->pbData, pBuf->cbSize + _4K);
    629             if (pNewBuf == NULL)
    630                 break;
    631             pBuf->cbSize += _4K;
    632             pBuf->pbData = pNewBuf;
    633         }
    634 
    635         rc = VINF_SUCCESS;
    636         if (pBuf->pbData)
    637         {
    638             memcpy(pBuf->pbData + pBuf->cbOffset, pbData, cbData);
    639             pBuf->cbOffset += cbData;
    640             /** @todo Add offset clamping! */
    641         }
    642         else
    643             rc = VERR_NO_MEMORY;
     658        if (pBuf->fAlive)
     659        {
     660            /** @todo Buffer size limit! 4MB */
     661
     662            /* Resize buffer if not enough space for storing the read in data left. */
     663            uint8_t *pNewBuf;
     664            while (pBuf->cbAllocated - pBuf->cbSize < cbData)
     665            {
     666                pNewBuf = (uint8_t*)RTMemRealloc(pBuf->pbData, pBuf->cbAllocated + _4K);
     667                if (pNewBuf == NULL)
     668                    break;
     669                pBuf->cbAllocated += _4K;
     670                pBuf->pbData = pNewBuf;
     671            }
     672
     673            rc = VINF_SUCCESS;
     674            if (pBuf->pbData)
     675            {
     676                memcpy(pBuf->pbData + pBuf->cbSize, pbData, cbData);
     677                pBuf->cbSize += cbData;
     678                /** @todo Add offset clamping! */
     679            }
     680            else
     681                rc = VERR_NO_MEMORY;
     682        }
    644683        int rc2 = RTCritSectLeave(&pBuf->CritSect);
    645684        if (RT_SUCCESS(rc))
     
    731770        if (RT_SUCCESS(rc))
    732771            rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdErr);
     772            if (RT_SUCCESS(rc))
     773                rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdIn);
    733774    }
    734775
     
    763804        VBoxServiceControlExecDestroyPipeBuffer(&pData->stdOut);
    764805        VBoxServiceControlExecDestroyPipeBuffer(&pData->stdErr);
     806        VBoxServiceControlExecDestroyPipeBuffer(&pData->stdIn);
    765807
    766808        RTMemFree(pData);
     
    852894            RTHANDLE    hStdIn;
    853895            PRTHANDLE   phStdIn;
    854             RTPIPE      hStdInW;
    855             rc = VBoxServiceControlExecSetupPipe(0 /* stdin */, &hStdIn, &phStdIn, &hStdInW);
     896            rc = VBoxServiceControlExecSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pData->pipeStdInW);
    856897            if (RT_SUCCESS(rc))
    857898            {
     
    859900                PRTHANDLE   phStdOut;
    860901                RTPIPE      hStdOutR;
    861                 rc = VBoxServiceControlExecSetupPipe(1 /* stdout */, &hStdOut, &phStdOut, &hStdOutR);
     902                rc = VBoxServiceControlExecSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR);
    862903                if (RT_SUCCESS(rc))
    863904                {
     
    865906                    PRTHANDLE   phStdErr;
    866907                    RTPIPE      hStdErrR;
    867                     rc = VBoxServiceControlExecSetupPipe(2 /* stderr */, &hStdErr, &phStdErr, &hStdErrR);
     908                    rc = VBoxServiceControlExecSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR);
    868909                    if (RT_SUCCESS(rc))
    869910                    {
     
    876917                        if (RT_SUCCESS(rc))
    877918                        {
    878                             rc = RTPollSetAddPipe(hPollSet, hStdInW, RTPOLL_EVT_ERROR, 0 /* TXSEXECHNDID_STDIN */);
     919                            rc = RTPollSetAddPipe(hPollSet, pData->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN_ERROR);
    879920                            if (RT_SUCCESS(rc))
    880                                 rc = RTPollSetAddPipe(hPollSet, hStdOutR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 1 /* TXSEXECHNDID_STDOUT */);
     921                                rc = RTPollSetAddPipe(hPollSet, hStdOutR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDOUT);
    881922                            if (RT_SUCCESS(rc))
    882                                 rc = RTPollSetAddPipe(hPollSet, hStdErrR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 2 /* TXSEXECHNDID_TESTPIPE */);
     923                                rc = RTPollSetAddPipe(hPollSet, hStdErrR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDERR);
     924                            if (RT_SUCCESS(rc))
     925                                rc = RTPollSetAddPipe(hPollSet, pData->pipeStdInW, RTPOLL_EVT_WRITE, VBOXSERVICECTRLPIPEID_STDIN_WRITABLE);
    883926                            if (RT_SUCCESS(rc))
    884927                            {
     
    915958                                    rc = VBoxServiceControlExecProcLoop(pThread,
    916959                                                                        hProcess, pData->uTimeLimitMS, hPollSet,
    917                                                                         hStdInW, hStdOutR, hStdErrR);
     960                                                                        pData->pipeStdInW, hStdOutR, hStdErrR);
    918961
    919962                                    /*
     
    924967                                     */
    925968                                    if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 0 /* stdin */, NULL)))
    926                                         hStdInW = NIL_RTPIPE;
     969                                        pData->pipeStdInW = NIL_RTPIPE;
    927970                                    if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 1 /* stdout */, NULL)))
    928971                                        hStdOutR = NIL_RTPIPE;
     
    943986                                }
    944987                            }
     988                            RTPollSetDestroy(hPollSet);
    945989                        }
    946990                        RTPipeClose(hStdErrR);
     
    950994                    RTHandleClose(phStdOut);
    951995                }
    952                 RTPipeClose(hStdInW);
     996                RTPipeClose(pData->pipeStdInW);
    953997                RTHandleClose(phStdIn);
    954998            }
     
    9681012        RTThreadUserSignal(RTThreadSelf());
    9691013    return rc;
     1014}
     1015
     1016PVBOXSERVICECTRLTHREAD VBoxServiceControlExecFindProcess(uint32_t uPID)
     1017{
     1018    PVBOXSERVICECTRLTHREAD pNode;
     1019    bool fFound = false;
     1020    RTListForEach(&g_GuestControlExecThreads, pNode, VBOXSERVICECTRLTHREAD, Node)
     1021    {
     1022        if (   pNode->fStarted
     1023            && pNode->enmType == VBoxServiceCtrlThreadDataExec)
     1024        {
     1025            PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     1026            if (pData && pData->uPID == uPID)
     1027            {
     1028                return pNode;
     1029            }
     1030        }
     1031    }
     1032    return NULL;
    9701033}
    9711034
     
    10331096}
    10341097
     1098
     1099/**
     1100 *
     1101 *
     1102 * @return  int
     1103 *
     1104 * @param   u32ClientId
     1105 * @param   uNumParms
     1106 */
     1107int VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms)
     1108{
     1109    uint32_t uContextID;
     1110    char szCmd[_1K];
     1111    uint32_t uFlags;
     1112    char szArgs[_1K];
     1113    uint32_t uNumArgs;
     1114    char szEnv[_64K];
     1115    uint32_t cbEnv = sizeof(szEnv);
     1116    uint32_t uNumEnvVars;
     1117    char szUser[128];
     1118    char szPassword[128];
     1119    uint32_t uTimeLimitMS;
     1120
     1121#if 0 /* for valgrind */
     1122    RT_ZERO(szCmd);
     1123    RT_ZERO(szArgs);
     1124    RT_ZERO(szEnv);
     1125    RT_ZERO(szUser);
     1126    RT_ZERO(szPassword);
     1127#endif
     1128
     1129    if (uNumParms != 11)
     1130        return VERR_INVALID_PARAMETER;
     1131
     1132    int rc = VbglR3GuestCtrlExecGetHostCmd(u32ClientId,
     1133                                           uNumParms,
     1134                                           &uContextID,
     1135                                           /* Command */
     1136                                           szCmd,      sizeof(szCmd),
     1137                                           /* Flags */
     1138                                           &uFlags,
     1139                                           /* Arguments */
     1140                                           szArgs,     sizeof(szArgs), &uNumArgs,
     1141                                           /* Environment */
     1142                                           szEnv, &cbEnv, &uNumEnvVars,
     1143                                           /* Credentials */
     1144                                           szUser,     sizeof(szUser),
     1145                                           szPassword, sizeof(szPassword),
     1146                                           /* Timelimit */
     1147                                           &uTimeLimitMS);
     1148    if (RT_FAILURE(rc))
     1149    {
     1150        VBoxServiceError("ControlExec: Failed to retrieve exec start command! Error: %Rrc\n", rc);
     1151    }
     1152    else
     1153    {
     1154        rc = VBoxServiceControlExecProcess(uContextID, szCmd, uFlags, szArgs, uNumArgs,
     1155                                           szEnv, cbEnv, uNumEnvVars,
     1156                                           szUser, szPassword, uTimeLimitMS);
     1157    }
     1158
     1159    VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdStartProcess returned with %Rrc\n", rc);
     1160    return rc;
     1161}
     1162
     1163
     1164/**
     1165 * Handles input for the started process by copying the received data into its
     1166 * stdin pipe.
     1167 *
     1168 * @return  int
     1169 *
     1170 * @param   u32ClientId
     1171 * @param   uNumParms
     1172 */
     1173int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms)
     1174{
     1175    uint32_t uContextID;
     1176    uint32_t uPID;
     1177    uint32_t uFlags;
     1178    uint8_t  aBuffer[_64K];
     1179    uint32_t cbSize;
     1180
     1181    if (uNumParms != 5)
     1182        return VERR_INVALID_PARAMETER;
     1183
     1184    int rc = VbglR3GuestCtrlExecGetHostCmdInput(u32ClientId, uNumParms,
     1185                                                &uContextID, &uPID, &uFlags,
     1186                                                aBuffer, sizeof(aBuffer), &cbSize);
     1187    if (RT_FAILURE(rc))
     1188    {
     1189        VBoxServiceError("ControlExec: Failed to retrieve exec input command! Error: %Rrc\n", rc);
     1190    }
     1191    else
     1192    {
     1193        PVBOXSERVICECTRLTHREAD pNode = VBoxServiceControlExecFindProcess(uPID);
     1194        if (pNode)
     1195        {
     1196            PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     1197            AssertPtr(pData);
     1198            rc = VBoxServiceControlExecWritePipeBuffer(&pData->stdIn, aBuffer, cbSize);
     1199            if (RT_SUCCESS(rc))
     1200            {
     1201                size_t cbWritten;
     1202                rc = VBoxServiceControlExecProcWriteStdIn(&pData->stdIn, pData->pipeStdInW, &cbWritten);
     1203                if (RT_SUCCESS(rc))
     1204                    rc = VbglR3GuestCtrlExecReportStatusIn(u32ClientId, uContextID, uPID, 0 /* Flags */,
     1205                                                           cbWritten);
     1206            }
     1207        }
     1208        else
     1209            rc = VERR_NOT_FOUND; /* PID not found! */
     1210    }
     1211    VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdSetInput returned with %Rrc\n", rc);
     1212    return rc;
     1213}
     1214
     1215
     1216/**
     1217 *
     1218 *
     1219 * @return  int
     1220 *
     1221 * @param   u32ClientId
     1222 * @param   uNumParms
     1223 */
     1224int VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms)
     1225{
     1226    uint32_t uContextID;
     1227    uint32_t uPID;
     1228    uint32_t uHandleID;
     1229    uint32_t uFlags;
     1230
     1231    int rc = VbglR3GuestCtrlExecGetHostCmdOutput(u32ClientId, uNumParms,
     1232                                                 &uContextID, &uPID, &uHandleID, &uFlags);
     1233    if (RT_FAILURE(rc))
     1234    {
     1235        VBoxServiceError("ControlExec: Failed to retrieve exec output command! Error: %Rrc\n", rc);
     1236    }
     1237    else
     1238    {
     1239        PVBOXSERVICECTRLTHREAD pNode = VBoxServiceControlExecFindProcess(uPID);
     1240        if (pNode)
     1241        {
     1242            PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pNode->pvData;
     1243            AssertPtr(pData);
     1244
     1245            const uint32_t cbSize = _4K;
     1246            uint32_t cbRead = cbSize;
     1247            uint8_t *pBuf = (uint8_t*)RTMemAlloc(cbSize);
     1248            if (pBuf)
     1249            {
     1250                rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbSize, &cbRead);
     1251                if (RT_SUCCESS(rc))
     1252                {
     1253                    /* cbRead now contains actual size. */
     1254                    rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* handle ID */, 0 /* flags */,
     1255                                                    pBuf, cbRead);
     1256                }
     1257                RTMemFree(pBuf);
     1258            }
     1259            else
     1260                rc = VERR_NO_MEMORY;
     1261        }
     1262        else
     1263            rc = VERR_NOT_FOUND; /* PID not found! */
     1264    }
     1265    VBoxServiceVerbose(3, "ControlExec: VBoxServiceControlExecHandleCmdGetOutput returned with %Rrc\n", rc);
     1266    return rc;
     1267}
     1268
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r31202 r33064  
    112112};
    113113
     114enum VBOXSERVICECTRLPIPEID
     115{
     116    VBOXSERVICECTRLPIPEID_STDIN_ERROR  = 0,
     117    VBOXSERVICECTRLPIPEID_STDIN_WRITABLE = 1,
     118    VBOXSERVICECTRLPIPEID_STDOUT = 10,
     119    VBOXSERVICECTRLPIPEID_STDERR = 20
     120};
     121
     122/* Structure for holding buffered pipe data. */
    114123typedef struct
    115124{
     125    /** The data buffer. */
    116126    uint8_t    *pbData;
     127    /** The amount of allocated buffer space. */
     128    uint32_t    cbAllocated;
     129    /** The actual used/occupied buffer space. */
    117130    uint32_t    cbSize;
    118     uint32_t    cbOffset;
    119     uint32_t    cbRead;
     131    /** Helper variable for keeping track of what
     132     *  already was processed and what not. */
     133    uint32_t    cbProcessed;
    120134    RTCRITSECT  CritSect;
     135    bool        fAlive;
    121136} VBOXSERVICECTRLEXECPIPEBUF;
    122 /** Pointer to thread data. */
     137/** Pointer to buffered pipe data. */
    123138typedef VBOXSERVICECTRLEXECPIPEBUF *PVBOXSERVICECTRLEXECPIPEBUF;
    124139
     
    137152    uint32_t  uTimeLimitMS;
    138153
     154    RTPIPE                     pipeStdInW;
     155    VBOXSERVICECTRLEXECPIPEBUF stdIn;
    139156    VBOXSERVICECTRLEXECPIPEBUF stdOut;
    140157    VBOXSERVICECTRLEXECPIPEBUF stdErr;
     
    168185/** Pointer to thread data. */
    169186typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD;
    170 
    171 /**
    172  * For buffering process input supplied by the client.
    173  */
    174 typedef struct VBOXSERVICECTRLSTDINBUF
    175 {
    176     /** The mount of buffered data. */
    177     size_t  cb;
    178     /** The current data offset. */
    179     size_t  off;
    180     /** The data buffer. */
    181     char   *pch;
    182     /** The amount of allocated buffer space. */
    183     size_t  cbAllocated;
    184     /** Send further input into the bit bucket (stdin is dead). */
    185     bool    fBitBucket;
    186     /** The CRC-32 for standard input (received part). */
    187     uint32_t uCrc32;
    188 } VBOXSERVICECTRLSTDINBUF;
    189 /** Pointer to a standard input buffer. */
    190 typedef VBOXSERVICECTRLSTDINBUF *PVBOXSERVICECTRLSTDINBUF;
    191 
    192187#endif /* VBOX_WITH_GUEST_CONTROL */
    193188#ifdef VBOX_WITH_GUEST_PROPS
     
    277272
    278273#ifdef VBOX_WITH_GUEST_CONTROL
     274extern int  VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms);
     275extern int  VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
     276extern int  VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms);
     277extern int  VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms);
     278extern int  VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
    279279extern int  VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
    280280                                          const char *pszArgs, uint32_t uNumArgs,
     
    286286extern int  VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    287287                                                  uint8_t *pbData, uint32_t cbData);
    288 #endif
     288#endif /* VBOX_WITH_GUEST_CONTROL */
    289289
    290290#ifdef VBOXSERVICE_MANAGEMENT
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r32997 r33064  
    7474                 "                            [--flags <flags>] [--timeout <msec>]\n"
    7575                 "                            [--verbose] [--wait-for exit,stdout,stderr||]\n"
     76                 /** @todo Add a "--" parameter (has to be last parameter) to directly execute
     77                  *        stuff, e.g. "VBoxManage guestcontrol execute <VMName> --username <> ... -- /bin/rm -Rf /foo". */
    7678#ifdef VBOX_WITH_COPYTOGUEST
    7779                 "\n"
     
    447449                    }
    448450
     451#if 0
     452                    static int sent = 0;
     453                    if (sent < 1)
     454                    {
     455                        ULONG cbWritten;
     456                        SafeArray<BYTE> aInputData(_64K);
     457                        RTStrPrintf((char*)aInputData.raw(), _64K, "dir c:\\windows\n");
     458                        rc = guest->SetProcessInput(uPID, 0 /* aFlags */,
     459                                                    u32TimeoutMS, ComSafeArrayAsInParam(aInputData), &cbWritten);
     460                        if (FAILED(rc))
     461                        {
     462                            /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     463                             * because it contains more accurate info about what went wrong. */
     464                            ErrorInfo info(guest, COM_IIDOF(IGuest));
     465                            if (info.isFullAvailable())
     466                            {
     467                                if (rc == VBOX_E_IPRT_ERROR)
     468                                    RTMsgError("%ls.", info.getText().raw());
     469                                else
     470                                    RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode());
     471                            }
     472                        }
     473                        else
     474                        {
     475                            RTPrintf("sent\n");
     476                        }
     477                    }
     478                    sent++;
     479#endif
    449480                    if (cbOutputData <= 0) /* No more output data left? */
    450481                    {
     
    552583static int handleCtrlCopyTo(HandlerArg *a)
    553584{
     585#if 0
    554586    RTISOFSFILE file;
    555587    int vrc = RTIsoFsOpen(&file, "c:\\Downloads\\VBoxGuestAdditions_3.2.8.iso");
     
    562594    }
    563595    return vrc;
     596#endif
    564597
    565598    /*
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r30681 r33064  
    389389    if (cParms != pBuf->uParmCount)
    390390    {
     391        LogFlowFunc(("Parameter count does not match (%u (buffer), %u (guest))\n",
     392                     pBuf->uParmCount, cParms));
    391393        rc = VERR_INVALID_PARAMETER;
    392394    }
     
    583585            if (it->mNumParms >= 2)
    584586            {
    585                 it->mParms[0].setUInt32(GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID. */
    586                 it->mParms[1].setUInt32(0);                                /* Required parameters for message. */
     587                it->mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
     588                it->mParms[1].setUInt32(0);                         /* Required parameters for message. */
    587589            }
    588590            if (mpHelpers)
     
    628630        paParms[3].getUInt32(&data.u32Flags);
    629631        paParms[4].getPointer(&data.pvData, &data.cbData);
     632
     633        if (mpfnHostCallback)
     634            rc = mpfnHostCallback(mpvHostData, eFunction,
     635                                  (void *)(&data), sizeof(data));
     636    }
     637    else if (   eFunction == GUEST_EXEC_SEND_INPUT_STATUS
     638             && cParms    == 4)
     639    {
     640        CALLBACKDATAEXECINSTATUS data;
     641        data.hdr.u32Magic = CALLBACKDATAMAGICEXECINSTATUS;
     642        paParms[0].getUInt32(&data.hdr.u32ContextID);
     643
     644        paParms[1].getUInt32(&data.u32PID);
     645        paParms[2].getUInt32(&data.u32Flags);
     646        paParms[3].getUInt32(&data.cbProcessed);
    630647
    631648        if (mpfnHostCallback)
     
    745762
    746763            /*
    747              * The guest notifies the host of the current client status.
     764             * The guest notifies the host of the executed process status.
    748765             */
    749766            case GUEST_EXEC_SEND_STATUS:
    750                 LogFlowFunc(("SEND_STATUS\n"));
     767                LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
     768                rc = notifyHost(eFunction, cParms, paParms);
     769                break;
     770
     771            case GUEST_EXEC_SEND_INPUT_STATUS:
     772                LogFlowFunc(("GUEST_EXEC_SEND_INPUT_STATUS\n"));
    751773                rc = notifyHost(eFunction, cParms, paParms);
    752774                break;
     
    790812                break;
    791813
    792             /* The host wants to send something to the guest's stdin pipe. */
     814            /* The host wants to send something to the
     815             * started process' stdin pipe. */
    793816            case HOST_EXEC_SET_INPUT:
    794817                LogFlowFunc(("HOST_EXEC_SET_INPUT\n"));
     818                rc = processHostCmd(eFunction, cParms, paParms);
    795819                break;
    796820
  • trunk/src/VBox/Main/GuestImpl.cpp

    r32866 r33064  
    579579
    580580    int rc = VINF_SUCCESS;
    581     if (u32Function == GUEST_DISCONNECTED)
    582     {
    583         //LogFlowFunc(("GUEST_DISCONNECTED\n"));
    584 
    585         PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
    586         AssertPtr(pCBData);
    587         AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
    588         AssertReturn(CALLBACKDATAMAGICCLIENTDISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    589 
    590         rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
    591     }
    592     else if (u32Function == GUEST_EXEC_SEND_STATUS)
    593     {
    594         //LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
    595 
    596         PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
    597         AssertPtr(pCBData);
    598         AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
    599         AssertReturn(CALLBACKDATAMAGICEXECSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    600 
    601         rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
    602     }
    603     else if (u32Function == GUEST_EXEC_SEND_OUTPUT)
    604     {
    605         //LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
    606 
    607         PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
    608         AssertPtr(pCBData);
    609         AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
    610         AssertReturn(CALLBACKDATAMAGICEXECOUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    611 
    612         rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
    613     }
    614     else
    615         rc = VERR_NOT_SUPPORTED;
     581    switch (u32Function)
     582    {
     583        case GUEST_DISCONNECTED:
     584        {
     585            //LogFlowFunc(("GUEST_DISCONNECTED\n"));
     586
     587            PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
     588            AssertPtr(pCBData);
     589            AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
     590            AssertReturn(CALLBACKDATAMAGICCLIENTDISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     591
     592            rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
     593            break;
     594        }
     595
     596        case GUEST_EXEC_SEND_STATUS:
     597        {
     598            //LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
     599
     600            PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
     601            AssertPtr(pCBData);
     602            AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
     603            AssertReturn(CALLBACKDATAMAGICEXECSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     604
     605            rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
     606            break;
     607        }
     608
     609        case GUEST_EXEC_SEND_OUTPUT:
     610        {
     611            //LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
     612
     613            PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
     614            AssertPtr(pCBData);
     615            AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
     616            AssertReturn(CALLBACKDATAMAGICEXECOUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     617
     618            rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
     619            break;
     620        }
     621
     622        case GUEST_EXEC_SEND_INPUT_STATUS:
     623        {
     624            //LogFlowFunc(("GUEST_EXEC_SEND_INPUT_STATUS\n"));
     625
     626            PCALLBACKDATAEXECINSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECINSTATUS>(pvParms);
     627            AssertPtr(pCBData);
     628            AssertReturn(sizeof(CALLBACKDATAEXECINSTATUS) == cbParms, VERR_INVALID_PARAMETER);
     629            AssertReturn(CALLBACKDATAMAGICEXECINSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     630
     631            rc = pGuest->notifyCtrlExecInStatus(u32Function, pCBData);
     632            break;
     633        }
     634
     635        default:
     636            AssertMsgFailed(("Unknown guest control notification received, u32Function=%u", u32Function));
     637            rc = VERR_INVALID_PARAMETER;
     638            break;
     639    }
    616640    return rc;
    617641}
     
    775799
    776800                        default:
    777                             AssertMsgFailed(("unknown callback type %d\n", it2->second.mType));
     801                            AssertMsgFailed(("Unknown callback type %d\n", it2->second.mType));
    778802                            break;
    779803                    }
     
    808832    if (it != mCallbackMap.end())
    809833    {
    810         PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->second.pvData;
     834        PCALLBACKDATAEXECOUT pCBData = (PCALLBACKDATAEXECOUT)it->second.pvData;
    811835        AssertPtr(pCBData);
    812836
     
    841865                                                 Guest::getStaticComponentName(),
    842866                                                 Guest::tr("The output operation was canceled"));
     867        }
     868        else
     869            it->second.pProgress->notifyComplete(S_OK);
     870    }
     871    else
     872        LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
     873    return rc;
     874}
     875
     876/* Function for handling the execution input status notification. */
     877int Guest::notifyCtrlExecInStatus(uint32_t                  u32Function,
     878                                  PCALLBACKDATAEXECINSTATUS pData)
     879{
     880    int rc = VINF_SUCCESS;
     881
     882    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     883
     884    AssertPtr(pData);
     885    CallbackMapIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
     886    if (it != mCallbackMap.end())
     887    {
     888        PCALLBACKDATAEXECINSTATUS pCBData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData;
     889        AssertPtr(pCBData);
     890
     891        /* Nothing to do here yet. */
     892
     893        /* Was progress canceled before? */
     894        BOOL fCanceled;
     895        ComAssert(!it->second.pProgress.isNull());
     896        if (SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) && fCanceled)
     897        {
     898            it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR,
     899                                                 COM_IIDOF(IGuest),
     900                                                 Guest::getStaticComponentName(),
     901                                                 Guest::tr("The input operation was canceled"));
    843902        }
    844903        else
     
    13031362}
    13041363
     1364STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
     1365{
     1366#ifndef VBOX_WITH_GUEST_CONTROL
     1367    ReturnComNotImplemented();
     1368#else  /* VBOX_WITH_GUEST_CONTROL */
     1369    using namespace guestControl;
     1370
     1371    CheckComArgExpr(aPID, aPID > 0);
     1372    if (aFlags != 0) /* Flags are not supported at the moment. */
     1373        return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
     1374
     1375    AutoCaller autoCaller(this);
     1376    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1377
     1378    HRESULT rc = S_OK;
     1379
     1380    try
     1381    {
     1382        /* Search for existing PID. */
     1383        GuestProcessMapIterConst it = getProcessByPID(aPID);
     1384        if (it != mGuestProcessMap.end())
     1385        {
     1386            /* PID exists; check if process is still running. */
     1387            if (it->second.mStatus != PROC_STS_STARTED)
     1388            {
     1389                rc = setError(VBOX_E_IPRT_ERROR,
     1390                              tr("Process (PID %u) does not run anymore! Status: %ld, Flags: %u, Exit Code: %u"),
     1391                              aPID, it->second.mStatus, it->second.mFlags, it->second.mExitCode);
     1392            }
     1393        }
     1394        else
     1395            rc = setError(VBOX_E_IPRT_ERROR,
     1396                          tr("Process (PID %u) not found!"), aPID);
     1397
     1398        if (SUCCEEDED(rc))
     1399        {
     1400            /*
     1401             * Create progress object.
     1402             * This progress object, compared to the one in executeProgress() above
     1403             * is only local and is used to determine whether the operation finished
     1404             * or got canceled.
     1405             */
     1406            ComObjPtr <Progress> progress;
     1407            rc = progress.createObject();
     1408            if (SUCCEEDED(rc))
     1409            {
     1410                rc = progress->init(static_cast<IGuest*>(this),
     1411                                    Bstr(tr("Getting output of process")).raw(),
     1412                                    TRUE);
     1413            }
     1414            if (FAILED(rc)) return rc;
     1415
     1416            /* Adjust timeout */
     1417            if (aTimeoutMS == 0)
     1418                aTimeoutMS = UINT32_MAX;
     1419
     1420            PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
     1421            AssertReturn(pData, VBOX_E_IPRT_ERROR);
     1422            RT_ZERO(*pData);
     1423            /* Save PID + output flags for later use. */
     1424            pData->u32PID = aPID;
     1425            pData->u32Flags = aFlags;
     1426            /* Add job to callback contexts. */
     1427            uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS,
     1428                                                         pData, sizeof(CALLBACKDATAEXECINSTATUS), progress);
     1429            Assert(uContextID > 0);
     1430
     1431            com::SafeArray<BYTE> sfaData(ComSafeArrayInArg(aData));
     1432
     1433            VBOXHGCMSVCPARM paParms[6];
     1434            int i = 0;
     1435            paParms[i++].setUInt32(uContextID);
     1436            paParms[i++].setUInt32(aPID);
     1437            paParms[i++].setUInt32(aFlags);
     1438            paParms[i++].setPointer(sfaData.raw(), sfaData.size());
     1439            paParms[i++].setUInt32(sfaData.size());
     1440
     1441            int vrc = VINF_SUCCESS;
     1442
     1443            {
     1444                VMMDev *vmmDev;
     1445                {
     1446                    /* Make sure mParent is valid, so set the read lock while using.
     1447                     * Do not keep this lock while doing the actual call, because in the meanwhile
     1448                     * another thread could request a write lock which would be a bad idea ... */
     1449                    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1450
     1451                    /* Forward the information to the VMM device. */
     1452                    AssertPtr(mParent);
     1453                    vmmDev = mParent->getVMMDev();
     1454                }
     1455
     1456                if (vmmDev)
     1457                {
     1458                    LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
     1459                    vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_SET_INPUT,
     1460                                               i, paParms);
     1461                }
     1462            }
     1463
     1464            if (RT_SUCCESS(vrc))
     1465            {
     1466                LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
     1467
     1468                /*
     1469                 * Wait for the HGCM low level callback until the process
     1470                 * has been started (or something went wrong). This is necessary to
     1471                 * get the PID.
     1472                 */
     1473                CallbackMapIter it = getCtrlCallbackContextByID(uContextID);
     1474                BOOL fCanceled = FALSE;
     1475                if (it != mCallbackMap.end())
     1476                {
     1477                    ComAssert(!it->second.pProgress.isNull());
     1478
     1479                    /* Wait until operation completed. */
     1480                    rc = it->second.pProgress->WaitForCompletion(aTimeoutMS);
     1481                    if (FAILED(rc)) throw rc;
     1482
     1483                    /* Was the operation canceled by one of the parties? */
     1484                    rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled);
     1485                    if (FAILED(rc)) throw rc;
     1486
     1487                    if (!fCanceled)
     1488                    {
     1489                        BOOL fCompleted;
     1490                        if (   SUCCEEDED(it->second.pProgress->COMGETTER(Completed)(&fCompleted))
     1491                            && fCompleted)
     1492                        {
     1493                            /* Nothing to do here yet. */
     1494                        }
     1495                        else /* If callback not called within time ... well, that's a timeout! */
     1496                            vrc = VERR_TIMEOUT;
     1497                    }
     1498                    else /* Operation was canceled. */
     1499                    {
     1500                        vrc = VERR_CANCELLED;
     1501                    }
     1502
     1503                    if (RT_FAILURE(vrc))
     1504                    {
     1505                        if (vrc == VERR_TIMEOUT)
     1506                        {
     1507                            rc = setError(VBOX_E_IPRT_ERROR,
     1508                                          tr("The guest did not process input within time (%ums)"), aTimeoutMS);
     1509                        }
     1510                        else if (vrc == VERR_CANCELLED)
     1511                        {
     1512                            rc = setError(VBOX_E_IPRT_ERROR,
     1513                                          tr("The input operation was canceled"));
     1514                        }
     1515                        else
     1516                        {
     1517                            rc = setError(E_UNEXPECTED,
     1518                                          tr("The service call failed with error %Rrc"), vrc);
     1519                        }
     1520                    }
     1521
     1522                    {
     1523                        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1524                        /*
     1525                         * Destroy locally used progress object.
     1526                         */
     1527                        destroyCtrlCallbackContext(it);
     1528                    }
     1529
     1530                    /* Remove callback context (not used anymore). */
     1531                    mCallbackMap.erase(it);
     1532                }
     1533                else /* PID lookup failed. */
     1534                    rc = setError(VBOX_E_IPRT_ERROR,
     1535                                  tr("Process (PID %u) not found!"), aPID);
     1536            }
     1537            else /* HGCM operation failed. */
     1538                rc = setError(E_UNEXPECTED,
     1539                              tr("The HGCM call failed with error %Rrc"), vrc);
     1540
     1541            /* Cleanup. */
     1542            progress->uninit();
     1543            progress.setNull();
     1544        }
     1545    }
     1546    catch (std::bad_alloc &)
     1547    {
     1548        rc = E_OUTOFMEMORY;
     1549    }
     1550    return rc;
     1551#endif
     1552}
     1553
    13051554STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
    13061555{
     
    15521801    LogFlowFunc(("Appending to pList=%p: %s\n", pList, pszPath));
    15531802
    1554     DirEntry *pNode = (DirEntry*)RTMemAlloc(sizeof(DirEntry));
     1803    VBoxGuestDirEntry *pNode = (VBoxGuestDirEntry*)RTMemAlloc(sizeof(VBoxGuestDirEntry));
    15551804    if (pNode == NULL)
    15561805        return VERR_NO_MEMORY;
    15571806
     1807    pNode->pszPath = NULL;
    15581808    if (RT_SUCCESS(RTStrAAppend(&pNode->pszPath, pszPath)))
    15591809    {
     
    15791829                 pszDirectory, pszFilter ? pszFilter : "<None>"));
    15801830
    1581     char *pszDirWithFilter = NULL;
    1582     PRTDIR pDir;
    1583     int rc = RTStrAAppend(&pszDirWithFilter, pszDirectory);
     1831    PRTDIR pDir = NULL;
     1832    int rc = RTDirOpenFiltered(&pDir, pszDirectory,
     1833#ifdef RT_OS_WINDOWS
     1834                               RTDIRFILTER_WINNT);
     1835#else
     1836                               RTDIRFILTER_UNIX);
     1837#endif
     1838    char *pszDirectoryStrip = RTStrDup(pszDirectory);
     1839    if (!pszDirectoryStrip)
     1840        rc = VERR_NO_MEMORY;
     1841
    15841842    if (RT_SUCCESS(rc))
    15851843    {
    1586         if (pszFilter)
    1587         {
    1588             RTStrAAppend(&pszDirWithFilter, pszDirectory);
    1589             rc = RTDirOpenFiltered(&pDir, pszDirectory, RTDIRFILTER_WINNT);
    1590         }
    1591         else
    1592             rc = RTDirOpen(&pDir, pszDirectory);
    1593     }
    1594 
    1595     if (RT_SUCCESS(rc))
    1596     {
    1597         rc = directoryEntryAppend(pszDirectory, pList);
    1598         if (RT_SUCCESS(rc))
    1599         {
    1600             *pcObjects = *pcObjects + 1;
    1601             for (;;)
     1844        RTPathStripFilename(pszDirectoryStrip);
     1845        for (;;)
     1846        {
     1847            RTDIRENTRY DirEntry;
     1848            rc = RTDirRead(pDir, &DirEntry, NULL);
     1849            if (RT_FAILURE(rc))
    16021850            {
    1603                 RTDIRENTRY DirEntry;
    1604                 rc = RTDirRead(pDir, &DirEntry, NULL);
    1605                 if (RT_FAILURE(rc))
    1606                     break;
    1607                 switch (DirEntry.enmType)
    1608                 {
    1609                     case RTDIRENTRYTYPE_DIRECTORY:
    1610                         if (uFlags & CopyFileFlag_Recursive)
    1611                             rc = directoryRead(DirEntry.szName, pszFilter,
    1612                                                uFlags, pcObjects, pList);
    1613                         break;
    1614 
    1615                     case RTDIRENTRYTYPE_FILE:
     1851                if (rc == VERR_NO_MORE_FILES)
     1852                    rc = VINF_SUCCESS;
     1853                break;
     1854            }
     1855            switch (DirEntry.enmType)
     1856            {
     1857                case RTDIRENTRYTYPE_DIRECTORY:
     1858                    /* Skip "." and ".." entrires. */
     1859                    if (   !strcmp(DirEntry.szName, ".")
     1860                        || !strcmp(DirEntry.szName, ".."))
    16161861                    {
    1617                         char *pszFile;
    1618                         if (RTStrAPrintf(&pszFile, "%s/%s",
    1619                                          pszDirectory, DirEntry.szName))
    1620                         {
    1621                             rc = directoryEntryAppend(pszFile, pList);
    1622                             if (RT_SUCCESS(rc))
    1623                                 *pcObjects = *pcObjects + 1;
    1624                             RTStrFree(pszFile);
    1625                         }
    16261862                        break;
    16271863                    }
    1628 
    1629                     case RTDIRENTRYTYPE_SYMLINK:
    1630                         if (   (uFlags & CopyFileFlag_Recursive)
    1631                             && (uFlags & CopyFileFlag_FollowLinks))
    1632                         {
    1633                             rc = directoryRead(DirEntry.szName, pszFilter,
    1634                                                uFlags, pcObjects, pList);
    1635                         }
    1636                         break;
    1637 
    1638                     default:
    1639                         break;
     1864                    if (uFlags & CopyFileFlag_Recursive)
     1865                        rc = directoryRead(DirEntry.szName, pszFilter,
     1866                                           uFlags, pcObjects, pList);
     1867                    break;
     1868
     1869                case RTDIRENTRYTYPE_FILE:
     1870                {
     1871                    char *pszFile;
     1872                    if (RTStrAPrintf(&pszFile, "%s%c%s",
     1873                                     pszDirectoryStrip, RTPATH_SLASH, DirEntry.szName))
     1874                    {
     1875                        rc = directoryEntryAppend(pszFile, pList);
     1876                        if (RT_SUCCESS(rc))
     1877                            *pcObjects = *pcObjects + 1;
     1878                        RTStrFree(pszFile);
     1879                    }
     1880                    break;
    16401881                }
    1641                 if (RT_FAILURE(rc))
     1882
     1883                case RTDIRENTRYTYPE_SYMLINK:
     1884                    if (   (uFlags & CopyFileFlag_Recursive)
     1885                        && (uFlags & CopyFileFlag_FollowLinks))
     1886                    {
     1887                        rc = directoryRead(DirEntry.szName, pszFilter,
     1888                                           uFlags, pcObjects, pList);
     1889                    }
     1890                    break;
     1891
     1892                default:
    16421893                    break;
    16431894            }
    1644         }
     1895            if (RT_FAILURE(rc))
     1896                break;
     1897        }
     1898        RTStrFree(pszDirectoryStrip);
     1899    }
     1900
     1901    if (pDir)
    16451902        RTDirClose(pDir);
    1646     }
    1647     if (pszDirWithFilter)
    1648         RTStrFree(pszDirWithFilter);
    16491903    return rc;
    16501904}
     
    16821936    try
    16831937    {
    1684         char szSourceAbs[RTPATH_MAX];
    1685         Utf8Str Utf8Dest(aDest);
    1686 
    1687         int vrc = RTPathAbs(Utf8Str(aSource).c_str(),
    1688                             szSourceAbs, sizeof(szSourceAbs));
    1689         if (RT_SUCCESS(vrc))
    1690         {
    1691             LogRel(("Copying \"%s\" to guest into \"%s\" ...\n",
    1692                     szSourceAbs, Utf8Dest.c_str()));
    1693         }
    1694         else
    1695             rc = setError(VBOX_E_IPRT_ERROR,
    1696                           tr("Could not determine absolute path! rc=%Rrc"), vrc);
    1697 
    16981938        ULONG cObjectsToCopy = 0;
    16991939        RTLISTNODE listEntries;
    1700         if (SUCCEEDED(rc))
    1701         {
    1702             /*
    1703              * Count objects to copy.
    1704              * This is needed for have multi operation progress object.
    1705              * Examples:
    1706              *     D:\ -> D:\*
    1707              *     E:\asdf\qwer\ -> E:\asdf\qwer\*
    1708              *     C:\temp.txt
    1709              *     C:\Foo\bar\*.txt
    1710              *     /home/foo/bar/movie.avi
    1711              */
    1712             char *pszFileName = RTPathFilename(szSourceAbs);
    1713             RTListInit(&listEntries);
    1714 
    1715             vrc = directoryRead(szSourceAbs, pszFileName /* Filter */,
    1716                                     aFlags, &cObjectsToCopy, &listEntries);
    1717             if (RT_FAILURE(vrc))
    1718                 rc = setError(VBOX_E_IPRT_ERROR,
    1719                               tr("Could not open source directory! rc=%Rrc"), vrc);
    1720         }
    1721 
    1722         if (SUCCEEDED(rc))
    1723         {
    1724             /*
    1725              * Create progress object.  Note that this is a multi operation
    1726              * object to perform an operation per the following steps:
    1727              * - Operation 1 (0): Create/start process.
    1728              * - Operation 2 (1): Wait for process to exit.
    1729              * If this progress completed successfully (S_OK), the process
    1730              * started and exited normally. In any other case an error/exception
    1731              * occured.
    1732              */
    1733             ComObjPtr <Progress> progress;
    1734             rc = progress.createObject();
     1940
     1941        Utf8Str Utf8Source(aSource);
     1942        Utf8Str Utf8Dest(aDest);
     1943
     1944        char *pszSourceAbs = RTPathAbsDup(Utf8Source.c_str());
     1945        if (!pszSourceAbs)
     1946        {
     1947            rc = setError(VBOX_E_IPRT_ERROR,
     1948                          tr("Could not determine absolute path of \"%s\""), Utf8Source.c_str());
     1949        }
     1950        else
     1951        {
     1952            if (RTDirExists(pszSourceAbs))
     1953            {
     1954                size_t cch = strlen(pszSourceAbs);
     1955                if (    cch > 1
     1956                    &&  !RTPATH_IS_SLASH(pszSourceAbs[cch - 1])
     1957                    &&  !RTPATH_IS_SLASH(pszSourceAbs[cch - 2]))
     1958                {
     1959                    int vrc = RTStrAAppend(&pszSourceAbs, RTPATH_SLASH_STR);
     1960                    if (RT_FAILURE(vrc))
     1961                        rc = setError(VBOX_E_IPRT_ERROR,
     1962                                      tr("Failed to extend source path, rc=%Rrc\n"), vrc);
     1963                }
     1964            }
     1965
    17351966            if (SUCCEEDED(rc))
    17361967            {
    1737                 rc = progress->init(static_cast<IGuest*>(this),
    1738                                     Bstr(tr("Executing process")).raw(),
    1739                                     TRUE,
    1740                                     cObjectsToCopy,                             /* Number of operations. */
    1741                                     Bstr(tr("Starting process ...")).raw());    /* Description of first stage. */
     1968                LogRel(("Copying \"%s\" to guest into \"%s\" ...\n",
     1969                    pszSourceAbs, Utf8Dest.c_str()));
     1970
     1971                /*
     1972                 * Count objects to copy and build file list.
     1973                 */
     1974                RTListInit(&listEntries);
     1975                int vrc = directoryRead(pszSourceAbs, NULL /* Filter */,
     1976                                        aFlags, &cObjectsToCopy, &listEntries);
     1977                if (RT_FAILURE(vrc))
     1978                {
     1979                    if (vrc != VERR_FILE_NOT_FOUND) /* If no files found, this is no error! */
     1980                        rc = setError(VBOX_E_IPRT_ERROR,
     1981                                      tr("Error reading source directory \"%s\", rc=%Rrc"),
     1982                                      pszSourceAbs, vrc);
     1983                }
    17421984            }
    1743             if (FAILED(rc)) return rc;
    1744         }
    1745 
    1746         /* Destroy list. */
    1747         DirEntry *pNode = RTListNodeGetFirst(&listEntries, DirEntry, Node);
    1748         while (pNode)
    1749         {
    1750             DirEntry *pNext = RTListNodeGetNext(&pNode->Node, DirEntry, Node);
    1751             bool fLast = RTListNodeIsLast(&listEntries, &pNode->Node);
    1752 
    1753             if (pNode->pszPath)
    1754                 RTStrFree(pNode->pszPath);
    1755             RTListNodeRemove(&pNode->Node);
    1756             RTMemFree(pNode);
    1757 
    1758             if (fLast)
    1759                 break;
    1760 
    1761             pNode = pNext;
    1762         }
    1763     }
    1764 
     1985            RTStrFree(pszSourceAbs);
     1986        }
     1987
     1988        if (SUCCEEDED(rc))
     1989        {
     1990            if (cObjectsToCopy) /* Do we have some objects to copy? */
     1991            {
     1992                /*
     1993                 * Create progress object.  Note that this is a multi operation
     1994                 * object to perform an operation per file object we just gathered
     1995                 * in our list above.
     1996                 */
     1997                ComObjPtr <Progress> progress;
     1998                rc = progress.createObject();
     1999                if (SUCCEEDED(rc))
     2000                {
     2001                    rc = progress->init(static_cast<IGuest*>(this),
     2002                                        Bstr(tr("Copying to guest")).raw(),
     2003                                        TRUE,
     2004                                        cObjectsToCopy,                      /* Number of operations. */
     2005                                        Bstr(tr("Copying ...")).raw());      /* Description of first stage. */
     2006                }
     2007                if (FAILED(rc)) return rc;
    17652008#if 0
    1766 
    1767         /*
    1768          * Prepare process execution.
    1769          */
    1770         int vrc = VINF_SUCCESS;
    1771         Utf8Str Utf8Command(aCommand);
    1772 
    1773         /* Adjust timeout */
    1774         if (aTimeoutMS == 0)
    1775             aTimeoutMS = UINT32_MAX;
    1776 
    1777         /* Prepare arguments. */
    1778         char **papszArgv = NULL;
    1779         uint32_t uNumArgs = 0;
    1780         if (aArguments > 0)
    1781         {
    1782             com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
    1783             uNumArgs = args.size();
    1784             papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
    1785             AssertReturn(papszArgv, E_OUTOFMEMORY);
    1786             for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
    1787                 vrc = RTUtf16ToUtf8(args[i], &papszArgv[i]);
    1788             papszArgv[uNumArgs] = NULL;
    1789         }
    1790 
    1791         Utf8Str Utf8UserName(aUserName);
    1792         Utf8Str Utf8Password(aPassword);
    1793         if (RT_SUCCESS(vrc))
    1794         {
    1795             uint32_t uContextID = 0;
    1796 
    1797             char *pszArgs = NULL;
    1798             if (uNumArgs > 0)
    1799                 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, 0);
    1800             if (RT_SUCCESS(vrc))
    1801             {
    1802                 uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
    1803 
    1804                 /* Prepare environment. */
    1805                 void *pvEnv = NULL;
    1806                 uint32_t uNumEnv = 0;
    1807                 uint32_t cbEnv = 0;
    1808                 if (aEnvironment > 0)
    1809                 {
    1810                     com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
    1811 
    1812                     for (unsigned i = 0; i < env.size(); i++)
    1813                     {
    1814                         vrc = prepareExecuteEnv(Utf8Str(env[i]).c_str(), &pvEnv, &cbEnv, &uNumEnv);
    1815                         if (RT_FAILURE(vrc))
    1816                             break;
    1817                     }
    1818                 }
    1819 
    1820                 LogRel(("Executing guest process \"%s\" as user \"%s\" ...\n",
    1821                         Utf8Command.c_str(), Utf8UserName.c_str()));
    1822 
    1823                 if (RT_SUCCESS(vrc))
     2009                if (SUCCEEDED(rc))
    18242010                {
    18252011                    PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
     
    18642050                    else
    18652051                        vrc = VERR_INVALID_VM_HANDLE;
    1866                     RTMemFree(pvEnv);
    18672052                }
    1868                 RTStrFree(pszArgs);
     2053#endif
     2054                /* Destroy list. */
     2055                VBoxGuestDirEntry *pNode = RTListNodeGetFirst(&listEntries, VBoxGuestDirEntry, Node);
     2056                while (pNode)
     2057                {
     2058                    VBoxGuestDirEntry *pNext = RTListNodeGetNext(&pNode->Node, VBoxGuestDirEntry, Node);
     2059                    bool fLast = RTListNodeIsLast(&listEntries, &pNode->Node);
     2060
     2061                    if (pNode->pszPath)
     2062                        RTStrFree(pNode->pszPath);
     2063                    RTListNodeRemove(&pNode->Node);
     2064                    RTMemFree(pNode);
     2065
     2066                    if (fLast)
     2067                        break;
     2068
     2069                    pNode = pNext;
     2070                }
    18692071            }
    1870             if (RT_SUCCESS(vrc))
    1871             {
    1872                 LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
    1873 
    1874                 /*
    1875                  * Wait for the HGCM low level callback until the process
    1876                  * has been started (or something went wrong). This is necessary to
    1877                  * get the PID.
    1878                  */
    1879                 CallbackMapIter it = getCtrlCallbackContextByID(uContextID);
    1880                 BOOL fCanceled = FALSE;
    1881                 if (it != mCallbackMap.end())
    1882                 {
    1883                     ComAssert(!it->second.pProgress.isNull());
    1884 
    1885                     /*
    1886                      * Wait for the first stage (=0) to complete (that is starting the process).
    1887                      */
    1888                     PCALLBACKDATAEXECSTATUS pData = NULL;
    1889                     rc = it->second.pProgress->WaitForOperationCompletion(0, aTimeoutMS);
    1890                     if (SUCCEEDED(rc))
    1891                     {
    1892                         /* Was the operation canceled by one of the parties? */
    1893                         rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled);
    1894                         if (FAILED(rc)) throw rc;
    1895 
    1896                         if (!fCanceled)
    1897                         {
    1898                             AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1899 
    1900                             pData = (PCALLBACKDATAEXECSTATUS)it->second.pvData;
    1901                             Assert(it->second.cbData == sizeof(CALLBACKDATAEXECSTATUS));
    1902                             AssertPtr(pData);
    1903 
    1904                             /* Did we get some status? */
    1905                             switch (pData->u32Status)
    1906                             {
    1907                                 case PROC_STS_STARTED:
    1908                                     /* Process is (still) running; get PID. */
    1909                                     *aPID = pData->u32PID;
    1910                                     break;
    1911 
    1912                                 /* In any other case the process either already
    1913                                  * terminated or something else went wrong, so no PID ... */
    1914                                 case PROC_STS_TEN: /* Terminated normally. */
    1915                                 case PROC_STS_TEA: /* Terminated abnormally. */
    1916                                 case PROC_STS_TES: /* Terminated through signal. */
    1917                                 case PROC_STS_TOK:
    1918                                 case PROC_STS_TOA:
    1919                                 case PROC_STS_DWN:
    1920                                     /*
    1921                                      * Process (already) ended, but we want to get the
    1922                                      * PID anyway to retrieve the output in a later call.
    1923                                      */
    1924                                     *aPID = pData->u32PID;
    1925                                     break;
    1926 
    1927                                 case PROC_STS_ERROR:
    1928                                     vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */
    1929                                     break;
    1930 
    1931                                 case PROC_STS_UNDEFINED:
    1932                                     vrc = VERR_TIMEOUT;    /* Operation did not complete within time. */
    1933                                     break;
    1934 
    1935                                 default:
    1936                                     vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */
    1937                                     break;
    1938                             }
    1939                         }
    1940                         else /* Operation was canceled. */
    1941                             vrc = VERR_CANCELLED;
    1942                     }
    1943                     else /* Operation did not complete within time. */
    1944                         vrc = VERR_TIMEOUT;
    1945 
    1946                     /*
    1947                      * Do *not* remove the callback yet - we might wait with the IProgress object on something
    1948                      * else (like end of process) ...
    1949                      */
    1950                     if (RT_FAILURE(vrc))
    1951                     {
    1952                         if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
    1953                             rc = setError(VBOX_E_IPRT_ERROR,
    1954                                           tr("The file '%s' was not found on guest"), Utf8Command.c_str());
    1955                         else if (vrc == VERR_PATH_NOT_FOUND)
    1956                             rc = setError(VBOX_E_IPRT_ERROR,
    1957                                           tr("The path to file '%s' was not found on guest"), Utf8Command.c_str());
    1958                         else if (vrc == VERR_BAD_EXE_FORMAT)
    1959                             rc = setError(VBOX_E_IPRT_ERROR,
    1960                                           tr("The file '%s' is not an executable format on guest"), Utf8Command.c_str());
    1961                         else if (vrc == VERR_AUTHENTICATION_FAILURE)
    1962                             rc = setError(VBOX_E_IPRT_ERROR,
    1963                                           tr("The specified user '%s' was not able to logon on guest"), Utf8UserName.c_str());
    1964                         else if (vrc == VERR_TIMEOUT)
    1965                             rc = setError(VBOX_E_IPRT_ERROR,
    1966                                           tr("The guest did not respond within time (%ums)"), aTimeoutMS);
    1967                         else if (vrc == VERR_CANCELLED)
    1968                             rc = setError(VBOX_E_IPRT_ERROR,
    1969                                           tr("The execution operation was canceled"));
    1970                         else if (vrc == VERR_PERMISSION_DENIED)
    1971                             rc = setError(VBOX_E_IPRT_ERROR,
    1972                                           tr("Invalid user/password credentials"));
    1973                         else
    1974                         {
    1975                             if (pData && pData->u32Status == PROC_STS_ERROR)
    1976                                 rc = setError(VBOX_E_IPRT_ERROR,
    1977                                               tr("Process could not be started: %Rrc"), pData->u32Flags);
    1978                             else
    1979                                 rc = setError(E_UNEXPECTED,
    1980                                               tr("The service call failed with error %Rrc"), vrc);
    1981                         }
    1982                     }
    1983                     else /* Execution went fine. */
    1984                     {
    1985                         /* Return the progress to the caller. */
    1986                         progress.queryInterfaceTo(aProgress);
    1987                     }
    1988                 }
    1989                 else /* Callback context not found; should never happen! */
    1990                     AssertMsg(it != mCallbackMap.end(), ("Callback context with ID %u not found!", uContextID));
    1991             }
    1992             else /* HGCM related error codes .*/
    1993             {
    1994                 if (vrc == VERR_INVALID_VM_HANDLE)
    1995                     rc = setError(VBOX_E_VM_ERROR,
    1996                                   tr("VMM device is not available (is the VM running?)"));
    1997                 else if (vrc == VERR_TIMEOUT)
    1998                     rc = setError(VBOX_E_VM_ERROR,
    1999                                   tr("The guest execution service is not ready"));
    2000                 else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
    2001                     rc = setError(VBOX_E_VM_ERROR,
    2002                                   tr("The guest execution service is not available"));
    2003                 else /* HGCM call went wrong. */
    2004                     rc = setError(E_UNEXPECTED,
    2005                                   tr("The HGCM call failed with error %Rrc"), vrc);
    2006             }
    2007 
    2008             for (unsigned i = 0; i < uNumArgs; i++)
    2009                 RTMemFree(papszArgv[i]);
    2010             RTMemFree(papszArgv);
    2011         }
    2012 
    2013         if (RT_FAILURE(vrc))
    2014             LogRel(("Executing guest process \"%s\" as user \"%s\" failed with %Rrc\n",
    2015                     Utf8Command.c_str(), Utf8UserName.c_str(), vrc));
    2016 #endif
     2072        }
     2073    }
    20172074    catch (std::bad_alloc &)
    20182075    {
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r33061 r33064  
    77467746  <interface
    77477747     name="IGuest" extends="$unknown"
    7748      uuid="6e3113ac-ed90-4864-8c2c-942c8022324d"
     7748     uuid="c165a809-0882-4c76-9220-746da84b5ecf"
    77497749     wsmap="managed"
    77507750     >
     
    80618061      <param name="progress" type="IProgress" dir="return">
    80628062        <desc>Progress object to track the operation completion.</desc>
     8063      </param>
     8064    </method>
     8065
     8066    <method name="setProcessInput">
     8067      <desc>
     8068        Sends input into a formerly started process.
     8069
     8070        <result name="VBOX_E_IPRT_ERROR">
     8071          Could not send input.
     8072        </result>
     8073
     8074      </desc>
     8075      <param name="pid" type="unsigned long" dir="in">
     8076        <desc>
     8077          Process id returned by earlier executeProcess() call.
     8078        </desc>
     8079      </param>
     8080      <param name="flags" type="unsigned long" dir="in">
     8081        <desc>
     8082          Not used, must be set to zero.
     8083        </desc>
     8084      </param>
     8085      <param name="timeoutMS" type="unsigned long" dir="in">
     8086        <desc>
     8087          The maximum timeout value (in msec) to wait for handling
     8088          the input data. Pass 0 for an infinite timeout.
     8089        </desc>
     8090      </param>
     8091      <param name="data" type="octet" dir="in" safearray="yes">
     8092        <desc>
     8093          Buffer of input data to send to the started process to.
     8094        </desc>
     8095      </param>
     8096      <param name="written" type="unsigned long" dir="return">
     8097        <desc>
     8098          Number of bytes written.
     8099        </desc>
    80638100      </param>
    80648101    </method>
  • trunk/src/VBox/Main/include/GuestImpl.h

    r32866 r33064  
    9999                              ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress);
    100100    STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData));
     101    STDMETHOD(SetProcessInput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten);
    101102    STDMETHOD(GetProcessStatus)(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ULONG *aStatus);
    102103    STDMETHOD(CopyToGuest)(IN_BSTR aSource, IN_BSTR aDest, ULONG aFlags, IProgress **aProgress);
     
    153154#ifdef VBOX_WITH_COPYTOGUEST
    154155    /*
    155      *
     156     * Structure holding a directory entry.
    156157     */
    157     struct DirEntry
     158    struct VBoxGuestDirEntry
    158159    {
    159160        char       *pszPath;
     
    170171    int notifyCtrlExecStatus(uint32_t u32Function, PCALLBACKDATAEXECSTATUS pData);
    171172    int notifyCtrlExecOut(uint32_t u32Function, PCALLBACKDATAEXECOUT pData);
     173    int notifyCtrlExecInStatus(uint32_t u32Function, PCALLBACKDATAEXECINSTATUS pData);
    172174    CallbackMapIter getCtrlCallbackContextByID(uint32_t u32ContextID);
    173175    GuestProcessMapIter getProcessByPID(uint32_t u32PID);
Note: See TracChangeset for help on using the changeset viewer.

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