VirtualBox

Changeset 104640 in vbox


Ignore:
Timestamp:
May 15, 2024 1:16:55 PM (7 months ago)
Author:
vboxsync
Message:

Main/Guest Additions Auto Update: Implemented support for logging guest process output to the release log. That way it will be much easier to diagnose what's happening on the guest side while updating.

Location:
trunk/src/VBox/Main
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r104178 r104640  
    248248    int terminate(uint32_t uTimeoutMS, int *pvrcGuest);
    249249
     250    int wait(int *pvrcGuest);
     251
     252public:
     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
    250260protected:
    251261
  • trunk/src/VBox/Main/include/GuestSessionImplTasks.h

    r104636 r104640  
    354354
    355355/**
     356 * Implementation for a Guest Additions update process for logging process output to the release log.
     357 */
     358class UpdateAdditionsProcess : public GuestProcessWrapper
     359{
     360public:
     361
     362    UpdateAdditionsProcess(void) { }
     363
     364    virtual ~UpdateAdditionsProcess();
     365
     366    int onOutputCallback(uint32_t uHandle, const BYTE *pbData, size_t cbData);
     367
     368protected:
     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 */
     379class UpdateAdditionsStartupInfo : public GuestProcessStartupInfo
     380{
     381public:
     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/**
    356391 * Guest session task for automatically updating the Guest Additions on the guest.
    357392 */
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r104178 r104640  
    24442444}
    24452445
     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 */
     2456int 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 */
     2503int 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 */
     2542int 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 */
     2559int 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
    24462704///////////////////////////////////////////////////////////////////////////////
    24472705
     
    24762734 * @param   pvrcGuest           Where to return the guest error when
    24772735 *                              VERR_GSTCTL_GUEST_ERROR was returned. Optional.
     2736 *
     2737 * @sa GuestProcessWrapper::wait() -- mostly duplicate code, kept for backwards compatibility.
    24782738 */
    24792739int GuestProcessToolbox::waitEx(uint32_t fToolWaitFlags, GuestToolboxStreamBlock *pStrmBlkOut, int *pvrcGuest)
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r104637 r104640  
    24832483}
    24842484
     2485UpdateAdditionsProcess::~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 */
     2505int 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
    24852560GuestSessionTaskUpdateAdditions::GuestSessionTaskUpdateAdditions(GuestSession *pSession,
    24862561                                                                 const Utf8Str &strSource,
     
    26622737    LogRel(("Guest Additions Update: Running \"%s\" ...\n", procInfo.mName.c_str()));
    26632738
    2664     GuestProcessToolbox procToRun;
     2739    UpdateAdditionsProcess guestProc;
    26652740    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);
    26672742    if (RT_SUCCESS(vrc))
    26682743    {
    26692744        if (RT_SUCCESS(vrcGuest))
    2670             vrc = procToRun.wait(GUESTPROCESSTOOL_WAIT_FLAG_NONE, &vrcGuest);
     2745            vrc = guestProc.wait(&vrcGuest);
    26712746        if (RT_SUCCESS(vrc))
    2672             vrc = procToRun.getTerminationStatus();
     2747            vrc = guestProc.getTerminationStatus();
    26732748    }
    26742749
     
    26792754        {
    26802755            case VERR_GSTCTL_PROCESS_EXIT_CODE:
     2756            {
     2757                int32_t iExitCode;
     2758                vrc = guestProc.getTerminationStatus(&iExitCode);
     2759                Assert(vrc == VERR_GSTCTL_PROCESS_EXIT_CODE);
    26812760                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));
    26842763                break;
    26852764
     2765            }
    26862766            case VERR_GSTCTL_GUEST_ERROR:
    26872767                setUpdateErrorMsg(VBOX_E_GSTCTL_GUEST_ERROR, tr("Running update file on guest failed"),
     
    30983178                                    /* First pass: Copy over the file (first time only) + execute it to remove any
    30993179                                     *             existing VBox certificates. */
    3100                                     GuestProcessStartupInfo siCertUtilRem;
     3180                                    UpdateAdditionsStartupInfo siCertUtilRem;
    31013181                                    siCertUtilRem.mName = "VirtualBox Certificate Utility, removing old VirtualBox certificates";
    31023182                                    /* The argv[0] should contain full path to the executable module */
     
    31133193                                    /* Second pass: Only execute (but don't copy) again, this time installng the
    31143194                                     *              recent certificates just copied over. */
    3115                                     GuestProcessStartupInfo siCertUtilAdd;
     3195                                    UpdateAdditionsStartupInfo siCertUtilAdd;
    31163196                                    siCertUtilAdd.mName = "VirtualBox Certificate Utility, installing VirtualBox certificates";
    31173197                                    /* The argv[0] should contain full path to the executable module */
     
    31363216                                                     ISOFILE_FLAG_COPY_FROM_ISO));
    31373217                            /* The stub loader which decides which flavor to run. */
    3138                             GuestProcessStartupInfo siInstaller;
     3218                            UpdateAdditionsStartupInfo siInstaller;
    31393219                            siInstaller.mName = "VirtualBox Windows Guest Additions Installer";
    31403220                            /* Set a running timeout of 5 minutes -- the Windows Guest Additions
     
    31733253                                                     strUpdateDir + "VBoxLinuxAdditions.run", ISOFILE_FLAG_COPY_FROM_ISO));
    31743254
    3175                             GuestProcessStartupInfo siInstaller;
     3255                            UpdateAdditionsStartupInfo siInstaller;
    31763256                            siInstaller.mName = "VirtualBox Linux Guest Additions Installer";
    31773257                            /* 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.

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