Changeset 39418 in vbox
- Timestamp:
- Nov 25, 2011 10:11:06 AM (13 years ago)
- Location:
- trunk
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/HostServices/GuestControlSvc.h
r38870 r39418 75 75 #define INPUT_FLAG_NONE 0 76 76 #define INPUT_FLAG_EOF RT_BIT(0) 77 78 /** 79 * Execution flags. 80 * Note: Has to match Main's ExecuteProcessFlag_* flags! 81 */ 82 #define EXECUTEPROCESSFLAG_NONE 0x0 83 #define EXECUTEPROCESSFLAG_WAIT_START RT_BIT(1) 84 #define EXECUTEPROCESSFLAG_HIDDEN RT_BIT(2) 85 #define EXECUTEPROCESSFLAG_NO_PROFILE RT_BIT(3) 86 #define EXECUTEPROCESSFLAG_WAIT_STDOUT RT_BIT(4) 87 #define EXECUTEPROCESSFLAG_WAIT_STDERR RT_BIT(5) 77 88 78 89 /** -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
r39392 r39418 314 314 /* Tell the host. */ 315 315 rc = VbglR3GuestCtrlExecReportStatus(uClientID, uContextID, 0 /* PID, invalid. */, 316 PROC_STS_ERROR, VERR_MAX_PROCS_REACHED, 316 PROC_STS_ERROR, 317 !fAllowed ? VERR_MAX_PROCS_REACHED : rc, 317 318 NULL /* pvData */, 0 /* cbData */); 318 319 } … … 335 336 * @param pcbRead Pointer to number of bytes read. Optional. 336 337 */ 337 int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uHandleId, uint32_t uTimeout, 338 int VBoxServiceControlExecGetOutput(uint32_t uPID, uint32_t uCID, 339 uint32_t uHandleId, uint32_t uTimeout, 338 340 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 339 341 { … … 345 347 346 348 VBOXSERVICECTRLREQUEST ctrlRequest; 349 ctrlRequest.uCID = uCID; 347 350 ctrlRequest.cbData = cbBuf; 348 351 ctrlRequest.pvData = (uint8_t*)pvBuf; … … 389 392 * @param pcbWritten Pointer to number of bytes written to the process. Optional. 390 393 */ 391 int VBoxServiceControlSetInput(uint32_t uPID, bool fPendingClose, 394 int VBoxServiceControlSetInput(uint32_t uPID, uint32_t uCID, 395 bool fPendingClose, 392 396 void *pvBuf, uint32_t cbBuf, 393 397 uint32_t *pcbWritten) … … 400 404 401 405 VBOXSERVICECTRLREQUEST ctrlRequest; 406 ctrlRequest.uCID = uCID; 402 407 ctrlRequest.cbData = cbBuf; 403 408 ctrlRequest.pvData = pvBuf; … … 470 475 } 471 476 472 rc = VBoxServiceControlSetInput(uPID, fPendingClose, pabBuffer,477 rc = VBoxServiceControlSetInput(uPID, uContextID, fPendingClose, pabBuffer, 473 478 cbSize, &cbWritten); 474 VBoxServiceVerbose(4, "Control: [PID %u]: Written input, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",475 uPID, rc, uFlags, fPendingClose, cbSize, cbWritten);479 VBoxServiceVerbose(4, "Control: [PID %u]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n", 480 uPID, uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten); 476 481 if (RT_SUCCESS(rc)) 477 482 { … … 543 548 if (pBuf) 544 549 { 545 rc = VBoxServiceControlExecGetOutput(uPID, u HandleID, RT_INDEFINITE_WAIT /* Timeout */,550 rc = VBoxServiceControlExecGetOutput(uPID, uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */, 546 551 pBuf, _64K /* cbSize */, &cbRead); 552 553 /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary 554 * data which the host needs to work with -- so just pass through all data unfiltered! */ 555 547 556 if (RT_SUCCESS(rc)) 548 VBoxServiceVerbose( 3, "Control: [PID %u]: Got output, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",557 VBoxServiceVerbose(2, "Control: Got output, PID=%u, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n", 549 558 uPID, uContextID, cbRead, uHandleID, uFlags); 559 else if (rc == VERR_NOT_FOUND) 560 VBoxServiceVerbose(2, "Control: PID=%u not found, CID=%u, uHandle=%u\n", 561 uPID, uContextID, uHandleID, rc); 550 562 else 551 VBoxServiceError("Control: [PID %u]: Failed to retrieve output, CID=%u, uHandle=%u, rc=%Rrc\n",563 VBoxServiceError("Control: Failed to retrieve output for PID=%u, CID=%u, uHandle=%u, rc=%Rrc\n", 552 564 uPID, uContextID, uHandleID, rc); 553 565 /* Note: Since the context ID is unique the request *has* to be completed here, … … 598 610 599 611 612 /** 613 * Destroys all guest process threads which are still active. 614 */ 600 615 static void VBoxServiceControlDestroyThreads(void) 601 616 { 602 VBoxServiceVerbose( 3, "Control: Destroying threads ...\n");617 VBoxServiceVerbose(2, "Control: Destroying threads ...\n"); 603 618 604 619 /* Signal all threads that we want to shutdown. */ … … 625 640 } 626 641 642 #ifdef DEBUG 643 PVBOXSERVICECTRLTHREAD pThreadCur; 644 uint32_t cThreads = 0; 645 RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 646 cThreads++; 647 VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads); 648 #endif 627 649 AssertMsg(RTListIsEmpty(&g_GuestControlThreads), 628 650 ("Guest process thread list still contains children when it should not\n")); … … 680 702 RTListForEach(&g_GuestControlThreads, pThread, VBOXSERVICECTRLTHREAD, Node) 681 703 { 682 // THREAD LOCKING!! 683 Assert(pThread->fStarted != pThread->fStopped); 684 if (pThread->fStarted) 704 VBOXSERVICECTRLTHREADSTATUS enmStatus = VBoxServiceControlThreadGetStatus(pThread); 705 if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STARTED) 685 706 uProcsRunning++; 686 else if ( pThread->fStopped)707 else if (enmStatus == VBOXSERVICECTRLTHREADSTATUS_STOPPED) 687 708 uProcsStopped++; 688 709 else … … 690 711 } 691 712 692 VBoxServiceVerbose( 2, "Control: Maximum served guest processes set to %u, running=%u, stopped=%u\n",713 VBoxServiceVerbose(3, "Control: Maximum served guest processes set to %u, running=%u, stopped=%u\n", 693 714 g_GuestControlProcsMaxKept, uProcsRunning, uProcsStopped); 694 715 … … 714 735 715 736 /** 716 * Finds a (formerly) started process given by its PID. 737 * Finds a (formerly) started process given by its PID and locks it. Must be unlocked 738 * by the caller with VBoxServiceControlThreadUnlock(). 717 739 * 718 740 * @return PVBOXSERVICECTRLTHREAD Process structure if found, otherwise NULL. 719 741 * @param uPID PID to search for. 720 742 */ 721 PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID)743 const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadLocked(uint32_t uPID) 722 744 { 723 745 PVBOXSERVICECTRLTHREAD pThread = NULL; … … 730 752 if (pThreadCur->uPID == uPID) 731 753 { 732 pThread = pThreadCur; 754 rc = RTCritSectEnter(&pThreadCur->CritSect); 755 if (RT_SUCCESS(rc)) 756 pThread = pThreadCur; 733 757 break; 734 758 } … … 745 769 746 770 /** 771 * Unlocks a previously locked guest process thread. 772 * 773 * @param pThread Thread to unlock. 774 */ 775 void VBoxServiceControlThreadUnlock(const PVBOXSERVICECTRLTHREAD pThread) 776 { 777 AssertPtr(pThread); 778 779 int rc = RTCritSectLeave(&pThread->CritSect); 780 AssertRC(rc); 781 } 782 783 784 /** 785 * Assigns a valid PID to a guest control thread and also checks if there already was 786 * another (stale) guest process which was using that PID before and destroys it. 787 * 788 * @return IPRT status code. 789 * @param pThread Thread to assign PID to. 790 * @param uPID PID to assign to the specified guest control execution thread. 791 */ 792 int VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID) 793 { 794 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 795 AssertReturn(uPID, VERR_INVALID_PARAMETER); 796 797 int rc = RTCritSectEnter(&g_GuestControlThreadsCritSect); 798 if (RT_SUCCESS(rc)) 799 { 800 /* Search old threads using the desired PID and shut them down completely -- it's 801 * not used anymore. */ 802 PVBOXSERVICECTRLTHREAD pThreadCur; 803 RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 804 { 805 if ( pThreadCur->uPID == uPID 806 && pThreadCur != pThread) 807 { 808 VBoxServiceVerbose(2, "ControlThread: PID %u was used before, shutting down stale exec thread ...\n", 809 uPID); 810 rc = VBoxServiceControlThreadSignalShutdown(pThreadCur); 811 if (RT_SUCCESS(rc)) 812 rc = VBoxServiceControlThreadWaitForShutdown(pThreadCur, 813 30 * 1000 /* Wait 30 seconds max. */); 814 } 815 } 816 817 /* Assign PID to current thread. */ 818 pThread->uPID = uPID; 819 820 rc = RTCritSectLeave(&g_GuestControlThreadsCritSect); 821 AssertRC(rc); 822 } 823 824 return rc; 825 } 826 827 828 /** 747 829 * Removes the specified guest process thread from the global thread 748 830 * list. … … 751 833 * @param pThread Thread to remove. 752 834 */ 753 void VBoxServiceControlRemoveThread( PVBOXSERVICECTRLTHREAD pThread)835 void VBoxServiceControlRemoveThread(const PVBOXSERVICECTRLTHREAD pThread) 754 836 { 755 837 if (!pThread) … … 763 845 RTListNodeRemove(&pThread->Node); 764 846 765 int rc2 = RTCritSectLeave(&g_GuestControlThreadsCritSect); 766 AssertRC(rc2); 847 #ifdef DEBUG 848 PVBOXSERVICECTRLTHREAD pThreadCur; 849 uint32_t cThreads = 0; 850 RTListForEach(&g_GuestControlThreads, pThreadCur, VBOXSERVICECTRLTHREAD, Node) 851 cThreads++; 852 VBoxServiceVerbose(4, "Control: Guest process threads left=%u\n", cThreads); 853 #endif 854 rc = RTCritSectLeave(&g_GuestControlThreadsCritSect); 855 AssertRC(rc); 767 856 } 768 857 } -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlThread.cpp
r39393 r39418 42 42 43 43 /* Internal functions. */ 44 static int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pData, uint32_t uPID); 45 static void vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pData); 46 static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread); 44 static int vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread); 47 45 48 46 /** … … 154 152 155 153 /** 154 * Frees a guest thread. 155 * 156 * @return IPRT status code. 157 * @param pThread Thread to shut down. 158 */ 159 static int vboxServiceControlThreadFree(PVBOXSERVICECTRLTHREAD pThread) 160 { 161 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 162 163 VBoxServiceVerbose(1, "ControlThread: [PID %u]: Shutting down ...\n", 164 pThread->uPID); 165 166 /* Signal the request event to unblock potential waiters. */ 167 int rc = RTSemEventMultiSignal(pThread->RequestEvent); 168 if (RT_FAILURE(rc)) 169 VBoxServiceError("ControlThread: [PID %u]: Signalling request event failed, rc=%Rrc\n", 170 pThread->uPID, rc); 171 172 rc = RTCritSectEnter(&pThread->CritSect); 173 if (RT_SUCCESS(rc)) 174 { 175 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Freeing thread data ...\n", 176 pThread->uPID); 177 178 RTStrFree(pThread->pszCmd); 179 if (pThread->uNumEnvVars) 180 { 181 for (uint32_t i = 0; i < pThread->uNumEnvVars; i++) 182 RTStrFree(pThread->papszEnv[i]); 183 RTMemFree(pThread->papszEnv); 184 } 185 RTGetOptArgvFree(pThread->papszArgs); 186 RTStrFree(pThread->pszUser); 187 RTStrFree(pThread->pszPassword); 188 189 rc = RTSemEventMultiDestroy(pThread->RequestEvent); 190 AssertRC(rc); 191 192 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cleaning up ...\n", 193 pThread->uPID); 194 195 /* Set stopped status. */ 196 ASMAtomicXchgBool(&pThread->fStopped, true); 197 198 rc = RTCritSectLeave(&pThread->CritSect); 199 AssertRC(rc); 200 } 201 202 /* 203 * Destroy other thread data. 204 */ 205 if (RTCritSectIsInitialized(&pThread->CritSect)) 206 RTCritSectDelete(&pThread->CritSect); 207 208 /* 209 * Destroy thread structure as final step. 210 */ 211 RTMemFree(pThread); 212 pThread = NULL; 213 214 return rc; 215 } 216 217 218 /** 156 219 * Signals a guest process thread that we want it to shut down in 157 220 * a gentle way. … … 164 227 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 165 228 166 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Signalling shutdown ...\n",229 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Signalling shutdown ...\n", 167 230 pThread->uPID); 168 231 … … 176 239 int rc = VBoxServiceControlThreadPerform(pThread->uPID, &ctrlRequest); 177 240 if (RT_FAILURE(rc)) 178 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Sending quit request failed with rc=%Rrc\n",241 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Sending quit request failed with rc=%Rrc\n", 179 242 pThread->uPID, rc); 180 243 return rc; … … 197 260 && !ASMAtomicReadBool(&pThread->fStopped)) /* Only shutdown threads which aren't yet. */ 198 261 { 199 VBoxServiceVerbose( 3, "ControlThead: [PID %u]: Waiting for shutdown ...\n",262 VBoxServiceVerbose(2, "ControlThread: [PID %u]: Waiting for shutdown ...\n", 200 263 pThread->uPID); 201 264 … … 205 268 if (RT_FAILURE(rcThread)) 206 269 { 207 VBoxServiceError("ControlTh ead: [PID %u]: Shutdown returned error rc=%Rrc\n",270 VBoxServiceError("ControlThread: [PID %u]: Shutdown returned error rc=%Rrc\n", 208 271 pThread->uPID, rcThread); 209 272 if (RT_SUCCESS(rc)) … … 216 279 217 280 /** 218 * Frees an allocated thread data structure along with all its allocated parameters. 219 * 220 * @param pThread Pointer to thread data to free. 221 */ 222 static void vboxServiceControlThreadFree(const PVBOXSERVICECTRLTHREAD pThread) 223 { 224 if (!pThread) 225 return; 226 227 VBoxServiceVerbose(3, "ControlThead: [PID %u]: Freeing thread data ...\n", 228 pThread->uPID); 229 230 RTStrFree(pThread->pszCmd); 231 if (pThread->uNumEnvVars) 232 { 233 for (uint32_t i = 0; i < pThread->uNumEnvVars; i++) 234 RTStrFree(pThread->papszEnv[i]); 235 RTMemFree(pThread->papszEnv); 236 } 237 RTGetOptArgvFree(pThread->papszArgs); 238 RTStrFree(pThread->pszUser); 239 RTStrFree(pThread->pszPassword); 240 241 if (pThread->RequestEvent != NIL_RTSEMEVENTMULTI) 242 { 243 int rc2 = RTSemEventMultiDestroy(pThread->RequestEvent); 244 AssertRC(rc2); 245 } 281 * Returns the guest process thread's current status. 282 * 283 * @return VBOXSERVICECTRLTHREADSTATUS 284 * @param pThread Thread to determine current status for. 285 */ 286 VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread) 287 { 288 AssertPtrReturn(pThread, VBOXSERVICECTRLTHREADSTATUS_UNKNOWN); 289 290 int rc = RTCritSectEnter(&pThread->CritSect); 291 if (RT_SUCCESS(rc)) 292 { 293 Assert(pThread->fStarted != pThread->fStopped); 294 295 VBOXSERVICECTRLTHREADSTATUS enmStatus = VBOXSERVICECTRLTHREADSTATUS_UNKNOWN; 296 /** @todo Add more logic here. */ 297 /** @todo Remove fStarted/fStopped and just use this VBOXSERVICECTRLTHREADSTATUS. */ 298 if (pThread->fStarted) 299 enmStatus = VBOXSERVICECTRLTHREADSTATUS_STARTED; 300 else if (pThread->fStopped) 301 enmStatus = VBOXSERVICECTRLTHREADSTATUS_STOPPED; 302 else 303 AssertMsgFailed(("ControlThread: Uknown thread status (0x%x)\n")); 304 305 rc = RTCritSectLeave(&pThread->CritSect); 306 AssertRC(rc); 307 308 return enmStatus; 309 } 310 311 return VBOXSERVICECTRLTHREADSTATUS_UNKNOWN; 246 312 } 247 313 … … 294 360 * 295 361 */ 362 static int VBoxServiceControlThreadHandleOutputError(RTPOLLSET hPollSet, uint32_t fPollEvt, 363 PRTPIPE phPipeR, uint32_t idPollHnd) 364 { 365 int rc = VINF_SUCCESS; 366 367 rc = RTPollSetRemove(hPollSet, idPollHnd); 368 AssertRC(rc); 369 370 rc = RTPipeClose(*phPipeR); 371 AssertRC(rc); 372 *phPipeR = NIL_RTPIPE; 373 374 return rc; 375 } 376 377 378 /** 379 * Handle pending output data or error on standard out or standard error. 380 * 381 * @returns IPRT status code from client send. 382 * @param hPollSet The polling set. 383 * @param fPollEvt The event mask returned by RTPollNoResume. 384 * @param phPipeR The pipe handle. 385 * @param idPollHnd The pipe ID to handle. 386 * 387 */ 296 388 static int VBoxServiceControlThreadHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, 297 389 PRTPIPE phPipeR, uint32_t idPollHnd) 298 390 { 299 391 int rc = VINF_SUCCESS; 300 301 #if 0 302 if (fPollEvt & RTPOLL_EVT_READ) 303 { 304 /** @todo Later: Notify the host about the read operation! */ 305 306 /* Make sure we go another poll round in case there was too much data 307 for the buffer to hold. */ 308 fPollEvt &= RTPOLL_EVT_ERROR; 309 310 /* Remove read event from poll set and just poll for errors from now on. 311 * This is necessary for doing a RTPipeRead. */ 312 rc = RTPollSetEventsChange(hPollSet, idPollHnd, RTPOLL_EVT_ERROR); 313 AssertRC(rc); 314 } 392 if (fPollEvt == RTPOLL_EVT_READ) 393 { 394 char abBuf[_64K]; 395 size_t cbRead; 396 int rc = RTPipeRead(*phPipeR, abBuf, sizeof(abBuf), &cbRead); 397 if (RT_SUCCESS(rc) && cbRead) 398 { 399 #ifdef DEBUG 400 VBoxServiceVerbose(4, "ControlThread: Drain idPollHnd=%u, abBuf=0x%p, cbRead=%u\n", 401 idPollHnd, abBuf, cbRead); 315 402 #endif 316 403 /* Goes to bit bucket ... */ 404 405 /* Make sure we go another poll round in case there was too much data 406 for the buffer to hold. */ 407 fPollEvt &= RTPOLL_EVT_ERROR; 408 } 409 else if (RT_FAILURE(rc)) 410 { 411 fPollEvt |= RTPOLL_EVT_ERROR; 412 AssertMsg(rc == VERR_BROKEN_PIPE, ("%Rrc\n", rc)); 413 } 414 } 415 416 if (fPollEvt & RTPOLL_EVT_ERROR) 417 rc = VBoxServiceControlThreadHandleOutputError(hPollSet, fPollEvt, 418 phPipeR, idPollHnd); 419 return rc; 420 } 421 422 423 static int VBoxServiceControlThreadHandleRequest(RTPOLLSET hPollSet, uint32_t fPollEvt, 424 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR, 425 PVBOXSERVICECTRLTHREAD pThread) 426 { 317 427 #ifdef DEBUG_andy 318 VBoxServiceVerbose(4, "ControlThead: HandleOutputEvent fPollEvt=0x%x, idPollHnd=%u\n", 319 fPollEvt, idPollHnd); 320 #endif 321 322 /* 323 * If an error was raised signalled 324 */ 325 if (fPollEvt & RTPOLL_EVT_ERROR) 326 { 327 rc = RTPollSetRemove(hPollSet, idPollHnd); 328 AssertRC(rc); 329 330 rc = RTPipeClose(*phPipeR); 331 AssertRC(rc); 332 *phPipeR = NIL_RTPIPE; 333 } 334 335 return rc; 336 } 337 338 339 static int VBoxServiceControlThreadHandleIPCRequest(RTPOLLSET hPollSet, uint32_t fPollEvt, 340 PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR, 341 PVBOXSERVICECTRLTHREAD pThread) 342 { 343 #ifdef DEBUG_andy 344 VBoxServiceVerbose(4, "ControlThead: HandleIPCRequest\n"); 428 VBoxServiceVerbose(4, "ControlThread: HandleIPCRequest\n"); 345 429 #endif 346 430 … … 350 434 AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER); 351 435 352 int rc = RTCritSectEnter(&pThread->CritSect);436 /*int rc = RTCritSectEnter(&pThread->CritSect); 353 437 if (RT_SUCCESS(rc)) 354 { 438 {*/ 355 439 /* Drain the notification pipe. */ 356 440 uint8_t abBuf[8]; … … 358 442 rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore); 359 443 if (RT_FAILURE(rc)) 360 VBoxServiceError("ControlTh ead: Draining IPC notification pipe failed with rc=%Rrc\n", rc);444 VBoxServiceError("ControlThread: Draining IPC notification pipe failed with rc=%Rrc\n", rc); 361 445 362 446 int rcReq = VINF_SUCCESS; /* Actual request result. */ … … 438 522 ? rcReq : rc; 439 523 440 VBoxServiceVerbose( 4, "ControlThead: Handled IPC request with rcReq=%Rrc, enmType=%u, cbData=%u\n",441 rcReq, pRequest->enmType, pRequest->cbData);524 VBoxServiceVerbose(2, "ControlThread: [PID %u]: Handled req=%u, CID=%u, rcReq=%Rrc, cbData=%u\n", 525 pThread->uPID, pRequest->enmType, pRequest->uCID, rcReq, pRequest->cbData); 442 526 443 527 /* In any case, regardless of the result, we notify … … 448 532 * or modified already! */ 449 533 450 rc2 = RTCritSectLeave(&pThread->CritSect);534 /*rc2 = RTCritSectLeave(&pThread->CritSect); 451 535 AssertRC(rc2); 452 } 536 }*/ 453 537 454 538 return rc; … … 475 559 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 476 560 AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER); 477 AssertPtrReturn(phStdOutR, VERR_INVALID_PARAMETER); 478 AssertPtrReturn(phStdErrR, VERR_INVALID_PARAMETER); 561 /* Rest is optional. */ 479 562 480 563 int rc; … … 495 578 * the first (stale) entry will be found and we get really weird results! 496 579 */ 497 rc = vboxServiceControlThreadAssignPID(pThread, hProcess);580 rc = VBoxServiceControlAssignPID(pThread, hProcess); 498 581 if (RT_FAILURE(rc)) 499 582 { 500 VBoxServiceError("ControlThead: Unable to assign PID to new thread, rc=%Rrc\n", rc); 583 VBoxServiceError("ControlThread: Unable to assign PID=%u, to new thread, rc=%Rrc\n", 584 hProcess, rc); 501 585 return rc; 502 586 } … … 506 590 * and that it's now OK to send input to the process. 507 591 */ 508 VBoxServiceVerbose( 3, "ControlThead: [PID %u]: Processstarted, CID=%u, User=%s\n",509 pThread->uPID, pThread-> uContextID, pThread->pszUser);592 VBoxServiceVerbose(2, "ControlThread: [PID %u]: Process \"%s\" started, CID=%u, User=%s\n", 593 pThread->uPID, pThread->pszCmd, pThread->uContextID, pThread->pszUser); 510 594 rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, 511 595 pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */, … … 531 615 if (RT_SUCCESS(rc2)) 532 616 { 533 /*VBoxServiceVerbose(4, "ControlTh ead: [PID %u}: RTPollNoResume idPollHnd=%u\n",617 /*VBoxServiceVerbose(4, "ControlThread: [PID %u}: RTPollNoResume idPollHnd=%u\n", 534 618 pThread->uPID, idPollHnd);*/ 535 619 switch (idPollHnd) … … 550 634 551 635 case VBOXSERVICECTRLPIPEID_IPC_NOTIFY: 552 rc = VBoxServiceControlThreadHandle IPCRequest(hPollSet, fPollEvt,553 phStdInW,phStdOutR,phStdErrR, pThread);636 rc = VBoxServiceControlThreadHandleRequest(hPollSet, fPollEvt, 637 phStdInW, phStdOutR, phStdErrR, pThread); 554 638 break; 555 639 } … … 608 692 if (cMsElapsed >= cMsTimeout) 609 693 { 610 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...",694 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...", 611 695 pThread->uPID, cMsElapsed, cMsTimeout); 612 696 … … 644 728 if (MsProcessKilled == UINT64_MAX) 645 729 { 646 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Is still alive and not killed yet\n",730 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Is still alive and not killed yet\n", 647 731 pThread->uPID); 648 732 … … 654 738 for (size_t i = 0; i < 10; i++) 655 739 { 656 VBoxServiceVerbose(4, "ControlTh ead: [PID %u]: Kill attempt %d/10: Waiting to exit ...\n",740 VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Waiting to exit ...\n", 657 741 pThread->uPID, i + 1); 658 742 rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus); 659 743 if (RT_SUCCESS(rc2)) 660 744 { 661 VBoxServiceVerbose(4, "ControlTh ead: [PID %u]: Kill attempt %d/10: Exited\n",745 VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Exited\n", 662 746 pThread->uPID, i + 1); 663 747 fProcessAlive = false; … … 666 750 if (i >= 5) 667 751 { 668 VBoxServiceVerbose(4, "ControlTh ead: [PID %u]: Kill attempt %d/10: Trying to terminate ...\n",752 VBoxServiceVerbose(4, "ControlThread: [PID %u]: Kill attempt %d/10: Trying to terminate ...\n", 669 753 pThread->uPID, i + 1); 670 754 RTProcTerminate(hProcess); … … 674 758 675 759 if (fProcessAlive) 676 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Could not be killed\n", pThread->uPID);760 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Could not be killed\n", pThread->uPID); 677 761 } 678 762 … … 688 772 if ( fProcessTimedOut && !fProcessAlive && MsProcessKilled != UINT64_MAX) 689 773 { 690 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Timed out and got killed\n",774 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out and got killed\n", 691 775 pThread->uPID); 692 776 uStatus = PROC_STS_TOK; … … 694 778 else if (fProcessTimedOut && fProcessAlive && MsProcessKilled != UINT64_MAX) 695 779 { 696 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Timed out and did *not* get killed\n",780 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Timed out and did *not* get killed\n", 697 781 pThread->uPID); 698 782 uStatus = PROC_STS_TOA; … … 700 784 else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX)) 701 785 { 702 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Got terminated because system/service is about to shutdown\n",786 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Got terminated because system/service is about to shutdown\n", 703 787 pThread->uPID); 704 788 uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */ … … 707 791 else if (fProcessAlive) 708 792 { 709 VBoxServiceError("ControlTh ead: [PID %u]: Is alive when it should not!\n",793 VBoxServiceError("ControlThread: [PID %u]: Is alive when it should not!\n", 710 794 pThread->uPID); 711 795 } 712 796 else if (MsProcessKilled != UINT64_MAX) 713 797 { 714 VBoxServiceError("ControlTh ead: [PID %u]: Has been killed when it should not!\n",798 VBoxServiceError("ControlThread: [PID %u]: Has been killed when it should not!\n", 715 799 pThread->uPID); 716 800 } 717 801 else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL) 718 802 { 719 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n",803 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_NORMAL (%u)\n", 720 804 pThread->uPID, ProcessStatus.iStatus); 721 805 … … 725 809 else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL) 726 810 { 727 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n",811 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_SIGNAL (%u)\n", 728 812 pThread->uPID, ProcessStatus.iStatus); 729 813 … … 733 817 else if (ProcessStatus.enmReason == RTPROCEXITREASON_ABEND) 734 818 { 735 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n",819 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Ended with RTPROCEXITREASON_ABEND (%u)\n", 736 820 pThread->uPID, ProcessStatus.iStatus); 737 821 … … 740 824 } 741 825 else 742 VBoxServiceVerbose(1, "ControlTh ead: [PID %u]: Handling process status %u not implemented\n",826 VBoxServiceVerbose(1, "ControlThread: [PID %u]: Handling process status %u not implemented\n", 743 827 pThread->uPID, ProcessStatus.enmReason); 744 828 745 VBoxServiceVerbose( 3, "ControlThead: [PID %u]: Sending final status, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",829 VBoxServiceVerbose(2, "ControlThread: [PID %u]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n", 746 830 pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags); 747 831 rc = VbglR3GuestCtrlExecReportStatus(pThread->uClientID, pThread->uContextID, … … 749 833 NULL /* pvData */, 0 /* cbData */); 750 834 if (RT_FAILURE(rc)) 751 VBoxServiceError("ControlTh ead: [PID %u]: Error reporting final status to host; rc=%Rrc\n",835 VBoxServiceError("ControlThread: [PID %u]: Error reporting final status to host; rc=%Rrc\n", 752 836 pThread->uPID, rc); 753 837 754 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Process loop ended with rc=%Rrc\n",838 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Process loop ended with rc=%Rrc\n", 755 839 pThread->uPID, rc); 756 840 } 757 841 else 758 VBoxServiceError("ControlTh ead: [PID %u]: Loop failed with rc=%Rrc\n",842 VBoxServiceError("ControlThread: [PID %u]: Loop failed with rc=%Rrc\n", 759 843 pThread->uPID, rc); 760 844 return rc; 845 } 846 847 848 static int vboxServiceControlThreadInitPipe(PRTHANDLE ph, PRTPIPE phPipe) 849 { 850 AssertPtrReturn(ph, VERR_INVALID_PARAMETER); 851 AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER); 852 853 ph->enmType = RTHANDLETYPE_PIPE; 854 ph->u.hPipe = NIL_RTPIPE; 855 *phPipe = NIL_RTPIPE; 856 857 return VINF_SUCCESS; 761 858 } 762 859 … … 781 878 AssertPtrReturn(phPipe, VERR_INVALID_PARAMETER); 782 879 783 ph->enmType = RTHANDLETYPE_PIPE;784 ph->u.hPipe = NIL_RTPIPE;785 *pph = NULL;786 *phPipe = NIL_RTPIPE;787 788 880 int rc; 789 881 … … 833 925 #endif 834 926 #ifdef DEBUG 835 VBoxServiceVerbose(3, "ControlTh ead: VBoxServiceControlExecMakeFullPath: %s -> %s\n",927 VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlExecMakeFullPath: %s -> %s\n", 836 928 pszPath, pszExpanded); 837 929 #endif … … 870 962 rc = VBoxServiceControlThreadMakeFullPath(pszExecResolved, pszResolved, cbResolved); 871 963 #ifdef DEBUG 872 VBoxServiceVerbose(3, "ControlTh ead: VBoxServiceControlExecResolveExecutable: %s -> %s\n",964 VBoxServiceVerbose(3, "ControlThread: VBoxServiceControlExecResolveExecutable: %s -> %s\n", 873 965 pszFileName, pszResolved); 874 966 #endif … … 1024 1116 if (fFlags) 1025 1117 { 1026 /* Process Main flag "ExecuteProcessFlag_Hidden". */ 1027 if (fFlags & RT_BIT(2)) 1118 if (fFlags & EXECUTEPROCESSFLAG_HIDDEN) 1028 1119 uProcFlags |= RTPROC_FLAGS_HIDDEN; 1029 /* Process Main flag "ExecuteProcessFlag_NoProfile". */ 1030 if (fFlags & RT_BIT(3)) 1120 if (fFlags & EXECUTEPROCESSFLAG_NO_PROFILE) 1031 1121 uProcFlags |= RTPROC_FLAGS_NO_PROFILE; 1032 1122 } … … 1041 1131 uProcFlags |= RTPROC_FLAGS_SERVICE; 1042 1132 #ifdef DEBUG 1043 VBoxServiceVerbose(3, "ControlTh ead: Command: %s\n", szExecExp);1133 VBoxServiceVerbose(3, "ControlThread: Command: %s\n", szExecExp); 1044 1134 for (size_t i = 0; papszArgsExp[i]; i++) 1045 VBoxServiceVerbose(3, "ControlTh ead:\targv[%ld]: %s\n", i, papszArgsExp[i]);1135 VBoxServiceVerbose(3, "ControlThread:\targv[%ld]: %s\n", i, papszArgsExp[i]); 1046 1136 #endif 1047 1137 /* Do normal execution. */ … … 1066 1156 { 1067 1157 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1068 VBoxServiceVerbose(3, "ControlTh ead: Thread of process \"%s\" started\n", pThread->pszCmd);1158 VBoxServiceVerbose(3, "ControlThread: Thread of process \"%s\" started\n", pThread->pszCmd); 1069 1159 1070 1160 int rc = VbglR3GuestCtrlConnect(&pThread->uClientID); 1071 1161 if (RT_FAILURE(rc)) 1072 1162 { 1073 VBoxServiceError("ControlTh ead: Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);1163 VBoxServiceError("ControlThread: Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc); 1074 1164 RTThreadUserSignal(RTThreadSelf()); 1075 1165 return rc; 1076 1166 } 1077 VBoxServiceVerbose(3, "ControlTh ead: Guest process \"%s\" got client ID=%u\n",1078 pThread->pszCmd, pThread->uClientID );1167 VBoxServiceVerbose(3, "ControlThread: Guest process \"%s\" got client ID=%u, flags=0x%x\n", 1168 pThread->pszCmd, pThread->uClientID, pThread->uFlags); 1079 1169 1080 1170 bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */ … … 1130 1220 /* Stdout. */ 1131 1221 if (RT_SUCCESS(rc)) 1132 rc = RTPollSetAddPipe(hPollSet, hStdOutR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDOUT); 1222 { 1223 uint32_t uFlags = RTPOLL_EVT_ERROR; 1224 if (!(pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)) 1225 { 1226 uFlags |= RTPOLL_EVT_READ; 1227 VBoxServiceVerbose(3, "ControlThread: Host is not interested in getting stdout for \"%s\", poll flags=0x%x\n", 1228 pThread->pszCmd, uFlags); 1229 } 1230 rc = RTPollSetAddPipe(hPollSet, hStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT); 1231 } 1133 1232 /* Stderr. */ 1134 1233 if (RT_SUCCESS(rc)) 1135 rc = RTPollSetAddPipe(hPollSet, hStdErrR, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDERR); 1234 { 1235 uint32_t uFlags = RTPOLL_EVT_ERROR; 1236 if (!(pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)) 1237 { 1238 uFlags |= RTPOLL_EVT_READ; 1239 VBoxServiceVerbose(3, "ControlThread: Host is not interested in getting stderr for \"%s\", poll flags=0x%x\n", 1240 pThread->pszCmd, uFlags); 1241 } 1242 rc = RTPollSetAddPipe(hPollSet, hStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR); 1243 } 1136 1244 /* IPC notification pipe. */ 1137 1245 if (RT_SUCCESS(rc)) … … 1148 1256 &hProcess); 1149 1257 if (RT_FAILURE(rc)) 1150 VBoxServiceError("ControlTh ead: Error starting process, rc=%Rrc\n", rc);1258 VBoxServiceError("ControlThread: Error starting process, rc=%Rrc\n", rc); 1151 1259 /* 1152 1260 * Tell the control thread that it can continue … … 1176 1284 hProcess, pThread->uTimeLimitMS, hPollSet, 1177 1285 &pThread->pipeStdInW, &hStdOutR, &hStdErrR); 1178 1179 /*1180 * Remove thread from global thread list. After this it's safe to shutdown1181 * and deallocate this thread.1182 */1183 VBoxServiceControlRemoveThread(pThread);1184 1185 1286 /* 1186 1287 * The handles that are no longer in the set have … … 1203 1304 else /* Something went wrong; report error! */ 1204 1305 { 1205 VBoxServiceError("ControlTh ead: Could not start process '%s' (CID: %u)! Error: %Rrc\n",1306 VBoxServiceError("ControlThread: Could not start process '%s' (CID: %u)! Error: %Rrc\n", 1206 1307 pThread->pszCmd, pThread->uContextID, rc); 1207 1308 … … 1210 1311 NULL /* pvData */, 0 /* cbData */); 1211 1312 if (RT_FAILURE(rc2)) 1212 VBoxServiceError("ControlTh ead: Could not report process start error! Error: %Rrc (process error %Rrc)\n",1313 VBoxServiceError("ControlThread: Could not report process start error! Error: %Rrc (process error %Rrc)\n", 1213 1314 rc2, rc); 1214 1315 } … … 1238 1339 if (pThread->uClientID) 1239 1340 { 1240 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Cancelling pending waits (client ID=%u)\n",1341 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Cancelling pending waits (client ID=%u)\n", 1241 1342 pThread->uPID, pThread->uClientID); 1242 1343 int rc2 = VbglR3GuestCtrlCancelPendingWaits(pThread->uClientID); 1243 1344 if (RT_FAILURE(rc2)) 1244 1345 { 1245 VBoxServiceError("ControlTh ead: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n",1346 VBoxServiceError("ControlThread: [PID %u]: Cancelling pending waits failed; rc=%Rrc\n", 1246 1347 pThread->uPID, rc2); 1247 1348 if (RT_SUCCESS(rc)) … … 1250 1351 1251 1352 /* Disconnect from guest control service. */ 1252 VBoxService Error("ControlThead: [PID %u]: Disconnecting (client ID=%u) ...\n",1253 pThread->uPID, pThread->uClientID);1353 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Disconnecting (client ID=%u) ...\n", 1354 pThread->uPID, pThread->uClientID); 1254 1355 VbglR3GuestCtrlDisconnect(pThread->uClientID); 1255 1356 pThread->uClientID = 0; 1256 1357 } 1257 1358 1258 VBoxServiceVerbose(3, "ControlTh ead: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",1359 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n", 1259 1360 pThread->uPID, pThread->pszCmd, rc); 1260 1361 … … 1268 1369 RTThreadUserSignal(RTThreadSelf()); 1269 1370 1270 int rc2 = vboxServiceControlThreadShutdown(pThread); 1371 /* 1372 * Remove thread from global thread list. After this it's safe to shutdown 1373 * and deallocate this thread. 1374 */ 1375 VBoxServiceControlRemoveThread(pThread); 1376 1377 int rc2 = vboxServiceControlThreadFree(pThread); 1271 1378 if (RT_SUCCESS(rc)) 1272 1379 rc = rc2; … … 1348 1455 if (RT_FAILURE(rc)) 1349 1456 { 1350 VBoxServiceError("ControlTh ead: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n",1457 VBoxServiceError("ControlThread: RTThreadCreate failed, rc=%Rrc\n, pThread=%p\n", 1351 1458 rc, pThread); 1352 1459 } 1353 1460 else 1354 1461 { 1355 VBoxServiceVerbose(4, "ControlTh ead: Waiting for thread to initialize ...\n");1462 VBoxServiceVerbose(4, "ControlThread: Waiting for thread to initialize ...\n"); 1356 1463 1357 1464 /* Wait for the thread to initialize. */ … … 1359 1466 if (ASMAtomicReadBool(&pThread->fShutdown)) 1360 1467 { 1361 VBoxServiceError("ControlTh ead: Thread for process \"%s\" failed to start!\n", pszCmd);1468 VBoxServiceError("ControlThread: Thread for process \"%s\" failed to start!\n", pszCmd); 1362 1469 rc = VERR_GENERAL_FAILURE; 1363 1470 } … … 1380 1487 1381 1488 /** 1382 * Assigns a valid PID to a guest control thread and also checks if there already was1383 * another (stale) guest process which was using that PID before and destroys it.1384 *1385 * @return IPRT status code.1386 * @param pData Pointer to guest control execution thread data.1387 * @param uPID PID to assign to the specified guest control execution thread.1388 */1389 int vboxServiceControlThreadAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID)1390 {1391 AssertPtrReturn(pThread, VERR_INVALID_POINTER);1392 AssertReturn(uPID, VERR_INVALID_PARAMETER);1393 1394 int rc = VINF_SUCCESS;1395 1396 /* Search an old thread using the desired PID and shut it down completely -- it's1397 * not used anymore. */1398 PVBOXSERVICECTRLTHREAD pOldThread = VBoxServiceControlGetThreadByPID(uPID);1399 if ( pOldThread1400 && pOldThread != pThread)1401 {1402 PVBOXSERVICECTRLTHREAD pNext = RTListNodeGetNext(&pOldThread->Node, VBOXSERVICECTRLTHREAD, Node);1403 1404 VBoxServiceVerbose(3, "ControlThead: PID %u was used before, shutting down stale exec thread ...\n",1405 uPID);1406 rc = vboxServiceControlThreadShutdown(pOldThread);1407 if (RT_FAILURE(rc))1408 {1409 VBoxServiceVerbose(3, "ControlThead: Unable to shut down stale exec thread, rc=%Rrc\n", rc);1410 /* Keep going. */1411 }1412 }1413 1414 /* Assign PID to current thread. */1415 pThread->uPID = uPID;1416 1417 return rc;1418 }1419 1420 1421 /**1422 1489 * Performs a request to a specific (formerly started) guest process and waits 1423 1490 * for its response. … … 1433 1500 /* Rest in pRequest is optional (based on the request type). */ 1434 1501 1435 VBoxServiceVerbose(4, "ControlThead: Performing PID=%u, enmType=%u, pvData=0x%p, cbData=%u ...\n", 1436 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1437 1438 int rc; 1439 const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadByPID(uPID); 1440 if ( pThread 1441 && !ASMAtomicReadBool(&pThread->fStopped)) 1442 { 1443 rc = RTCritSectEnter(&pThread->CritSect); 1502 int rc = VINF_SUCCESS; 1503 const PVBOXSERVICECTRLTHREAD pThread = VBoxServiceControlGetThreadLocked(uPID); 1504 if (pThread) 1505 { 1506 /* Set request result to some defined state in case 1507 * it got cancelled. */ 1508 pRequest->rc = VERR_CANCELLED; 1509 1510 /* Set request structure pointer. */ 1511 pThread->pRequest = pRequest; 1512 1513 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1514 * or queue in order to wait for the request to happen. Later. */ 1515 1516 /* Wake up guest thrad by sending a wakeup byte to the notification pipe so 1517 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1518 if (pThread->hNotificationPipeW == NIL_RTPIPE) 1519 rc = VERR_BROKEN_PIPE; 1520 size_t cbWritten; 1444 1521 if (RT_SUCCESS(rc)) 1445 { 1446 /* Set request structure pointer. */ 1447 pThread->pRequest = pRequest; 1448 1449 /** @todo To speed up simultaneous guest process handling we could add a worker threads 1450 * or queue in order to wait for the request to happen. Later. */ 1451 1452 /* Wake up guest thrad by sending a wakeup byte to the notification pipe so 1453 * that RTPoll unblocks (returns) and we then can do our requested operation. */ 1454 if (pThread->hNotificationPipeW == NIL_RTPIPE) 1455 rc = VERR_BROKEN_PIPE; 1456 size_t cbWritten; 1522 rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten); 1523 1524 if ( RT_SUCCESS(rc) 1525 && cbWritten) 1526 { 1527 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n", 1528 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1529 /* Wait on the request to get completed (or we are asked to abort/shutdown). */ 1530 rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT); 1457 1531 if (RT_SUCCESS(rc)) 1458 rc = RTPipeWrite(pThread->hNotificationPipeW, "i", 1, &cbWritten);1459 1460 /* Make sure we leave the critical section before doing the wait. */1461 int rc2 = RTCritSectLeave(&pThread->CritSect);1462 AssertRCReturn(rc2, rc2);1463 1464 if (RT_SUCCESS(rc) && cbWritten)1465 1532 { 1466 VBoxServiceVerbose(4, "ControlThead: [PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n", 1467 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData); 1468 /* Wait on the request to get completed (or we are asked to abort/shutdown). */ 1469 rc = RTSemEventMultiWait(pThread->RequestEvent, RT_INDEFINITE_WAIT); 1470 if (RT_SUCCESS(rc)) 1471 { 1472 VBoxServiceVerbose(4, "ControlThead: [PID %u]: Performed with rc=%Rrc, cbData=%u\n", 1473 uPID, pRequest->rc, pRequest->cbData); 1474 1475 rc = RTCritSectEnter(&pThread->CritSect); 1476 if (RT_SUCCESS(rc)) 1477 { 1478 /* Give back overall request result. */ 1479 rc = pRequest->rc; 1480 1481 /* Reset the semaphore. */ 1482 rc2 = RTSemEventMultiReset(pThread->RequestEvent); 1483 if (RT_FAILURE(rc2)) 1484 VBoxServiceError("ControlThead: Unable to reset request event, rc=%Rrc\n", rc2); 1485 1486 rc2 = RTCritSectLeave(&pThread->CritSect); 1487 AssertRCReturn(rc2, rc2); 1488 } 1489 } 1533 VBoxServiceVerbose(4, "ControlThread: [PID %u]: Performed with rc=%Rrc, cbData=%u\n", 1534 uPID, pRequest->rc, pRequest->cbData); 1535 1536 /* Give back overall request result. */ 1537 rc = pRequest->rc; 1538 1539 /* Reset the semaphore. */ 1540 int rc2 = RTSemEventMultiReset(pThread->RequestEvent); 1541 if (RT_FAILURE(rc2)) 1542 VBoxServiceError("ControlThread: [PID %u]: Unable to reset request event, rc=%Rrc\n", 1543 uPID, rc2); 1490 1544 } 1491 } 1545 else 1546 VBoxServiceError("ControlThread: [PID %u]: Wait failed, rc=%Rrc\n", 1547 uPID, rc); 1548 } 1549 1550 VBoxServiceControlThreadUnlock(pThread); 1492 1551 } 1493 1552 else /* PID not found! */ 1494 1553 rc = VERR_NOT_FOUND; 1495 1554 1496 VBoxServiceVerbose(4, "ControlThead: Performed PID=%u, enmType=%u, pvData=0x%p, cbData=%u with rc=%Rrc\n", 1497 uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData, rc); 1498 return rc; 1499 } 1500 1501 1502 /** 1503 * Shuts down a guest thread. 1504 * 1505 * @return IPRT status code. 1506 * @param pThread Thread to shut down. 1507 */ 1508 static int vboxServiceControlThreadShutdown(PVBOXSERVICECTRLTHREAD pThread) 1509 { 1510 AssertPtrReturn(pThread, VERR_INVALID_POINTER); 1511 1512 int rc = RTCritSectEnter(&pThread->CritSect); 1513 if (RT_SUCCESS(rc)) 1514 { 1515 VBoxServiceVerbose(3, "ControlThead: [PID %u]: Shutting down ...\n", 1516 pThread->uPID); 1517 1518 /* 1519 * Destroy thread-specific data. 1520 */ 1521 vboxServiceControlThreadFree(pThread); 1522 1523 /* Set stopped status. */ 1524 ASMAtomicXchgBool(&pThread->fStopped, true); 1525 1526 rc = RTCritSectLeave(&pThread->CritSect); 1527 } 1528 1529 /* 1530 * Destroy other thread data. 1531 */ 1532 if (RTCritSectIsInitialized(&pThread->CritSect)) 1533 RTCritSectDelete(&pThread->CritSect); 1534 1535 /* 1536 * Destroy thread structure as final step. 1537 */ 1538 RTMemFree(pThread); 1539 pThread = NULL; 1540 1541 return rc; 1542 } 1543 1555 VBoxServiceVerbose(3, "ControlThread: [PID %u]: Performed enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n", 1556 uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc); 1557 return rc; 1558 } 1559 -
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
r39392 r39418 171 171 /** Payload data; a pre-allocated data buffer for input/output. */ 172 172 void *pvData; 173 /** The context ID which is required to complete the 174 * request. */ 175 uint32_t uCID; 173 176 /** The overall result of the operation. */ 174 177 int rc; … … 230 233 /** Pointer to thread data. */ 231 234 typedef VBOXSERVICECTRLTHREAD *PVBOXSERVICECTRLTHREAD; 235 236 /** 237 * Request types to perform on a started guest process. 238 */ 239 typedef enum VBOXSERVICECTRLTHREADSTATUS 240 { 241 /** Unknown status. Do not use / should not happen. */ 242 VBOXSERVICECTRLTHREADSTATUS_UNKNOWN = 0, 243 VBOXSERVICECTRLTHREADSTATUS_STARTED = 100, 244 VBOXSERVICECTRLTHREADSTATUS_STOPPED = 200 245 } VBOXSERVICECTRLTHREADSTATUS; 232 246 #endif /* VBOX_WITH_GUEST_CONTROL */ 233 247 #ifdef VBOX_WITH_GUEST_PROPS … … 329 343 extern int VBoxServiceControlHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms, size_t cbMaxBufSize); 330 344 extern int VBoxServiceControlHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms); 331 extern PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadByPID(uint32_t uPID); 332 extern void VBoxServiceControlRemoveThread(PVBOXSERVICECTRLTHREAD pThread); 345 extern const PVBOXSERVICECTRLTHREAD VBoxServiceControlGetThreadLocked(uint32_t uPID); 346 extern void VBoxServiceControlThreadUnlock(const PVBOXSERVICECTRLTHREAD pThread); 347 extern int VBoxServiceControlAssignPID(PVBOXSERVICECTRLTHREAD pThread, uint32_t uPID); 348 extern void VBoxServiceControlRemoveThread(const PVBOXSERVICECTRLTHREAD pThread); 333 349 /* Guest process functions. */ 350 extern VBOXSERVICECTRLTHREADSTATUS VBoxServiceControlThreadGetStatus(const PVBOXSERVICECTRLTHREAD pThread); 334 351 extern int VBoxServiceControlThreadStart(uint32_t uClientID, uint32_t uContext, 335 352 const char *pszCmd, uint32_t uFlags, … … 338 355 const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS, 339 356 PRTLISTNODE *ppNode); 340 intVBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest);357 extern int VBoxServiceControlThreadPerform(uint32_t uPID, PVBOXSERVICECTRLREQUEST pRequest); 341 358 extern int VBoxServiceControlThreadSignalShutdown(const PVBOXSERVICECTRLTHREAD pThread); 342 359 extern int VBoxServiceControlThreadWaitForShutdown(const PVBOXSERVICECTRLTHREAD pThread, RTMSINTERVAL msTimeout); -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
r38656 r39418 570 570 571 571 case GETOPTDEF_EXEC_WAITFORSTDOUT: 572 f WaitForExit = true;573 fWaitFor StdOut = true;572 fExecFlags |= ExecuteProcessFlag_WaitForStdOut; 573 fWaitForExit = fWaitForStdOut = true; 574 574 break; 575 575 576 576 case GETOPTDEF_EXEC_WAITFORSTDERR: 577 fExecFlags |= ExecuteProcessFlag_WaitForStdErr; 577 578 fWaitForExit = (fOutputFlags |= ProcessOutputFlag_StdErr) ? true : false; 578 579 break; … … 662 663 if (fCancelable) 663 664 ctrlSignalHandlerInstall(); 665 666 vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */); 667 if (RT_FAILURE(vrc)) 668 RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc); 664 669 665 670 /* Wait for process to exit ... */ … … 711 716 if (cbOutputData > 0) 712 717 { 718 BYTE *pBuf = aOutputData.raw(); 719 AssertPtr(pBuf); 720 pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */ 721 713 722 /** @todo r=bird: Use a VFS I/O stream filter for doing this, it's a 714 723 * generic problem and the new VFS APIs will handle it more … … 721 730 * Windows. Otherwise we end up with CR/CR/LF on Windows. 722 731 */ 723 ULONG cbOutputDataPrint = cbOutputData; 724 for (BYTE *s = aOutputData.raw(), *d = s;725 s - aOutputData.raw() < (ssize_t)cbOutputData;726 s++, d++)732 733 char *pszBufUTF8; 734 vrc = RTStrCurrentCPToUtf8(&pszBufUTF8, (const char*)aOutputData.raw()); 735 if (RT_SUCCESS(vrc)) 727 736 { 728 if (*s == '\r') 737 cbOutputData = strlen(pszBufUTF8); 738 739 ULONG cbOutputDataPrint = cbOutputData; 740 for (char *s = pszBufUTF8, *d = s; 741 s - pszBufUTF8 < (ssize_t)cbOutputData; 742 s++, d++) 729 743 { 730 /* skip over CR, adjust destination */ 731 d--; 732 cbOutputDataPrint--; 744 if (*s == '\r') 745 { 746 /* skip over CR, adjust destination */ 747 d--; 748 cbOutputDataPrint--; 749 } 750 else if (s != d) 751 *d = *s; 733 752 } 734 else if (s != d) 735 *d = *s; 753 754 vrc = RTStrmWrite(g_pStdOut, pszBufUTF8, cbOutputDataPrint); 755 if (RT_FAILURE(vrc)) 756 RTMsgError("Unable to write output, rc=%Rrc\n", vrc); 757 758 RTStrFree(pszBufUTF8); 736 759 } 737 RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint); 760 else 761 RTMsgError("Unable to convert output, rc=%Rrc\n", vrc); 738 762 } 739 763 } … … 2240 2264 AssertPtrReturn(pArg, VERR_INVALID_PARAMETER); 2241 2265 2242 #ifdef DEBUG_andy 2266 #ifdef DEBUG_andy_disabled 2243 2267 if (RT_FAILURE(tstTranslatePath())) 2244 2268 return RTEXITCODE_FAILURE; … … 2290 2314 2291 2315 ctrlUninitVM(pArg); 2292 return rcExit;2316 return RT_FAILURE(rcExit) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS; 2293 2317 } 2294 2318 return RTEXITCODE_FAILURE; -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r39058 r39418 8438 8438 <enum 8439 8439 name="ExecuteProcessFlag" 8440 uuid=" 286ceb91-5f66-4c96-9845-4483e90e00ae"8440 uuid="1c49b831-b2c7-4a30-97dd-999a2e2cbf90" 8441 8441 > 8442 8442 <desc> … … 8455 8455 </const> 8456 8456 <const name="Hidden" value="4"> 8457 <desc>Do n't show the started process according to the guest OS guidelines.</desc>8457 <desc>Do not show the started process according to the guest OS guidelines.</desc> 8458 8458 </const> 8459 8459 <const name="NoProfile" value="8"> 8460 8460 <desc>Do not use the user's profile data when exeuting a process. Only available for Windows guests.</desc> 8461 </const> 8462 <const name="WaitForStdOut" value="16"> 8463 <desc>The guest process waits until all data from stdout is read out.</desc> 8464 </const> 8465 <const name="WaitForStdErr" value="32"> 8466 <desc>The guest process waits until all data from stderr is read out.</desc> 8461 8467 </const> 8462 8468 </enum> -
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r38439 r39418 121 121 uint32_t GetOffset(); 122 122 123 uint32_t GetSize(); 124 123 125 int ParseBlock(GuestProcessStreamBlock &streamBlock); 124 126 -
trunk/src/VBox/Main/include/GuestImpl.h
r38439 r39418 153 153 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment), 154 154 IN_BSTR aUsername, IN_BSTR aPassword, 155 ULONG uFlagsToAdd, 156 GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr, 155 157 IProgress **aProgress, ULONG *aPID); 156 158 HRESULT executeProcessInternal(IN_BSTR aCommand, ULONG aFlags, … … 158 160 IN_BSTR aUsername, IN_BSTR aPassword, 159 161 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC); 162 HRESULT getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, 163 LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC); 160 164 HRESULT executeProcessResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID); 161 165 HRESULT executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs); 162 int executeStreamDrain(ULONG aPID, GuestProcessStream &stream); 163 int executeStreamGetNextBlock(ULONG aPID, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock); 164 HRESULT executeStreamParse(ULONG aPID, GuestCtrlStreamObjects &streamObjects); 166 int executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream &stream); 167 int executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock); 168 int executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock); 169 HRESULT executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects); 165 170 HRESULT executeWaitForStatusChange(ULONG uPID, ULONG uTimeoutMS, ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode); 166 171 // Internal guest file functions … … 229 234 typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst; 230 235 231 int processAdd(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 232 int processGetByPID(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess); 233 int processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 236 int processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess); 237 int processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags); 234 238 235 239 // Internal guest directory representation. -
trunk/src/VBox/Main/src-client/GuestCtrlIO.cpp
r38439 r39418 318 318 } 319 319 320 uint32_t GuestProcessStream::GetSize() 321 { 322 return m_cbSize; 323 } 324 320 325 /** 321 326 * Tries to parse the next upcoming pair block within the internal -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r38627 r39418 162 162 AssertReturnVoid(uContextID); 163 163 164 LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));165 166 /* Notify callback (if necessary). */167 int rc = callbackNotifyEx(uContextID, VERR_CANCELLED,168 Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));169 AssertRC(rc);170 171 164 CallbackMapIter it = mCallbackMap.find(uContextID); 172 165 if (it != mCallbackMap.end()) 173 166 { 167 LogFlowFunc(("Callback with CID=%u found\n", uContextID)); 174 168 if (it->second.pvData) 175 169 { 170 LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID)); 171 176 172 callbackFreeUserData(it->second.pvData); 177 173 it->second.cbData = 0; … … 385 381 386 382 /** 387 * TODO383 * Notifies a specified callback about its final status. 388 384 * 389 385 * @return IPRT status code. … … 395 391 { 396 392 AssertReturn(uContextID, VERR_INVALID_PARAMETER); 397 398 LogFlowFunc(("Notifying callback with CID=%u, iRC=%d, pszMsg=%s ...\n", 393 if (RT_FAILURE(iRC)) 394 AssertReturn(pszMessage, VERR_INVALID_PARAMETER); 395 396 LogFlowFunc(("Checking whether callback (CID=%u) needs notification iRC=%Rrc, pszMsg=%s\n", 399 397 uContextID, iRC, pszMessage ? pszMessage : "<No message given>")); 400 398 … … 430 428 && !fCompleted) 431 429 { 430 LogFlowFunc(("Notifying callback with CID=%u, iRC=%Rrc, pszMsg=%s\n", 431 uContextID, iRC, pszMessage ? pszMessage : "<No message given>")); 432 432 433 /* 433 434 * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only … … 437 438 * progress object to become signalled. 438 439 */ 439 if ( RT_SUCCESS(iRC) 440 && !pszMessage) 440 if (RT_SUCCESS(iRC)) 441 441 { 442 442 hRC = pProgress->notifyComplete(S_OK); … … 444 444 else 445 445 { 446 AssertPtrReturn(pszMessage, VERR_INVALID_PARAMETER); 446 447 447 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */, 448 448 COM_IIDOF(IGuest), … … 450 450 pszMessage); 451 451 } 452 } 453 ComAssertComRC(hRC); 452 453 LogFlowFunc(("Notified callback with CID=%u returned %Rhrc (0x%x)\n", 454 uContextID, hRC, hRC)); 455 } 456 else 457 LogFlowFunc(("Callback with CID=%u already notified\n", uContextID)); 454 458 455 459 /* … … 564 568 if (RT_SUCCESS(vrc)) 565 569 { 570 LogFlowFunc(("Waiting for callback completion (CID=%u, Stage=%RI32, timeout=%RI32ms) ...\n", 571 uContextID, lStage, lTimeout)); 566 572 HRESULT rc; 567 573 if (lStage < 0) … … 579 585 } 580 586 587 LogFlowFunc(("Callback (CID=%u) completed with rc=%Rrc\n", 588 uContextID, vrc)); 581 589 return vrc; 582 590 } … … 603 611 */ 604 612 #ifdef DEBUG_andy 605 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms =%d\n",613 LogFlowFunc(("pvExtension=%p, u32Function=%d, pvParms=%p, cbParms=%d\n", 606 614 pvExtension, u32Function, pvParms, cbParms)); 607 615 #endif … … 686 694 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 687 695 696 LogFlowFunc(("Execution status (CID=%u, pData=0x%p)\n", 697 uContextID, pData)); 698 688 699 PCALLBACKDATAEXECSTATUS pCallbackData = 689 700 (PCALLBACKDATAEXECSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */); … … 695 706 /** @todo Copy void* buffer contents? */ 696 707 } 697 else698 AssertReleaseMsgFailed(("Process status (PID=%u, CID=%u) does not have allocated callback data!\n",699 pData->u32PID, uContextID));700 } 701 702 int vrc = VINF_SUCCESS;708 /* If pCallbackData is NULL this might be an old request for which no user data 709 * might exist anymore. */ 710 } 711 712 int vrc = VINF_SUCCESS; /* Function result. */ 713 int rcCallback = VINF_SUCCESS; /* Callback result. */ 703 714 Utf8Str errMsg; 704 715 705 716 /* Was progress canceled before? */ 706 bool fCbCanceled = callbackIsCanceled(uContextID); 707 if (!fCbCanceled) 708 { 717 bool fCanceled = callbackIsCanceled(uContextID); 718 if (!fCanceled) 719 { 720 /* Handle process map. This needs to be done first in order to have a valid 721 * map in case some callback gets notified a bit below. */ 722 723 /* Note: PIDs never get removed here in case the guest process signalled its 724 * end; instead the next call of GetProcessStatus() will remove the PID 725 * from the process map after we got the process' final (exit) status. 726 * See waitpid() for an example. */ 727 if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */ 728 { 729 switch (pData->u32Status) 730 { 731 /* Interprete u32Flags as the guest process' exit code. */ 732 case PROC_STS_TES: 733 case PROC_STS_TOK: 734 vrc = processSetStatus(pData->u32PID, 735 (ExecuteProcessStatus_T)pData->u32Status, 736 pData->u32Flags /* Exit code. */, 0 /* Flags. */); 737 break; 738 /* Just reach through flags. */ 739 default: 740 vrc = processSetStatus(pData->u32PID, 741 (ExecuteProcessStatus_T)pData->u32Status, 742 0 /* Exit code. */, pData->u32Flags); 743 break; 744 } 745 } 746 709 747 /* Do progress handling. */ 710 748 switch (pData->u32Status) … … 725 763 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"), 726 764 pData->u32Flags); 765 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 727 766 break; 728 767 … … 732 771 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"), 733 772 pData->u32Flags); 773 rcCallback = VERR_GENERAL_FAILURE; /** @todo */ 734 774 break; 735 775 … … 737 777 LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */ 738 778 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed")); 779 rcCallback = VERR_TIMEOUT; 739 780 break; 740 781 … … 742 783 LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */ 743 784 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed")); 785 rcCallback = VERR_TIMEOUT; 744 786 break; 745 787 … … 758 800 } 759 801 else 802 { 760 803 errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down")); 804 rcCallback = VERR_CANCELLED; 805 } 761 806 break; 762 807 763 808 case PROC_STS_ERROR: 764 LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n", 765 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 809 if (pData->u32PID) 810 { 811 LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n", 812 pData->u32PID, pData->u32Flags)); /** @todo Add process name */ 813 } 814 else 815 { 816 switch (pData->u32Flags) 817 { 818 case VERR_MAX_PROCS_REACHED: 819 LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n")); 820 break; 821 822 default: 823 LogRel(("Guest process could not be started because of rc=%Rrc\n", 824 pData->u32Flags)); 825 } 826 827 } 766 828 errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pData->u32Flags); 829 rcCallback = pData->u32Flags; /* Report back rc. */ 767 830 break; 768 831 … … 771 834 break; 772 835 } 773 774 /* Handle process map. */ 775 /** @todo What happens on/deal with PID reuse? */ 776 /** @todo How to deal with multiple updates at once? */ 836 } 837 else 838 { 839 errMsg = Utf8StrFmt(Guest::tr("Process execution canceled")); 840 rcCallback = VERR_CANCELLED; 841 } 842 843 /* Do we need to handle the callback error? */ 844 if (RT_FAILURE(rcCallback)) 845 { 846 AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n")); 847 848 /* Notify all callbacks which are still waiting on something 849 * which is related to the current PID. */ 777 850 if (pData->u32PID) 778 851 { 779 VBOXGUESTCTRL_PROCESS process; 780 vrc = processGetByPID(pData->u32PID, &process); 781 if (vrc == VERR_NOT_FOUND) 782 { 783 /* Not found, add to map. */ 784 vrc = processAdd(pData->u32PID, 785 (ExecuteProcessStatus_T)pData->u32Status, 786 pData->u32Flags /* Contains exit code. */, 787 0 /*Flags. */); 788 AssertRC(vrc); 789 } 790 else if (RT_SUCCESS(vrc)) 791 { 792 /* Process found, update process map. */ 793 vrc = processSetStatus(pData->u32PID, 794 (ExecuteProcessStatus_T)pData->u32Status, 795 pData->u32Flags /* Contains exit code. */, 796 0 /*Flags. */); 797 AssertRC(vrc); 798 } 799 else 800 AssertReleaseMsgFailed(("Process was neither found nor absent!?\n")); 801 } 802 } 803 else 804 errMsg = Utf8StrFmt(Guest::tr("Process execution canceled")); 805 806 if (!callbackIsComplete(uContextID)) 807 { 808 if ( errMsg.length() 809 || fCbCanceled) /* If canceled we have to report E_FAIL! */ 810 { 811 /* Notify all callbacks which are still waiting on something 812 * which is related to the current PID. */ 813 if (pData->u32PID) 814 { 815 vrc = callbackNotifyAllForPID(pData->u32PID, VERR_GENERAL_FAILURE, errMsg.c_str()); 816 if (RT_FAILURE(vrc)) 817 LogFlowFunc(("Failed to notify other callbacks for PID=%u\n", 818 pData->u32PID)); 819 } 820 821 /* Let the caller know what went wrong ... */ 822 int rc2 = callbackNotifyEx(uContextID, VERR_GENERAL_FAILURE, errMsg.c_str()); 852 int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str()); 823 853 if (RT_FAILURE(rc2)) 824 854 { 825 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n", 826 uContextID, pData->u32PID)); 827 855 LogFlowFunc(("Failed to notify other callbacks for PID=%u\n", 856 pData->u32PID)); 828 857 if (RT_SUCCESS(vrc)) 829 858 vrc = rc2; 830 859 } 831 LogFlowFunc(("Process (CID=%u, status=%u) reported error: %s\n", 832 uContextID, pData->u32Status, errMsg.c_str())); 833 } 834 } 835 LogFlowFunc(("Returned with rc=%Rrc\n", vrc)); 860 } 861 862 /* Let the caller know what went wrong ... */ 863 int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str()); 864 if (RT_FAILURE(rc2)) 865 { 866 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n", 867 uContextID, pData->u32PID)); 868 if (RT_SUCCESS(vrc)) 869 vrc = rc2; 870 } 871 LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n", 872 uContextID, pData->u32Status, errMsg.c_str())); 873 } 874 LogFlowFunc(("Returned with rc=%Rrc, rcCallback=%Rrc\n", 875 vrc, rcCallback)); 836 876 return vrc; 837 877 } … … 851 891 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 852 892 893 LogFlowFunc(("Output status (CID=%u, pData=0x%p)\n", 894 uContextID, pData)); 895 853 896 PCALLBACKDATAEXECOUT pCallbackData = 854 897 (PCALLBACKDATAEXECOUT)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */); … … 878 921 } 879 922 } 880 else 881 AssertReleaseMsgFailed(("Process output status (PID=%u, CID=%u) does not have allocated callback data!\n", 882 pData->u32PID, uContextID)); 923 /* If pCallbackData is NULL this might be an old request for which no user data 924 * might exist anymore. */ 883 925 } 884 926 … … 909 951 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 910 952 953 LogFlowFunc(("Input status (CID=%u, pData=0x%p)\n", 954 uContextID, pData)); 955 911 956 PCALLBACKDATAEXECINSTATUS pCallbackData = 912 957 (PCALLBACKDATAEXECINSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */); … … 915 960 /* Save bytes processed. */ 916 961 pCallbackData->cbProcessed = pData->cbProcessed; 917 pCallbackData->u32Status = pData->u32Status; 918 pCallbackData->u32Flags = pData->u32Flags; 919 pCallbackData->u32PID = pData->u32PID; 920 } 921 else 922 AssertReleaseMsgFailed(("Process input status (PID=%u, CID=%u) does not have allocated callback data!\n", 923 pData->u32PID, uContextID)); 962 pCallbackData->u32Status = pData->u32Status; 963 pCallbackData->u32Flags = pData->u32Flags; 964 pCallbackData->u32PID = pData->u32PID; 965 } 966 /* If pCallbackData is NULL this might be an old request for which no user data 967 * might exist anymore. */ 924 968 } 925 969 … … 936 980 Assert(uContextID); 937 981 938 return callbackNotifyEx(uContextID, S_OK, 982 LogFlowFunc(("Client disconnected (CID=%u)\n,", uContextID)); 983 984 return callbackNotifyEx(uContextID, VERR_CANCELLED, 939 985 Guest::tr("Client disconnected")); 940 986 } 941 987 942 int Guest::processAdd(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, 943 uint32_t uExitCode, uint32_t uFlags) 988 /** 989 * Gets guest process information. Removes the process from the map 990 * after the process was marked as exited/terminated. 991 * 992 * @return IPRT status code. 993 * @param u32PID 994 * @param pProcess 995 */ 996 int Guest::processGetStatus(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess) 944 997 { 945 998 AssertReturn(u32PID, VERR_INVALID_PARAMETER); 946 999 1000 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 1001 1002 GuestProcessMapIter it = mGuestProcessMap.find(u32PID); 1003 if (it != mGuestProcessMap.end()) 1004 { 1005 if (pProcess) 1006 { 1007 pProcess->mStatus = it->second.mStatus; 1008 pProcess->mExitCode = it->second.mExitCode; 1009 pProcess->mFlags = it->second.mFlags; 1010 } 1011 1012 /* If the is marked as stopped/terminated 1013 * remove it from the map. */ 1014 if (it->second.mStatus != ExecuteProcessStatus_Started) 1015 mGuestProcessMap.erase(it); 1016 1017 return VINF_SUCCESS; 1018 } 1019 1020 return VERR_NOT_FOUND; 1021 } 1022 1023 int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags) 1024 { 1025 AssertReturn(u32PID, VERR_INVALID_PARAMETER); 1026 947 1027 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 948 1028 949 GuestProcessMapIterConst it = mGuestProcessMap.find(u32PID); 950 if (it == mGuestProcessMap.end()) 1029 GuestProcessMapIter it = mGuestProcessMap.find(u32PID); 1030 if (it != mGuestProcessMap.end()) 1031 { 1032 it->second.mStatus = enmStatus; 1033 it->second.mExitCode = uExitCode; 1034 it->second.mFlags = uFlags; 1035 } 1036 else 951 1037 { 952 1038 VBOXGUESTCTRL_PROCESS process; … … 957 1043 958 1044 mGuestProcessMap[u32PID] = process; 959 960 return VINF_SUCCESS; 961 } 962 963 return VERR_ALREADY_EXISTS; 964 } 965 966 int Guest::processGetByPID(uint32_t u32PID, PVBOXGUESTCTRL_PROCESS pProcess) 967 { 968 AssertReturn(u32PID, VERR_INVALID_PARAMETER); 969 AssertPtrReturn(pProcess, VERR_INVALID_PARAMETER); 970 971 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 972 973 GuestProcessMapIterConst it = mGuestProcessMap.find(u32PID); 974 if (it != mGuestProcessMap.end()) 975 { 976 pProcess->mStatus = it->second.mStatus; 977 pProcess->mExitCode = it->second.mExitCode; 978 pProcess->mFlags = it->second.mFlags; 979 980 return VINF_SUCCESS; 981 } 982 983 return VERR_NOT_FOUND; 984 } 985 986 int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags) 987 { 988 AssertReturn(u32PID, VERR_INVALID_PARAMETER); 989 990 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 991 992 GuestProcessMapIter it = mGuestProcessMap.find(u32PID); 993 if (it != mGuestProcessMap.end()) 994 { 995 it->second.mStatus = enmStatus; 996 it->second.mExitCode = uExitCode; 997 it->second.mFlags = uFlags; 998 999 return VINF_SUCCESS; 1000 } 1001 1002 return VERR_NOT_FOUND; 1045 } 1046 1047 return VINF_SUCCESS; 1003 1048 } 1004 1049 … … 1080 1125 * @param aUsername Username to execute tool under. 1081 1126 * @param aPassword The user's password. 1127 * @param uFlagsToAdd ExecuteProcessFlag flags to add to the execution operation. 1082 1128 * @param aProgress Pointer which receives the tool's progress object. Optional. 1083 1129 * @param aPID Pointer which receives the tool's PID. Optional. … … 1086 1132 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment), 1087 1133 IN_BSTR aUsername, IN_BSTR aPassword, 1134 ULONG uFlagsToAdd, 1135 GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr, 1088 1136 IProgress **aProgress, ULONG *aPID) 1089 1137 { … … 1091 1139 ULONG uPID; 1092 1140 1141 ULONG uFlags = ExecuteProcessFlag_Hidden 1142 | ExecuteProcessFlag_WaitForProcessStartOnly; 1143 if (uFlagsToAdd) 1144 uFlags |= uFlagsToAdd; 1145 1146 bool fWaitForOutput = false; 1147 if ( ( (uFlags & ExecuteProcessFlag_WaitForStdOut) 1148 && pObjStdOut) 1149 || ( (uFlags & ExecuteProcessFlag_WaitForStdErr) 1150 && pObjStdErr)) 1151 { 1152 fWaitForOutput = true; 1153 } 1154 1093 1155 HRESULT rc = ExecuteProcess(aTool, 1094 ExecuteProcessFlag_Hidden,1156 uFlags, 1095 1157 ComSafeArrayInArg(aArguments), 1096 1158 ComSafeArrayInArg(aEnvironment), 1097 1159 aUsername, aPassword, 1098 5 * 1000 /* Wait 5s for getting the process started. */,1160 0 /* No timeout. */, 1099 1161 &uPID, progressTool.asOutParam()); 1162 if ( SUCCEEDED(rc) 1163 && fWaitForOutput) 1164 { 1165 BOOL fCompleted; 1166 while ( SUCCEEDED(progressTool->COMGETTER(Completed)(&fCompleted)) 1167 && !fCompleted) 1168 { 1169 BOOL fCanceled; 1170 rc = progressTool->COMGETTER(Canceled)(&fCanceled); 1171 ComAssertRC(rc); 1172 if (fCanceled) 1173 { 1174 rc = setError(VBOX_E_IPRT_ERROR, 1175 tr("%s was cancelled"), Utf8Str(aDescription)); 1176 break; 1177 } 1178 1179 if ( (uFlags & ExecuteProcessFlag_WaitForStdOut) 1180 && pObjStdOut) 1181 { 1182 rc = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut); 1183 } 1184 1185 if ( (uFlags & ExecuteProcessFlag_WaitForStdErr) 1186 && pObjStdErr) 1187 { 1188 rc = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr); 1189 } 1190 1191 if (FAILED(rc)) 1192 break; 1193 } 1194 } 1195 1100 1196 if (SUCCEEDED(rc)) 1101 1197 { 1102 /* Wait for process to exit ... */ 1103 rc = progressTool->WaitForCompletion(-1); 1104 if (FAILED(rc)) return rc; 1105 1106 BOOL fCompleted = FALSE; 1107 BOOL fCanceled = FALSE; 1108 progressTool->COMGETTER(Completed)(&fCompleted); 1109 if (!fCompleted) 1110 progressTool->COMGETTER(Canceled)(&fCanceled); 1111 1112 if (fCompleted) 1113 { 1114 ExecuteProcessStatus_T retStatus; 1115 ULONG uRetExitCode, uRetFlags; 1116 if (SUCCEEDED(rc)) 1117 { 1118 rc = GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); 1119 if (SUCCEEDED(rc)) 1120 { 1121 if (uRetExitCode != 0) /* Not equal 0 means some error occured. */ 1122 { 1123 /** @todo IPRT exit code to string! */ 1124 rc = setError(VBOX_E_IPRT_ERROR, 1125 tr("%s: Error %u occured"), 1126 Utf8Str(aDescription).c_str(), uRetExitCode); 1127 } 1128 else /* Return code 0, success. */ 1129 { 1130 if (aProgress) 1131 { 1132 /* Return the progress to the caller. */ 1133 progressTool.queryInterfaceTo(aProgress); 1134 } 1135 if (aPID) 1136 *aPID = uPID; 1137 } 1138 } 1139 } 1140 } 1141 else if (fCanceled) 1142 { 1143 rc = setError(VBOX_E_IPRT_ERROR, 1144 tr("%s was aborted"), aDescription); 1145 } 1146 else 1147 AssertReleaseMsgFailed(("%s: Operation neither completed nor canceled!?\n", 1148 Utf8Str(aDescription).c_str())); 1198 if (aProgress) 1199 { 1200 /* Return the progress to the caller. */ 1201 progressTool.queryInterfaceTo(aProgress); 1202 } 1203 1204 if (aPID) 1205 *aPID = uPID; 1149 1206 } 1150 1207 … … 1267 1324 1268 1325 /** 1269 * Tries to drain the guest's output (from stdout)and fill it into1326 * Tries to drain the guest's output and fill it into 1270 1327 * a guest process stream object for later usage. 1271 1328 * 1329 * @todo What's about specifying stderr? 1272 1330 * @return IPRT status code. 1273 1331 * @param aPID PID of process to get the output from. 1332 * @param aFlags Which stream to drain (stdout or stderr). 1274 1333 * @param stream Reference to guest process stream to fill. 1275 1334 */ 1276 int Guest::executeStreamDrain(ULONG aPID, GuestProcessStream &stream)1335 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream &stream) 1277 1336 { 1278 1337 AssertReturn(aPID, VERR_INVALID_PARAMETER); 1279 1280 /** @todo Should we try to drain the stream harder? */1281 1338 1282 1339 int rc = VINF_SUCCESS; 1283 1340 for (;;) 1284 1341 { 1285 SafeArray<BYTE> aOutputData; 1286 HRESULT hr = GetProcessOutput(aPID, ProcessOutputFlag_None /* Stdout */, 1287 10 * 1000 /* Timeout in ms */, 1288 _64K, ComSafeArrayAsOutParam(aOutputData)); 1289 if ( SUCCEEDED(hr) 1290 && aOutputData.size()) 1291 { 1292 rc = stream.AddData(aOutputData.raw(), aOutputData.size()); 1293 if (RT_UNLIKELY(RT_FAILURE(rc))) 1342 SafeArray<BYTE> aData; 1343 HRESULT hr = getProcessOutputInternal(aPID, aFlags, 1344 0 /* Infinite timeout */, 1345 _64K, ComSafeArrayAsOutParam(aData), &rc); 1346 if (SUCCEEDED(hr)) 1347 { 1348 if (aData.size()) 1349 { 1350 rc = stream.AddData(aData.raw(), aData.size()); 1351 if (RT_UNLIKELY(RT_FAILURE(rc))) 1352 break; 1353 } 1354 1355 continue; /* Try one more time. */ 1356 } 1357 else /* No more output and/or error! */ 1358 { 1359 if (rc == VERR_NOT_FOUND) 1360 rc = VINF_SUCCESS; 1361 break; 1362 } 1363 } 1364 1365 return rc; 1366 } 1367 1368 /** 1369 * Tries to retrieve the next stream block of a given stream and 1370 * drains the process output only as much as needed to get this next 1371 * stream block. 1372 * 1373 * @return IPRT status code. 1374 * @param ulPID 1375 * @param ulFlags 1376 * @param stream 1377 * @param streamBlock 1378 */ 1379 int Guest::executeStreamGetNextBlock(ULONG ulPID, 1380 ULONG ulFlags, 1381 GuestProcessStream &stream, 1382 GuestProcessStreamBlock &streamBlock) 1383 { 1384 AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER); 1385 1386 bool fDrainStream = true; 1387 int rc; 1388 do 1389 { 1390 rc = stream.ParseBlock(streamBlock); 1391 if (RT_FAILURE(rc)) /* More data needed or empty buffer? */ 1392 { 1393 if (fDrainStream) 1394 { 1395 SafeArray<BYTE> aData; 1396 HRESULT hr = getProcessOutputInternal(ulPID, ulFlags, 1397 0 /* Infinite timeout */, 1398 _64K, ComSafeArrayAsOutParam(aData), &rc); 1399 if (SUCCEEDED(hr)) 1400 { 1401 if (aData.size()) 1402 { 1403 rc = stream.AddData(aData.raw(), aData.size()); 1404 if (RT_UNLIKELY(RT_FAILURE(rc))) 1405 break; 1406 } 1407 1408 continue; /* Try one more time. */ 1409 } 1410 else 1411 { 1412 /* No more output to drain from stream. */ 1413 if (rc == VERR_NOT_FOUND) 1414 { 1415 fDrainStream = false; 1416 continue; 1417 } 1418 1419 break; 1420 } 1421 } 1422 else 1423 { 1424 /* We haved drained the stream as much as we can and reached the 1425 * end of our stream buffer -- that means that there simply is no 1426 * stream block anymore, which is ok. */ 1427 if (rc == VERR_NO_DATA) 1428 rc = VINF_SUCCESS; 1294 1429 break; 1295 }1296 else /* No more output and/or error! */1297 break;1298 }1430 } 1431 } 1432 } 1433 while (!streamBlock.GetCount()); 1299 1434 1300 1435 return rc; … … 1306 1441 * 1307 1442 * @return IPRT status code. 1308 * @param aPID PID of process to get/parse the output from. 1443 * @param ulPID PID of process to get/parse the output from. 1444 * @param ulFlags ? 1309 1445 * @param stream Reference to process stream object to use. 1310 1446 * @param streamBlock Reference that receives the next stream block data. 1311 1447 * 1312 1448 */ 1313 int Guest::executeStreamGetNextBlock(ULONG aPID, GuestProcessStream &stream, 1314 GuestProcessStreamBlock &streamBlock) 1315 { 1316 int rc = executeStreamDrain(aPID, stream); 1317 if (RT_SUCCESS(rc)) 1318 { 1319 do 1320 { 1321 rc = stream.ParseBlock(streamBlock); 1322 if (streamBlock.GetCount()) 1323 break; /* We got a block, bail out! */ 1324 } while (RT_SUCCESS(rc)); 1325 1326 /* In case this was the last block, VERR_NO_DATA is returned. 1327 * Overwrite this to get a proper return value for the last block. */ 1328 if( streamBlock.GetCount() 1329 && rc == VERR_NO_DATA) 1330 { 1331 rc = VINF_SUCCESS; 1332 } 1333 } 1449 int Guest::executeStreamParseNextBlock(ULONG ulPID, 1450 ULONG ulFlags, 1451 GuestProcessStream &stream, 1452 GuestProcessStreamBlock &streamBlock) 1453 { 1454 AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER); 1455 1456 int rc; 1457 do 1458 { 1459 rc = stream.ParseBlock(streamBlock); 1460 if (RT_FAILURE(rc)) 1461 break; 1462 } 1463 while (!streamBlock.GetCount()); 1334 1464 1335 1465 return rc; … … 1342 1472 * 1343 1473 * @return HRESULT 1344 * @param aPID PID of process to get/parse the output from. 1474 * @param ulPID PID of process to get/parse the output from. 1475 * @param ulFlags ? 1345 1476 * @param streamObjects Reference to a guest stream object structure for 1346 1477 * storing the parsed data. 1347 1478 */ 1348 HRESULT Guest::executeStreamParse(ULONG aPID, GuestCtrlStreamObjects &streamObjects)1349 { 1350 GuestProcessStream guestStream;1351 HRESULT hr = executeStreamDrain(aPID, guestStream);1352 if ( SUCCEEDED(hr))1353 { 1354 for (;;)1479 HRESULT Guest::executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects) 1480 { 1481 GuestProcessStream stream; 1482 int rc = executeStreamDrain(ulPID, ulFlags, stream); 1483 if (RT_SUCCESS(rc)) 1484 { 1485 do 1355 1486 { 1356 1487 /* Try to parse the stream output we gathered until now. If we still need more 1357 1488 * data the parsing routine will tell us and we just do another poll round. */ 1358 1489 GuestProcessStreamBlock curBlock; 1359 int vrc = guestStream.ParseBlock(curBlock); 1360 if (RT_SUCCESS(vrc)) 1361 { 1362 if (curBlock.GetCount()) 1363 { 1364 streamObjects.push_back(curBlock); 1365 } 1366 else 1367 break; /* No more data. */ 1368 } 1369 else /* Everything else would be an error! */ 1370 hr = setError(VBOX_E_IPRT_ERROR, 1371 tr("Error while parsing guest output (%Rrc)"), vrc); 1372 } 1373 } 1374 1375 /** @todo Add check if there now are any sream objects at all! */ 1376 1377 return hr; 1490 rc = executeStreamParseNextBlock(ulPID, ulFlags, stream, curBlock); 1491 if (RT_SUCCESS(rc)) 1492 streamObjects.push_back(curBlock); 1493 } while (RT_SUCCESS(rc)); 1494 1495 if (rc == VERR_NO_DATA) /* End of data reached. */ 1496 rc = VINF_SUCCESS; 1497 } 1498 1499 if (RT_FAILURE(rc)) 1500 return setError(VBOX_E_IPRT_ERROR, 1501 tr("Error while parsing guest output (%Rrc)"), rc); 1502 return rc; 1378 1503 } 1379 1504 … … 1461 1586 && !(aFlags & ExecuteProcessFlag_WaitForProcessStartOnly) 1462 1587 && !(aFlags & ExecuteProcessFlag_Hidden) 1463 && !(aFlags & ExecuteProcessFlag_NoProfile)) 1588 && !(aFlags & ExecuteProcessFlag_NoProfile) 1589 && !(aFlags & ExecuteProcessFlag_WaitForStdOut) 1590 && !(aFlags & ExecuteProcessFlag_WaitForStdErr)) 1464 1591 { 1465 1592 if (pRC) … … 1619 1746 if (RT_SUCCESS(vrc)) 1620 1747 { 1621 LogFlowFunc(("Waiting for HGCM callback (timeout=% dms) ...\n", aTimeoutMS));1748 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS)); 1622 1749 1623 1750 /* … … 1629 1756 PCALLBACKDATAEXECSTATUS pExecStatus = NULL; 1630 1757 1631 1758 /* 1632 1759 * Wait for the first stage (=0) to complete (that is starting the process). 1633 1760 */ … … 1713 1840 { 1714 1841 VBOXGUESTCTRL_PROCESS process; 1715 int vrc = processGet ByPID(aPID, &process);1842 int vrc = processGetStatus(aPID, &process); 1716 1843 if (RT_SUCCESS(vrc)) 1717 1844 { … … 1871 1998 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData)) 1872 1999 { 2000 #ifndef VBOX_WITH_GUEST_CONTROL 2001 ReturnComNotImplemented(); 2002 #else /* VBOX_WITH_GUEST_CONTROL */ 2003 using namespace guestControl; 2004 2005 return getProcessOutputInternal(aPID, aFlags, aTimeoutMS, 2006 aSize, ComSafeArrayOutArg(aData), NULL /* rc */); 2007 #endif 2008 } 2009 2010 HRESULT Guest::getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, 2011 LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC) 2012 { 1873 2013 /** @todo r=bird: Eventually we should clean up all the timeout parameters 1874 2014 * in the API and have the same way of specifying infinite waits! */ … … 1898 2038 try 1899 2039 { 1900 VBOXGUESTCTRL_PROCESS proc ess;1901 int vrc = processGet ByPID(aPID, &process);2040 VBOXGUESTCTRL_PROCESS proc; 2041 int vrc = processGetStatus(aPID, &proc); 1902 2042 if (RT_FAILURE(vrc)) 2043 { 1903 2044 rc = setError(VBOX_E_IPRT_ERROR, 1904 Guest::tr(" Cannot get output from non-existent guest process (PID %u)"), aPID);1905 1906 if (SUCCEEDED(rc))2045 Guest::tr("Guest process (PID %u) does not exist"), aPID); 2046 } 2047 else 1907 2048 { 1908 2049 uint32_t uContextID = 0; … … 1979 2120 if (RT_SUCCESS(vrc)) 1980 2121 { 1981 LogFlowFunc(("Waiting for HGCM callback (timeout=% dms) ...\n", aTimeoutMS));2122 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS)); 1982 2123 1983 2124 /* … … 1987 2128 */ 1988 2129 1989 PCALLBACKDATAEXECOUT pExecOut = NULL;1990 1991 2130 /* 1992 2131 * Wait for the first output callback notification to arrive. 1993 2132 */ 1994 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging */, aTimeoutMS);2133 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS); 1995 2134 if (RT_SUCCESS(vrc)) 1996 2135 { 2136 PCALLBACKDATAEXECOUT pExecOut = NULL; 1997 2137 vrc = callbackGetUserData(uContextID, NULL /* We know the type. */, 1998 2138 (void**)&pExecOut, NULL /* Don't need the size. */); … … 2042 2182 pProgress.setNull(); 2043 2183 } 2184 2185 if (pRC) 2186 *pRC = vrc; 2044 2187 } 2045 2188 catch (std::bad_alloc &) … … 2068 2211 { 2069 2212 VBOXGUESTCTRL_PROCESS process; 2070 int vrc = processGet ByPID(aPID, &process);2213 int vrc = processGetStatus(aPID, &process); 2071 2214 if (RT_SUCCESS(vrc)) 2072 2215 { -
trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp
r39387 r39418 126 126 ComSafeArrayAsInParam(env), 127 127 aUsername, aPassword, 128 ExecuteProcessFlag_None, 129 NULL, NULL, 128 130 NULL /* Progress */, NULL /* PID */); 129 131 } … … 301 303 { 302 304 return executeStreamGetNextBlock(it->second.mPID, 305 ProcessOutputFlag_None /* StdOut */, 303 306 it->second.mStream, streamBlock); 304 307 } … … 405 408 406 409 ULONG uPID; 407 /** @todo Don't wait for tool to finish! Might take a lot of time! */ 410 /* We only start the directory listing and requesting stdout data but don't get its 411 * data here; this is done in sequential IGuest::DirectoryRead calls then. */ 408 412 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_LS).raw(), Bstr("Opening directory").raw(), 409 413 ComSafeArrayAsInParam(args), 410 414 ComSafeArrayAsInParam(env), 411 415 aUsername, aPassword, 416 ExecuteProcessFlag_WaitForStdOut, 417 NULL, NULL, 412 418 NULL /* Progress */, &uPID); 413 419 if (SUCCEEDED(hr)) … … 477 483 */ 478 484 ULONG uPID; 485 GuestCtrlStreamObjects stdOut; 479 486 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(), 480 487 ComSafeArrayAsInParam(args), 481 488 ComSafeArrayAsInParam(env), 482 489 aUsername, aPassword, 490 ExecuteProcessFlag_WaitForStdOut, 491 &stdOut, NULL /* stdErr */, 483 492 NULL /* Progress */, &uPID); 484 493 if (SUCCEEDED(hr)) 485 494 { 486 GuestCtrlStreamObjects streamObjs; 487 hr = executeStreamParse(uPID, streamObjs); 488 if (SUCCEEDED(hr)) 495 int rc = VINF_SUCCESS; 496 497 Assert(stdOut.size()); 498 const char *pszFsType = stdOut[0].GetString("ftype"); 499 if (!pszFsType) /* Attribute missing? */ 500 rc = VERR_NOT_FOUND; 501 if ( RT_SUCCESS(rc) 502 && strcmp(pszFsType, "d")) /* Directory? */ 489 503 { 490 int rc = VINF_SUCCESS; 491 492 Assert(streamObjs.size()); 493 const char *pszFsType = streamObjs[0].GetString("ftype"); 494 if (!pszFsType) /* Attribute missing? */ 495 rc = VERR_NOT_FOUND; 496 if ( RT_SUCCESS(rc) 497 && strcmp(pszFsType, "d")) /* Directory? */ 498 { 499 rc = VERR_FILE_NOT_FOUND; 500 /* This is not critical for Main, so don't set hr -- 501 * we will take care of rc then. */ 502 } 503 if ( RT_SUCCESS(rc) 504 && aObjInfo) /* Do we want object details? */ 505 { 506 hr = executeStreamQueryFsObjInfo(aDirectory, streamObjs[0], 507 aObjInfo, enmAddAttribs); 508 } 509 510 if (pRC) 511 *pRC = rc; 504 rc = VERR_FILE_NOT_FOUND; 505 /* This is not critical for Main, so don't set hr -- 506 * we will take care of rc then. */ 512 507 } 508 if ( RT_SUCCESS(rc) 509 && aObjInfo) /* Do we want object details? */ 510 { 511 hr = executeStreamQueryFsObjInfo(aDirectory, stdOut[0], 512 aObjInfo, enmAddAttribs); 513 } 514 515 if (pRC) 516 *pRC = rc; 513 517 } 514 518 } … … 540 544 if (RT_SUCCESS(rc)) 541 545 { 542 ComObjPtr <GuestDirEntry> pDirEntry; 543 hr = pDirEntry.createObject(); 544 ComAssertComRC(hr); 545 546 Assert(streamBlock.GetCount()); 547 hr = pDirEntry->init(this, streamBlock); 548 if (SUCCEEDED(hr)) 546 if (streamBlock.GetCount()) 549 547 { 550 pDirEntry.queryInterfaceTo(aDirEntry); 548 ComObjPtr <GuestDirEntry> pDirEntry; 549 hr = pDirEntry.createObject(); 550 ComAssertComRC(hr); 551 552 Assert(streamBlock.GetCount()); 553 hr = pDirEntry->init(this, streamBlock); 554 if (SUCCEEDED(hr)) 555 { 556 pDirEntry.queryInterfaceTo(aDirEntry); 557 } 558 else 559 hr = setError(VBOX_E_IPRT_ERROR, 560 Guest::tr("Failed to init guest directory entry")); 551 561 } 552 562 else 553 hr = setError(VBOX_E_IPRT_ERROR, 554 Guest::tr("Failed to init guest directory entry")); 555 } 556 else if (rc == VERR_NO_DATA) 557 { 558 /* No more directory entries to read. That's fine. */ 559 hr = E_ABORT; /** @todo Find/define a better rc! */ 563 { 564 /* No more directory entries to read. That's fine. */ 565 hr = E_ABORT; /** @todo Find/define a better rc! */ 566 } 560 567 } 561 568 else -
trunk/src/VBox/Main/src-client/GuestCtrlImplFile.cpp
r38627 r39418 135 135 */ 136 136 ULONG uPID; 137 GuestCtrlStreamObjects stdOut; 137 138 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying file information").raw(), 138 139 ComSafeArrayAsInParam(args), 139 140 ComSafeArrayAsInParam(env), 140 141 aUsername, aPassword, 142 ExecuteProcessFlag_WaitForStdOut, 143 &stdOut, NULL, 141 144 NULL /* Progress */, &uPID); 142 145 if (SUCCEEDED(hr)) 143 146 { 144 GuestCtrlStreamObjects streamObjs; 145 hr = executeStreamParse(uPID, streamObjs); 146 if (SUCCEEDED(hr)) 147 int rc = VINF_SUCCESS; 148 const char *pszFsType = stdOut[0].GetString("ftype"); 149 if (!pszFsType) /* Attribute missing? */ 150 rc = VERR_NOT_FOUND; 151 if ( RT_SUCCESS(rc) 152 && strcmp(pszFsType, "-")) /* Regular file? */ 147 153 { 148 int rc = VINF_SUCCESS; 149 const char *pszFsType = streamObjs[0].GetString("ftype"); 150 if (!pszFsType) /* Attribute missing? */ 151 rc = VERR_NOT_FOUND; 152 if ( RT_SUCCESS(rc) 153 && strcmp(pszFsType, "-")) /* Regular file? */ 154 { 155 rc = VERR_FILE_NOT_FOUND; 156 /* This is not critical for Main, so don't set hr -- 157 * we will take care of rc then. */ 158 } 159 if ( RT_SUCCESS(rc) 160 && aObjInfo) /* Do we want object details? */ 161 { 162 hr = executeStreamQueryFsObjInfo(aFile, streamObjs[0], 163 aObjInfo, enmAddAttribs); 164 } 165 166 if (pRC) 167 *pRC = rc; 154 rc = VERR_FILE_NOT_FOUND; 155 /* This is not critical for Main, so don't set hr -- 156 * we will take care of rc then. */ 168 157 } 158 if ( RT_SUCCESS(rc) 159 && aObjInfo) /* Do we want object details? */ 160 { 161 hr = executeStreamQueryFsObjInfo(aFile, stdOut[0], 162 aObjInfo, enmAddAttribs); 163 } 164 165 if (pRC) 166 *pRC = rc; 169 167 } 170 168 } -
trunk/src/VBox/Main/src-client/GuestCtrlImplTasks.cpp
r38627 r39418 522 522 * actual copying, start the guest part now. 523 523 */ 524 rc = pGuest->ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(), 525 ExecuteProcessFlag_Hidden, 526 ComSafeArrayAsInParam(args), 527 ComSafeArrayAsInParam(env), 528 Bstr(aTask->strUserName).raw(), 529 Bstr(aTask->strPassword).raw(), 530 5 * 1000 /* Wait 5s for getting the process started. */, 531 &uPID, execProgress.asOutParam()); 524 rc = pGuest->executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_CAT).raw(), 525 Bstr("Copying file to host").raw(), 526 ComSafeArrayAsInParam(args), 527 ComSafeArrayAsInParam(env), 528 Bstr(aTask->strUserName).raw(), 529 Bstr(aTask->strPassword).raw(), 530 ExecuteProcessFlag_WaitForStdOut, 531 NULL, NULL, 532 execProgress.asOutParam(), &uPID); 532 533 if (FAILED(rc)) 533 534 rc = GuestTask::setProgressErrorInfo(rc, aTask->progress, pGuest); … … 551 552 size_t cbTransfered = 0; 552 553 SafeArray<BYTE> aOutputData(_64K); 553 while (SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))) 554 { 555 rc = this->GetProcessOutput(uPID, ProcessOutputFlag_None, 556 10 * 1000 /* Timeout in ms */, 557 _64K, ComSafeArrayAsOutParam(aOutputData)); 554 while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) 555 && !fCompleted) 556 { 557 rc = pGuest->GetProcessOutput(uPID, ProcessOutputFlag_None /* StdOut */, 558 0 /* No timeout. */, 559 _64K, ComSafeArrayAsOutParam(aOutputData)); 558 560 if (SUCCEEDED(rc)) 559 561 { 560 if (!aOutputData.size()) 561 { 562 /* 563 * Only bitch about an unexpected end of a file when there already 564 * was data read from that file. If this was the very first read we can 565 * be (almost) sure that this file is not meant to be read by the specified user. 566 */ 567 if ( cbTransfered 568 && cbToRead) 562 if (aOutputData.size()) 563 { 564 vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */); 565 if (RT_FAILURE(vrc)) 569 566 { 570 567 rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 571 Guest::tr("Unexpected end of file \"%s\" (%u bytes left, %u bytes written)"), 572 aTask->strSource.c_str(), cbToRead, cbTransfered); 568 Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"), 569 aTask->strSource.c_str(), cbToRead, vrc); 570 break; 573 571 } 574 break; 575 } 576 577 vrc = RTFileWrite(hFileDest, aOutputData.raw(), aOutputData.size(), NULL /* No partial writes */); 578 if (RT_FAILURE(vrc)) 579 { 580 rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 581 Guest::tr("Error writing to file \"%s\" (%u bytes left), rc=%Rrc"), 582 aTask->strSource.c_str(), cbToRead, vrc); 583 break; 584 } 585 586 cbToRead -= aOutputData.size(); 587 cbTransfered += aOutputData.size(); 588 589 aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0)); 572 573 cbToRead -= aOutputData.size(); 574 Assert(cbToRead >= 0); 575 cbTransfered += aOutputData.size(); 576 577 aTask->progress->SetCurrentOperationProgress(cbTransfered / (lFileSize / 100.0)); 578 } 579 580 /* Nothing read this time; try next round. */ 590 581 } 591 582 else … … 596 587 } 597 588 589 RTFileClose(hFileDest); 590 591 if ( cbTransfered 592 && (cbTransfered != lFileSize)) 593 { 594 /* 595 * Only bitch about an unexpected end of a file when there already 596 * was data read from that file. If this was the very first read we can 597 * be (almost) sure that this file is not meant to be read by the specified user. 598 */ 599 rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->progress, 600 Guest::tr("Unexpected end of file \"%s\" (%u bytes total, %u bytes transferred)"), 601 aTask->strSource.c_str(), lFileSize, cbTransfered); 602 } 603 598 604 if (SUCCEEDED(rc)) 599 605 aTask->progress->notifyComplete(S_OK); 600 601 RTFileClose(hFileDest);602 606 } 603 607 } -
trunk/src/VBox/Main/src-client/GuestImpl.cpp
r39248 r39418 120 120 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 121 121 122 /* Clean up callback data. */122 /* Notify left over callbacks that we are about to shutdown ... */ 123 123 CallbackMapIter it; 124 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++) 125 { 126 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED, 127 Guest::tr("VM is shutting down, canceling uncompleted guest requests ...")); 128 AssertRC(rc2); 129 } 130 131 /* Destroy left over callback data. */ 124 132 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++) 125 133 callbackDestroy(it->first);
Note:
See TracChangeset
for help on using the changeset viewer.