Changeset 33064 in vbox
- Timestamp:
- Oct 12, 2010 1:20:50 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestControlSvc.h
r32852 r33064 108 108 /** Optional data buffer. */ 109 109 void *pvData; 110 /** Size of optional data buffer. */110 /** Size (in bytes) of optional data buffer. */ 111 111 uint32_t cbData; 112 112 } CALLBACKDATAEXECOUT, *PCALLBACKDATAEXECOUT; 113 114 typedef 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; 113 125 114 126 typedef struct _VBoxGuestCtrlCallbackDataClientDisconnected … … 125 137 CALLBACKDATAMAGICEXECSTATUS = 0x26011982, 126 138 /** 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 128 142 }; 129 143 … … 132 146 VBOXGUESTCTRLCALLBACKTYPE_UNKNOWN = 0, 133 147 VBOXGUESTCTRLCALLBACKTYPE_EXEC_START = 1, 134 VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT = 2 148 VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT = 2, 149 VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS = 3 135 150 }; 136 151 … … 140 155 enum eHostFn 141 156 { 157 /** 158 * The host asks the client to cancel all pending waits and exit. 159 */ 160 HOST_CANCEL_PENDING_WAITS = 0, 142 161 /** 143 162 * The host wants to execute something in the guest. This can be a command line … … 179 198 GUEST_DISCONNECTED = 3, 180 199 /** 181 * TODO200 * Guests sends output from an executed process. 182 201 */ 183 202 GUEST_EXEC_SEND_OUTPUT = 100, 184 203 /** 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 214 211 }; 215 212 … … 265 262 } VBoxGuestCtrlHGCMMsgExecCmd; 266 263 264 typedef 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 267 280 typedef struct _VBoxGuestCtrlHGCMMsgExecOut 268 281 { … … 272 285 /** The process ID (PID). */ 273 286 HGCMFunctionParameter pid; 274 /** The pipe handle ID . */287 /** The pipe handle ID (stdout/stderr). */ 275 288 HGCMFunctionParameter handle; 276 289 /** Optional flags. */ … … 296 309 297 310 } VBoxGuestCtrlHGCMMsgExecStatus; 311 312 typedef 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; 298 325 #pragma pack () 299 326 -
trunk/include/VBox/VBoxGuestLib.h
r32574 r33064 557 557 char *pszPassword, uint32_t cbPassword, 558 558 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); 559 VBGLR3DECL(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); 563 VBGLR3DECL(int) VbglR3GuestCtrlExecGetHostCmdOutput(uint32_t u32ClientId, uint32_t uNumParms, 564 uint32_t *puContext, uint32_t *puPID, 565 uint32_t *puHandle, uint32_t *puFlags); 562 566 VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatus(uint32_t u32ClientId, 563 567 uint32_t u32Context, … … 574 578 void *pvData, 575 579 uint32_t cbData); 580 VBGLR3DECL(int) VbglR3GuestCtrlExecReportStatusIn(uint32_t u32ClientId, 581 uint32_t u32Context, 582 uint32_t u32PID, 583 uint32_t u32Flags, 584 uint32_t cbWritten); 576 585 /** @} */ 577 586 # endif /* VBOX_WITH_GUEST_CONTROL defined */ -
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp
r30013 r33064 105 105 VBGLR3DECL(int) VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms) 106 106 { 107 AssertPtr (puMsg);108 AssertPtr (puNumParms);107 AssertPtrReturn(puMsg, VERR_INVALID_PARAMETER); 108 AssertPtrReturn(puNumParms, VERR_INVALID_PARAMETER); 109 109 110 110 VBoxGuestCtrlHGCMMsgType Msg; … … 178 178 uint32_t *puTimeLimit) 179 179 { 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); 191 191 192 192 VBoxGuestCtrlHGCMMsgExecCmd Msg; … … 197 197 Msg.hdr.cParms = uNumParms; 198 198 199 VbglHGCMParmUInt32Set(&Msg.context, 0); /** @todo Put this some header struct! */199 VbglHGCMParmUInt32Set(&Msg.context, 0); 200 200 VbglHGCMParmPtrSet(&Msg.cmd, pszCmd, cbCmd); 201 201 VbglHGCMParmUInt32Set(&Msg.flags, 0); … … 245 245 uint32_t *puHandle, uint32_t *puFlags) 246 246 { 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); 249 251 250 252 VBoxGuestCtrlHGCMMsgExecOut Msg; … … 255 257 Msg.hdr.cParms = uNumParms; 256 258 257 VbglHGCMParmUInt32Set(&Msg.context, 0); /** @todo Put this some header struct! */259 VbglHGCMParmUInt32Set(&Msg.context, 0); 258 260 VbglHGCMParmUInt32Set(&Msg.pid, 0); 259 261 VbglHGCMParmUInt32Set(&Msg.handle, 0); … … 274 276 Msg.handle.GetUInt32(puHandle); 275 277 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 */ 295 VBGLR3DECL(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); 276 334 } 277 335 } … … 355 413 } 356 414 415 416 /** 417 * Reports back the input status to the host. 418 * 419 * @returns VBox status code. 420 ** @todo Docs! 421 */ 422 VBGLR3DECL(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 39 39 ifdef VBOX_WITH_GUEST_PROPS 40 40 VBoxService_DEFS += VBOX_WITH_GUEST_PROPS VBOXSERVICE_VMINFO 41 if1of ($(KBUILD_TARGET), win)42 VBoxService_DEFS += VBOXSERVICE_EXEC43 endif44 41 endif 45 42 ifdef VBOX_WITH_GUEST_CONTROL -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r32431 r33064 105 105 106 106 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 #endif128 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 else153 {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 else178 {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->fStarted185 && 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 else216 rc = VERR_NO_MEMORY;217 }218 else219 rc = VERR_NOT_FOUND; /* PID not found! */220 }221 VBoxServiceVerbose(3, "Control: VBoxServiceControlHandleCmdGetOutput returned with %Rrc\n", rc);222 return rc;223 }224 225 226 107 /** @copydoc VBOXSERVICE::pfnWorker */ 227 108 DECLCALLBACK(int) VBoxServiceControlWorker(bool volatile *pfShutdown) … … 263 144 switch(uMsg) 264 145 { 265 case GETHOSTMSG_EXEC_HOST_CANCEL_WAIT:146 case HOST_CANCEL_PENDING_WAITS: 266 147 VBoxServiceVerbose(3, "Control: Host asked us to quit ...\n"); 267 148 break; 268 149 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); 275 160 break; 276 161 … … 287 172 /* Do we need to shutdown? */ 288 173 if ( *pfShutdown 289 || uMsg == GETHOSTMSG_EXEC_HOST_CANCEL_WAIT)174 || uMsg == HOST_CANCEL_PENDING_WAITS) 290 175 { 291 176 rc = VINF_SUCCESS; -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp
r32852 r33064 47 47 extern RTLISTNODE g_GuestControlExecThreads; 48 48 49 49 50 /** 50 51 * Handle an error event on standard input. 51 52 * 53 * @returns IPRT status code. 52 54 * @param hPollSet The polling set. 53 55 * @param fPollEvt The event mask returned by RTPollNoResume. … … 55 57 * @param pStdInBuf The standard input buffer. 56 58 */ 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*/); 59 static 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); 64 82 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; 80 89 } 81 90 … … 88 97 * @param hStdInW The standard input pipe. 89 98 */ 90 static int VBoxServiceControlExecProcWriteStdIn(PVBOXSERVICECTRL STDINBUF 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);99 static int VBoxServiceControlExecProcWriteStdIn(PVBOXSERVICECTRLEXECPIPEBUF pStdInBuf, RTPIPE hStdInW, size_t *pcbWritten) 100 { 101 AssertPtrReturn(pcbWritten, VERR_INVALID_PARAMETER); 102 103 int rc = RTCritSectEnter(&pStdInBuf->CritSect); 95 104 if (RT_SUCCESS(rc)) 96 105 { 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; 99 124 } 100 125 return rc; … … 106 131 * child process. 107 132 * 133 * @returns IPRT status code. 108 134 * @param hPollSet The polling set. 109 135 * @param fPollEvt The event mask returned by RTPollNoResume. … … 111 137 * @param pStdInBuf The standard input buffer. 112 138 */ 113 static void VBoxServiceControlExecProcHandleStdInWritableEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW, 114 PVBOXSERVICECTRLSTDINBUF pStdInBuf) 115 { 116 int rc; 139 static 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; 117 145 if (!(fPollEvt & RTPOLL_EVT_ERROR)) 118 146 { 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? */ 123 153 AssertRC(rc); 124 154 } 125 155 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); 129 161 AssertRC(rc); 130 162 } 131 163 } 132 164 else 133 VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf); 165 rc = VBoxServiceControlExecProcHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW, pStdInBuf); 166 return rc; 167 } 168 169 170 static 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; 134 179 } 135 180 … … 146 191 * @param pu32Crc The current CRC-32 of the stream. (In/Out) 147 192 * @param uHandleId The handle ID. 148 * @param pszOpcode The opcode for the data upload.149 193 * 150 194 * @todo Put the last 4 parameters into a struct! 151 195 */ 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)); 196 static 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); 157 200 158 201 /* … … 163 206 uint8_t abBuf[_64K]; 164 207 165 AssertPtr(pThread);166 PVBOXSERVICECTRLTHREADDATAEXEC pData = (PVBOXSERVICECTRLTHREADDATAEXEC)pThread->pvData;167 AssertPtr(pData);168 169 208 int rc2 = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead); 170 209 if (RT_SUCCESS(rc2) && cbRead) … … 183 222 { 184 223 #endif 185 rc = VBoxServiceControlExecWritePipeBuffer( &pData->stdOut, abBuf, cbRead);224 rc = VBoxServiceControlExecWritePipeBuffer(pStdOutBuf, abBuf, cbRead); 186 225 if (RT_SUCCESS(rc)) 187 226 { … … 229 268 */ 230 269 static 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*/); 237 273 } 238 274 … … 244 280 int rc; 245 281 int rc2; 246 VBOXSERVICECTRLSTDINBUF StdInBuf = { 0, 0, NULL, 0, hStdInW == NIL_RTPIPE, RTCrc32Start() };247 uint32_t uStdOutCrc32 = RTCrc32Start();248 uint32_t uStdErrCrc32 = uStdOutCrc32;249 282 uint64_t const MsStart = RTTimeMilliTS(); 250 283 RTPROCSTATUS ProcessStatus = { 254, RTPROCEXITREASON_ABEND }; … … 253 286 uint64_t MsProcessKilled = UINT64_MAX; 254 287 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. */ 257 290 RTMSINTERVAL cMsPollCur = 0; 258 291 … … 290 323 continue; 291 324 292 cMsPollCur = 0; /* no rest until we've checked everything. */325 cMsPollCur = 0; /* No rest until we've checked everything. */ 293 326 294 327 if (RT_SUCCESS(rc2)) 295 328 { 329 VBoxServiceVerbose(4, "ControlExec: RTPollNoResume idPollHnd=%u\n", idPollHnd); 296 330 switch (idPollHnd) 297 331 { 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); 300 335 break; 301 336 302 case 1 /* TXSEXECHNDID_STDOUT */:303 rc = VBoxServiceControlExecProcHandle OutputEvent(pThread, hPollSet, fPollEvt, &hStdOutR, &uStdOutCrc32, 1 /* TXSEXECHNDID_STDOUT */);337 case VBOXSERVICECTRLPIPEID_STDIN_WRITABLE: 338 rc = VBoxServiceControlExecProcHandleStdInWritableEvent(hPollSet, fPollEvt, &hStdInW, &pData->stdIn); 304 339 break; 305 340 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); 308 344 break; 309 345 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); 312 349 break; 313 350 314 351 default: 315 rc = VBoxServiceControlExecProcHandleTransportEvent(hPollSet, fPollEvt, idPollHnd, &hStdInW, &StdInBuf);352 //rc = VBoxServiceControlExecProcHandleTransportEvent(hPollSet, fPollEvt, idPollHnd, &hStdInW, &pData->stdIn); 316 353 break; 317 354 } 318 355 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. */ 320 357 continue; 321 358 } 322 323 /*324 * Check for incoming data.325 */326 359 327 360 /* … … 501 534 else 502 535 VBoxServiceError("ControlExec: Process loop failed with rc=%Rrc\n", rc); 503 RTMemFree(StdInBuf.pch);504 536 return rc; 505 537 } … … 510 542 * 511 543 * @returns IPRT status code. No client replies made. 512 * @param pszHowTo How to set up this standard handle.513 544 * @param fd Which standard handle it is (0 == stdin, 1 == 514 545 * stdout, 2 == stderr). … … 560 591 AssertPtr(pBuf); 561 592 593 /** @todo Add allocation size as function parameter! */ 562 594 pBuf->pbData = (uint8_t*)RTMemAlloc(_64K); /* Start with a 64k buffer. */ 563 595 AssertReturn(pBuf->pbData, VERR_NO_MEMORY); 596 pBuf->cbAllocated = _64K; 564 597 pBuf->cbSize = 0; 565 pBuf->cb Offset= 0;566 pBuf-> cbRead = 0;598 pBuf->cbProcessed = 0; 599 pBuf->fAlive = true; 567 600 568 601 return RTCritSectInit(&pBuf->CritSect); … … 576 609 RTMemFree(pBuf->pbData); 577 610 pBuf->pbData = NULL; 611 pBuf->cbAllocated = 0; 578 612 pBuf->cbSize = 0; 579 pBuf->cb Offset= 0;580 pBuf->cbRead = 0;581 }613 pBuf->cbProcessed = 0; 614 } 615 pBuf->fAlive = false; 582 616 return RTCritSectDelete(&pBuf->CritSect); 583 617 } … … 592 626 if (RT_SUCCESS(rc)) 593 627 { 594 Assert(pBuf->cb Offset >= pBuf->cbRead);595 if (*pcbToRead > pBuf->cb Offset - pBuf->cbRead)596 *pcbToRead = pBuf->cb Offset - pBuf->cbRead;628 Assert(pBuf->cbSize >= pBuf->cbProcessed); 629 if (*pcbToRead > pBuf->cbSize - pBuf->cbProcessed) 630 *pcbToRead = pBuf->cbSize - pBuf->cbProcessed; 597 631 598 632 if (*pcbToRead > cbBuffer) … … 601 635 if (*pcbToRead > 0) 602 636 { 603 memcpy(pbBuffer, pBuf->pbData + pBuf->cb Read, *pcbToRead);604 pBuf->cb Read += *pcbToRead;637 memcpy(pbBuffer, pBuf->pbData + pBuf->cbProcessed, *pcbToRead); 638 pBuf->cbProcessed += *pcbToRead; 605 639 } 606 640 else … … 622 656 if (RT_SUCCESS(rc)) 623 657 { 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 } 644 683 int rc2 = RTCritSectLeave(&pBuf->CritSect); 645 684 if (RT_SUCCESS(rc)) … … 731 770 if (RT_SUCCESS(rc)) 732 771 rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdErr); 772 if (RT_SUCCESS(rc)) 773 rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdIn); 733 774 } 734 775 … … 763 804 VBoxServiceControlExecDestroyPipeBuffer(&pData->stdOut); 764 805 VBoxServiceControlExecDestroyPipeBuffer(&pData->stdErr); 806 VBoxServiceControlExecDestroyPipeBuffer(&pData->stdIn); 765 807 766 808 RTMemFree(pData); … … 852 894 RTHANDLE hStdIn; 853 895 PRTHANDLE phStdIn; 854 RTPIPE hStdInW; 855 rc = VBoxServiceControlExecSetupPipe(0 /* stdin */, &hStdIn, &phStdIn, &hStdInW); 896 rc = VBoxServiceControlExecSetupPipe(0 /*STDIN_FILENO*/, &hStdIn, &phStdIn, &pData->pipeStdInW); 856 897 if (RT_SUCCESS(rc)) 857 898 { … … 859 900 PRTHANDLE phStdOut; 860 901 RTPIPE hStdOutR; 861 rc = VBoxServiceControlExecSetupPipe(1 /* stdout*/, &hStdOut, &phStdOut, &hStdOutR);902 rc = VBoxServiceControlExecSetupPipe(1 /*STDOUT_FILENO*/, &hStdOut, &phStdOut, &hStdOutR); 862 903 if (RT_SUCCESS(rc)) 863 904 { … … 865 906 PRTHANDLE phStdErr; 866 907 RTPIPE hStdErrR; 867 rc = VBoxServiceControlExecSetupPipe(2 /* stderr*/, &hStdErr, &phStdErr, &hStdErrR);908 rc = VBoxServiceControlExecSetupPipe(2 /*STDERR_FILENO*/, &hStdErr, &phStdErr, &hStdErrR); 868 909 if (RT_SUCCESS(rc)) 869 910 { … … 876 917 if (RT_SUCCESS(rc)) 877 918 { 878 rc = RTPollSetAddPipe(hPollSet, hStdInW, RTPOLL_EVT_ERROR, 0 /* TXSEXECHNDID_STDIN */);919 rc = RTPollSetAddPipe(hPollSet, pData->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN_ERROR); 879 920 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); 881 922 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); 883 926 if (RT_SUCCESS(rc)) 884 927 { … … 915 958 rc = VBoxServiceControlExecProcLoop(pThread, 916 959 hProcess, pData->uTimeLimitMS, hPollSet, 917 hStdInW, hStdOutR, hStdErrR);960 pData->pipeStdInW, hStdOutR, hStdErrR); 918 961 919 962 /* … … 924 967 */ 925 968 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 0 /* stdin */, NULL))) 926 hStdInW = NIL_RTPIPE;969 pData->pipeStdInW = NIL_RTPIPE; 927 970 if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, 1 /* stdout */, NULL))) 928 971 hStdOutR = NIL_RTPIPE; … … 943 986 } 944 987 } 988 RTPollSetDestroy(hPollSet); 945 989 } 946 990 RTPipeClose(hStdErrR); … … 950 994 RTHandleClose(phStdOut); 951 995 } 952 RTPipeClose( hStdInW);996 RTPipeClose(pData->pipeStdInW); 953 997 RTHandleClose(phStdIn); 954 998 } … … 968 1012 RTThreadUserSignal(RTThreadSelf()); 969 1013 return rc; 1014 } 1015 1016 PVBOXSERVICECTRLTHREAD 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; 970 1033 } 971 1034 … … 1033 1096 } 1034 1097 1098 1099 /** 1100 * 1101 * 1102 * @return int 1103 * 1104 * @param u32ClientId 1105 * @param uNumParms 1106 */ 1107 int 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 */ 1173 int 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 */ 1224 int 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 112 112 }; 113 113 114 enum 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. */ 114 123 typedef struct 115 124 { 125 /** The data buffer. */ 116 126 uint8_t *pbData; 127 /** The amount of allocated buffer space. */ 128 uint32_t cbAllocated; 129 /** The actual used/occupied buffer space. */ 117 130 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; 120 134 RTCRITSECT CritSect; 135 bool fAlive; 121 136 } VBOXSERVICECTRLEXECPIPEBUF; 122 /** Pointer to threaddata. */137 /** Pointer to buffered pipe data. */ 123 138 typedef VBOXSERVICECTRLEXECPIPEBUF *PVBOXSERVICECTRLEXECPIPEBUF; 124 139 … … 137 152 uint32_t uTimeLimitMS; 138 153 154 RTPIPE pipeStdInW; 155 VBOXSERVICECTRLEXECPIPEBUF stdIn; 139 156 VBOXSERVICECTRLEXECPIPEBUF stdOut; 140 157 VBOXSERVICECTRLEXECPIPEBUF stdErr; … … 168 185 /** Pointer to thread data. */ 169 186 typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD; 170 171 /**172 * For buffering process input supplied by the client.173 */174 typedef struct VBOXSERVICECTRLSTDINBUF175 {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 192 187 #endif /* VBOX_WITH_GUEST_CONTROL */ 193 188 #ifdef VBOX_WITH_GUEST_PROPS … … 277 272 278 273 #ifdef VBOX_WITH_GUEST_CONTROL 274 extern int VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms); 275 extern int VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms); 276 extern int VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms); 277 extern int VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms); 278 extern int VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms); 279 279 extern int VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags, 280 280 const char *pszArgs, uint32_t uNumArgs, … … 286 286 extern int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf, 287 287 uint8_t *pbData, uint32_t cbData); 288 #endif 288 #endif /* VBOX_WITH_GUEST_CONTROL */ 289 289 290 290 #ifdef VBOXSERVICE_MANAGEMENT -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r32997 r33064 74 74 " [--flags <flags>] [--timeout <msec>]\n" 75 75 " [--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". */ 76 78 #ifdef VBOX_WITH_COPYTOGUEST 77 79 "\n" … … 447 449 } 448 450 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 449 480 if (cbOutputData <= 0) /* No more output data left? */ 450 481 { … … 552 583 static int handleCtrlCopyTo(HandlerArg *a) 553 584 { 585 #if 0 554 586 RTISOFSFILE file; 555 587 int vrc = RTIsoFsOpen(&file, "c:\\Downloads\\VBoxGuestAdditions_3.2.8.iso"); … … 562 594 } 563 595 return vrc; 596 #endif 564 597 565 598 /* -
trunk/src/VBox/HostServices/GuestControl/service.cpp
r30681 r33064 389 389 if (cParms != pBuf->uParmCount) 390 390 { 391 LogFlowFunc(("Parameter count does not match (%u (buffer), %u (guest))\n", 392 pBuf->uParmCount, cParms)); 391 393 rc = VERR_INVALID_PARAMETER; 392 394 } … … 583 585 if (it->mNumParms >= 2) 584 586 { 585 it->mParms[0].setUInt32( GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID. */586 it->mParms[1].setUInt32(0); 587 it->mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 588 it->mParms[1].setUInt32(0); /* Required parameters for message. */ 587 589 } 588 590 if (mpHelpers) … … 628 630 paParms[3].getUInt32(&data.u32Flags); 629 631 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); 630 647 631 648 if (mpfnHostCallback) … … 745 762 746 763 /* 747 * The guest notifies the host of the current clientstatus.764 * The guest notifies the host of the executed process status. 748 765 */ 749 766 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")); 751 773 rc = notifyHost(eFunction, cParms, paParms); 752 774 break; … … 790 812 break; 791 813 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. */ 793 816 case HOST_EXEC_SET_INPUT: 794 817 LogFlowFunc(("HOST_EXEC_SET_INPUT\n")); 818 rc = processHostCmd(eFunction, cParms, paParms); 795 819 break; 796 820 -
trunk/src/VBox/Main/GuestImpl.cpp
r32866 r33064 579 579 580 580 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 } 616 640 return rc; 617 641 } … … 775 799 776 800 default: 777 AssertMsgFailed((" unknown callback type %d\n", it2->second.mType));801 AssertMsgFailed(("Unknown callback type %d\n", it2->second.mType)); 778 802 break; 779 803 } … … 808 832 if (it != mCallbackMap.end()) 809 833 { 810 PCALLBACKDATAEXECOUT pCBData = ( CALLBACKDATAEXECOUT*)it->second.pvData;834 PCALLBACKDATAEXECOUT pCBData = (PCALLBACKDATAEXECOUT)it->second.pvData; 811 835 AssertPtr(pCBData); 812 836 … … 841 865 Guest::getStaticComponentName(), 842 866 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. */ 877 int 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")); 843 902 } 844 903 else … … 1303 1362 } 1304 1363 1364 STDMETHODIMP 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 1305 1554 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData)) 1306 1555 { … … 1552 1801 LogFlowFunc(("Appending to pList=%p: %s\n", pList, pszPath)); 1553 1802 1554 DirEntry *pNode = (DirEntry*)RTMemAlloc(sizeof(DirEntry));1803 VBoxGuestDirEntry *pNode = (VBoxGuestDirEntry*)RTMemAlloc(sizeof(VBoxGuestDirEntry)); 1555 1804 if (pNode == NULL) 1556 1805 return VERR_NO_MEMORY; 1557 1806 1807 pNode->pszPath = NULL; 1558 1808 if (RT_SUCCESS(RTStrAAppend(&pNode->pszPath, pszPath))) 1559 1809 { … … 1579 1829 pszDirectory, pszFilter ? pszFilter : "<None>")); 1580 1830 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 1584 1842 if (RT_SUCCESS(rc)) 1585 1843 { 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)) 1602 1850 { 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, "..")) 1616 1861 { 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 }1626 1862 break; 1627 1863 } 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; 1640 1881 } 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: 1642 1893 break; 1643 1894 } 1644 } 1895 if (RT_FAILURE(rc)) 1896 break; 1897 } 1898 RTStrFree(pszDirectoryStrip); 1899 } 1900 1901 if (pDir) 1645 1902 RTDirClose(pDir); 1646 }1647 if (pszDirWithFilter)1648 RTStrFree(pszDirWithFilter);1649 1903 return rc; 1650 1904 } … … 1682 1936 try 1683 1937 { 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 else1695 rc = setError(VBOX_E_IPRT_ERROR,1696 tr("Could not determine absolute path! rc=%Rrc"), vrc);1697 1698 1938 ULONG cObjectsToCopy = 0; 1699 1939 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 1735 1966 if (SUCCEEDED(rc)) 1736 1967 { 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 } 1742 1984 } 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; 1765 2008 #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)) 1824 2010 { 1825 2011 PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS)); … … 1864 2050 else 1865 2051 vrc = VERR_INVALID_VM_HANDLE; 1866 RTMemFree(pvEnv);1867 2052 } 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 } 1869 2071 } 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 } 2017 2074 catch (std::bad_alloc &) 2018 2075 { -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r33061 r33064 7746 7746 <interface 7747 7747 name="IGuest" extends="$unknown" 7748 uuid=" 6e3113ac-ed90-4864-8c2c-942c8022324d"7748 uuid="c165a809-0882-4c76-9220-746da84b5ecf" 7749 7749 wsmap="managed" 7750 7750 > … … 8061 8061 <param name="progress" type="IProgress" dir="return"> 8062 8062 <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> 8063 8100 </param> 8064 8101 </method> -
trunk/src/VBox/Main/include/GuestImpl.h
r32866 r33064 99 99 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress); 100 100 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); 101 102 STDMETHOD(GetProcessStatus)(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ULONG *aStatus); 102 103 STDMETHOD(CopyToGuest)(IN_BSTR aSource, IN_BSTR aDest, ULONG aFlags, IProgress **aProgress); … … 153 154 #ifdef VBOX_WITH_COPYTOGUEST 154 155 /* 155 * 156 * Structure holding a directory entry. 156 157 */ 157 struct DirEntry158 struct VBoxGuestDirEntry 158 159 { 159 160 char *pszPath; … … 170 171 int notifyCtrlExecStatus(uint32_t u32Function, PCALLBACKDATAEXECSTATUS pData); 171 172 int notifyCtrlExecOut(uint32_t u32Function, PCALLBACKDATAEXECOUT pData); 173 int notifyCtrlExecInStatus(uint32_t u32Function, PCALLBACKDATAEXECINSTATUS pData); 172 174 CallbackMapIter getCtrlCallbackContextByID(uint32_t u32ContextID); 173 175 GuestProcessMapIter getProcessByPID(uint32_t u32PID);
Note:
See TracChangeset
for help on using the changeset viewer.