Changeset 104640 in vbox
- Timestamp:
- May 15, 2024 1:16:55 PM (7 months ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/GuestProcessImpl.h
r104178 r104640 248 248 int terminate(uint32_t uTimeoutMS, int *pvrcGuest); 249 249 250 int wait(int *pvrcGuest); 251 252 public: 253 254 virtual int onOutputCallback(uint32_t uHandle, const std::vector<Utf8Str> &vecData); 255 256 virtual int onOutputCallback(uint32_t uHandle, const BYTE *pbData, size_t cbData); 257 258 virtual int onInputCallback(uint32_t uHandle, std::vector<Utf8Str> &vecData); 259 250 260 protected: 251 261 -
trunk/src/VBox/Main/include/GuestSessionImplTasks.h
r104636 r104640 354 354 355 355 /** 356 * Implementation for a Guest Additions update process for logging process output to the release log. 357 */ 358 class UpdateAdditionsProcess : public GuestProcessWrapper 359 { 360 public: 361 362 UpdateAdditionsProcess(void) { } 363 364 virtual ~UpdateAdditionsProcess(); 365 366 int onOutputCallback(uint32_t uHandle, const BYTE *pbData, size_t cbData); 367 368 protected: 369 370 /** Current line of stdout. */ 371 Utf8Str mLineStdOut; 372 /** Current line of stderr. */ 373 Utf8Str mLineStdErr; 374 }; 375 376 /** 377 * Tweaked startup info for a guest Guest Additions update process. 378 */ 379 class UpdateAdditionsStartupInfo : public GuestProcessStartupInfo 380 { 381 public: 382 383 UpdateAdditionsStartupInfo(void) 384 { 385 /* We want to have stdout / stderr handled by default for update processes. */ 386 mFlags = ProcessCreateFlag_WaitForStdOut | ProcessCreateFlag_WaitForStdErr; 387 } 388 }; 389 390 /** 356 391 * Guest session task for automatically updating the Guest Additions on the guest. 357 392 */ -
trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp
r104178 r104640 2444 2444 } 2445 2445 2446 /** 2447 * Default callback implementation for process output. 2448 * 2449 * @returns VBox status code. 2450 * @param uHandle Process output handle. 2451 * @param vecData Process output data. 2452 * 2453 * @note Only stdout (handle ID 1) and stderr (handle ID 2) are implemented. 2454 */ 2455 /* virtual */ 2456 int GuestProcessWrapper::onOutputCallback(uint32_t uHandle, const std::vector<Utf8Str> &vecData) 2457 { 2458 GuestProcessOutputStream *pStream = NULL; 2459 2460 switch (uHandle) 2461 { 2462 case GUEST_PROC_OUT_H_STDOUT: 2463 pStream = &mStdOut; 2464 break; 2465 2466 case GUEST_PROC_OUT_H_STDERR: 2467 pStream = &mStdErr; 2468 break; 2469 2470 default: 2471 /* Ignore. */ 2472 break; 2473 } 2474 2475 int vrc = VINF_SUCCESS; 2476 2477 if (pStream) 2478 { 2479 std::vector<Utf8Str>::const_iterator itData = vecData.begin(); 2480 while (itData != vecData.end()) 2481 { 2482 vrc = pStream->AddData((BYTE *)(*itData).c_str(), (*itData).length()); 2483 if (RT_FAILURE(vrc)) 2484 break; 2485 ++itData; 2486 } 2487 } 2488 2489 return vrc; 2490 } 2491 2492 /** 2493 * Default callback implementation for process output. 2494 * 2495 * @returns VBox status code. 2496 * @param uHandle Process output handle. 2497 * @param pbData Pointer to data. 2498 * @param cbData Size (in bytes) of \a pbData. 2499 * 2500 * @note Only stdout (handle ID 1) and stderr (handle ID 2) are implemented. 2501 */ 2502 /* virtual */ 2503 int GuestProcessWrapper::onOutputCallback(uint32_t uHandle, const BYTE *pbData, size_t cbData) 2504 { 2505 AssertPtrReturn(pbData, VERR_INVALID_POINTER); 2506 AssertReturn(cbData, VERR_INVALID_PARAMETER); 2507 2508 GuestProcessOutputStream *pStream = NULL; 2509 2510 switch (uHandle) 2511 { 2512 case GUEST_PROC_OUT_H_STDOUT: 2513 pStream = &mStdOut; 2514 break; 2515 2516 case GUEST_PROC_OUT_H_STDERR: 2517 pStream = &mStdErr; 2518 break; 2519 2520 default: 2521 /* Ignore. */ 2522 break; 2523 } 2524 2525 int vrc = VINF_SUCCESS; 2526 2527 if (pStream) 2528 vrc = pStream->AddData(pbData, cbData); 2529 2530 return vrc; 2531 } 2532 2533 /** 2534 * Default callback implementation for process input. 2535 * Does not provide any input data. 2536 * 2537 * @returns VBox status code. 2538 * @param uHandle Process input handle. 2539 * @param vecData Process input data. 2540 */ 2541 /* virtual */ 2542 int GuestProcessWrapper::onInputCallback(uint32_t uHandle, std::vector<Utf8Str> &vecData) 2543 { 2544 RT_NOREF(uHandle); 2545 2546 vecData.clear(); 2547 2548 /* No input data given by default. */ 2549 return VINF_SUCCESS; 2550 } 2551 2552 /** 2553 * Waits for a guest process and handle input / output via callbacks. 2554 * 2555 * @returns VBox status code. 2556 * @param pvrcGuest Where to return the guest error when 2557 * VERR_GSTCTL_GUEST_ERROR was returned. Optional. 2558 */ 2559 int GuestProcessWrapper::wait(int *pvrcGuest) 2560 { 2561 int vrc; 2562 2563 /* Do the waiting. */ 2564 uint32_t fProcWaitForFlags = ProcessWaitForFlag_Terminate; 2565 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut) 2566 fProcWaitForFlags |= ProcessWaitForFlag_StdOut; 2567 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr) 2568 fProcWaitForFlags |= ProcessWaitForFlag_StdErr; 2569 2570 /** @todo Decrease timeout while running. */ 2571 uint64_t u64StartMS = RTTimeMilliTS(); 2572 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS; 2573 2574 int vrcGuest = VINF_SUCCESS; 2575 bool fDone = false; 2576 2577 BYTE abBuf[_64K]; 2578 uint32_t cbRead; 2579 2580 bool fHandleStdOut = false; 2581 bool fHandleStdErr = false; 2582 2583 /** 2584 * Updates the elapsed time and checks if a 2585 * timeout happened, then breaking out of the loop. 2586 */ 2587 #define UPDATE_AND_CHECK_ELAPSED_TIME() \ 2588 u64ElapsedMS = RTTimeMilliTS() - u64StartMS; \ 2589 if ( uTimeoutMS != RT_INDEFINITE_WAIT \ 2590 && u64ElapsedMS >= uTimeoutMS) \ 2591 { \ 2592 vrc = VERR_TIMEOUT; \ 2593 break; \ 2594 } 2595 2596 /** 2597 * Returns the remaining time (in ms). 2598 */ 2599 #define GET_REMAINING_TIME (uTimeoutMS == RT_INDEFINITE_WAIT ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS) 2600 2601 ProcessWaitResult_T waitRes = ProcessWaitResult_None; 2602 do 2603 { 2604 uint64_t u64ElapsedMS; 2605 UPDATE_AND_CHECK_ELAPSED_TIME(); 2606 2607 vrc = pProcess->i_waitFor(fProcWaitForFlags, GET_REMAINING_TIME, waitRes, &vrcGuest); 2608 if (RT_FAILURE(vrc)) 2609 break; 2610 2611 switch (waitRes) 2612 { 2613 case ProcessWaitResult_StdIn: 2614 vrc = VERR_NOT_IMPLEMENTED; 2615 break; 2616 2617 case ProcessWaitResult_StdOut: 2618 fHandleStdOut = true; 2619 break; 2620 2621 case ProcessWaitResult_StdErr: 2622 fHandleStdErr = true; 2623 break; 2624 2625 case ProcessWaitResult_WaitFlagNotSupported: 2626 if (fProcWaitForFlags & ProcessWaitForFlag_StdOut) 2627 fHandleStdOut = true; 2628 if (fProcWaitForFlags & ProcessWaitForFlag_StdErr) 2629 fHandleStdErr = true; 2630 /* Since waiting for stdout / stderr is not supported by the guest, 2631 * wait a bit to not hog the CPU too much when polling for data. */ 2632 RTThreadSleep(1); /* Optional, don't check vrc. */ 2633 break; 2634 2635 case ProcessWaitResult_Error: 2636 vrc = VERR_GSTCTL_GUEST_ERROR; 2637 break; 2638 2639 case ProcessWaitResult_Terminate: 2640 fDone = true; 2641 break; 2642 2643 case ProcessWaitResult_Timeout: 2644 vrc = VERR_TIMEOUT; 2645 break; 2646 2647 case ProcessWaitResult_Start: 2648 case ProcessWaitResult_Status: 2649 /* Not used here, just skip. */ 2650 break; 2651 2652 default: 2653 AssertMsgFailed(("Unhandled process wait result %RU32\n", waitRes)); 2654 break; 2655 } 2656 2657 if (RT_FAILURE(vrc)) 2658 break; 2659 2660 #define HANDLE_OUTPUT(a_Handle) \ 2661 cbRead = 0; \ 2662 vrc = pProcess->i_readData(a_Handle, sizeof(abBuf), \ 2663 GET_REMAINING_TIME, \ 2664 abBuf, sizeof(abBuf), \ 2665 &cbRead, &vrcGuest); \ 2666 if ( RT_FAILURE(vrc) \ 2667 || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED) \ 2668 break; \ 2669 if (cbRead) \ 2670 vrc = onOutputCallback(GUEST_PROC_OUT_H_STDOUT, abBuf, cbRead); 2671 2672 if (fHandleStdOut) 2673 { 2674 UPDATE_AND_CHECK_ELAPSED_TIME(); 2675 HANDLE_OUTPUT(GUEST_PROC_OUT_H_STDOUT); 2676 fHandleStdOut = false; 2677 } 2678 2679 if (fHandleStdErr) 2680 { 2681 UPDATE_AND_CHECK_ELAPSED_TIME(); 2682 HANDLE_OUTPUT(GUEST_PROC_OUT_H_STDERR); 2683 fHandleStdErr = false; 2684 } 2685 2686 #undef HANDLE_OUTPUT 2687 2688 } while (!fDone && RT_SUCCESS(vrc)); 2689 2690 #undef UPDATE_AND_CHECK_ELAPSED_TIME 2691 #undef GET_REMAINING_TIME 2692 2693 if (RT_FAILURE(vrcGuest)) 2694 vrc = VERR_GSTCTL_GUEST_ERROR; 2695 2696 LogFlowThisFunc(("Loop ended with vrc=%Rrc, vrcGuest=%Rrc, waitRes=%RU32\n", vrc, vrcGuest, waitRes)); 2697 if (pvrcGuest) 2698 *pvrcGuest = vrcGuest; 2699 2700 LogFlowFuncLeaveRC(vrc); 2701 return vrc; 2702 } 2703 2446 2704 /////////////////////////////////////////////////////////////////////////////// 2447 2705 … … 2476 2734 * @param pvrcGuest Where to return the guest error when 2477 2735 * VERR_GSTCTL_GUEST_ERROR was returned. Optional. 2736 * 2737 * @sa GuestProcessWrapper::wait() -- mostly duplicate code, kept for backwards compatibility. 2478 2738 */ 2479 2739 int GuestProcessToolbox::waitEx(uint32_t fToolWaitFlags, GuestToolboxStreamBlock *pStrmBlkOut, int *pvrcGuest) -
trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
r104637 r104640 2483 2483 } 2484 2484 2485 UpdateAdditionsProcess::~UpdateAdditionsProcess() 2486 { 2487 /* Log any remainders if not done yet. */ 2488 if (mLineStdOut.isNotEmpty()) 2489 LogRel(("Guest Additions Update: %s\n", mLineStdOut.c_str())); 2490 if (mLineStdErr.isNotEmpty()) 2491 LogRel(("Guest Additions Update: %s\n", mLineStdErr.c_str())); 2492 } 2493 2494 /** 2495 * Callback implementation to output guest update process stdout / stderr output to the release log. 2496 * Only complete lines will be logged for cosmetic reasons. 2497 * 2498 * @returns VBox status code. 2499 * @param uHandle Process output handle. 2500 * @param pbData Pointer to data. 2501 * @param cbData Size (in bytes) of \a pbData. 2502 * 2503 * @note Only stdout (handle ID 1) and stderr (handle ID 2) are implemented. 2504 */ 2505 int UpdateAdditionsProcess::onOutputCallback(uint32_t uHandle, const BYTE *pbData, size_t cbData) 2506 { 2507 AssertReturn(RTStrValidateEncodingEx((const char *)pbData, cbData, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH 2508 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED), 2509 VERR_INVALID_PARAMETER); 2510 2511 Utf8Str *pstrLine = NULL; 2512 2513 switch (uHandle) 2514 { 2515 case GUEST_PROC_OUT_H_STDOUT: 2516 pstrLine = &mLineStdOut; 2517 break; 2518 2519 case GUEST_PROC_OUT_H_STDERR: 2520 pstrLine = &mLineStdErr; 2521 break; 2522 2523 default: 2524 /* Ignore. */ 2525 break; 2526 } 2527 2528 int vrc = VINF_SUCCESS; 2529 2530 if (pstrLine) 2531 { 2532 const char *cch = (const char *)pbData; 2533 while (cbData) 2534 { 2535 if (*cch == '\n') 2536 break; 2537 pstrLine->append(*cch); 2538 cch++; 2539 cbData--; 2540 } 2541 2542 if (*cch == '\n') 2543 { 2544 LogRel(("Guest Additions Update: %s\n", pstrLine->c_str())); 2545 pstrLine->setNull(); 2546 cch++; 2547 } 2548 2549 while (cbData) 2550 { 2551 pstrLine->append(*cch); 2552 cch++; 2553 cbData--; 2554 } 2555 } 2556 2557 return vrc; 2558 } 2559 2485 2560 GuestSessionTaskUpdateAdditions::GuestSessionTaskUpdateAdditions(GuestSession *pSession, 2486 2561 const Utf8Str &strSource, … … 2662 2737 LogRel(("Guest Additions Update: Running \"%s\" ...\n", procInfo.mName.c_str())); 2663 2738 2664 GuestProcessToolbox procToRun;2739 UpdateAdditionsProcess guestProc; 2665 2740 int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS; 2666 int vrc = procToRun.init(pSession, procInfo, false /* Async */, &vrcGuest);2741 int vrc = guestProc.init(pSession, procInfo, false /* Async */, &vrcGuest); 2667 2742 if (RT_SUCCESS(vrc)) 2668 2743 { 2669 2744 if (RT_SUCCESS(vrcGuest)) 2670 vrc = procToRun.wait(GUESTPROCESSTOOL_WAIT_FLAG_NONE,&vrcGuest);2745 vrc = guestProc.wait(&vrcGuest); 2671 2746 if (RT_SUCCESS(vrc)) 2672 vrc = procToRun.getTerminationStatus();2747 vrc = guestProc.getTerminationStatus(); 2673 2748 } 2674 2749 … … 2679 2754 { 2680 2755 case VERR_GSTCTL_PROCESS_EXIT_CODE: 2756 { 2757 int32_t iExitCode; 2758 vrc = guestProc.getTerminationStatus(&iExitCode); 2759 Assert(vrc == VERR_GSTCTL_PROCESS_EXIT_CODE); 2681 2760 setUpdateErrorMsg(VBOX_E_GSTCTL_GUEST_ERROR, 2682 Utf8StrFmt(tr("Running update file \"%s\" on guest failed : %Rrc"),2683 procInfo.mExecutable.c_str(), procToRun.getRc()));2761 Utf8StrFmt(tr("Running update file \"%s\" on guest failed with exit code %d"), 2762 procInfo.mExecutable.c_str(), iExitCode)); 2684 2763 break; 2685 2764 2765 } 2686 2766 case VERR_GSTCTL_GUEST_ERROR: 2687 2767 setUpdateErrorMsg(VBOX_E_GSTCTL_GUEST_ERROR, tr("Running update file on guest failed"), … … 3098 3178 /* First pass: Copy over the file (first time only) + execute it to remove any 3099 3179 * existing VBox certificates. */ 3100 GuestProcessStartupInfo siCertUtilRem;3180 UpdateAdditionsStartupInfo siCertUtilRem; 3101 3181 siCertUtilRem.mName = "VirtualBox Certificate Utility, removing old VirtualBox certificates"; 3102 3182 /* The argv[0] should contain full path to the executable module */ … … 3113 3193 /* Second pass: Only execute (but don't copy) again, this time installng the 3114 3194 * recent certificates just copied over. */ 3115 GuestProcessStartupInfo siCertUtilAdd;3195 UpdateAdditionsStartupInfo siCertUtilAdd; 3116 3196 siCertUtilAdd.mName = "VirtualBox Certificate Utility, installing VirtualBox certificates"; 3117 3197 /* The argv[0] should contain full path to the executable module */ … … 3136 3216 ISOFILE_FLAG_COPY_FROM_ISO)); 3137 3217 /* The stub loader which decides which flavor to run. */ 3138 GuestProcessStartupInfo siInstaller;3218 UpdateAdditionsStartupInfo siInstaller; 3139 3219 siInstaller.mName = "VirtualBox Windows Guest Additions Installer"; 3140 3220 /* Set a running timeout of 5 minutes -- the Windows Guest Additions … … 3173 3253 strUpdateDir + "VBoxLinuxAdditions.run", ISOFILE_FLAG_COPY_FROM_ISO)); 3174 3254 3175 GuestProcessStartupInfo siInstaller;3255 UpdateAdditionsStartupInfo siInstaller; 3176 3256 siInstaller.mName = "VirtualBox Linux Guest Additions Installer"; 3177 3257 /* Set a running timeout of 5 minutes -- compiling modules and stuff for the Linux Guest Additions
Note:
See TracChangeset
for help on using the changeset viewer.