/**
 * 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;
}
/**
 * Issued by the guest when a guest user changed its state.
 *
 * @return  IPRT status code.
 * @param   aUser               Guest user name.
 * @param   aDomain             Domain of guest user account. Optional.
 * @param   enmState            New state to indicate.
 * @param   pbDetails           Pointer to state details. Optional.
 * @param   cbDetails           Size (in bytes) of state details. Pass 0 if not used.
 */
void Guest::i_onUserStateChange(Bstr aUser, Bstr aDomain, VBoxGuestUserState enmState,
                                const uint8_t *pbDetails, uint32_t cbDetails)
{
    LogFlowThisFunc(("\n"));

    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    Bstr strDetails; /** @todo Implement state details here. */

    fireGuestUserStateChangedEvent(mEventSource, aUser.raw(), aDomain.raw(),
                                   (GuestUserState_T)enmState, strDetails.raw());
    LogFlowFuncLeave();
}
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!");
    }
}
示例#4
0
/**
 * Sets the Guest Additions version information details.
 * Gets called by vmmdevUpdateGuestInfo2.
 *
 * @param aAdditionsVersion
 * @param aVersionName
 */
void Guest::setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision)
{
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!aVersionName.isEmpty())
        /*
         * aVersionName could be "x.y.z_BETA1_FOOBAR", so append revision manually to
         * become "x.y.z_BETA1_FOOBAR r12345".
         */
        mData.mAdditionsVersion = BstrFmt("%ls r%ls", aVersionName.raw(), aRevision.raw());
    else /* aAdditionsVersion is in x.y.zr12345 format. */
        mData.mAdditionsVersion = aAdditionsVersion;
}
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;
}
示例#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);
}
示例#7
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;
}
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;
}
示例#11
0
RTEXITCODE handleUSBDevSource(HandlerArg *a)
{
    HRESULT rc = S_OK;

    /* at least: 0: command, 1: source id */
    if (a->argc < 2)
        return errorSyntax(USAGE_USBDEVSOURCE, "Not enough parameters");

    ComPtr<IHost> host;
    if (!strcmp(a->argv[0], "add"))
    {
        Bstr strBackend;
        Bstr strAddress;
        if (a->argc != 6)
            return errorSyntax(USAGE_USBDEVSOURCE, "Invalid number of parameters");

        for (int i = 2; i < a->argc; i++)
        {
            if (!strcmp(a->argv[i], "--backend"))
            {
                i++;
                strBackend = a->argv[i];
            }
            else if (!strcmp(a->argv[i], "--address"))
            {
                i++;
                strAddress = a->argv[i];
            }
            else
                return errorSyntax(USAGE_USBDEVSOURCE, "Parameter \"%s\" is invalid", a->argv[i]);
        }

        SafeArray<BSTR> usbSourcePropNames;
        SafeArray<BSTR> usbSourcePropValues;

        CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
        CHECK_ERROR_RET(host, AddUSBDeviceSource(strBackend.raw(), Bstr(a->argv[1]).raw(), strAddress.raw(),
                                                 ComSafeArrayAsInParam(usbSourcePropNames), ComSafeArrayAsInParam(usbSourcePropValues)),
                        RTEXITCODE_FAILURE);
    }
    else if (!strcmp(a->argv[0], "remove"))
    {
        CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
        CHECK_ERROR_RET(host, RemoveUSBDeviceSource(Bstr(a->argv[1]).raw()), RTEXITCODE_FAILURE);
    }

    return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
示例#12
0
void GluePrintErrorInfo(const com::ErrorInfo &info)
{
    bool haveResultCode = false;
#if defined (RT_OS_WIN)
    haveResultCode = info.isFullAvailable();
    bool haveComponent = true;
    bool haveInterfaceID = true;
#else /* defined (RT_OS_WIN) */
    haveResultCode = true;
    bool haveComponent = info.isFullAvailable();
    bool haveInterfaceID = info.isFullAvailable();
#endif

    Utf8Str str;
    RTCList<Utf8Str> comp;

    Bstr bstrDetailsText = info.getText();
    if (!bstrDetailsText.isEmpty())
        str = Utf8StrFmt("%ls\n",
                         bstrDetailsText.raw());
    if (haveResultCode)
        comp.append(Utf8StrFmt("code %Rhrc (0x%RX32)",
                               info.getResultCode(),
                               info.getResultCode()));
    if (haveComponent)
        comp.append(Utf8StrFmt("component %ls",
                               info.getComponent().raw()));
    if (haveInterfaceID)
        comp.append(Utf8StrFmt("interface %ls",
                               info.getInterfaceName().raw()));
    if (!info.getCalleeName().isEmpty())
        comp.append(Utf8StrFmt("callee %ls",
                               info.getCalleeName().raw()));

    if (comp.size() > 0)
    {
        str += "Details: ";
        for (size_t i = 0; i < comp.size() - 1; ++i)
            str += comp.at(i) + ", ";
        str += comp.last();
        str += "\n";
    }

    // print and log
    RTMsgError("%s", str.c_str());
    Log(("ERROR: %s", str.c_str()));
}
/**
 * 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;
}
示例#14
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);
}
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;
}
STDMETHODIMP VFSExplorer::Update(IProgress **aProgress)
{
    CheckComArgOutPointerValid(aProgress);

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

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT rc = S_OK;

    ComObjPtr<Progress> progress;
    try
    {
        Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
                                    m->strPath.c_str());
        /* Create the progress object */
        progress.createObject();

        rc = progress->init(mVirtualBox,
                            static_cast<IVFSExplorer*>(this),
                            progressDesc.raw(),
                            TRUE /* aCancelable */);
        if (FAILED(rc)) throw rc;

        /* Initialize our worker task */
        std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress));

        rc = task->startThread();
        if (FAILED(rc)) throw rc;

        /* Don't destruct on success */
        task.release();
    }
    catch (HRESULT aRC)
    {
        rc = aRC;
    }

    if (SUCCEEDED(rc))
        /* Return progress to the caller */
        progress.queryInterfaceTo(aProgress);

    return rc;
}
/**
 * Initializes the host object.
 *
 * @returns COM result indicator
 * @param   aInterfaceName name of the network interface
 * @param   aGuid GUID of the host network interface
 */
HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Guid aGuid, HostNetworkInterfaceType_T ifType)
{
    LogFlowThisFunc(("aInterfaceName={%ls}, aGuid={%s}\n",
                      aInterfaceName.raw(), aGuid.toString().c_str()));

    ComAssertRet(!aInterfaceName.isEmpty(), E_INVALIDARG);
    ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG);

    /* Enclose the state transition NotReady->InInit->Ready */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), E_FAIL);

    unconst(mInterfaceName) = aInterfaceName;
    unconst(mGuid) = aGuid;
    mIfType = ifType;

    /* Confirm a successful initialization */
    autoInitSpan.setSucceeded();

    return S_OK;
}
/**
 * Removes a specified machine from the list of handled machines.
 * Does not do locking -- needs to be done by caller!
 *
 * @return  IPRT status code.
 * @param   strUuid                 UUID of the specified machine.
 */
static int machineRemove(const Bstr &strUuid)
{
    AssertReturn(!strUuid.isEmpty(), VERR_INVALID_PARAMETER);
    int rc = VINF_SUCCESS;

    mapVMIter it = g_mapVM.find(strUuid);
    if (it != g_mapVM.end())
    {
        int rc2 = machineDestroy(strUuid);
        if (RT_FAILURE(rc))
        {
            serviceLog(("Machine \"%ls\" failed to destroy, rc=%Rc\n"));
            if (RT_SUCCESS(rc))
                rc = rc2;
        }
    }
    else
    {
        serviceLogVerbose(("Warning: Removing not added machine \"%ls\"\n", strUuid.raw()));
        rc = VERR_NOT_FOUND;
    }

    return rc;
}
static int machineDestroy(const Bstr &strUuid)
{
    AssertReturn(!strUuid.isEmpty(), VERR_INVALID_PARAMETER);
    int rc = VINF_SUCCESS;

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

    /* Must log before erasing the iterator because of the UUID ref! */
    serviceLogVerbose(("Removing machine \"%ls\"\n", strUuid.raw()));

    try
    {
        mapVMIter itVM = g_mapVM.find(strUuid);
        Assert(itVM != g_mapVM.end());

        /* Remove machine from group(s). */
        mapGroupsIterConst itGroups = itVM->second.groups.begin();
        while (itGroups != itVM->second.groups.end())
        {
            mapGroupIter itGroup = g_mapGroup.find(itGroups->first);
            Assert(itGroup != g_mapGroup.end());

            vecGroupMembers vecMembers = itGroup->second;
            vecGroupMembersIter itMember = std::find(vecMembers.begin(),
                                                     vecMembers.end(),
                                                     strUuid);
            Assert(itMember != vecMembers.end());
            vecMembers.erase(itMember);

            serviceLogVerbose(("Group \"%s\" has %ld machines left\n",
                               itGroup->first.c_str(), vecMembers.size()));
            if (!vecMembers.size())
            {
                serviceLogVerbose(("Deleting group \"%s\"\n", itGroup->first.c_str()));
                g_mapGroup.erase(itGroup);
            }

            ++itGroups;
        }

#ifndef VBOX_WATCHDOG_GLOBAL_PERFCOL
        itVM->second.collector.setNull();
#endif
        itVM->second.machine.setNull();

        /*
         * Remove machine from map.
         */
        g_mapVM.erase(itVM);
    }
    catch (...)
    {
        AssertFailed();
    }

    return rc;
}
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;
}
/**
 * Adds a specified machine to the list (map) of handled machines.
 * Does not do locking -- needs to be done by caller!
 *
 * @return  IPRT status code.
 * @param   strUuid                 UUID of the specified machine.
 */
static int machineAdd(const Bstr &strUuid)
{
    HRESULT rc;

    /** @todo Add exception handling! */

    do
    {
        ComPtr <IMachine> machine;
        CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine(strUuid.raw(), machine.asOutParam()));
        Assert(!machine.isNull());

        /*
         * Get groups for this machine.
        */
        com::SafeArray<BSTR> groups;
        CHECK_ERROR_BREAK(machine, COMGETTER(Groups)(ComSafeArrayAsOutParam(groups)));
        Utf8Str strGroups;
        for (size_t i = 0; i < groups.size(); i++)
        {
            if (i != 0)
                strGroups.append(",");
            strGroups.append(Utf8Str(groups[i]));
        }

        /*
         * Add machine to map.
         */
        VBOXWATCHDOG_MACHINE m;
        m.machine = machine;
        int rc2 = groupAdd(m.groups, strGroups.c_str(), 0 /* Flags */);
        AssertRC(rc2);

        mapVMIter it = g_mapVM.find(strUuid);
        Assert(it == g_mapVM.end());
        g_mapVM.insert(std::make_pair(strUuid, m));
        serviceLogVerbose(("Added machine \"%ls\"\n", strUuid.raw()));

        /*
         * Get the machine's VM group(s).
         */
        mapGroupsIterConst itGroup = m.groups.begin();
        while (itGroup != m.groups.end())
        {
            serviceLogVerbose(("Machine \"%ls\" is in VM group \"%s\"\n",
                               strUuid.raw(), itGroup->first.c_str()));

            /* Add machine to group(s). */
            mapGroupIter itGroups = g_mapGroup.find(itGroup->first);
            if (itGroups == g_mapGroup.end())
            {
                vecGroupMembers vecMembers;
                vecMembers.push_back(strUuid);
                g_mapGroup.insert(std::make_pair(itGroup->first, vecMembers));

                itGroups = g_mapGroup.find(itGroup->first);
                Assert(itGroups != g_mapGroup.end());
            }
            else
                itGroups->second.push_back(strUuid);
            serviceLogVerbose(("Group \"%s\" has now %ld machine(s)\n",
                               itGroup->first.c_str(), itGroups->second.size()));
            ++itGroup;
        }

        /*
         * Let all modules know. Typically all modules would register
         * their per-machine payload here.
         */
        for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++)
            if (g_aModules[j].fEnabled)
            {
                rc2 = g_aModules[j].pDesc->pfnOnMachineRegistered(strUuid);
                if (RT_FAILURE(rc2))
                    serviceLog("OnMachineRegistered: Module '%s' reported an error: %Rrc\n",
                               g_aModules[j].pDesc->pszName, rc);
                /* Keep going. */
            }

    } while (0);

    /** @todo Add std exception handling! */

    return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_COM_IPRT_ERROR; /* @todo Find a better error! */
}
int handleCloneVM(HandlerArg *a)
{
    HRESULT                        rc;
    const char                    *pszSrcName       = NULL;
    const char                    *pszSnapshotName  = NULL;
    CloneMode_T                    mode             = CloneMode_MachineState;
    com::SafeArray<CloneOptions_T> options;
    const char                    *pszTrgName       = NULL;
    const char                    *pszTrgBaseFolder = NULL;
    bool                           fRegister        = false;
    Bstr                           bstrUuid;
    com::SafeArray<BSTR> groups;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneVMOptions, RT_ELEMENTS(g_aCloneVMOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 's':   // --snapshot
                pszSnapshotName = ValueUnion.psz;
                break;

            case 'n':   // --name
                pszTrgName = ValueUnion.psz;
                break;

            case 'g':   // --groups
                parseGroups(ValueUnion.psz, &groups);
                break;

            case 'p':   // --basefolder
                pszTrgBaseFolder = ValueUnion.psz;
                break;

            case 'm':   // --mode
                if (RT_FAILURE(parseCloneMode(ValueUnion.psz, &mode)))
                    return errorArgument("Invalid clone mode '%s'\n", ValueUnion.psz);
                break;

            case 'o':   // --options
                if (RT_FAILURE(parseCloneOptions(ValueUnion.psz, &options)))
                    return errorArgument("Invalid clone options '%s'\n", ValueUnion.psz);
                break;

            case 'u':   // --uuid
                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
                break;

            case 'r':   // --register
                fRegister = true;
                break;

            case VINF_GETOPT_NOT_OPTION:
                if (!pszSrcName)
                    pszSrcName = ValueUnion.psz;
                else
                    return errorSyntax(USAGE_CLONEVM, "Invalid parameter '%s'", ValueUnion.psz);
                break;

            default:
                return errorGetOpt(USAGE_CLONEVM, c, &ValueUnion);
        }
    }

    /* Check for required options */
    if (!pszSrcName)
        return errorSyntax(USAGE_CLONEVM, "VM name required");

    /* Get the machine object */
    ComPtr<IMachine> srcMachine;
    CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(pszSrcName).raw(),
                                               srcMachine.asOutParam()),
                    RTEXITCODE_FAILURE);

    /* If a snapshot name/uuid was given, get the particular machine of this
     * snapshot. */
    if (pszSnapshotName)
    {
        ComPtr<ISnapshot> srcSnapshot;
        CHECK_ERROR_RET(srcMachine, FindSnapshot(Bstr(pszSnapshotName).raw(),
                                                 srcSnapshot.asOutParam()),
                        RTEXITCODE_FAILURE);
        CHECK_ERROR_RET(srcSnapshot, COMGETTER(Machine)(srcMachine.asOutParam()),
                        RTEXITCODE_FAILURE);
    }

    /* Default name necessary? */
    if (!pszTrgName)
        pszTrgName = RTStrAPrintf2("%s Clone", pszSrcName);

    Bstr createFlags;
    if (!bstrUuid.isEmpty())
        createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
    Bstr bstrPrimaryGroup;
    if (groups.size())
        bstrPrimaryGroup = groups[0];
    Bstr bstrSettingsFile;
    CHECK_ERROR_RET(a->virtualBox,
                    ComposeMachineFilename(Bstr(pszTrgName).raw(),
                                           bstrPrimaryGroup.raw(),
                                           createFlags.raw(),
                                           Bstr(pszTrgBaseFolder).raw(),
                                           bstrSettingsFile.asOutParam()),
                    RTEXITCODE_FAILURE);

    ComPtr<IMachine> trgMachine;
    CHECK_ERROR_RET(a->virtualBox, CreateMachine(bstrSettingsFile.raw(),
                                                 Bstr(pszTrgName).raw(),
                                                 ComSafeArrayAsInParam(groups),
                                                 NULL,
                                                 createFlags.raw(),
                                                 trgMachine.asOutParam()),
                    RTEXITCODE_FAILURE);

    /* Start the cloning */
    ComPtr<IProgress> progress;
    CHECK_ERROR_RET(srcMachine, CloneTo(trgMachine,
                                        mode,
                                        ComSafeArrayAsInParam(options),
                                        progress.asOutParam()),
                    RTEXITCODE_FAILURE);
    rc = showProgress(progress);
    CHECK_PROGRESS_ERROR_RET(progress, ("Clone VM failed"), RTEXITCODE_FAILURE);

    if (fRegister)
        CHECK_ERROR_RET(a->virtualBox, RegisterMachine(trgMachine), RTEXITCODE_FAILURE);

    Bstr bstrNewName;
    CHECK_ERROR_RET(trgMachine, COMGETTER(Name)(bstrNewName.asOutParam()), RTEXITCODE_FAILURE);
    RTPrintf("Machine has been successfully cloned as \"%ls\"\n", bstrNewName.raw());

    return RTEXITCODE_SUCCESS;
}
int handleStartVM(HandlerArg *a)
{
    HRESULT rc = S_OK;
    std::list<const char *> VMs;
    Bstr sessionType = "gui";

    static const RTGETOPTDEF s_aStartVMOptions[] =
    {
        { "--type",         't', RTGETOPT_REQ_STRING },
        { "-type",          't', RTGETOPT_REQ_STRING },     // deprecated
    };
    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, s_aStartVMOptions, RT_ELEMENTS(s_aStartVMOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 't':   // --type
                if (!RTStrICmp(ValueUnion.psz, "gui"))
                {
                    sessionType = "gui";
                }
#ifdef VBOX_WITH_VBOXSDL
                else if (!RTStrICmp(ValueUnion.psz, "sdl"))
                {
                    sessionType = "sdl";
                }
#endif
#ifdef VBOX_WITH_HEADLESS
                else if (!RTStrICmp(ValueUnion.psz, "capture"))
                {
                    sessionType = "capture";
                }
                else if (!RTStrICmp(ValueUnion.psz, "headless"))
                {
                    sessionType = "headless";
                }
#endif
                else
                    sessionType = ValueUnion.psz;
                break;

            case VINF_GETOPT_NOT_OPTION:
                VMs.push_back(ValueUnion.psz);
                break;

            default:
                if (c > 0)
                {
                    if (RT_C_IS_PRINT(c))
                        return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
                    else
                        return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
                }
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
                    return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
                else if (ValueUnion.pDef)
                    return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
                else
                    return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
        }
    }

    /* check for required options */
    if (VMs.empty())
        return errorSyntax(USAGE_STARTVM, "at least one VM name or uuid required");

    for (std::list<const char *>::const_iterator it = VMs.begin();
         it != VMs.end();
         ++it)
    {
        HRESULT rc2 = rc;
        const char *pszVM = *it;
        ComPtr<IMachine> machine;
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(pszVM).raw(),
                                               machine.asOutParam()));
        if (machine)
        {
            Bstr env;
#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
            /* make sure the VM process will start on the same display as VBoxManage */
            Utf8Str str;
            const char *pszDisplay = RTEnvGet("DISPLAY");
            if (pszDisplay)
                str = Utf8StrFmt("DISPLAY=%s\n", pszDisplay);
            const char *pszXAuth = RTEnvGet("XAUTHORITY");
            if (pszXAuth)
                str.append(Utf8StrFmt("XAUTHORITY=%s\n", pszXAuth));
            env = str;
#endif
            ComPtr<IProgress> progress;
            CHECK_ERROR(machine, LaunchVMProcess(a->session, sessionType.raw(),
                                                 env.raw(), progress.asOutParam()));
            if (SUCCEEDED(rc) && !progress.isNull())
            {
                RTPrintf("Waiting for VM \"%s\" to power on...\n", pszVM);
                CHECK_ERROR(progress, WaitForCompletion(-1));
                if (SUCCEEDED(rc))
                {
                    BOOL completed = true;
                    CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
                    if (SUCCEEDED(rc))
                    {
                        ASSERT(completed);

                        LONG iRc;
                        CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
                        if (SUCCEEDED(rc))
                        {
                            if (FAILED(iRc))
                            {
                                ProgressErrorInfo info(progress);
                                com::GluePrintErrorInfo(info);
                            }
                            else
                            {
                                RTPrintf("VM \"%s\" has been successfully started.\n", pszVM);
                            }
                        }
                    }
                }
            }
        }

        /* it's important to always close sessions */
        a->session->UnlockMachine();

        /* make sure that we remember the failed state */
        if (FAILED(rc2))
            rc = rc2;
    }

    return SUCCEEDED(rc) ? 0 : 1;
}
int handleExtPack(HandlerArg *a)
{
    if (a->argc < 1)
        return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");

    ComObjPtr<IExtPackManager> ptrExtPackMgr;
    CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);

    RTGETOPTSTATE   GetState;
    RTGETOPTUNION   ValueUnion;
    int             ch;
    HRESULT         hrc = S_OK;

    if (!strcmp(a->argv[0], "install"))
    {
        const char *pszName  = NULL;
        bool        fReplace = false;

        static const RTGETOPTDEF s_aInstallOptions[] =
        {
            { "--replace",  'r', RTGETOPT_REQ_NOTHING },
        };

        RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
        while ((ch = RTGetOpt(&GetState, &ValueUnion)))
        {
            switch (ch)
            {
                case 'r':
                    fReplace = true;
                    break;

                case VINF_GETOPT_NOT_OPTION:
                    if (pszName)
                        return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
                    pszName = ValueUnion.psz;
                    break;

                default:
                    return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
            }
        }
        if (!pszName)
            return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");

        char szPath[RTPATH_MAX];
        int vrc = RTPathAbs(pszName, szPath, sizeof(szPath));
        if (RT_FAILURE(vrc))
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", pszName, vrc);

        Bstr bstrTarball(szPath);
        Bstr bstrName;
        ComPtr<IExtPackFile> ptrExtPackFile;
        CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
        CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
        ComPtr<IProgress> ptrProgress;
        CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
        hrc = showProgress(ptrProgress);
        CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to install \"%s\"", szPath), RTEXITCODE_FAILURE);

        RTPrintf("Successfully installed \"%ls\".\n", bstrName.raw());
    }
    else if (!strcmp(a->argv[0], "uninstall"))
    {
        const char *pszName = NULL;
        bool        fForced = false;

        static const RTGETOPTDEF s_aUninstallOptions[] =
        {
            { "--force",  'f', RTGETOPT_REQ_NOTHING },
        };

        RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
        while ((ch = RTGetOpt(&GetState, &ValueUnion)))
        {
            switch (ch)
            {
                case 'f':
                    fForced = true;
                    break;

                case VINF_GETOPT_NOT_OPTION:
                    if (pszName)
                        return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
                    pszName = ValueUnion.psz;
                    break;

                default:
                    return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
            }
        }
        if (!pszName)
            return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");

        Bstr bstrName(pszName);
        ComPtr<IProgress> ptrProgress;
        CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
        hrc = showProgress(ptrProgress);
        CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to uninstall \"%s\"", pszName), RTEXITCODE_FAILURE);

        RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
    }
    else if (!strcmp(a->argv[0], "cleanup"))
    {
        if (a->argc > 1)
            return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");

        CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
        RTPrintf("Successfully performed extension pack cleanup\n");
    }
    else
        return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);

    return RTEXITCODE_SUCCESS;
}
int handleCreateVM(HandlerArg *a)
{
    HRESULT rc;
    Bstr bstrBaseFolder;
    Bstr bstrName;
    Bstr bstrOsTypeId;
    Bstr bstrUuid;
    bool fRegister = false;
    com::SafeArray<BSTR> groups;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateVMOptions, RT_ELEMENTS(g_aCreateVMOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 'n':   // --name
                bstrName = ValueUnion.psz;
                break;

            case 'g':   // --groups
                parseGroups(ValueUnion.psz, &groups);
                break;

            case 'p':   // --basefolder
                bstrBaseFolder = ValueUnion.psz;
                break;

            case 'o':   // --ostype
                bstrOsTypeId = ValueUnion.psz;
                break;

            case 'u':   // --uuid
                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
                break;

            case 'r':   // --register
                fRegister = true;
                break;

            default:
                return errorGetOpt(USAGE_CREATEVM, c, &ValueUnion);
        }
    }

    /* check for required options */
    if (bstrName.isEmpty())
        return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");

    do
    {
        Bstr createFlags;
        if (!bstrUuid.isEmpty())
            createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
        Bstr bstrPrimaryGroup;
        if (groups.size())
            bstrPrimaryGroup = groups[0];
        Bstr bstrSettingsFile;
        CHECK_ERROR_BREAK(a->virtualBox,
                          ComposeMachineFilename(bstrName.raw(),
                                                 bstrPrimaryGroup.raw(),
                                                 createFlags.raw(),
                                                 bstrBaseFolder.raw(),
                                                 bstrSettingsFile.asOutParam()));
        ComPtr<IMachine> machine;
        CHECK_ERROR_BREAK(a->virtualBox,
                          CreateMachine(bstrSettingsFile.raw(),
                                        bstrName.raw(),
                                        ComSafeArrayAsInParam(groups),
                                        bstrOsTypeId.raw(),
                                        createFlags.raw(),
                                        machine.asOutParam()));

        CHECK_ERROR_BREAK(machine, SaveSettings());
        if (fRegister)
        {
            CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
        }
        Bstr uuid;
        CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
        Bstr settingsFile;
        CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
        RTPrintf("Virtual machine '%ls' is created%s.\n"
                 "UUID: %s\n"
                 "Settings file: '%ls'\n",
                 bstrName.raw(), fRegister ? " and registered" : "",
                 Utf8Str(uuid).c_str(), settingsFile.raw());
    }
    while (0);

    return SUCCEEDED(rc) ? 0 : 1;
}
示例#26
0
HRESULT Progress::waitForAsyncProgressCompletion(const ComPtr<IProgress> &aPProgressAsync)
{
    LogFlowThisFuncEnter();

    /* Note: we don't lock here, cause we just using public methods. */

    HRESULT rc           = S_OK;
    BOOL fCancelable     = FALSE;
    BOOL fCompleted      = FALSE;
    BOOL fCanceled       = FALSE;
    ULONG prevPercent    = UINT32_MAX;
    ULONG currentPercent = 0;
    ULONG cOp            = 0;
    /* Is the async process cancelable? */
    rc = aPProgressAsync->COMGETTER(Cancelable)(&fCancelable);
    if (FAILED(rc)) return rc;
    /* Loop as long as the sync process isn't completed. */
    while (SUCCEEDED(aPProgressAsync->COMGETTER(Completed(&fCompleted))))
    {
        /* We can forward any cancel request to the async process only when
         * it is cancelable. */
        if (fCancelable)
        {
            rc = COMGETTER(Canceled)(&fCanceled);
            if (FAILED(rc)) return rc;
            if (fCanceled)
            {
                rc = aPProgressAsync->Cancel();
                if (FAILED(rc)) return rc;
            }
        }
        /* Even if the user canceled the process, we have to wait until the
           async task has finished his work (cleanup and such). Otherwise there
           will be sync trouble (still wrong state, dead locks, ...) on the
           used objects. So just do nothing, but wait for the complete
           notification. */
        if (!fCanceled)
        {
            /* Check if the current operation has changed. It is also possible that
             * in the meantime more than one async operation was finished. So we
             * have to loop as long as we reached the same operation count. */
            ULONG curOp;
            for (;;)
            {
                rc = aPProgressAsync->COMGETTER(Operation(&curOp));
                if (FAILED(rc)) return rc;
                if (cOp != curOp)
                {
                    Bstr bstr;
                    ULONG currentWeight;
                    rc = aPProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
                    if (FAILED(rc)) return rc;
                    rc = aPProgressAsync->COMGETTER(OperationWeight(&currentWeight));
                    if (FAILED(rc)) return rc;
                    rc = SetNextOperation(bstr.raw(), currentWeight);
                    if (FAILED(rc)) return rc;
                    ++cOp;
                }
                else
                    break;
            }

            rc = aPProgressAsync->COMGETTER(OperationPercent(&currentPercent));
            if (FAILED(rc)) return rc;
            if (currentPercent != prevPercent)
            {
                prevPercent = currentPercent;
                rc = SetCurrentOperationProgress(currentPercent);
                if (FAILED(rc)) return rc;
            }
        }
        if (fCompleted)
            break;

        /* Make sure the loop is not too tight */
        rc = aPProgressAsync->WaitForCompletion(100);
        if (FAILED(rc)) return rc;
    }

    LogFlowThisFuncLeave();

    return rc;
}
示例#27
0
/**
 * Sets the other progress object unless the operation has been completed /
 * canceled already.
 *
 * @returns false if failed/canceled, true if not.
 * @param   pOtherProgress      The other progress object. Must not be NULL.
 */
bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress)
{
    LogFlowThisFunc(("setOtherProgressObject: %p\n", pOtherProgress));
    ComPtr<IProgress> ptrOtherProgress = pOtherProgress;

    /*
     * Query information from the other progress object before we grab the
     * lock.
     */
    ULONG cOperations;
    HRESULT hrc = pOtherProgress->COMGETTER(OperationCount)(&cOperations);
    if (FAILED(hrc))
        cOperations = 1;

    Bstr bstrOperationDescription;
    hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam());
    if (FAILED(hrc))
        bstrOperationDescription = "oops";


    /*
     * Take the lock and check for cancelation, cancel the other object if
     * we've been canceled already.
     */
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    BOOL fCompletedOrCanceled = mCompleted || mCanceled;
    if (!fCompletedOrCanceled)
    {
        /*
         * Advance to the next object and operation. If the other object has
         * more operations than anticipated, adjust our internal count.
         */
        mptrOtherProgress = ptrOtherProgress;
        mfMultiOperation  = cOperations > 1;

        muOtherProgressStartWeight = m_ulOperationsCompletedWeight + m_ulCurrentOperationWeight;
        muOtherProgressWeight      = m_ulTotalOperationsWeight - muOtherProgressStartWeight;
        Progress::SetNextOperation(bstrOperationDescription.raw(), muOtherProgressWeight);

        muOtherProgressStartOperation = m_ulCurrentOperation;
        m_cOperations = cOperations + m_ulCurrentOperation;

        /*
         * Check for cancelation and completion.
         */
        BOOL f;
        hrc = ptrOtherProgress->COMGETTER(Completed)(&f);
        fCompletedOrCanceled = FAILED(hrc) || f;

        if (!fCompletedOrCanceled)
        {
            hrc = ptrOtherProgress->COMGETTER(Canceled)(&f);
            fCompletedOrCanceled = SUCCEEDED(hrc) && f;
        }

        if (fCompletedOrCanceled)
        {
            LogFlowThisFunc(("Other object completed or canceled, clearing...\n"));
            clearOtherProgressObjectInternal(false /*fEarly*/);
        }
        else
        {
            /*
             * Finally, mirror the cancelable property.
             * Note! Note necessary if we do passthru!
             */
            if (mCancelable)
            {
                hrc = ptrOtherProgress->COMGETTER(Cancelable)(&f);
                if (SUCCEEDED(hrc) && !f)
                {
                    LogFlowThisFunc(("The other progress object is not cancelable\n"));
                    mCancelable = FALSE;
                }
            }
        }
    }
    else
    {
        LogFlowThisFunc(("mCompleted=%RTbool mCanceled=%RTbool - Canceling the other progress object!\n",
                         mCompleted, mCanceled));
        hrc = ptrOtherProgress->Cancel();
        LogFlowThisFunc(("Cancel -> %Rhrc", hrc));
    }

    LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled));
    return !fCompletedOrCanceled;
}
/**
 * Enumerates the properties in the guest property store.
 *
 * @returns 0 on success, 1 on failure
 * @note see the command line API description for parameters
 */
static int handleWaitGuestProperty(HandlerArg *a)
{
    /*
     * Handle arguments
     */
    bool        fFailOnTimeout = false;
    const char *pszPatterns    = NULL;
    uint32_t    cMsTimeout     = RT_INDEFINITE_WAIT;
    bool        usageOK        = true;
    if (a->argc < 2)
        usageOK = false;
    else
        pszPatterns = a->argv[1];
    ComPtr<IMachine> machine;
    HRESULT rc;
    CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
                                           machine.asOutParam()));
    if (!machine)
        usageOK = false;
    for (int i = 2; usageOK && i < a->argc; ++i)
    {
        if (   !strcmp(a->argv[i], "--timeout")
            || !strcmp(a->argv[i], "-timeout"))
        {
            if (   i + 1 >= a->argc
                || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
                usageOK = false;
            else
                ++i;
        }
        else if (!strcmp(a->argv[i], "--fail-on-timeout"))
            fFailOnTimeout = true;
        else
            usageOK = false;
    }
    if (!usageOK)
        return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");

    /*
     * Set up the event listener and wait until found match or timeout.
     */
    Bstr aMachStrGuid;
    machine->COMGETTER(Id)(aMachStrGuid.asOutParam());
    Guid aMachGuid(aMachStrGuid);
    ComPtr<IEventSource> es;
    CHECK_ERROR(a->virtualBox, COMGETTER(EventSource)(es.asOutParam()));
    ComPtr<IEventListener> listener;
    CHECK_ERROR(es, CreateListener(listener.asOutParam()));
    com::SafeArray <VBoxEventType_T> eventTypes(1);
    eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
    CHECK_ERROR(es, RegisterListener(listener, ComSafeArrayAsInParam(eventTypes), false));

    uint64_t u64Started = RTTimeMilliTS();
    bool fSignalled = false;
    do
    {
        unsigned cMsWait;
        if (cMsTimeout == RT_INDEFINITE_WAIT)
            cMsWait = 1000;
        else
        {
            uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
            if (cMsElapsed >= cMsTimeout)
                break; /* timed out */
            cMsWait = RT_MIN(1000, cMsTimeout - (uint32_t)cMsElapsed);
        }

        ComPtr<IEvent> ev;
        rc = es->GetEvent(listener, cMsWait, ev.asOutParam());
        if (ev)
        {
            VBoxEventType_T aType;
            rc = ev->COMGETTER(Type)(&aType);
            switch (aType)
            {
                case VBoxEventType_OnGuestPropertyChanged:
                {
                    ComPtr<IGuestPropertyChangedEvent> gpcev = ev;
                    Assert(gpcev);
                    Bstr aNextStrGuid;
                    gpcev->COMGETTER(MachineId)(aNextStrGuid.asOutParam());
                    if (aMachGuid != Guid(aNextStrGuid))
                        continue;
                    Bstr aNextName;
                    gpcev->COMGETTER(Name)(aNextName.asOutParam());
                    if (RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
                                                     Utf8Str(aNextName).c_str(), RTSTR_MAX, NULL))
                    {
                        Bstr aNextValue, aNextFlags;
                        gpcev->COMGETTER(Value)(aNextValue.asOutParam());
                        gpcev->COMGETTER(Flags)(aNextFlags.asOutParam());
                        RTPrintf("Name: %ls, value: %ls, flags: %ls\n",
                                 aNextName.raw(), aNextValue.raw(), aNextFlags.raw());
                        fSignalled = true;
                    }
                    break;
                }
                default:
                     AssertFailed();
            }
        }
    } while (!fSignalled);

    es->UnregisterListener(listener);

    int rcRet = 0;
    if (!fSignalled)
    {
        RTMsgError("Time out or interruption while waiting for a notification.");
        if (fFailOnTimeout)
            rcRet = 2;
    }
    return rcRet;
}
HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
                       const ComPtr<IMedium> &pMedium,
                       const char *pszParentUUID,
                       bool fOptLong)
{
    HRESULT rc = S_OK;
    do
    {
        Bstr uuid;
        pMedium->COMGETTER(Id)(uuid.asOutParam());
        RTPrintf("UUID:           %ls\n", uuid.raw());
        if (pszParentUUID)
            RTPrintf("Parent UUID:    %s\n", pszParentUUID);

        /* check for accessibility */
        MediumState_T enmState;
        CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
        pMedium->RefreshState(&enmState);
        const char *pszState = "unknown";
        switch (enmState)
        {
            case MediumState_NotCreated:
                pszState = "not created";
                break;
            case MediumState_Created:
                pszState = "created";
                break;
            case MediumState_LockedRead:
                pszState = "locked read";
                break;
            case MediumState_LockedWrite:
                pszState = "locked write";
                break;
            case MediumState_Inaccessible:
                pszState = "inaccessible";
                break;
            case MediumState_Creating:
                pszState = "creating";
                break;
            case MediumState_Deleting:
                pszState = "deleting";
                break;
        }
        RTPrintf("State:          %s\n", pszState);

        if (fOptLong && enmState == MediumState_Inaccessible)
        {
            Bstr err;
            CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
            RTPrintf("Access Error:   %ls\n", err.raw());
        }

        if (fOptLong)
        {
            Bstr description;
            pMedium->COMGETTER(Description)(description.asOutParam());
            if (!description.isEmpty())
                RTPrintf("Description:    %ls\n", description.raw());
        }

        MediumType_T type;
        pMedium->COMGETTER(Type)(&type);
        const char *typeStr = "unknown";
        switch (type)
        {
            case MediumType_Normal:
                if (pszParentUUID && Guid(pszParentUUID).isValid())
                    typeStr = "normal (differencing)";
                else
                    typeStr = "normal (base)";
                break;
            case MediumType_Immutable:
                typeStr = "immutable";
                break;
            case MediumType_Writethrough:
                typeStr = "writethrough";
                break;
            case MediumType_Shareable:
                typeStr = "shareable";
                break;
            case MediumType_Readonly:
                typeStr = "readonly";
                break;
            case MediumType_MultiAttach:
                typeStr = "multiattach";
                break;
        }
        RTPrintf("Type:           %s\n", typeStr);

        /* print out information specific for differencing hard disks */
        if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
        {
            BOOL autoReset = FALSE;
            pMedium->COMGETTER(AutoReset)(&autoReset);
            RTPrintf("Auto-Reset:     %s\n", autoReset ? "on" : "off");
        }

        Bstr loc;
        pMedium->COMGETTER(Location)(loc.asOutParam());
        RTPrintf("Location:       %ls\n", loc.raw());

        Bstr format;
        pMedium->COMGETTER(Format)(format.asOutParam());
        RTPrintf("Storage format: %ls\n", format.raw());

        if (fOptLong)
        {
            com::SafeArray<MediumVariant_T> safeArray_variant;

            pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
            ULONG variant=0;
            for (size_t i = 0; i < safeArray_variant.size(); i++)
                variant |= safeArray_variant[i];

            const char *variantStr = "unknown";
            switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
            {
                case MediumVariant_VmdkSplit2G:
                    variantStr = "split2G";
                    break;
                case MediumVariant_VmdkStreamOptimized:
                    variantStr = "streamOptimized";
                    break;
                case MediumVariant_VmdkESX:
                    variantStr = "ESX";
                    break;
                case MediumVariant_Standard:
                    variantStr = "default";
                    break;
            }
            const char *variantTypeStr = "dynamic";
            if (variant & MediumVariant_Fixed)
                variantTypeStr = "fixed";
            else if (variant & MediumVariant_Diff)
                variantTypeStr = "differencing";
            RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
        }

        LONG64 logicalSize;
        pMedium->COMGETTER(LogicalSize)(&logicalSize);
        RTPrintf("Capacity:       %lld MBytes\n", logicalSize >> 20);
        if (fOptLong)
        {
            LONG64 actualSize;
            pMedium->COMGETTER(Size)(&actualSize);
            RTPrintf("Size on disk:   %lld MBytes\n", actualSize >> 20);
        }

        if (fOptLong)
        {
            com::SafeArray<BSTR> names;
            com::SafeArray<BSTR> values;
            pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
            size_t cNames = names.size();
            size_t cValues = values.size();
            bool fFirst = true;
            for (size_t i = 0; i < cNames; i++)
            {
                Bstr value;
                if (i < cValues)
                    value = values[i];
                RTPrintf("%s%ls=%ls\n",
                         fFirst ? "Property:       " : "                ",
                         names[i], value.raw());
            }
        }

        if (fOptLong)
        {
            bool fFirst = true;
            com::SafeArray<BSTR> machineIds;
            pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
            for (size_t i = 0; i < machineIds.size(); i++)
            {
                ComPtr<IMachine> machine;
                CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], machine.asOutParam()));
                if (machine)
                {
                    Bstr name;
                    machine->COMGETTER(Name)(name.asOutParam());
                    machine->COMGETTER(Id)(uuid.asOutParam());
                    RTPrintf("%s%ls (UUID: %ls)",
                             fFirst ? "In use by VMs:  " : "                ",
                             name.raw(), machineIds[i]);
                    fFirst = false;
                    com::SafeArray<BSTR> snapshotIds;
                    pMedium->GetSnapshotIds(machineIds[i],
                                            ComSafeArrayAsOutParam(snapshotIds));
                    for (size_t j = 0; j < snapshotIds.size(); j++)
                    {
                        ComPtr<ISnapshot> snapshot;
                        machine->FindSnapshot(snapshotIds[j], snapshot.asOutParam());
                        if (snapshot)
                        {
                            Bstr snapshotName;
                            snapshot->COMGETTER(Name)(snapshotName.asOutParam());
                            RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
                        }
                    }
                    RTPrintf("\n");
                }
            }
        }

        if (fOptLong)
        {
            com::SafeIfaceArray<IMedium> children;
            pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
            bool fFirst = true;
            for (size_t i = 0; i < children.size(); i++)
            {
                ComPtr<IMedium> pChild(children[i]);
                if (pChild)
                {
                    Bstr childUUID;
                    pChild->COMGETTER(Id)(childUUID.asOutParam());
                    RTPrintf("%s%ls\n",
                             fFirst ? "Child UUIDs:    " : "                ",
                             childUUID.raw());
                    fFirst = false;
                }
            }
        }
    }
    while (0);

    return rc;
}
int handleCloneHardDisk(HandlerArg *a)
{
    HRESULT rc;
    int vrc;
    const char *pszSrc = NULL;
    const char *pszDst = NULL;
    Bstr format;
    MediumVariant_T DiskVariant = MediumVariant_Standard;
    bool fExisting = false;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 'o':   // --format
                format = ValueUnion.psz;
                break;

            case 'F':   // --static
            {
                unsigned uDiskVariant = (unsigned)DiskVariant;
                uDiskVariant |= MediumVariant_Fixed;
                DiskVariant = (MediumVariant_T)uDiskVariant;
                break;
            }

            case 'E':   // --existing
                fExisting = true;
                break;

            case 'm':   // --variant
                vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
                if (RT_FAILURE(vrc))
                    return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
                break;

            case VINF_GETOPT_NOT_OPTION:
                if (!pszSrc)
                    pszSrc = ValueUnion.psz;
                else if (!pszDst)
                    pszDst = ValueUnion.psz;
                else
                    return errorSyntax(USAGE_CLONEHD, "Invalid parameter '%s'", ValueUnion.psz);
                break;

            default:
                if (c > 0)
                {
                    if (RT_C_IS_GRAPH(c))
                        return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
                    else
                        return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
                }
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
                    return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
                else if (ValueUnion.pDef)
                    return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
                else
                    return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
        }
    }

    if (!pszSrc)
        return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
    if (!pszDst)
        return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
    if (fExisting && (!format.isEmpty() || DiskVariant != MediumType_Normal))
        return errorSyntax(USAGE_CLONEHD, "Specified options which cannot be used with --existing");

    ComPtr<IMedium> srcDisk;
    ComPtr<IMedium> dstDisk;

    rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly,
                    srcDisk, false /* fForceNewUuidOnOpen */,
                    false /* fSilent */);
    if (FAILED(rc))
        return 1;

    do
    {
        /* open/create destination hard disk */
        if (fExisting)
        {
            rc = openMedium(a, pszDst, DeviceType_HardDisk,
                            AccessMode_ReadWrite, dstDisk,
                            false /* fForceNewUuidOnOpen */,
                            false /* fSilent */);
            if (FAILED(rc))
                break;

            /* Perform accessibility check now. */
            MediumState_T state;
            CHECK_ERROR_BREAK(dstDisk, RefreshState(&state));
            CHECK_ERROR_BREAK(dstDisk, COMGETTER(Format)(format.asOutParam()));
        }
        else
        {
            /* use the format of the source hard disk if unspecified */
            if (format.isEmpty())
                CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format)(format.asOutParam()));
            rc = createHardDisk(a, Utf8Str(format).c_str(), pszDst, dstDisk);
            if (FAILED(rc))
                break;
        }

        ComPtr<IProgress> progress;
        com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);

        for (ULONG i = 0; i < l_variants.size(); ++i)
        {
            ULONG temp = DiskVariant;
            temp &= 1<<i;
            l_variants [i] = (MediumVariant_T)temp;
        }

        CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, ComSafeArrayAsInParam(l_variants), NULL, progress.asOutParam()));

        rc = showProgress(progress);
        CHECK_PROGRESS_ERROR_BREAK(progress, ("Failed to clone hard disk"));

        Bstr uuid;
        CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));

        RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
                 format.raw(), Utf8Str(uuid).c_str());
    }
    while (0);

    return SUCCEEDED(rc) ? 0 : 1;
}