/**
 *  Initializes itself by fetching error information from the given error info
 *  object.
 */
HRESULT VirtualBoxErrorInfo::init(IErrorInfo *aInfo)
{
    AssertReturn(aInfo, E_FAIL);

    HRESULT rc = S_OK;

    /* We don't return a failure if talking to IErrorInfo fails below to
     * protect ourselves from bad IErrorInfo implementations (the
     * corresponding fields will simply remain null in this case). */

    m_resultCode = S_OK;
    m_resultDetail = 0;
    rc = aInfo->GetGUID(m_IID.asOutParam());
    AssertComRC(rc);
    Bstr bstrComponent;
    rc = aInfo->GetSource(bstrComponent.asOutParam());
    AssertComRC(rc);
    m_strComponent = bstrComponent;
    Bstr bstrText;
    rc = aInfo->GetDescription(bstrText.asOutParam());
    AssertComRC(rc);
    m_strText = bstrText;

    return S_OK;
}
/**
 * List host information.
 *
 * @returns See produceList.
 * @param   pVirtualBox         Reference to the IVirtualBox smart pointer.
 */
static HRESULT listHostInfo(const ComPtr<IVirtualBox> pVirtualBox)
{
    HRESULT rc;
    ComPtr<IHost> Host;
    CHECK_ERROR(pVirtualBox, COMGETTER(Host)(Host.asOutParam()));

    RTPrintf("Host Information:\n\n");

    LONG64      u64UtcTime = 0;
    CHECK_ERROR(Host, COMGETTER(UTCTime)(&u64UtcTime));
    RTTIMESPEC  timeSpec;
    char        szTime[32];
    RTPrintf("Host time: %s\n", RTTimeSpecToString(RTTimeSpecSetMilli(&timeSpec, u64UtcTime), szTime, sizeof(szTime)));

    ULONG processorOnlineCount = 0;
    CHECK_ERROR(Host, COMGETTER(ProcessorOnlineCount)(&processorOnlineCount));
    RTPrintf("Processor online count: %lu\n", processorOnlineCount);
    ULONG processorCount = 0;
    CHECK_ERROR(Host, COMGETTER(ProcessorCount)(&processorCount));
    RTPrintf("Processor count: %lu\n", processorCount);
    ULONG processorOnlineCoreCount = 0;
    CHECK_ERROR(Host, COMGETTER(ProcessorOnlineCoreCount)(&processorOnlineCoreCount));
    RTPrintf("Processor online core count: %lu\n", processorOnlineCoreCount);
    ULONG processorCoreCount = 0;
    CHECK_ERROR(Host, COMGETTER(ProcessorCoreCount)(&processorCoreCount));
    RTPrintf("Processor core count: %lu\n", processorCoreCount);
    ULONG processorSpeed = 0;
    Bstr processorDescription;
    for (ULONG i = 0; i < processorCount; i++)
    {
        CHECK_ERROR(Host, GetProcessorSpeed(i, &processorSpeed));
        if (processorSpeed)
            RTPrintf("Processor#%u speed: %lu MHz\n", i, processorSpeed);
        else
            RTPrintf("Processor#%u speed: unknown\n", i);
        CHECK_ERROR(Host, GetProcessorDescription(i, processorDescription.asOutParam()));
        RTPrintf("Processor#%u description: %ls\n", i, processorDescription.raw());
    }

    ULONG memorySize = 0;
    CHECK_ERROR(Host, COMGETTER(MemorySize)(&memorySize));
    RTPrintf("Memory size: %lu MByte\n", memorySize);

    ULONG memoryAvailable = 0;
    CHECK_ERROR(Host, COMGETTER(MemoryAvailable)(&memoryAvailable));
    RTPrintf("Memory available: %lu MByte\n", memoryAvailable);

    Bstr operatingSystem;
    CHECK_ERROR(Host, COMGETTER(OperatingSystem)(operatingSystem.asOutParam()));
    RTPrintf("Operating system: %ls\n", operatingSystem.raw());

    Bstr oSVersion;
    CHECK_ERROR(Host, COMGETTER(OSVersion)(oSVersion.asOutParam()));
    RTPrintf("Operating system version: %ls\n", oSVersion.raw());
    return rc;
}
/**
 * Determines the requested balloon size to set for the specified machine.
 *
 * @return  Requested ballooning size (in MB), 0 if ballooning should be disabled.
 * @param   pMachine                Machine to determine maximum ballooning size for.
 */
static uint32_t balloonGetRequestedSize(PVBOXWATCHDOG_MACHINE pMachine)
{
    const ComPtr<IMachine> &rptrMachine = pMachine->machine;

    /*
     * The maximum balloning size can be set
     * - via per-VM extra-data ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
     * - via per-VM extra-data (legacy) ("VBoxInternal/Guest/BalloonSizeMax")
     *
     * Precedence from top to bottom.
     */
    uint32_t cMbBalloonReq = 0;
    char szSource[64];

    Bstr strValue;
    HRESULT hr = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
                                           strValue.asOutParam());
    if (   SUCCEEDED(hr)
        && strValue.isNotEmpty())
    {
        cMbBalloonReq = Utf8Str(strValue).toUInt32();
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data");
    }
    else
    {
        hr = rptrMachine->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
                                       strValue.asOutParam());
        if (   SUCCEEDED(hr)
            && strValue.isNotEmpty())
        {
            cMbBalloonReq = Utf8Str(strValue).toUInt32();
            if (g_fVerbose)
                RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data (legacy)");
        }
    }

    if (   FAILED(hr)
        || strValue.isEmpty())
    {
        cMbBalloonReq = 0;
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "none (disabled)");
    }

    serviceLogVerbose(("[%ls] Requested balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, cMbBalloonReq));
    return cMbBalloonReq;
}
/**
 * List media information.
 *
 * @returns See produceList.
 * @param   pVirtualBox         Reference to the IVirtualBox smart pointer.
 * @param   aMedia              Medium objects to list information for.
 * @param   pszParentUUIDStr    String with the parent UUID string (or "base").
 * @param   fOptLong            Long (@c true) or short list format.
 */
static HRESULT listMedia(const ComPtr<IVirtualBox> pVirtualBox,
                         const com::SafeIfaceArray<IMedium> &aMedia,
                         const char *pszParentUUIDStr,
                         bool fOptLong)
{
    HRESULT rc = S_OK;
    for (size_t i = 0; i < aMedia.size(); ++i)
    {
        ComPtr<IMedium> pMedium = aMedia[i];

        rc = showMediumInfo(pVirtualBox, pMedium, pszParentUUIDStr, fOptLong);

        RTPrintf("\n");

        com::SafeIfaceArray<IMedium> children;
        CHECK_ERROR(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(children)));
        if (children.size() > 0)
        {
            Bstr uuid;
            pMedium->COMGETTER(Id)(uuid.asOutParam());

            // depth first listing of child media
            rc = listMedia(pVirtualBox, children, Utf8Str(uuid).c_str(), fOptLong);
        }
    }

    return rc;
}
static int NetIfAdpCtl(HostNetworkInterface * pIf, const char *pszAddr, const char *pszOption, const char *pszMask)
{
    Bstr interfaceName;
    pIf->COMGETTER(Name)(interfaceName.asOutParam());
    Utf8Str strName(interfaceName);
    return NetIfAdpCtl(strName.c_str(), pszAddr, pszOption, pszMask);
}
Exemple #6
0
/**
 * Helper function used with "VBoxManage snapshot ... dump". Called from DumpSnapshot()
 * for each hard disk attachment found in a virtual machine. This then writes out the
 * root (base) medium for that hard disk attachment and recurses into the children
 * tree of that medium, correlating it with the snapshots of the machine.
 * @param pCurrentStateMedium constant, the medium listed in the current machine data (latest diff image).
 * @param pMedium variant, initially the base medium, then a child of the base medium when recursing.
 * @param pRootSnapshot constant, the root snapshot of the machine, if any; this then looks into the child snapshots.
 * @param pCurrentSnapshot constant, the machine's current snapshot (so we can mark it in the output).
 * @param uLevel variant, the recursion level for output indentation.
 */
void DumpMediumWithChildren(ComPtr<IMedium> &pCurrentStateMedium,
                            ComPtr<IMedium> &pMedium,
                            ComPtr<ISnapshot> &pRootSnapshot,
                            ComPtr<ISnapshot> &pCurrentSnapshot,
                            uint32_t uLevel)
{
    HRESULT rc;
    do
    {
        // print this medium
        Bstr bstrMediumName;
        CHECK_ERROR_BREAK(pMedium, COMGETTER(Name)(bstrMediumName.asOutParam()));
        RTPrintf("%*s  \"%ls\"%s\n",
                 uLevel * 2, "",            // indent
                 bstrMediumName.raw(),
                 (pCurrentStateMedium == pMedium) ? " (CURSTATE)" : "");

        // find and print the snapshot that uses this particular medium (diff image)
        FindAndPrintSnapshotUsingMedium(pMedium, pRootSnapshot, pCurrentSnapshot, uLevel, 0);

        // recurse into children
        SafeIfaceArray<IMedium> aChildren;
        CHECK_ERROR_BREAK(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(aChildren)));
        for (uint32_t i = 0;
                i < aChildren.size();
                ++i)
        {
            ComPtr<IMedium> pChild(aChildren[i]);
            DumpMediumWithChildren(pCurrentStateMedium, pChild, pRootSnapshot, pCurrentSnapshot, uLevel + 1);
        }
    } while (0);
}
Exemple #7
0
/**
 * Determines the maximum balloon size to set for the specified machine.
 *
 * @return  unsigned long           Balloon size (in MB) to set, 0 if no ballooning required.
 * @param   rptrMachine             Pointer to interface of specified machine.
 */
static unsigned long balloonGetMaxSize(const ComPtr<IMachine> &rptrMachine)
{
    /*
     * Try to retrieve the balloon maximum size via the following order:
     *  - command line parameter ("--balloon-max")
     *  Legacy (VBoxBalloonCtrl):
     *  - per-VM parameter ("VBoxInternal/Guest/BalloonSizeMax")
     *  Global:
     *  - global parameter ("VBoxInternal/Guest/BalloonSizeMax")
     *  New:
     *  - per-VM parameter ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
     *
     *  By default (e.g. if none of above is set), ballooning is disabled.
     */
    unsigned long ulBalloonMax = g_ulMemoryBalloonMaxMB;
    if (!ulBalloonMax)
    {
        int vrc = cfgGetValueULong(g_pVirtualBox, rptrMachine,
                                  "VBoxInternal/Guest/BalloonSizeMax", "VBoxInternal/Guest/BalloonSizeMax", &ulBalloonMax, 0 /* Ballooning disabled */);
        if (RT_FAILURE(vrc))
        {
            /* Try (new) VBoxWatch per-VM approach. */
            Bstr strValue;
            HRESULT rc = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
                                                   strValue.asOutParam());
            if (   SUCCEEDED(rc)
                && !strValue.isEmpty())
            {
                ulBalloonMax = Utf8Str(strValue).toUInt32();
            }
        }
    }

    return ulBalloonMax;
}
STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary)
{
    CheckComArgOutPointerValid(aLibrary);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    Bstr bstrLibrary;

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    bstrLibrary = mData->mAuthLibrary;
    alock.release();

    if (bstrLibrary.isEmpty())
    {
        /* Get the global setting. */
        ComPtr<ISystemProperties> systemProperties;
        HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());

        if (SUCCEEDED(hrc))
            hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());

        if (FAILED(hrc))
            return setError(hrc, "failed to query the library setting\n");
    }

    bstrLibrary.cloneTo(aLibrary);

    return S_OK;
}
STDMETHODIMP GuestFileEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent)
{
    switch (aType)
    {
    case VBoxEventType_OnGuestFileStateChanged:
    {
        HRESULT rc;
        do
        {
            ComPtr<IGuestFileStateChangedEvent> pEvent = aEvent;
            Assert(!pEvent.isNull());

            ComPtr<IGuestFile> pProcess;
            CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pProcess.asOutParam()));
            AssertBreak(!pProcess.isNull());
            FileStatus_T fileSts;
            CHECK_ERROR_BREAK(pEvent, COMGETTER(Status)(&fileSts));
            Bstr strPath;
            CHECK_ERROR_BREAK(pProcess, COMGETTER(FileName)(strPath.asOutParam()));
            ULONG uID;
            CHECK_ERROR_BREAK(pProcess, COMGETTER(Id)(&uID));

            RTPrintf("File ID=%RU32 \"%s\" changed status to [%s]\n",
                     uID, Utf8Str(strPath).c_str(), gctlFileStatusToText(fileSts));

        } while (0);
        break;
    }

    default:
        AssertFailed();
    }

    return S_OK;
}
HRESULT VRDEServer::getAuthLibrary(com::Utf8Str &aLibrary)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    aLibrary = mData->mAuthLibrary;
    alock.release();

    if (aLibrary.isEmpty())
    {
        /* Get the global setting. */
        ComPtr<ISystemProperties> systemProperties;
        HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());
        if (SUCCEEDED(hrc))
        {
            Bstr strlib;
            hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(strlib.asOutParam());
            if (SUCCEEDED(hrc))
                aLibrary = Utf8Str(strlib).c_str();
        }

        if (FAILED(hrc))
            return setError(hrc, "failed to query the library setting\n");
    }

    return S_OK;
}
static void listAffectedMetrics(ComPtr<IVirtualBox> aVirtualBox,
                                ComSafeArrayIn(IPerformanceMetric*, aMetrics))
{
    HRESULT rc;
    com::SafeIfaceArray<IPerformanceMetric> metrics(ComSafeArrayInArg(aMetrics));
    if (metrics.size())
    {
        ComPtr<IUnknown> object;
        Bstr metricName;
        RTPrintf("The following metrics were modified:\n\n"
                 "Object     Metric\n"
                 "---------- --------------------\n");
        for (size_t i = 0; i < metrics.size(); i++)
        {
            CHECK_ERROR(metrics[i], COMGETTER(Object)(object.asOutParam()));
            CHECK_ERROR(metrics[i], COMGETTER(MetricName)(metricName.asOutParam()));
            RTPrintf("%-10ls %-20ls\n",
                getObjectName(aVirtualBox, object).raw(), metricName.raw());
        }
        RTPrintf("\n");
    }
    else
    {
        RTMsgError("No metrics match the specified filter!");
    }
}
static RTEXITCODE handleCreate(HandlerArg *a)
{
    /*
     * Parse input.
     */
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState, a->argc, a->argv, NULL, 0, 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    int ch = RTGetOpt(&GetState, &ValueUnion);
    if (ch != 0)
        return errorGetOpt(USAGE_HOSTONLYIFS, ch, &ValueUnion);

    /*
     * Do the work.
     */
    ComPtr<IHost> host;
    CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);

    ComPtr<IHostNetworkInterface> hif;
    ComPtr<IProgress> progress;

    CHECK_ERROR2I_RET(host, CreateHostOnlyNetworkInterface(hif.asOutParam(), progress.asOutParam()), RTEXITCODE_FAILURE);

    /*HRESULT hrc =*/ showProgress(progress);
    CHECK_PROGRESS_ERROR_RET(progress, ("Failed to create the host-only adapter"), RTEXITCODE_FAILURE);

    Bstr bstrName;
    CHECK_ERROR2I(hif, COMGETTER(Name)(bstrName.asOutParam()));

    RTPrintf("Interface '%ls' was successfully created\n", bstrName.raw());

    return RTEXITCODE_SUCCESS;
}
Exemple #13
0
/**
 * @interface_method_impl{PDMIPCIRAWUP,pfnPciDeviceConstructComplete}
 */
DECLCALLBACK(int) PCIRawDev::drvDeviceConstructComplete(PPDMIPCIRAWCONNECTOR pInterface, const char *pcszName,
                                                        uint32_t uHostPCIAddress, uint32_t uGuestPCIAddress,
                                                        int rc)
{
    PDRVMAINPCIRAWDEV pThis = RT_FROM_CPP_MEMBER(pInterface, DRVMAINPCIRAWDEV, IConnector);
    Console *pConsole = pThis->pPCIRawDev->getParent();
    const ComPtr<IMachine>& machine = pConsole->machine();
    ComPtr<IVirtualBox> vbox;

    HRESULT hrc = machine->COMGETTER(Parent)(vbox.asOutParam());
    Assert(SUCCEEDED(hrc));

    ComPtr<IEventSource> es;
    hrc = vbox->COMGETTER(EventSource)(es.asOutParam());
    Assert(SUCCEEDED(hrc));

    Bstr bstrId;
    hrc = machine->COMGETTER(Id)(bstrId.asOutParam());
    Assert(SUCCEEDED(hrc));

    ComObjPtr<PCIDeviceAttachment> pda;
    BstrFmt bstrName(pcszName);
    pda.createObject();
    pda->init(machine, bstrName, uHostPCIAddress, uGuestPCIAddress, TRUE);

    Bstr msg("");
    if (RT_FAILURE(rc))
        msg = BstrFmt("runtime error %Rrc", rc);

    fireHostPCIDevicePlugEvent(es, bstrId.raw(), true /* plugged */, RT_SUCCESS(rc) /* success */, pda, msg.raw());

    return VINF_SUCCESS;
}
STDMETHODIMP VirtualBoxErrorInfo::GetGUID (GUID *guid)
{
    Bstr iid;
    HRESULT rc = COMGETTER(InterfaceID) (iid.asOutParam());
    if (SUCCEEDED(rc))
        *guid = Guid(iid).ref();
    return rc;
}
Exemple #15
0
void ErrorInfo::init(IVirtualBoxErrorInfo *info)
{
    AssertReturnVoid(info);

    HRESULT rc = E_FAIL;
    bool gotSomething = false;
    bool gotAll = true;
    LONG lrc, lrd;

    rc = info->COMGETTER(ResultCode)(&lrc); mResultCode = lrc;
    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);

    rc = info->COMGETTER(ResultDetail)(&lrd); mResultDetail = lrd;
    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);

    Bstr iid;
    rc = info->COMGETTER(InterfaceID)(iid.asOutParam());
    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);
    if (SUCCEEDED(rc))
    {
        mInterfaceID = iid;
        GetInterfaceNameByIID(mInterfaceID.ref(), mInterfaceName.asOutParam());
    }

    rc = info->COMGETTER(Component)(mComponent.asOutParam());
    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);

    rc = info->COMGETTER(Text)(mText.asOutParam());
    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);

    m_pNext = NULL;

    ComPtr<IVirtualBoxErrorInfo> next;
    rc = info->COMGETTER(Next)(next.asOutParam());
    if (SUCCEEDED(rc) && !next.isNull())
    {
        m_pNext = new ErrorInfo(next);
        Assert(m_pNext != NULL);
        if (!m_pNext)
            rc = E_OUTOFMEMORY;
    }

    gotSomething |= SUCCEEDED(rc);
    gotAll &= SUCCEEDED(rc);

    mIsBasicAvailable = gotSomething;
    mIsFullAvailable = gotAll;

    mErrorInfo = info;

    AssertMsg(gotSomething, ("Nothing to fetch!\n"));
}
HRESULT HostNetworkInterface::i_setVirtualBox(VirtualBox *pVirtualBox)
{
    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AssertReturn(mVirtualBox != pVirtualBox, S_OK);

    unconst(mVirtualBox) = pVirtualBox;

#if !defined(RT_OS_WINDOWS)
    /* If IPv4 address hasn't been initialized */
    if (m.IPAddress == 0 && mIfType == HostNetworkInterfaceType_HostOnly)
    {
        Bstr tmpAddr, tmpMask;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpAddr.asOutParam());
        if (FAILED(hrc) || tmpAddr.isEmpty())
            tmpAddr = getDefaultIPv4Address(mInterfaceName);

        hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
                                                mInterfaceName.c_str()).raw(),
                                        tmpMask.asOutParam());
        if (FAILED(hrc) || tmpMask.isEmpty())
            tmpMask = Bstr(VBOXNET_IPV4MASK_DEFAULT);

        m.IPAddress = inet_addr(Utf8Str(tmpAddr).c_str());
        m.networkMask = inet_addr(Utf8Str(tmpMask).c_str());
    }

    if (m.IPV6Address.isEmpty())
    {
        Bstr bstrIPV4Addr;
        Bstr tmpPrefixLen;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
                                                        mInterfaceName.c_str()).raw(),
                                                bstrIPV4Addr.asOutParam());
        if (SUCCEEDED(hrc))
        {
            m.IPV6Address = bstrIPV4Addr;
            if (!m.IPV6Address.isEmpty())
            {
                hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6PrefixLen",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpPrefixLen.asOutParam());
                if (SUCCEEDED(hrc) && !tmpPrefixLen.isEmpty())
                    m.IPV6NetworkMaskPrefixLength = Utf8Str(tmpPrefixLen).toUInt32();
                else
                    m.IPV6NetworkMaskPrefixLength = 64;
            }
        }
    }
#endif

    return S_OK;
}
static int vmListBuild()
{
    serviceLogVerbose(("Building VM list ...\n"));

    int rc = RTCritSectEnter(&g_csMachines);
    if (RT_SUCCESS(rc))
    {
        /*
         * Make sure the list is empty.
         */
        g_mapVM.clear();

        /*
         * Get the list of all _running_ VMs
         */
        com::SafeIfaceArray<IMachine> machines;
        HRESULT hrc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
        if (SUCCEEDED(hrc))
        {
            /*
             * Iterate through the collection
             */
            for (size_t i = 0; i < machines.size(); ++i)
            {
                if (machines[i])
                {
                    Bstr strUUID;
                    CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(strUUID.asOutParam()));

                    BOOL fAccessible;
                    CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
                    if (!fAccessible)
                    {
                        serviceLogVerbose(("Machine \"%ls\" is inaccessible, skipping\n",
                                           strUUID.raw()));
                        continue;
                    }

                    rc = machineAdd(strUUID);
                    if (RT_FAILURE(rc))
                        break;
                }
            }

            if (!machines.size())
                serviceLogVerbose(("No machines to add found at the moment!\n"));
        }

        int rc2 = RTCritSectLeave(&g_csMachines);
        if (RT_SUCCESS(rc))
            rc = rc2;
    }
    return rc;
}
static int handleGetGuestProperty(HandlerArg *a)
{
    HRESULT rc = S_OK;

    bool verbose = false;
    if (    a->argc == 3
        &&  (   !strcmp(a->argv[2], "--verbose")
             || !strcmp(a->argv[2], "-verbose")))
        verbose = true;
    else if (a->argc != 2)
        return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");

    ComPtr<IMachine> machine;
    CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
                                           machine.asOutParam()));
    if (machine)
    {
        /* open a session for the VM - new or existing */
        CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);

        /* get the mutable session machine */
        a->session->COMGETTER(Machine)(machine.asOutParam());

        Bstr value;
        LONG64 i64Timestamp;
        Bstr flags;
        CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]).raw(),
                                              value.asOutParam(),
                                              &i64Timestamp, flags.asOutParam()));
        if (value.isEmpty())
            RTPrintf("No value set!\n");
        else
            RTPrintf("Value: %ls\n", value.raw());
        if (!value.isEmpty() && verbose)
        {
            RTPrintf("Timestamp: %lld\n", i64Timestamp);
            RTPrintf("Flags: %ls\n", flags.raw());
        }
    }
    return SUCCEEDED(rc) ? 0 : 1;
}
/**
 * List video capture devices.
 *
 * @returns See produceList.
 * @param   pVirtualBox         Reference to the IVirtualBox pointer.
 */
static HRESULT listVideoInputDevices(const ComPtr<IVirtualBox> pVirtualBox)
{
    HRESULT rc;
    ComPtr<IHost> host;
    CHECK_ERROR(pVirtualBox, COMGETTER(Host)(host.asOutParam()));
    com::SafeIfaceArray<IHostVideoInputDevice> hostVideoInputDevices;
    CHECK_ERROR(host, COMGETTER(VideoInputDevices)(ComSafeArrayAsOutParam(hostVideoInputDevices)));
    RTPrintf("Video Input Devices: %u\n", hostVideoInputDevices.size());
    for (size_t i = 0; i < hostVideoInputDevices.size(); ++i)
    {
        ComPtr<IHostVideoInputDevice> p = hostVideoInputDevices[i];
        Bstr name;
        p->COMGETTER(Name)(name.asOutParam());
        Bstr path;
        p->COMGETTER(Path)(path.asOutParam());
        Bstr alias;
        p->COMGETTER(Alias)(alias.asOutParam());
        RTPrintf("%ls \"%ls\"\n%ls\n", alias.raw(), name.raw(), path.raw());
    }
    return rc;
}
static DECLCALLBACK(int) VBoxModAPIMonitorMain(void)
{
    static uint64_t uLastRun = 0;
    uint64_t uNow = RTTimeProgramMilliTS();
    uint64_t uDelta = uNow - uLastRun;
    if (uDelta < 1000) /* Only check every second (or later). */
        return VINF_SUCCESS;
    uLastRun = uNow;

    int vrc = VINF_SUCCESS;
    HRESULT rc;

#ifdef DEBUG
    serviceLogVerbose(("apimon: Checking for API heartbeat (%RU64ms) ...\n",
                       g_ulAPIMonIslnTimeoutMS));
#endif

    do
    {
        Bstr strHeartbeat;
        CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Heartbeat").raw(),
                                                      strHeartbeat.asOutParam()));
        if (   SUCCEEDED(rc)
            && !strHeartbeat.isEmpty()
            && g_strAPIMonIslnLastBeat.compare(strHeartbeat, Bstr::CaseSensitive))
        {
            serviceLogVerbose(("apimon: API heartbeat received, resetting timeout\n"));

            g_uAPIMonIslnLastBeatMS = 0;
            g_strAPIMonIslnLastBeat = strHeartbeat;
        }
        else
        {
            g_uAPIMonIslnLastBeatMS += uDelta;
            if (g_uAPIMonIslnLastBeatMS > g_ulAPIMonIslnTimeoutMS)
            {
                serviceLogVerbose(("apimon: No API heartbeat within time received (%RU64ms)\n",
                                   g_ulAPIMonIslnTimeoutMS));

                vrc = apimonTrigger(g_enmAPIMonIslnResp);
                g_uAPIMonIslnLastBeatMS = 0;
            }
        }
    } while (0);

    if (FAILED(rc))
        vrc = VERR_COM_IPRT_ERROR;

    return vrc;
}
int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVirtualBox, IN_GUID aId,
                                        IProgress **aProgress)
{
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    /* create a progress object */
    ComObjPtr<Progress> progress;
    progress.createObject();
    ComPtr<IHost> host;
    int rc = VINF_SUCCESS;
    HRESULT hr = pVirtualBox->COMGETTER(Host)(host.asOutParam());
    if (SUCCEEDED(hr))
    {
        Bstr ifname;
        ComPtr<IHostNetworkInterface> iface;
        if (FAILED(host->FindHostNetworkInterfaceById(Guid(aId).toUtf16().raw(), iface.asOutParam())))
            return VERR_INVALID_PARAMETER;
        iface->COMGETTER(Name)(ifname.asOutParam());
        if (ifname.isEmpty())
            return VERR_INTERNAL_ERROR;

        rc = progress->init(pVirtualBox, host,
                            Bstr("Removing host network interface").raw(),
                            FALSE /* aCancelable */);
        if (SUCCEEDED(rc))
        {
            progress.queryInterfaceTo(aProgress);
            rc = NetIfAdpCtl(Utf8Str(ifname).c_str(), "remove", NULL, NULL);
            if (RT_FAILURE(rc))
                progress->i_notifyComplete(E_FAIL,
                                           COM_IIDOF(IHostNetworkInterface),
                                           HostNetworkInterface::getStaticComponentName(),
                                           "Failed to execute '" VBOXNETADPCTL_NAME "' (exit status: %d)", rc);
            else
                progress->i_notifyComplete(S_OK);
        }
    }
    else
    {
        progress->i_notifyComplete(hr);
        rc = VERR_INTERNAL_ERROR;
    }
    return rc;
#else
    NOREF(pVirtualBox);
    NOREF(aId);
    NOREF(aProgress);
    return VERR_NOT_IMPLEMENTED;
#endif
}
/**
 * Determines whether ballooning for the specified machine is enabled or not.
 * This can be specified on a per-VM basis or as a globally set value for all VMs.
 *
 * @return  bool                    Whether ballooning is enabled or not.
 * @param   pMachine                Machine to determine enable status for.
 */
static bool balloonIsEnabled(PVBOXWATCHDOG_MACHINE pMachine)
{
    const ComPtr<IMachine> &rptrMachine = pMachine->machine;

    bool fEnabled = true; /* By default ballooning is enabled. */
    char szSource[64];

    Bstr strValue;
    HRESULT hr = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonEnabled").raw(),
                                             strValue.asOutParam());
    if (   SUCCEEDED(hr)
        && strValue.isNotEmpty())
    {
       if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "global extra-data");
    }
    else
    {
        hr = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonEnabled").raw(),
                                       strValue.asOutParam());
        if (SUCCEEDED(hr))
        {
            if (g_fVerbose)
                RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data");
        }
    }

    if (strValue.isNotEmpty())
    {
        fEnabled = RT_BOOL(Utf8Str(strValue).toUInt32());
        serviceLogVerbose(("[%ls] Ballooning is forced to %s (%s)\n",
                           pMachine->strName.raw(), fEnabled ? "enabled" : "disabled", szSource));
    }

    return fEnabled;
}
/**
 * List extension packs.
 *
 * @returns See produceList.
 * @param   pVirtualBox         Reference to the IVirtualBox smart pointer.
 */
static HRESULT listExtensionPacks(const ComPtr<IVirtualBox> &pVirtualBox)
{
    ComObjPtr<IExtPackManager> ptrExtPackMgr;
    CHECK_ERROR2_RET(pVirtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), hrcCheck);

    SafeIfaceArray<IExtPack> extPacks;
    CHECK_ERROR2_RET(ptrExtPackMgr, COMGETTER(InstalledExtPacks)(ComSafeArrayAsOutParam(extPacks)), hrcCheck);
    RTPrintf("Extension Packs: %u\n", extPacks.size());

    HRESULT hrc = S_OK;
    for (size_t i = 0; i < extPacks.size(); i++)
    {
        /* Read all the properties. */
        Bstr bstrName;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Name)(bstrName.asOutParam()),          hrc = hrcCheck; bstrName.setNull());
        Bstr bstrDesc;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Description)(bstrDesc.asOutParam()),   hrc = hrcCheck; bstrDesc.setNull());
        Bstr bstrVersion;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Version)(bstrVersion.asOutParam()),    hrc = hrcCheck; bstrVersion.setNull());
        ULONG uRevision;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Revision)(&uRevision),                 hrc = hrcCheck; uRevision = 0);
        Bstr bstrEdition;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Edition)(bstrEdition.asOutParam()),    hrc = hrcCheck; bstrEdition.setNull());
        Bstr bstrVrdeModule;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(VRDEModule)(bstrVrdeModule.asOutParam()),hrc=hrcCheck; bstrVrdeModule.setNull());
        BOOL fUsable;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(Usable)(&fUsable),                     hrc = hrcCheck; fUsable = FALSE);
        Bstr bstrWhy;
        CHECK_ERROR2_STMT(extPacks[i], COMGETTER(WhyUnusable)(bstrWhy.asOutParam()),    hrc = hrcCheck; bstrWhy.setNull());

        /* Display them. */
        if (i)
            RTPrintf("\n");
        RTPrintf("Pack no.%2zu:   %ls\n"
                 "Version:      %ls\n"
                 "Revision:     %u\n"
                 "Edition:      %ls\n"
                 "Description:  %ls\n"
                 "VRDE Module:  %ls\n"
                 "Usable:       %RTbool\n"
                 "Why unusable: %ls\n",
                 i, bstrName.raw(),
                 bstrVersion.raw(),
                 uRevision,
                 bstrEdition.raw(),
                 bstrDesc.raw(),
                 bstrVrdeModule.raw(),
                 fUsable != FALSE,
                 bstrWhy.raw());

        /* Query plugins and display them. */
    }
    return hrc;
}
Exemple #24
0
/**
 * Implementation for "VBoxManage snapshot ... dump". This goes thru the machine's
 * medium attachments and calls DumpMediumWithChildren() for each hard disk medium found,
 * which then dumps the parent/child tree of that medium together with the corresponding
 * snapshots.
 * @param pMachine Machine to dump snapshots for.
 */
void DumpSnapshot(ComPtr<IMachine> &pMachine)
{
    HRESULT rc;

    do
    {
        // get root snapshot
        ComPtr<ISnapshot> pSnapshot;
        CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr("").raw(), pSnapshot.asOutParam()));

        // get current snapshot
        ComPtr<ISnapshot> pCurrentSnapshot;
        CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()));

        // get media attachments
        SafeIfaceArray<IMediumAttachment> aAttachments;
        CHECK_ERROR_BREAK(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
        for (uint32_t i = 0;
                i < aAttachments.size();
                ++i)
        {
            ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
            DeviceType_T type;
            CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
            if (type == DeviceType_HardDisk)
            {
                ComPtr<IMedium> pCurrentStateMedium;
                CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pCurrentStateMedium.asOutParam()));

                ComPtr<IMedium> pBaseMedium;
                CHECK_ERROR_BREAK(pCurrentStateMedium, COMGETTER(Base)(pBaseMedium.asOutParam()));

                Bstr bstrBaseMediumName;
                CHECK_ERROR_BREAK(pBaseMedium, COMGETTER(Name)(bstrBaseMediumName.asOutParam()));

                RTPrintf("[%RI32] Images and snapshots for medium \"%ls\"\n", i, bstrBaseMediumName.raw());

                DumpMediumWithChildren(pCurrentStateMedium,
                                       pBaseMedium,
                                       pSnapshot,
                                       pCurrentSnapshot,
                                       0);
            }
        }
    } while (0);
}
/**
 *  Saves settings to the given machine node.
 *
 *  @param aMachineNode <Machine> node.
 *
 *  @note Locks this object for reading.
 */
HRESULT USBController::saveSettings(settings::USBController &data)
{
    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    data.fEnabled = !!m->bd->fEnabled;
    data.fEnabledEHCI = !!m->bd->fEnabledEHCI;

#ifdef VBOX_WITH_USB
    data.llDeviceFilters.clear();

    for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
         it != m->llDeviceFilters->end();
         ++it)
    {
        AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
        const USBDeviceFilter::Data &filterData = (*it)->getData();

        Bstr str;

        settings::USBDeviceFilter f;
        f.strName = filterData.mName;
        f.fActive = !!filterData.mActive;
        (*it)->COMGETTER(VendorId)(str.asOutParam());
        f.strVendorId = str;
        (*it)->COMGETTER(ProductId)(str.asOutParam());
        f.strProductId = str;
        (*it)->COMGETTER (Revision) (str.asOutParam());
        f.strRevision = str;
        (*it)->COMGETTER (Manufacturer) (str.asOutParam());
        f.strManufacturer = str;
        (*it)->COMGETTER (Product) (str.asOutParam());
        f.strProduct = str;
        (*it)->COMGETTER (SerialNumber) (str.asOutParam());
        f.strSerialNumber = str;
        (*it)->COMGETTER (Port) (str.asOutParam());
        f.strPort = str;
        f.strRemote = filterData.mRemote.string();
        f.ulMaskedInterfaces = filterData.mMaskedIfs;

        data.llDeviceFilters.push_back(f);
    }
#endif /* VBOX_WITH_USB */

    return S_OK;
}
static RTEXITCODE  handleRemove(HandlerArg *a)
{
    /*
     * Parse input.
     */
    const char *pszName = NULL;
    int ch;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    RTGetOptInit(&GetState, a->argc, a->argv, NULL, 0, 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
        switch (ch)
        {
            case VINF_GETOPT_NOT_OPTION:
                if (pszName)
                    return errorSyntax(USAGE_HOSTONLYIFS, "Only one interface name can be specified");
                pszName = ValueUnion.psz;
                break;

            default:
                return errorGetOpt(USAGE_HOSTONLYIFS, ch, &ValueUnion);
        }
    if (!pszName)
        return errorSyntax(USAGE_HOSTONLYIFS, "No interface name was specified");

    /*
     * Do the work.
     */
    ComPtr<IHost> host;
    CHECK_ERROR2I_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);

    ComPtr<IHostNetworkInterface> hif;
    CHECK_ERROR2I_RET(host, FindHostNetworkInterfaceByName(Bstr(pszName).raw(), hif.asOutParam()), RTEXITCODE_FAILURE);

    Bstr guid;
    CHECK_ERROR2I_RET(hif, COMGETTER(Id)(guid.asOutParam()), RTEXITCODE_FAILURE);

    ComPtr<IProgress> progress;
    CHECK_ERROR2I_RET(host, RemoveHostOnlyNetworkInterface(guid.raw(), progress.asOutParam()), RTEXITCODE_FAILURE);

    /*HRESULT hrc =*/ showProgress(progress);
    CHECK_PROGRESS_ERROR_RET(progress, ("Failed to remove the host-only adapter"), RTEXITCODE_FAILURE);

    return RTEXITCODE_SUCCESS;
}
static Bstr getObjectName(ComPtr<IVirtualBox> aVirtualBox,
                                  ComPtr<IUnknown> aObject)
{
    HRESULT rc;

    ComPtr<IHost> host = aObject;
    if (!host.isNull())
        return Bstr("host");

    ComPtr<IMachine> machine = aObject;
    if (!machine.isNull())
    {
        Bstr name;
        CHECK_ERROR(machine, COMGETTER(Name)(name.asOutParam()));
        if (SUCCEEDED(rc))
            return name;
    }
    return Bstr("unknown");
}
/**
 * Determines the maximum balloon size to set for the specified machine.
 *
 * @return  Maximum ballooning size (in MB), 0 if no maximum set.
 * @param   pMachine                Machine to determine maximum ballooning size for.
 */
static uint32_t balloonGetMaxSize(PVBOXWATCHDOG_MACHINE pMachine)
{
    /*
     * Is a maximum ballooning size set? Make sure we're within bounds.
     *
     * The maximum balloning size can be set
     * - via global extra-data ("VBoxInternal/Guest/BalloonSizeMax")
     * - via command line ("--balloon-max")
     *
     * Precedence from top to bottom.
     */
    uint32_t cMbBalloonMax = 0;
    char szSource[64];

    Bstr strValue;
    HRESULT hr = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
                                             strValue.asOutParam());
    if (   SUCCEEDED(hr)
        && strValue.isNotEmpty())
    {
        cMbBalloonMax = Utf8Str(strValue).toUInt32();
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "global extra-data");
    }

    if (strValue.isEmpty())
    {
        Assert(cMbBalloonMax == 0);

        cMbBalloonMax = g_cMbMemoryBalloonMax;
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "command line");
    }

    serviceLogVerbose(("[%ls] Maximum balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, cMbBalloonMax));
    return cMbBalloonMax;
}
        STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
        {
            switch (aType)
            {
                case VBoxEventType_OnMachineRegistered:
                {
                    ComPtr<IMachineRegisteredEvent> pEvent = aEvent;
                    Assert(pEvent);

                    Bstr uuid;
                    BOOL fRegistered;
                    HRESULT hr = pEvent->COMGETTER(Registered)(&fRegistered);
                    if (SUCCEEDED(hr))
                        hr = pEvent->COMGETTER(MachineId)(uuid.asOutParam());

                    if (SUCCEEDED(hr))
                    {
                        int rc = RTCritSectEnter(&g_csMachines);
                        if (RT_SUCCESS(rc))
                        {
                            rc = fRegistered
                               ? machineAdd(uuid)
                               : machineRemove(uuid);
                            int rc2 = RTCritSectLeave(&g_csMachines);
                            if (RT_SUCCESS(rc))
                                rc = rc2;
                            AssertRC(rc);
                        }
                    }
                    break;
                }

                case VBoxEventType_OnMachineStateChanged:
                {
                    ComPtr<IMachineStateChangedEvent> pEvent = aEvent;
                    Assert(pEvent);

                    MachineState_T machineState;
                    Bstr uuid;

                    HRESULT hr = pEvent->COMGETTER(State)(&machineState);
                    if (SUCCEEDED(hr))
                        hr = pEvent->COMGETTER(MachineId)(uuid.asOutParam());

                    if (SUCCEEDED(hr))
                    {
                        int rc = RTCritSectEnter(&g_csMachines);
                        if (RT_SUCCESS(rc))
                        {
                            for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++)
                                if (g_aModules[j].fEnabled)
                                {
                                    int rc2 = g_aModules[j].pDesc->pfnOnMachineStateChanged(uuid,
                                                                                            machineState);
                                    if (RT_FAILURE(rc2))
                                        serviceLog("Module '%s' reported an error: %Rrc\n",
                                                   g_aModules[j].pDesc->pszName, rc);
                                    /* Keep going. */
                                }

                            int rc2 = RTCritSectLeave(&g_csMachines);
                            if (RT_SUCCESS(rc))
                                rc = rc2;
                            AssertRC(rc);
                        }
                    }
                    break;
                }

                case VBoxEventType_OnVBoxSVCAvailabilityChanged:
                {
                    ComPtr<IVBoxSVCAvailabilityChangedEvent> pVSACEv = aEvent;
                    Assert(pVSACEv);
                    BOOL fAvailable = FALSE;
                    pVSACEv->COMGETTER(Available)(&fAvailable);

                    /* First, notify all modules. */
                    for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++)
                        if (g_aModules[j].fEnabled)
                        {
                            int rc2 = g_aModules[j].pDesc->pfnOnServiceStateChanged(RT_BOOL(fAvailable));
                            if (RT_FAILURE(rc2))
                                serviceLog("Module '%s' reported an error: %Rrc\n",
                                           g_aModules[j].pDesc->pszName, rc2);
                            /* Keep going. */
                        }

                    /* Do global teardown/re-creation stuff. */
                    if (!fAvailable)
                    {
                        serviceLog("VBoxSVC became unavailable\n");
                        watchdogShutdown();
                    }
                    else
                    {
                        serviceLog("VBoxSVC became available\n");
                        int rc2 = watchdogSetup();
                        if (RT_FAILURE(rc2))
                            serviceLog("Unable to re-set up watchdog (rc=%Rrc)!\n", rc2);
                    }

                    break;
                }

                default:
                    /* Not handled event, just skip it. */
                    break;
            }

            return S_OK;
        }
int handleGetExtraData(HandlerArg *a)
{
    HRESULT rc = S_OK;

    if (a->argc != 2)
        return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");

    /* global data? */
    if (!strcmp(a->argv[0], "global"))
    {
        /* enumeration? */
        if (!strcmp(a->argv[1], "enumerate"))
        {
            SafeArray<BSTR> aKeys;
            CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));

            for (size_t i = 0;
                 i < aKeys.size();
                 ++i)
            {
                Bstr bstrKey(aKeys[i]);
                Bstr bstrValue;
                CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey.raw(),
                                                        bstrValue.asOutParam()));

                RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
            }
        }
        else
        {
            Bstr value;
            CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]).raw(),
                                                    value.asOutParam()));
            if (!value.isEmpty())
                RTPrintf("Value: %ls\n", value.raw());
            else
                RTPrintf("No value set!\n");
        }
    }
    else
    {
        ComPtr<IMachine> machine;
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
                                               machine.asOutParam()));
        if (machine)
        {
            /* enumeration? */
            if (!strcmp(a->argv[1], "enumerate"))
            {
                SafeArray<BSTR> aKeys;
                CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));

                for (size_t i = 0;
                    i < aKeys.size();
                    ++i)
                {
                    Bstr bstrKey(aKeys[i]);
                    Bstr bstrValue;
                    CHECK_ERROR(machine, GetExtraData(bstrKey.raw(),
                                                      bstrValue.asOutParam()));

                    RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
                }
            }
            else
            {
                Bstr value;
                CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]).raw(),
                                                  value.asOutParam()));
                if (!value.isEmpty())
                    RTPrintf("Value: %ls\n", value.raw());
                else
                    RTPrintf("No value set!\n");
            }
        }
    }
    return SUCCEEDED(rc) ? 0 : 1;
}