diff options
Diffstat (limited to 'src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp')
-rw-r--r-- | src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp | 2691 |
1 files changed, 2691 insertions, 0 deletions
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp new file mode 100644 index 00000000..afc489a3 --- /dev/null +++ b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp @@ -0,0 +1,2691 @@ +/* $Id: VBoxManageInfo.cpp $ */ +/** @file + * VBoxManage - The 'showvminfo' command and helper routines. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef VBOX_ONLY_DOCS + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/Guid.h> +#include <VBox/com/array.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/errorprint.h> + +#include <VBox/com/VirtualBox.h> + +#ifdef VBOX_WITH_PCI_PASSTHROUGH +#include <VBox/pci.h> +#endif + +#include <VBox/log.h> +#include <VBox/version.h> +#include <iprt/stream.h> +#include <iprt/time.h> +#include <iprt/string.h> +#include <iprt/getopt.h> +#include <iprt/ctype.h> + +#include "VBoxManage.h" +using namespace com; + + +// funcs +/////////////////////////////////////////////////////////////////////////////// + +/** + * Helper for formatting an indexed name or some such thing. + */ +static const char *FmtNm(char psz[80], const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + RTStrPrintfV(psz, 80, pszFormat, va); + va_end(va); + return psz; +} + +HRESULT showSnapshots(ComPtr<ISnapshot> &rootSnapshot, + ComPtr<ISnapshot> ¤tSnapshot, + VMINFO_DETAILS details, + const Utf8Str &prefix /* = ""*/, + int level /*= 0*/) +{ + /* start with the root */ + Bstr name; + Bstr uuid; + Bstr description; + CHECK_ERROR2I_RET(rootSnapshot, COMGETTER(Name)(name.asOutParam()), hrcCheck); + CHECK_ERROR2I_RET(rootSnapshot, COMGETTER(Id)(uuid.asOutParam()), hrcCheck); + CHECK_ERROR2I_RET(rootSnapshot, COMGETTER(Description)(description.asOutParam()), hrcCheck); + bool fCurrent = (rootSnapshot == currentSnapshot); + if (details == VMINFO_MACHINEREADABLE) + { + /* print with hierarchical numbering */ + RTPrintf("SnapshotName%s=\"%ls\"\n", prefix.c_str(), name.raw()); + RTPrintf("SnapshotUUID%s=\"%s\"\n", prefix.c_str(), Utf8Str(uuid).c_str()); + if (!description.isEmpty()) + RTPrintf("SnapshotDescription%s=\"%ls\"\n", prefix.c_str(), description.raw()); + if (fCurrent) + { + RTPrintf("CurrentSnapshotName=\"%ls\"\n", name.raw()); + RTPrintf("CurrentSnapshotUUID=\"%s\"\n", Utf8Str(uuid).c_str()); + RTPrintf("CurrentSnapshotNode=\"SnapshotName%s\"\n", prefix.c_str()); + } + } + else + { + /* print with indentation */ + RTPrintf(" %sName: %ls (UUID: %s)%s\n", + prefix.c_str(), + name.raw(), + Utf8Str(uuid).c_str(), + (fCurrent) ? " *" : ""); + if (!description.isEmpty()) + RTPrintf(" %sDescription:\n%ls\n", prefix.c_str(), description.raw()); + } + + /* get the children */ + HRESULT hrc = S_OK; + SafeIfaceArray <ISnapshot> coll; + CHECK_ERROR2I_RET(rootSnapshot,COMGETTER(Children)(ComSafeArrayAsOutParam(coll)), hrcCheck); + if (!coll.isNull()) + { + for (size_t index = 0; index < coll.size(); ++index) + { + ComPtr<ISnapshot> snapshot = coll[index]; + if (snapshot) + { + Utf8Str newPrefix; + if (details == VMINFO_MACHINEREADABLE) + newPrefix = Utf8StrFmt("%s-%d", prefix.c_str(), index + 1); + else + { + newPrefix = Utf8StrFmt("%s ", prefix.c_str()); + } + + /* recursive call */ + HRESULT hrc2 = showSnapshots(snapshot, currentSnapshot, details, newPrefix, level + 1); + if (FAILED(hrc2)) + hrc = hrc2; + } + } + } + return hrc; +} + +static void makeTimeStr(char *s, int cb, int64_t millies) +{ + RTTIME t; + RTTIMESPEC ts; + + RTTimeSpecSetMilli(&ts, millies); + + RTTimeExplode(&t, &ts); + + RTStrPrintf(s, cb, "%04d/%02d/%02d %02d:%02d:%02d UTC", + t.i32Year, t.u8Month, t.u8MonthDay, + t.u8Hour, t.u8Minute, t.u8Second); +} + +const char *machineStateToName(MachineState_T machineState, bool fShort) +{ + switch (machineState) + { + case MachineState_PoweredOff: + return fShort ? "poweroff" : "powered off"; + case MachineState_Saved: + return "saved"; + case MachineState_Teleported: + return "teleported"; + case MachineState_Aborted: + return "aborted"; + case MachineState_Running: + return "running"; + case MachineState_Paused: + return "paused"; + case MachineState_Stuck: + return fShort ? "gurumeditation" : "guru meditation"; + case MachineState_Teleporting: + return "teleporting"; + case MachineState_LiveSnapshotting: + return fShort ? "livesnapshotting" : "live snapshotting"; + case MachineState_Starting: + return "starting"; + case MachineState_Stopping: + return "stopping"; + case MachineState_Saving: + return "saving"; + case MachineState_Restoring: + return "restoring"; + case MachineState_TeleportingPausedVM: + return fShort ? "teleportingpausedvm" : "teleporting paused vm"; + case MachineState_TeleportingIn: + return fShort ? "teleportingin" : "teleporting (incoming)"; + case MachineState_FaultTolerantSyncing: + return fShort ? "faulttolerantsyncing" : "fault tolerant syncing"; + case MachineState_DeletingSnapshotOnline: + return fShort ? "deletingsnapshotlive" : "deleting snapshot live"; + case MachineState_DeletingSnapshotPaused: + return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused"; + case MachineState_OnlineSnapshotting: + return fShort ? "onlinesnapshotting" : "online snapshotting"; + case MachineState_RestoringSnapshot: + return fShort ? "restoringsnapshot" : "restoring snapshot"; + case MachineState_DeletingSnapshot: + return fShort ? "deletingsnapshot" : "deleting snapshot"; + case MachineState_SettingUp: + return fShort ? "settingup" : "setting up"; + case MachineState_Snapshotting: + return fShort ? "snapshotting" : "offline snapshotting"; + default: + break; + } + return "unknown"; +} + +const char *facilityStateToName(AdditionsFacilityStatus_T faStatus, bool fShort) +{ + switch (faStatus) + { + case AdditionsFacilityStatus_Inactive: + return fShort ? "inactive" : "not active"; + case AdditionsFacilityStatus_Paused: + return "paused"; + case AdditionsFacilityStatus_PreInit: + return fShort ? "preinit" : "pre-initializing"; + case AdditionsFacilityStatus_Init: + return fShort ? "init" : "initializing"; + case AdditionsFacilityStatus_Active: + return fShort ? "active" : "active/running"; + case AdditionsFacilityStatus_Terminating: + return "terminating"; + case AdditionsFacilityStatus_Terminated: + return "terminated"; + case AdditionsFacilityStatus_Failed: + return "failed"; + case AdditionsFacilityStatus_Unknown: + default: + break; + } + return "unknown"; +} + +/** + * This takes care of escaping double quotes and slashes that the string might + * contain. + * + * @param pszName The variable name. + * @param pszValue The value. + */ +static void outputMachineReadableString(const char *pszName, const char *pszValue) +{ + Assert(strpbrk(pszName, "\"\\") == NULL); + + if ( !pszValue + || !*pszValue + || ( strchr(pszValue, '"') == NULL + && strchr(pszValue, '\\') == NULL) ) + RTPrintf("%s=\"%s\"\n", pszName, pszValue); + else + { + /* The value needs escaping. */ + RTPrintf("%s=\"", pszName); + const char *psz = pszValue; + for (;;) + { + const char *pszNext = strpbrk(psz, "\"\\"); + if (!pszNext) + { + RTPrintf("%s", psz); + break; + } + RTPrintf("%.*s\\%c", pszNext - psz, psz, *pszNext); + psz = pszNext + 1; + } + RTPrintf("\"\n"); + } +} + + +/** + * This takes care of escaping double quotes and slashes that the string might + * contain. + * + * @param pszName The variable name. + * @param pbstrValue The value. + */ +static void outputMachineReadableString(const char *pszName, Bstr const *pbstrValue) +{ + com::Utf8Str strValue(*pbstrValue); + outputMachineReadableString(pszName, strValue.c_str()); +} + +/** + * Converts bandwidth group type to a string. + * @returns String representation. + * @param enmType Bandwidth control group type. + */ +static const char * bwGroupTypeToString(BandwidthGroupType_T enmType) +{ + switch (enmType) + { + case BandwidthGroupType_Null: return "Null"; + case BandwidthGroupType_Disk: return "Disk"; + case BandwidthGroupType_Network: return "Network"; +#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK + case BandwidthGroupType_32BitHack: break; /* Shut up compiler warnings. */ +#endif + } + return "unknown"; +} + +HRESULT showBandwidthGroups(ComPtr<IBandwidthControl> &bwCtrl, + VMINFO_DETAILS details) +{ + int rc = S_OK; + SafeIfaceArray<IBandwidthGroup> bwGroups; + + CHECK_ERROR_RET(bwCtrl, GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)), rc); + + if (bwGroups.size() && details != VMINFO_MACHINEREADABLE) + RTPrintf("\n\n"); + for (size_t i = 0; i < bwGroups.size(); i++) + { + Bstr strName; + LONG64 cMaxBytesPerSec; + BandwidthGroupType_T enmType; + + CHECK_ERROR_RET(bwGroups[i], COMGETTER(Name)(strName.asOutParam()), rc); + CHECK_ERROR_RET(bwGroups[i], COMGETTER(Type)(&enmType), rc); + CHECK_ERROR_RET(bwGroups[i], COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec), rc); + + const char *pszType = bwGroupTypeToString(enmType); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("BandwidthGroup%zu=%ls,%s,%lld\n", i, strName.raw(), pszType, cMaxBytesPerSec); + else + { + const char *pszUnits = ""; + LONG64 cBytes = cMaxBytesPerSec; + if (cBytes == 0) + { + RTPrintf("Name: '%ls', Type: %s, Limit: none (disabled)\n", strName.raw(), pszType); + continue; + } + else if (!(cBytes % _1G)) + { + pszUnits = "G"; + cBytes /= _1G; + } + else if (!(cBytes % _1M)) + { + pszUnits = "M"; + cBytes /= _1M; + } + else if (!(cBytes % _1K)) + { + pszUnits = "K"; + cBytes /= _1K; + } + const char *pszNetUnits = NULL; + if (enmType == BandwidthGroupType_Network) + { + /* + * We want to report network rate limit in bits/s, not bytes. + * Only if it cannot be express it in kilobits we will fall + * back to reporting it in bytes. + */ + LONG64 cBits = cMaxBytesPerSec; + if (!(cBits % 125)) + { + cBits /= 125; + pszNetUnits = "k"; + if (!(cBits % 1000000)) + { + cBits /= 1000000; + pszNetUnits = "g"; + } + else if (!(cBits % 1000)) + { + cBits /= 1000; + pszNetUnits = "m"; + } + RTPrintf("Name: '%ls', Type: %s, Limit: %lld %sbits/sec (%lld %sbytes/sec)\n", strName.raw(), pszType, cBits, pszNetUnits, cBytes, pszUnits); + } + } + if (!pszNetUnits) + RTPrintf("Name: '%ls', Type: %s, Limit: %lld %sbytes/sec\n", strName.raw(), pszType, cBytes, pszUnits); + } + } + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(bwGroups.size() != 0 ? "\n" : "<none>\n\n"); + + return rc; +} + +/** Shows a shared folder. */ +static HRESULT showSharedFolder(ComPtr<ISharedFolder> &sf, VMINFO_DETAILS details, const char *pszDesc, + const char *pszMrInfix, size_t idxMr, bool fFirst) +{ + Bstr name, hostPath, bstrAutoMountPoint; + BOOL writable = FALSE, fAutoMount = FALSE; + CHECK_ERROR2I_RET(sf, COMGETTER(Name)(name.asOutParam()), hrcCheck); + CHECK_ERROR2I_RET(sf, COMGETTER(HostPath)(hostPath.asOutParam()), hrcCheck); + CHECK_ERROR2I_RET(sf, COMGETTER(Writable)(&writable), hrcCheck); + CHECK_ERROR2I_RET(sf, COMGETTER(AutoMount)(&fAutoMount), hrcCheck); + CHECK_ERROR2I_RET(sf, COMGETTER(AutoMountPoint)(bstrAutoMountPoint.asOutParam()), hrcCheck); + + if (fFirst && details != VMINFO_MACHINEREADABLE) + RTPrintf("\n\n"); + if (details == VMINFO_MACHINEREADABLE) + { + char szNm[80]; + outputMachineReadableString(FmtNm(szNm, "SharedFolderName%s%zu", pszMrInfix, idxMr), &name); + outputMachineReadableString(FmtNm(szNm, "SharedFolderPath%s%zu", pszMrInfix, idxMr), &hostPath); + } + else + { + RTPrintf("Name: '%ls', Host path: '%ls' (%s), %s%s", + name.raw(), hostPath.raw(), pszDesc, writable ? "writable" : "readonly", fAutoMount ? ", auto-mount" : ""); + if (bstrAutoMountPoint.isNotEmpty()) + RTPrintf(", mount-point: '%ls'\n", bstrAutoMountPoint.raw()); + else + RTPrintf("\n"); + } + return S_OK; +} + + +static const char *paravirtProviderToString(ParavirtProvider_T provider, VMINFO_DETAILS details) +{ + switch (provider) + { + case ParavirtProvider_None: + if (details == VMINFO_MACHINEREADABLE) + return "none"; + return "None"; + + case ParavirtProvider_Default: + if (details == VMINFO_MACHINEREADABLE) + return "default"; + return "Default"; + + case ParavirtProvider_Legacy: + if (details == VMINFO_MACHINEREADABLE) + return "legacy"; + return "Legacy"; + + case ParavirtProvider_Minimal: + if (details == VMINFO_MACHINEREADABLE) + return "minimal"; + return "Minimal"; + + case ParavirtProvider_HyperV: + if (details == VMINFO_MACHINEREADABLE) + return "hyperv"; + return "HyperV"; + + case ParavirtProvider_KVM: + if (details == VMINFO_MACHINEREADABLE) + return "kvm"; + return "KVM"; + + default: + if (details == VMINFO_MACHINEREADABLE) + return "unknown"; + return "Unknown"; + } +} + + +/* Disable global optimizations for MSC 8.0/64 to make it compile in reasonable + time. MSC 7.1/32 doesn't have quite as much trouble with it, but still + sufficient to qualify for this hack as well since this code isn't performance + critical and probably won't gain much from the extra optimizing in real life. */ +#if defined(_MSC_VER) +# pragma optimize("g", off) +# pragma warning(push) +# if _MSC_VER < RT_MSC_VER_VC120 +# pragma warning(disable: 4748) +# endif +#endif + +HRESULT showVMInfo(ComPtr<IVirtualBox> pVirtualBox, + ComPtr<IMachine> machine, + ComPtr<ISession> pSession, + VMINFO_DETAILS details /*= VMINFO_NONE*/) +{ + HRESULT rc; + ComPtr<IConsole> pConsole; + if (pSession) + pSession->COMGETTER(Console)(pConsole.asOutParam()); + + char szNm[80]; + char szValue[256]; + +#define SHOW_UTF8_STRING(a_pszMachine, a_pszHuman, a_szValue) \ + do \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, a_szValue); \ + else \ + RTPrintf("%-28s %s\n", a_pszHuman, a_szValue); \ + } while (0) + +#define SHOW_BSTR_STRING(a_pszMachine, a_pszHuman, a_bstrValue) \ + do \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, &a_bstrValue); \ + else \ + RTPrintf("%-28s %ls\n", a_pszHuman, a_bstrValue.raw()); \ + } while (0) + +#define SHOW_BOOL_VALUE_EX(a_pszMachine, a_pszHuman, a_fValue, a_szTrue, a_szFalse) \ + do \ + { \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, a_fValue ? "on" : "off"); \ + else \ + RTPrintf("%-28s %s\n", a_pszHuman, a_fValue ? a_szTrue: a_szFalse); \ + } while (0) + +#define SHOW_BOOL_VALUE(a_pszMachine, a_pszHuman, a_fValue) \ + SHOW_BOOL_VALUE_EX(a_pszMachine, a_pszHuman, a_fValue, "enabled", "disabled") + +#define SHOW_ULONG_VALUE(a_pszMachine, a_pszHuman, a_uValue, a_pszUnit) \ + do \ + { \ + if (details == VMINFO_MACHINEREADABLE) \ + RTPrintf("%s=%u\n", a_pszMachine, a_uValue); \ + else \ + RTPrintf("%-28s %u%s\n", a_pszHuman, a_uValue, a_pszUnit); \ + } while (0) + +#define SHOW_LONG64_VALUE(a_pszMachine, a_pszHuman, a_llValue, a_pszUnit) \ + do \ + { \ + if (details == VMINFO_MACHINEREADABLE) \ + RTPrintf("%s=%lld\n", a_pszMachine, a_llValue); \ + else \ + RTPrintf("%-28s %lld%s\n", a_pszHuman, a_llValue, a_pszUnit); \ + } while (0) + +#define SHOW_BOOLEAN_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + SHOW_BOOLEAN_PROP_EX(a_pObj, a_Prop, a_pszMachine, a_pszHuman, "enabled", "disabled") + +#define SHOW_BOOLEAN_PROP_EX(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_szTrue, a_szFalse) \ + do \ + { \ + BOOL f; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(&f), hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, f ? "on" : "off"); \ + else \ + RTPrintf("%-28s %s\n", a_pszHuman, f ? a_szTrue : a_szFalse); \ + } while (0) + +#define SHOW_BOOLEAN_METHOD(a_pObj, a_Invocation, a_pszMachine, a_pszHuman) \ + do \ + { \ + BOOL f; \ + CHECK_ERROR2I_RET(a_pObj, a_Invocation, hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, f ? "on" : "off"); \ + else \ + RTPrintf("%-28s %s\n", a_pszHuman, f ? "enabled" : "disabled"); \ + } while (0) + +#define SHOW_STRING_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + do \ + { \ + Bstr bstr; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(bstr.asOutParam()), hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, &bstr); \ + else \ + RTPrintf("%-28s %ls\n", a_pszHuman, bstr.raw()); \ + } while (0) + +#define SHOW_STRING_PROP_NOT_EMPTY(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + do \ + { \ + Bstr bstr; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(bstr.asOutParam()), hrcCheck); \ + if (bstr.isNotEmpty()) \ + { \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, &bstr); \ + else \ + RTPrintf("%-28s %ls\n", a_pszHuman, bstr.raw()); \ + } \ + } while (0) + + /** @def SHOW_STRING_PROP_MAJ + * For not breaking the output in a dot release we don't show default values. */ +#define SHOW_STRING_PROP_MAJ(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_pszUnless, a_uMajorVer) \ + do \ + { \ + Bstr bstr; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(bstr.asOutParam()), hrcCheck); \ + if ((a_uMajorVer) <= VBOX_VERSION_MAJOR || !bstr.equals(a_pszUnless)) \ + { \ + if (details == VMINFO_MACHINEREADABLE)\ + outputMachineReadableString(a_pszMachine, &bstr); \ + else \ + RTPrintf("%-28s %ls\n", a_pszHuman, bstr.raw()); \ + } \ + } while (0) + +#define SHOW_STRINGARRAY_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + do \ + { \ + SafeArray<BSTR> array; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(ComSafeArrayAsOutParam(array)), hrcCheck); \ + Utf8Str str; \ + for (size_t i = 0; i < array.size(); i++) \ + { \ + if (i != 0) \ + str.append(","); \ + str.append(Utf8Str(array[i]).c_str()); \ + } \ + Bstr bstr(str); \ + if (details == VMINFO_MACHINEREADABLE) \ + outputMachineReadableString(a_pszMachine, &bstr); \ + else \ + RTPrintf("%-28s %ls\n", a_pszHuman, bstr.raw()); \ + } while (0) + +#define SHOW_UUID_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + SHOW_STRING_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) + +#define SHOW_USHORT_PROP_EX2(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_pszUnit, a_szFmtMachine, a_szFmtHuman) \ + do \ + { \ + USHORT u16 = 0; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(&u16), hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + RTPrintf("%s=" a_szFmtMachine "\n", a_pszMachine, u16); \ + else \ + RTPrintf("%-28s " a_szFmtHuman "%s\n", a_pszHuman, u16, u16, a_pszUnit); \ + } while (0) + +#define SHOW_ULONG_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_pszUnit) \ + do \ + { \ + ULONG u32 = 0; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(&u32), hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + RTPrintf("%s=%u\n", a_pszMachine, u32); \ + else \ + RTPrintf("%-28s %u%s\n", a_pszHuman, u32, a_pszUnit); \ + } while (0) + +#define SHOW_LONG64_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_pszUnit) \ + do \ + { \ + LONG64 i64 = 0; \ + CHECK_ERROR2I_RET(a_pObj, COMGETTER(a_Prop)(&i64), hrcCheck); \ + if (details == VMINFO_MACHINEREADABLE) \ + RTPrintf("%s=%lld\n", a_pszMachine, i64); \ + else \ + RTPrintf("%-28s %'lld%s\n", a_pszHuman, i64, a_pszUnit); \ + } while (0) + + /* + * The rules for output in -argdump format: + * 1) the key part (the [0-9a-zA-Z_\-]+ string before the '=' delimiter) + * is all lowercase for "VBoxManage modifyvm" parameters. Any + * other values printed are in CamelCase. + * 2) strings (anything non-decimal) are printed surrounded by + * double quotes '"'. If the strings themselves contain double + * quotes, these characters are escaped by '\'. Any '\' character + * in the original string is also escaped by '\'. + * 3) numbers (containing just [0-9\-]) are written out unchanged. + */ + + BOOL fAccessible; + CHECK_ERROR2I_RET(machine, COMGETTER(Accessible)(&fAccessible), hrcCheck); + if (!fAccessible) + { + Bstr uuid; + machine->COMGETTER(Id)(uuid.asOutParam()); + if (details == VMINFO_COMPACT) + RTPrintf("\"<inaccessible>\" {%s}\n", Utf8Str(uuid).c_str()); + else + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("name=\"<inaccessible>\"\n"); + else + RTPrintf("Name: <inaccessible!>\n"); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("UUID=\"%s\"\n", Utf8Str(uuid).c_str()); + else + RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str()); + if (details != VMINFO_MACHINEREADABLE) + { + Bstr settingsFilePath; + rc = machine->COMGETTER(SettingsFilePath)(settingsFilePath.asOutParam()); + RTPrintf("Config file: %ls\n", settingsFilePath.raw()); + ComPtr<IVirtualBoxErrorInfo> accessError; + rc = machine->COMGETTER(AccessError)(accessError.asOutParam()); + RTPrintf("Access error details:\n"); + ErrorInfo ei(accessError); + GluePrintErrorInfo(ei); + RTPrintf("\n"); + } + } + return S_OK; + } + + if (details == VMINFO_COMPACT) + { + Bstr machineName; + machine->COMGETTER(Name)(machineName.asOutParam()); + Bstr uuid; + machine->COMGETTER(Id)(uuid.asOutParam()); + + RTPrintf("\"%ls\" {%s}\n", machineName.raw(), Utf8Str(uuid).c_str()); + return S_OK; + } + + SHOW_STRING_PROP( machine, Name, "name", "Name:"); + SHOW_STRINGARRAY_PROP( machine, Groups, "groups", "Groups:"); + Bstr osTypeId; + CHECK_ERROR2I_RET(machine, COMGETTER(OSTypeId)(osTypeId.asOutParam()), hrcCheck); + ComPtr<IGuestOSType> osType; + pVirtualBox->GetGuestOSType(osTypeId.raw(), osType.asOutParam()); + if (!osType.isNull()) + SHOW_STRING_PROP( osType, Description, "ostype", "Guest OS:"); + else + SHOW_STRING_PROP( machine, OSTypeId, "ostype", "Guest OS:"); + SHOW_UUID_PROP( machine, Id, "UUID", "UUID:"); + SHOW_STRING_PROP( machine, SettingsFilePath, "CfgFile", "Config file:"); + SHOW_STRING_PROP( machine, SnapshotFolder, "SnapFldr", "Snapshot folder:"); + SHOW_STRING_PROP( machine, LogFolder, "LogFldr", "Log folder:"); + SHOW_UUID_PROP( machine, HardwareUUID, "hardwareuuid", "Hardware UUID:"); + SHOW_ULONG_PROP( machine, MemorySize, "memory", "Memory size", "MB"); + SHOW_BOOLEAN_PROP( machine, PageFusionEnabled, "pagefusion", "Page Fusion:"); + SHOW_ULONG_PROP( machine, VRAMSize, "vram", "VRAM size:", "MB"); + SHOW_ULONG_PROP( machine, CPUExecutionCap, "cpuexecutioncap", "CPU exec cap:", "%"); + SHOW_BOOLEAN_PROP( machine, HPETEnabled, "hpet", "HPET:"); + SHOW_STRING_PROP_MAJ( machine, CPUProfile, "cpu-profile", "CPUProfile:", "host", 6); + + ChipsetType_T chipsetType; + CHECK_ERROR2I_RET(machine, COMGETTER(ChipsetType)(&chipsetType), hrcCheck); + const char *pszChipsetType; + switch (chipsetType) + { + case ChipsetType_Null: pszChipsetType = "invalid"; break; + case ChipsetType_PIIX3: pszChipsetType = "piix3"; break; + case ChipsetType_ICH9: pszChipsetType = "ich9"; break; + default: AssertFailed(); pszChipsetType = "unknown"; break; + } + SHOW_UTF8_STRING("chipset", "Chipset:", pszChipsetType); + + FirmwareType_T firmwareType; + CHECK_ERROR2I_RET(machine, COMGETTER(FirmwareType)(&firmwareType), hrcCheck); + const char *pszFirmwareType; + switch (firmwareType) + { + case FirmwareType_BIOS: pszFirmwareType = "BIOS"; break; + case FirmwareType_EFI: pszFirmwareType = "EFI"; break; + case FirmwareType_EFI32: pszFirmwareType = "EFI32"; break; + case FirmwareType_EFI64: pszFirmwareType = "EFI64"; break; + case FirmwareType_EFIDUAL: pszFirmwareType = "EFIDUAL"; break; + default: AssertFailed(); pszFirmwareType = "unknown"; break; + } + SHOW_UTF8_STRING("firmware", "Firmware:", pszFirmwareType); + + SHOW_ULONG_PROP( machine, CPUCount, "cpus", "Number of CPUs:", ""); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_PAE, &f), "pae", "PAE:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_LongMode, &f), "longmode", "Long Mode:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_TripleFaultReset, &f), "triplefaultreset", "Triple Fault Reset:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_APIC, &f), "apic", "APIC:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_X2APIC, &f), "x2apic", "X2APIC:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_HWVirt, &f), "nested-hw-virt", "Nested VT-x/AMD-V:"); + SHOW_ULONG_PROP( machine, CPUIDPortabilityLevel, "cpuid-portability-level", "CPUID Portability Level:", ""); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s ", "CPUID overrides:"); + ULONG uOrdinal = 0; + for (uOrdinal = 0; uOrdinal < _4K; uOrdinal++) + { + ULONG uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX; + rc = machine->GetCPUIDLeafByOrdinal(uOrdinal, &uLeaf, &uSubLeaf, &uEAX, &uEBX, &uECX, &uEDX); + if (SUCCEEDED(rc)) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("cpuid=%08x,%08x,%08x,%08x,%08x,%08x", uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX); + else + { + if (!uOrdinal) + RTPrintf("Leaf no. EAX EBX ECX EDX\n"); + RTPrintf("%-28s %08x/%03x %08x %08x %08x %08x\n", "", uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX); + } + } + else + { + if (rc != E_INVALIDARG) + com::GlueHandleComError(machine, "GetCPUIDLeaf", rc, __FILE__, __LINE__); + break; + } + } + if (!uOrdinal && details != VMINFO_MACHINEREADABLE) + RTPrintf("None\n"); + + ComPtr<IBIOSSettings> biosSettings; + CHECK_ERROR2I_RET(machine, COMGETTER(BIOSSettings)(biosSettings.asOutParam()), hrcCheck); + + BIOSBootMenuMode_T bootMenuMode; + CHECK_ERROR2I_RET(biosSettings, COMGETTER(BootMenuMode)(&bootMenuMode), hrcCheck); + const char *pszBootMenu; + switch (bootMenuMode) + { + case BIOSBootMenuMode_Disabled: + pszBootMenu = "disabled"; + break; + case BIOSBootMenuMode_MenuOnly: + if (details == VMINFO_MACHINEREADABLE) + pszBootMenu = "menuonly"; + else + pszBootMenu = "menu only"; + break; + default: + if (details == VMINFO_MACHINEREADABLE) + pszBootMenu = "messageandmenu"; + else + pszBootMenu = "message and menu"; + } + SHOW_UTF8_STRING("bootmenu", "Boot menu mode:", pszBootMenu); + + ComPtr<ISystemProperties> systemProperties; + CHECK_ERROR2I_RET(pVirtualBox, COMGETTER(SystemProperties)(systemProperties.asOutParam()), hrcCheck); + ULONG maxBootPosition = 0; + CHECK_ERROR2I_RET(systemProperties, COMGETTER(MaxBootPosition)(&maxBootPosition), hrcCheck); + for (ULONG i = 1; i <= maxBootPosition; i++) + { + DeviceType_T bootOrder; + CHECK_ERROR2I_RET(machine, GetBootOrder(i, &bootOrder), hrcCheck); + const char *pszDevice; + if (bootOrder == DeviceType_Floppy) + pszDevice = details == VMINFO_MACHINEREADABLE ? "floppy" : "Floppy"; + else if (bootOrder == DeviceType_DVD) + pszDevice = details == VMINFO_MACHINEREADABLE ? "dvd" : "DVD"; + else if (bootOrder == DeviceType_HardDisk) + pszDevice = details == VMINFO_MACHINEREADABLE ? "disk" : "HardDisk"; + else if (bootOrder == DeviceType_Network) + pszDevice = details == VMINFO_MACHINEREADABLE ? "net" : "Network"; + else if (bootOrder == DeviceType_USB) + pszDevice = details == VMINFO_MACHINEREADABLE ? "usb" : "USB"; + else if (bootOrder == DeviceType_SharedFolder) + pszDevice = details == VMINFO_MACHINEREADABLE ? "sharedfolder" : "Shared Folder"; + else + pszDevice = details == VMINFO_MACHINEREADABLE ? "none" : "Not Assigned"; + SHOW_UTF8_STRING(FmtNm(szNm, "boot%u", i), FmtNm(szNm, "Boot Device %u:", i), pszDevice); + } + + SHOW_BOOLEAN_PROP(biosSettings, ACPIEnabled, "acpi", "ACPI:"); + SHOW_BOOLEAN_PROP(biosSettings, IOAPICEnabled, "ioapic", "IOAPIC:"); + + APICMode_T apicMode; + CHECK_ERROR2I_RET(biosSettings, COMGETTER(APICMode)(&apicMode), hrcCheck); + const char *pszAPIC; + switch (apicMode) + { + case APICMode_Disabled: + pszAPIC = "disabled"; + break; + case APICMode_APIC: + default: + if (details == VMINFO_MACHINEREADABLE) + pszAPIC = "apic"; + else + pszAPIC = "APIC"; + break; + case APICMode_X2APIC: + if (details == VMINFO_MACHINEREADABLE) + pszAPIC = "x2apic"; + else + pszAPIC = "x2APIC"; + break; + } + SHOW_UTF8_STRING("biosapic", "BIOS APIC mode:", pszAPIC); + + SHOW_LONG64_PROP(biosSettings, TimeOffset, "biossystemtimeoffset", "Time offset:", "ms"); + SHOW_BOOLEAN_PROP_EX(machine, RTCUseUTC, "rtcuseutc", "RTC:", "UTC", "local time"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &f), "hwvirtex", "Hardw. virt.ext:"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &f),"nestedpaging", "Nested Paging:"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &f), "largepages", "Large Pages:"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_VPID, &f), "vtxvpid", "VT-x VPID:"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &f), "vtxux", "VT-x unr. exec.:"); + + ParavirtProvider_T paravirtProvider; + CHECK_ERROR2I_RET(machine, COMGETTER(ParavirtProvider)(¶virtProvider), hrcCheck); + const char *pszParavirtProvider = paravirtProviderToString(paravirtProvider, details); + SHOW_UTF8_STRING("paravirtprovider", "Paravirt. Provider:", pszParavirtProvider); + + ParavirtProvider_T effParavirtProvider; + CHECK_ERROR2I_RET(machine, GetEffectiveParavirtProvider(&effParavirtProvider), hrcCheck); + const char *pszEffParavirtProvider = paravirtProviderToString(effParavirtProvider, details); + SHOW_UTF8_STRING("effparavirtprovider", "Effective Paravirt. Prov.:", pszEffParavirtProvider); + + Bstr paravirtDebug; + CHECK_ERROR2I_RET(machine, COMGETTER(ParavirtDebug)(paravirtDebug.asOutParam()), hrcCheck); + if (paravirtDebug.isNotEmpty()) + SHOW_BSTR_STRING("paravirtdebug", "Paravirt. Debug:", paravirtDebug); + + MachineState_T machineState; + CHECK_ERROR2I_RET(machine, COMGETTER(State)(&machineState), hrcCheck); + const char *pszState = machineStateToName(machineState, details == VMINFO_MACHINEREADABLE /*=fShort*/); + + LONG64 stateSince; + machine->COMGETTER(LastStateChange)(&stateSince); + RTTIMESPEC timeSpec; + RTTimeSpecSetMilli(&timeSpec, stateSince); + char pszTime[30] = {0}; + RTTimeSpecToString(&timeSpec, pszTime, sizeof(pszTime)); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("VMState=\"%s\"\n", pszState); + RTPrintf("VMStateChangeTime=\"%s\"\n", pszTime); + + Bstr stateFile; + machine->COMGETTER(StateFilePath)(stateFile.asOutParam()); + if (!stateFile.isEmpty()) + RTPrintf("VMStateFile=\"%ls\"\n", stateFile.raw()); + } + else + RTPrintf("%-28s %s (since %s)\n", "State:", pszState, pszTime); + + SHOW_ULONG_PROP( machine, MonitorCount, "monitorcount", "Monitor count:", ""); + SHOW_BOOLEAN_PROP( machine, Accelerate3DEnabled, "accelerate3d", "3D Acceleration:"); +#ifdef VBOX_WITH_VIDEOHWACCEL + SHOW_BOOLEAN_PROP( machine, Accelerate2DVideoEnabled, "accelerate2dvideo", "2D Video Acceleration:"); +#endif + SHOW_BOOLEAN_PROP( machine, TeleporterEnabled, "teleporterenabled", "Teleporter Enabled:"); + SHOW_ULONG_PROP( machine, TeleporterPort, "teleporterport", "Teleporter Port:", ""); + SHOW_STRING_PROP( machine, TeleporterAddress, "teleporteraddress", "Teleporter Address:"); + SHOW_STRING_PROP( machine, TeleporterPassword, "teleporterpassword", "Teleporter Password:"); + SHOW_BOOLEAN_PROP( machine, TracingEnabled, "tracing-enabled", "Tracing Enabled:"); + SHOW_BOOLEAN_PROP( machine, AllowTracingToAccessVM, "tracing-allow-vm-access", "Allow Tracing to Access VM:"); + SHOW_STRING_PROP( machine, TracingConfig, "tracing-config", "Tracing Configuration:"); + SHOW_BOOLEAN_PROP( machine, AutostartEnabled, "autostart-enabled", "Autostart Enabled:"); + SHOW_ULONG_PROP( machine, AutostartDelay, "autostart-delay", "Autostart Delay:", ""); + SHOW_STRING_PROP( machine, DefaultFrontend, "defaultfrontend", "Default Frontend:"); + +/** @todo Convert the remainder of the function to SHOW_XXX macros and add error + * checking where missing. */ + /* + * Storage Controllers and their attached Mediums. + */ + com::SafeIfaceArray<IStorageController> storageCtls; + CHECK_ERROR(machine, COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(storageCtls))); + for (size_t i = 0; i < storageCtls.size(); ++ i) + { + ComPtr<IStorageController> storageCtl = storageCtls[i]; + StorageControllerType_T enmCtlType = StorageControllerType_Null; + const char *pszCtl = NULL; + ULONG ulValue = 0; + BOOL fBootable = FALSE; + Bstr storageCtlName; + + storageCtl->COMGETTER(Name)(storageCtlName.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollername%u=\"%ls\"\n", i, storageCtlName.raw()); + else + RTPrintf("Storage Controller Name (%u): %ls\n", i, storageCtlName.raw()); + + storageCtl->COMGETTER(ControllerType)(&enmCtlType); + switch (enmCtlType) + { + case StorageControllerType_LsiLogic: + pszCtl = "LsiLogic"; + break; + case StorageControllerType_LsiLogicSas: + pszCtl = "LsiLogicSas"; + break; + case StorageControllerType_BusLogic: + pszCtl = "BusLogic"; + break; + case StorageControllerType_IntelAhci: + pszCtl = "IntelAhci"; + break; + case StorageControllerType_PIIX3: + pszCtl = "PIIX3"; + break; + case StorageControllerType_PIIX4: + pszCtl = "PIIX4"; + break; + case StorageControllerType_ICH6: + pszCtl = "ICH6"; + break; + case StorageControllerType_I82078: + pszCtl = "I82078"; + break; + case StorageControllerType_USB: + pszCtl = "USB"; + break; + + default: + pszCtl = "unknown"; + } + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollertype%u=\"%s\"\n", i, pszCtl); + else + RTPrintf("Storage Controller Type (%u): %s\n", i, pszCtl); + + storageCtl->COMGETTER(Instance)(&ulValue); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollerinstance%u=\"%lu\"\n", i, ulValue); + else + RTPrintf("Storage Controller Instance Number (%u): %lu\n", i, ulValue); + + storageCtl->COMGETTER(MaxPortCount)(&ulValue); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollermaxportcount%u=\"%lu\"\n", i, ulValue); + else + RTPrintf("Storage Controller Max Port Count (%u): %lu\n", i, ulValue); + + storageCtl->COMGETTER(PortCount)(&ulValue); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollerportcount%u=\"%lu\"\n", i, ulValue); + else + RTPrintf("Storage Controller Port Count (%u): %lu\n", i, ulValue); + + storageCtl->COMGETTER(Bootable)(&fBootable); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("storagecontrollerbootable%u=\"%s\"\n", i, fBootable ? "on" : "off"); + else + RTPrintf("Storage Controller Bootable (%u): %s\n", i, fBootable ? "on" : "off"); + } + + for (size_t j = 0; j < storageCtls.size(); ++ j) + { + ComPtr<IStorageController> storageCtl = storageCtls[j]; + ComPtr<IMedium> medium; + Bstr storageCtlName; + Bstr filePath; + ULONG cDevices; + ULONG cPorts; + + storageCtl->COMGETTER(Name)(storageCtlName.asOutParam()); + storageCtl->COMGETTER(MaxDevicesPerPortCount)(&cDevices); + storageCtl->COMGETTER(PortCount)(&cPorts); + + for (ULONG i = 0; i < cPorts; ++ i) + { + for (ULONG k = 0; k < cDevices; ++ k) + { + ComPtr<IMediumAttachment> mediumAttach; + machine->GetMediumAttachment(storageCtlName.raw(), + i, k, + mediumAttach.asOutParam()); + BOOL fIsEjected = FALSE; + BOOL fTempEject = FALSE; + DeviceType_T devType = DeviceType_Null; + if (mediumAttach) + { + mediumAttach->COMGETTER(TemporaryEject)(&fTempEject); + mediumAttach->COMGETTER(IsEjected)(&fIsEjected); + mediumAttach->COMGETTER(Type)(&devType); + } + rc = machine->GetMedium(storageCtlName.raw(), i, k, + medium.asOutParam()); + if (SUCCEEDED(rc) && medium) + { + BOOL fPassthrough = FALSE; + + if (mediumAttach) + mediumAttach->COMGETTER(Passthrough)(&fPassthrough); + + medium->COMGETTER(Location)(filePath.asOutParam()); + Bstr uuid; + medium->COMGETTER(Id)(uuid.asOutParam()); + + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("\"%ls-%d-%d\"=\"%ls\"\n", storageCtlName.raw(), + i, k, filePath.raw()); + RTPrintf("\"%ls-ImageUUID-%d-%d\"=\"%s\"\n", + storageCtlName.raw(), i, k, Utf8Str(uuid).c_str()); + if (fPassthrough) + RTPrintf("\"%ls-dvdpassthrough\"=\"%s\"\n", storageCtlName.raw(), + fPassthrough ? "on" : "off"); + if (devType == DeviceType_DVD) + { + RTPrintf("\"%ls-tempeject\"=\"%s\"\n", storageCtlName.raw(), + fTempEject ? "on" : "off"); + RTPrintf("\"%ls-IsEjected\"=\"%s\"\n", storageCtlName.raw(), + fIsEjected ? "on" : "off"); + } + } + else + { + RTPrintf("%ls (%d, %d): %ls (UUID: %s)", + storageCtlName.raw(), i, k, filePath.raw(), + Utf8Str(uuid).c_str()); + if (fPassthrough) + RTPrintf(" (passthrough enabled)"); + if (fTempEject) + RTPrintf(" (temp eject)"); + if (fIsEjected) + RTPrintf(" (ejected)"); + RTPrintf("\n"); + } + } + else if (SUCCEEDED(rc)) + { + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("\"%ls-%d-%d\"=\"emptydrive\"\n", storageCtlName.raw(), i, k); + if (devType == DeviceType_DVD) + RTPrintf("\"%ls-IsEjected\"=\"%s\"\n", storageCtlName.raw(), + fIsEjected ? "on" : "off"); + } + else + { + RTPrintf("%ls (%d, %d): Empty", storageCtlName.raw(), i, k); + if (fTempEject) + RTPrintf(" (temp eject)"); + if (fIsEjected) + RTPrintf(" (ejected)"); + RTPrintf("\n"); + } + } + else + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("\"%ls-%d-%d\"=\"none\"\n", storageCtlName.raw(), i, k); + } + } + } + } + + /* get the maximum amount of NICS */ + ULONG maxNICs = getMaxNics(pVirtualBox, machine); + + for (ULONG currentNIC = 0; currentNIC < maxNICs; currentNIC++) + { + ComPtr<INetworkAdapter> nic; + rc = machine->GetNetworkAdapter(currentNIC, nic.asOutParam()); + if (SUCCEEDED(rc) && nic) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "nic%u" : "NIC %u:", currentNIC + 1); + + BOOL fEnabled; + nic->COMGETTER(Enabled)(&fEnabled); + if (!fEnabled) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"none\"\n", szNm); + else + RTPrintf("%-28s disabled\n", szNm); + } + else + { + Bstr strMACAddress; + nic->COMGETTER(MACAddress)(strMACAddress.asOutParam()); + Utf8Str strAttachment; + Utf8Str strNatSettings = ""; + Utf8Str strNatForwardings = ""; + NetworkAttachmentType_T attachment; + nic->COMGETTER(AttachmentType)(&attachment); + switch (attachment) + { + case NetworkAttachmentType_Null: + if (details == VMINFO_MACHINEREADABLE) + strAttachment = "null"; + else + strAttachment = "none"; + break; + + case NetworkAttachmentType_NAT: + { + Bstr strNetwork; + ComPtr<INATEngine> engine; + nic->COMGETTER(NATEngine)(engine.asOutParam()); + engine->COMGETTER(Network)(strNetwork.asOutParam()); + com::SafeArray<BSTR> forwardings; + engine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(forwardings)); + strNatForwardings = ""; + for (size_t i = 0; i < forwardings.size(); ++i) + { + bool fSkip = false; + BSTR r = forwardings[i]; + Utf8Str utf = Utf8Str(r); + Utf8Str strName; + Utf8Str strProto; + Utf8Str strHostPort; + Utf8Str strHostIP; + Utf8Str strGuestPort; + Utf8Str strGuestIP; + size_t pos, ppos; + pos = ppos = 0; + #define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \ + do { \ + pos = str.find(",", ppos); \ + if (pos == Utf8Str::npos) \ + { \ + Log(( #res " extracting from %s is failed\n", str.c_str())); \ + fSkip = true; \ + } \ + res = str.substr(ppos, pos - ppos); \ + Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \ + ppos = pos + 1; \ + } while (0) + ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos); + if (fSkip) continue; + ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos); + if (fSkip) continue; + ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos); + if (fSkip) continue; + ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos); + if (fSkip) continue; + ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos); + if (fSkip) continue; + strGuestPort = utf.substr(ppos, utf.length() - ppos); + #undef ITERATE_TO_NEXT_TERM + switch (strProto.toUInt32()) + { + case NATProtocol_TCP: + strProto = "tcp"; + break; + case NATProtocol_UDP: + strProto = "udp"; + break; + default: + strProto = "unk"; + break; + } + if (details == VMINFO_MACHINEREADABLE) + { + strNatForwardings = Utf8StrFmt("%sForwarding(%d)=\"%s,%s,%s,%s,%s,%s\"\n", + strNatForwardings.c_str(), i, strName.c_str(), strProto.c_str(), + strHostIP.c_str(), strHostPort.c_str(), + strGuestIP.c_str(), strGuestPort.c_str()); + } + else + { + strNatForwardings = Utf8StrFmt("%sNIC %d Rule(%d): name = %s, protocol = %s," + " host ip = %s, host port = %s, guest ip = %s, guest port = %s\n", + strNatForwardings.c_str(), currentNIC + 1, i, strName.c_str(), strProto.c_str(), + strHostIP.c_str(), strHostPort.c_str(), + strGuestIP.c_str(), strGuestPort.c_str()); + } + } + ULONG mtu = 0; + ULONG sockSnd = 0; + ULONG sockRcv = 0; + ULONG tcpSnd = 0; + ULONG tcpRcv = 0; + engine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); + +/** @todo r=klaus dnsproxy etc needs to be dumped, too */ + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("natnet%d=\"%ls\"\n", currentNIC + 1, strNetwork.length() ? strNetwork.raw(): Bstr("nat").raw()); + strAttachment = "nat"; + strNatSettings = Utf8StrFmt("mtu=\"%d\"\nsockSnd=\"%d\"\nsockRcv=\"%d\"\ntcpWndSnd=\"%d\"\ntcpWndRcv=\"%d\"\n", + mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64, tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64); + } + else + { + strAttachment = "NAT"; + strNatSettings = Utf8StrFmt("NIC %d Settings: MTU: %d, Socket (send: %d, receive: %d), TCP Window (send:%d, receive: %d)\n", + currentNIC + 1, mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64, tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64); + } + break; + } + + case NetworkAttachmentType_Bridged: + { + Bstr strBridgeAdp; + nic->COMGETTER(BridgedInterface)(strBridgeAdp.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("bridgeadapter%d=\"%ls\"\n", currentNIC + 1, strBridgeAdp.raw()); + strAttachment = "bridged"; + } + else + strAttachment = Utf8StrFmt("Bridged Interface '%ls'", strBridgeAdp.raw()); + break; + } + + case NetworkAttachmentType_Internal: + { + Bstr strNetwork; + nic->COMGETTER(InternalNetwork)(strNetwork.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("intnet%d=\"%ls\"\n", currentNIC + 1, strNetwork.raw()); + strAttachment = "intnet"; + } + else + strAttachment = Utf8StrFmt("Internal Network '%s'", Utf8Str(strNetwork).c_str()); + break; + } + + case NetworkAttachmentType_HostOnly: + { + Bstr strHostonlyAdp; + nic->COMGETTER(HostOnlyInterface)(strHostonlyAdp.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("hostonlyadapter%d=\"%ls\"\n", currentNIC + 1, strHostonlyAdp.raw()); + strAttachment = "hostonly"; + } + else + strAttachment = Utf8StrFmt("Host-only Interface '%ls'", strHostonlyAdp.raw()); + break; + } + + case NetworkAttachmentType_Generic: + { + Bstr strGenericDriver; + nic->COMGETTER(GenericDriver)(strGenericDriver.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("generic%d=\"%ls\"\n", currentNIC + 1, strGenericDriver.raw()); + strAttachment = "Generic"; + } + else + { + strAttachment = Utf8StrFmt("Generic '%ls'", strGenericDriver.raw()); + + // show the generic properties + com::SafeArray<BSTR> aProperties; + com::SafeArray<BSTR> aValues; + rc = nic->GetProperties(NULL, + ComSafeArrayAsOutParam(aProperties), + ComSafeArrayAsOutParam(aValues)); + if (SUCCEEDED(rc)) + { + strAttachment += " { "; + for (unsigned i = 0; i < aProperties.size(); ++i) + strAttachment += Utf8StrFmt(!i ? "%ls='%ls'" : ", %ls='%ls'", + aProperties[i], aValues[i]); + strAttachment += " }"; + } + } + break; + } + + case NetworkAttachmentType_NATNetwork: + { + Bstr strNetwork; + nic->COMGETTER(NATNetwork)(strNetwork.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("nat-network%d=\"%ls\"\n", currentNIC + 1, strNetwork.raw()); + strAttachment = "natnetwork"; + } + else + strAttachment = Utf8StrFmt("NAT Network '%s'", Utf8Str(strNetwork).c_str()); + break; + } + + default: + strAttachment = "unknown"; + break; + } + + /* cable connected */ + BOOL fConnected; + nic->COMGETTER(CableConnected)(&fConnected); + + /* promisc policy */ + NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy; + CHECK_ERROR2I_RET(nic, COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy), hrcCheck); + const char *pszPromiscuousGuestPolicy; + switch (enmPromiscModePolicy) + { + case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break; + case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-vms"; break; + case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break; + default: AssertFailedReturn(E_INVALIDARG); + } + + /* trace stuff */ + BOOL fTraceEnabled; + nic->COMGETTER(TraceEnabled)(&fTraceEnabled); + Bstr traceFile; + nic->COMGETTER(TraceFile)(traceFile.asOutParam()); + + /* NIC type */ + NetworkAdapterType_T NICType; + nic->COMGETTER(AdapterType)(&NICType); + const char *pszNICType; + switch (NICType) + { + case NetworkAdapterType_Am79C970A: pszNICType = "Am79C970A"; break; + case NetworkAdapterType_Am79C973: pszNICType = "Am79C973"; break; +#ifdef VBOX_WITH_E1000 + case NetworkAdapterType_I82540EM: pszNICType = "82540EM"; break; + case NetworkAdapterType_I82543GC: pszNICType = "82543GC"; break; + case NetworkAdapterType_I82545EM: pszNICType = "82545EM"; break; +#endif +#ifdef VBOX_WITH_VIRTIO + case NetworkAdapterType_Virtio: pszNICType = "virtio"; break; +#endif + default: AssertFailed(); pszNICType = "unknown"; break; + } + + /* reported line speed */ + ULONG ulLineSpeed; + nic->COMGETTER(LineSpeed)(&ulLineSpeed); + + /* boot priority of the adapter */ + ULONG ulBootPriority; + nic->COMGETTER(BootPriority)(&ulBootPriority); + + /* bandwidth group */ + ComObjPtr<IBandwidthGroup> pBwGroup; + Bstr strBwGroup; + nic->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); + if (!pBwGroup.isNull()) + pBwGroup->COMGETTER(Name)(strBwGroup.asOutParam()); + + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("macaddress%d=\"%ls\"\n", currentNIC + 1, strMACAddress.raw()); + RTPrintf("cableconnected%d=\"%s\"\n", currentNIC + 1, fConnected ? "on" : "off"); + RTPrintf("nic%d=\"%s\"\n", currentNIC + 1, strAttachment.c_str()); + RTPrintf("nictype%d=\"%s\"\n", currentNIC + 1, pszNICType); + RTPrintf("nicspeed%d=\"%d\"\n", currentNIC + 1, ulLineSpeed); + } + else + RTPrintf("%-28s MAC: %ls, Attachment: %s, Cable connected: %s, Trace: %s (file: %ls), Type: %s, Reported speed: %d Mbps, Boot priority: %d, Promisc Policy: %s, Bandwidth group: %ls\n", + szNm, strMACAddress.raw(), strAttachment.c_str(), + fConnected ? "on" : "off", + fTraceEnabled ? "on" : "off", + traceFile.isEmpty() ? Bstr("none").raw() : traceFile.raw(), + pszNICType, + ulLineSpeed / 1000, + (int)ulBootPriority, + pszPromiscuousGuestPolicy, + strBwGroup.isEmpty() ? Bstr("none").raw() : strBwGroup.raw()); + if (strNatSettings.length()) + RTPrintf(strNatSettings.c_str()); + if (strNatForwardings.length()) + RTPrintf(strNatForwardings.c_str()); + } + } + } + + /* Pointing device information */ + PointingHIDType_T aPointingHID; + const char *pszHID = "Unknown"; + const char *pszMrHID = "unknown"; + machine->COMGETTER(PointingHIDType)(&aPointingHID); + switch (aPointingHID) + { + case PointingHIDType_None: + pszHID = "None"; + pszMrHID = "none"; + break; + case PointingHIDType_PS2Mouse: + pszHID = "PS/2 Mouse"; + pszMrHID = "ps2mouse"; + break; + case PointingHIDType_USBMouse: + pszHID = "USB Mouse"; + pszMrHID = "usbmouse"; + break; + case PointingHIDType_USBTablet: + pszHID = "USB Tablet"; + pszMrHID = "usbtablet"; + break; + case PointingHIDType_ComboMouse: + pszHID = "USB Tablet and PS/2 Mouse"; + pszMrHID = "combomouse"; + break; + case PointingHIDType_USBMultiTouch: + pszHID = "USB Multi-Touch"; + pszMrHID = "usbmultitouch"; + break; + default: + break; + } + SHOW_UTF8_STRING("hidpointing", "Pointing Device:", details == VMINFO_MACHINEREADABLE ? pszMrHID : pszHID); + + /* Keyboard device information */ + KeyboardHIDType_T aKeyboardHID; + machine->COMGETTER(KeyboardHIDType)(&aKeyboardHID); + pszHID = "Unknown"; + pszMrHID = "unknown"; + switch (aKeyboardHID) + { + case KeyboardHIDType_None: + pszHID = "None"; + pszMrHID = "none"; + break; + case KeyboardHIDType_PS2Keyboard: + pszHID = "PS/2 Keyboard"; + pszMrHID = "ps2kbd"; + break; + case KeyboardHIDType_USBKeyboard: + pszHID = "USB Keyboard"; + pszMrHID = "usbkbd"; + break; + case KeyboardHIDType_ComboKeyboard: + pszHID = "USB and PS/2 Keyboard"; + pszMrHID = "combokbd"; + break; + default: + break; + } + SHOW_UTF8_STRING("hidkeyboard", "Keyboard Device:", details == VMINFO_MACHINEREADABLE ? pszMrHID : pszHID); + + ComPtr<ISystemProperties> sysProps; + pVirtualBox->COMGETTER(SystemProperties)(sysProps.asOutParam()); + + /* get the maximum amount of UARTs */ + ULONG maxUARTs = 0; + sysProps->COMGETTER(SerialPortCount)(&maxUARTs); + for (ULONG currentUART = 0; currentUART < maxUARTs; currentUART++) + { + ComPtr<ISerialPort> uart; + rc = machine->GetSerialPort(currentUART, uart.asOutParam()); + if (SUCCEEDED(rc) && uart) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "uart%u" : "UART %u:", currentUART + 1); + + /* show the config of this UART */ + BOOL fEnabled; + uart->COMGETTER(Enabled)(&fEnabled); + if (!fEnabled) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"off\"\n", szNm); + else + RTPrintf("%-28s disabled\n", szNm); + } + else + { + ULONG ulIRQ, ulIOBase; + PortMode_T HostMode; + Bstr path; + BOOL fServer; + UartType_T UartType; + uart->COMGETTER(IRQ)(&ulIRQ); + uart->COMGETTER(IOBase)(&ulIOBase); + uart->COMGETTER(Path)(path.asOutParam()); + uart->COMGETTER(Server)(&fServer); + uart->COMGETTER(HostMode)(&HostMode); + uart->COMGETTER(UartType)(&UartType); + + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"%#06x,%d\"\n", szNm, ulIOBase, ulIRQ); + else + RTPrintf("%-28s I/O base: %#06x, IRQ: %d", szNm, ulIOBase, ulIRQ); + switch (HostMode) + { + default: + case PortMode_Disconnected: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"disconnected\"\n", currentUART + 1); + else + RTPrintf(", disconnected"); + break; + case PortMode_RawFile: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"file,%ls\"\n", currentUART + 1, + path.raw()); + else + RTPrintf(", attached to raw file '%ls'\n", + path.raw()); + break; + case PortMode_TCP: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"%s,%ls\"\n", currentUART + 1, + fServer ? "tcpserver" : "tcpclient", path.raw()); + else + RTPrintf(", attached to tcp (%s) '%ls'", + fServer ? "server" : "client", path.raw()); + break; + case PortMode_HostPipe: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"%s,%ls\"\n", currentUART + 1, + fServer ? "server" : "client", path.raw()); + else + RTPrintf(", attached to pipe (%s) '%ls'", + fServer ? "server" : "client", path.raw()); + break; + case PortMode_HostDevice: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"%ls\"\n", currentUART + 1, + path.raw()); + else + RTPrintf(", attached to device '%ls'", path.raw()); + break; + } + switch (UartType) + { + default: + case UartType_U16450: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uarttype%d=\"16450\"\n", currentUART + 1); + else + RTPrintf(", 16450\n"); + break; + case UartType_U16550A: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uarttype%d=\"16550A\"\n", currentUART + 1); + else + RTPrintf(", 16550A\n"); + break; + case UartType_U16750: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uarttype%d=\"16750\"\n", currentUART + 1); + else + RTPrintf(", 16750\n"); + break; + } + } + } + } + + /* get the maximum amount of LPTs */ + ULONG maxLPTs = 0; + sysProps->COMGETTER(ParallelPortCount)(&maxLPTs); + for (ULONG currentLPT = 0; currentLPT < maxLPTs; currentLPT++) + { + ComPtr<IParallelPort> lpt; + rc = machine->GetParallelPort(currentLPT, lpt.asOutParam()); + if (SUCCEEDED(rc) && lpt) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "lpt%u" : "LPT %u:", currentLPT + 1); + + /* show the config of this LPT */ + BOOL fEnabled; + lpt->COMGETTER(Enabled)(&fEnabled); + if (!fEnabled) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"off\"\n", szNm); + else + RTPrintf("%-28s disabled\n", szNm); + } + else + { + ULONG ulIRQ, ulIOBase; + Bstr path; + lpt->COMGETTER(IRQ)(&ulIRQ); + lpt->COMGETTER(IOBase)(&ulIOBase); + lpt->COMGETTER(Path)(path.asOutParam()); + + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"%#06x,%d\"\n", szNm, ulIOBase, ulIRQ); + else + RTPrintf("%-28s I/O base: %#06x, IRQ: %d", szNm, ulIOBase, ulIRQ); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("lptmode%d=\"%ls\"\n", currentLPT + 1, path.raw()); + else + RTPrintf(", attached to device '%ls'\n", path.raw()); + } + } + } + + ComPtr<IAudioAdapter> AudioAdapter; + rc = machine->COMGETTER(AudioAdapter)(AudioAdapter.asOutParam()); + if (SUCCEEDED(rc)) + { + const char *pszDrv = "Unknown"; + const char *pszCtrl = "Unknown"; + const char *pszCodec = "Unknown"; + BOOL fEnabled; + rc = AudioAdapter->COMGETTER(Enabled)(&fEnabled); + if (SUCCEEDED(rc) && fEnabled) + { + AudioDriverType_T enmDrvType; + rc = AudioAdapter->COMGETTER(AudioDriver)(&enmDrvType); + switch (enmDrvType) + { + case AudioDriverType_Null: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "null"; + else + pszDrv = "Null"; + break; + case AudioDriverType_WinMM: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "winmm"; + else + pszDrv = "WINMM"; + break; + case AudioDriverType_DirectSound: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "dsound"; + else + pszDrv = "DSOUND"; + break; + case AudioDriverType_OSS: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "oss"; + else + pszDrv = "OSS"; + break; + case AudioDriverType_ALSA: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "alsa"; + else + pszDrv = "ALSA"; + break; + case AudioDriverType_Pulse: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "pulse"; + else + pszDrv = "PulseAudio"; + break; + case AudioDriverType_CoreAudio: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "coreaudio"; + else + pszDrv = "CoreAudio"; + break; + case AudioDriverType_SolAudio: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "solaudio"; + else + pszDrv = "SolAudio"; + break; + default: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "unknown"; + break; + } + AudioControllerType_T enmCtrlType; + rc = AudioAdapter->COMGETTER(AudioController)(&enmCtrlType); + switch (enmCtrlType) + { + case AudioControllerType_AC97: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "ac97"; + else + pszCtrl = "AC97"; + break; + case AudioControllerType_SB16: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "sb16"; + else + pszCtrl = "SB16"; + break; + case AudioControllerType_HDA: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "hda"; + else + pszCtrl = "HDA"; + break; + default: + break; + } + AudioCodecType_T enmCodecType; + rc = AudioAdapter->COMGETTER(AudioCodec)(&enmCodecType); + switch (enmCodecType) + { + case AudioCodecType_SB16: + pszCodec = "SB16"; + break; + case AudioCodecType_STAC9700: + pszCodec = "STAC9700"; + break; + case AudioCodecType_AD1980: + pszCodec = "AD1980"; + break; + case AudioCodecType_STAC9221: + pszCodec = "STAC9221"; + break; + case AudioCodecType_Null: break; /* Shut up MSC. */ + default: break; + } + } + else + fEnabled = FALSE; + + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("audio=\"%s\"\n", fEnabled ? pszDrv : "none"); + else + { + RTPrintf("%-28s %s", "Audio:", fEnabled ? "enabled" : "disabled"); + if (fEnabled) + RTPrintf(" (Driver: %s, Controller: %s, Codec: %s)", pszDrv, pszCtrl, pszCodec); + RTPrintf("\n"); + } + SHOW_BOOLEAN_PROP(AudioAdapter, EnabledIn, "audio_in", "Audio playback:"); + SHOW_BOOLEAN_PROP(AudioAdapter, EnabledOut, "audio_out", "Audio capture:"); + } + + /* Shared clipboard */ + { + const char *psz; + ClipboardMode_T enmMode = (ClipboardMode_T)0; + rc = machine->COMGETTER(ClipboardMode)(&enmMode); + switch (enmMode) + { + case ClipboardMode_Disabled: + psz = "disabled"; + break; + case ClipboardMode_HostToGuest: + psz = details == VMINFO_MACHINEREADABLE ? "hosttoguest" : "HostToGuest"; + break; + case ClipboardMode_GuestToHost: + psz = details == VMINFO_MACHINEREADABLE ? "guesttohost" : "GuestToHost"; + break; + case ClipboardMode_Bidirectional: + psz = details == VMINFO_MACHINEREADABLE ? "bidirectional" : "Bidirectional"; + break; + default: + psz = details == VMINFO_MACHINEREADABLE ? "unknown" : "Unknown"; + break; + } + SHOW_UTF8_STRING("clipboard", "Clipboard Mode:", psz); + } + + /* Drag and drop */ + { + const char *psz; + DnDMode_T enmMode; + rc = machine->COMGETTER(DnDMode)(&enmMode); + switch (enmMode) + { + case DnDMode_Disabled: + psz = "disabled"; + break; + case DnDMode_HostToGuest: + psz = details == VMINFO_MACHINEREADABLE ? "hosttoguest" : "HostToGuest"; + break; + case DnDMode_GuestToHost: + psz = details == VMINFO_MACHINEREADABLE ? "guesttohost" : "GuestToHost"; + break; + case DnDMode_Bidirectional: + psz = details == VMINFO_MACHINEREADABLE ? "bidirectional" : "Bidirectional"; + break; + default: + psz = details == VMINFO_MACHINEREADABLE ? "unknown" : "Unknown"; + break; + } + SHOW_UTF8_STRING("draganddrop", "Drag and drop Mode:", psz); + } + + { + SessionState_T sessState; + rc = machine->COMGETTER(SessionState)(&sessState); + if (SUCCEEDED(rc) && sessState != SessionState_Unlocked) + { + Bstr sessName; + rc = machine->COMGETTER(SessionName)(sessName.asOutParam()); + if (SUCCEEDED(rc) && !sessName.isEmpty()) + SHOW_BSTR_STRING("SessionName", "Session name:", sessName); + } + } + + if (pConsole) + { + do + { + ComPtr<IDisplay> display; + rc = pConsole->COMGETTER(Display)(display.asOutParam()); + if (rc == E_ACCESSDENIED || display.isNull()) + break; /* VM not powered up */ + if (FAILED(rc)) + { + com::GlueHandleComError(pConsole, "COMGETTER(Display)(display.asOutParam())", rc, __FILE__, __LINE__); + return rc; + } + ULONG xRes, yRes, bpp; + LONG xOrigin, yOrigin; + GuestMonitorStatus_T monitorStatus; + rc = display->GetScreenResolution(0, &xRes, &yRes, &bpp, &xOrigin, &yOrigin, &monitorStatus); + if (rc == E_ACCESSDENIED) + break; /* VM not powered up */ + if (FAILED(rc)) + { + com::ErrorInfo info(display, COM_IIDOF(IDisplay)); + GluePrintErrorInfo(info); + return rc; + } + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("VideoMode=\"%d,%d,%d\"@%d,%d %d\n", xRes, yRes, bpp, xOrigin, yOrigin, monitorStatus); + else + { + const char *pszMonitorStatus = "unknown status"; + switch (monitorStatus) + { + case GuestMonitorStatus_Blank: pszMonitorStatus = "blank"; break; + case GuestMonitorStatus_Enabled: pszMonitorStatus = "enabled"; break; + case GuestMonitorStatus_Disabled: pszMonitorStatus = "disabled"; break; + default: break; + } + RTPrintf("%-28s %dx%dx%d at %d,%d %s\n", "Video mode:", xRes, yRes, bpp, xOrigin, yOrigin, pszMonitorStatus); + } + } + while (0); + } + + /* + * Remote Desktop + */ + ComPtr<IVRDEServer> vrdeServer; + rc = machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam()); + if (SUCCEEDED(rc) && vrdeServer) + { + BOOL fEnabled = false; + vrdeServer->COMGETTER(Enabled)(&fEnabled); + if (fEnabled) + { + LONG currentPort = -1; + Bstr ports; + vrdeServer->GetVRDEProperty(Bstr("TCP/Ports").raw(), ports.asOutParam()); + Bstr address; + vrdeServer->GetVRDEProperty(Bstr("TCP/Address").raw(), address.asOutParam()); + BOOL fMultiCon; + vrdeServer->COMGETTER(AllowMultiConnection)(&fMultiCon); + BOOL fReuseCon; + vrdeServer->COMGETTER(ReuseSingleConnection)(&fReuseCon); + Bstr videoChannel; + vrdeServer->GetVRDEProperty(Bstr("VideoChannel/Enabled").raw(), videoChannel.asOutParam()); + BOOL fVideoChannel = (videoChannel.compare(Bstr("true"), Bstr::CaseInsensitive)== 0) + || (videoChannel == "1"); + Bstr videoChannelQuality; + vrdeServer->GetVRDEProperty(Bstr("VideoChannel/Quality").raw(), videoChannelQuality.asOutParam()); + AuthType_T authType = (AuthType_T)0; + const char *strAuthType; + vrdeServer->COMGETTER(AuthType)(&authType); + switch (authType) + { + case AuthType_Null: + strAuthType = "null"; + break; + case AuthType_External: + strAuthType = "external"; + break; + case AuthType_Guest: + strAuthType = "guest"; + break; + default: + strAuthType = "unknown"; + break; + } + if (pConsole) + { + ComPtr<IVRDEServerInfo> vrdeServerInfo; + CHECK_ERROR_RET(pConsole, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), rc); + if (!vrdeServerInfo.isNull()) + { + rc = vrdeServerInfo->COMGETTER(Port)(¤tPort); + if (rc == E_ACCESSDENIED) + { + currentPort = -1; /* VM not powered up */ + } + else if (FAILED(rc)) + { + com::ErrorInfo info(vrdeServerInfo, COM_IIDOF(IVRDEServerInfo)); + GluePrintErrorInfo(info); + return rc; + } + } + } + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("vrde=\"on\"\n"); + RTPrintf("vrdeport=%d\n", currentPort); + RTPrintf("vrdeports=\"%ls\"\n", ports.raw()); + RTPrintf("vrdeaddress=\"%ls\"\n", address.raw()); + RTPrintf("vrdeauthtype=\"%s\"\n", strAuthType); + RTPrintf("vrdemulticon=\"%s\"\n", fMultiCon ? "on" : "off"); + RTPrintf("vrdereusecon=\"%s\"\n", fReuseCon ? "on" : "off"); + RTPrintf("vrdevideochannel=\"%s\"\n", fVideoChannel ? "on" : "off"); + if (fVideoChannel) + RTPrintf("vrdevideochannelquality=\"%ls\"\n", videoChannelQuality.raw()); + } + else + { + if (address.isEmpty()) + address = "0.0.0.0"; + RTPrintf("%-28s enabled (Address %ls, Ports %ls, MultiConn: %s, ReuseSingleConn: %s, Authentication type: %s)\n", + "VRDE:", address.raw(), ports.raw(), fMultiCon ? "on" : "off", fReuseCon ? "on" : "off", strAuthType); + if (pConsole && currentPort != -1 && currentPort != 0) + RTPrintf("%-28s %d\n", "VRDE port:", currentPort); + if (fVideoChannel) + RTPrintf("%-28s enabled (Quality %ls)\n", "Video redirection:", videoChannelQuality.raw()); + else + RTPrintf("%-28s disabled\n", "Video redirection:"); + } + com::SafeArray<BSTR> aProperties; + if (SUCCEEDED(vrdeServer->COMGETTER(VRDEProperties)(ComSafeArrayAsOutParam(aProperties)))) + { + unsigned i; + for (i = 0; i < aProperties.size(); ++i) + { + Bstr value; + vrdeServer->GetVRDEProperty(aProperties[i], value.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + if (value.isEmpty()) + RTPrintf("vrdeproperty[%ls]=<not set>\n", aProperties[i]); + else + RTPrintf("vrdeproperty[%ls]=\"%ls\"\n", aProperties[i], value.raw()); + } + else + { + if (value.isEmpty()) + RTPrintf("%-28s: %-10lS = <not set>\n", "VRDE property", aProperties[i]); + else + RTPrintf("%-28s: %-10lS = \"%ls\"\n", "VRDE property", aProperties[i], value.raw()); + } + } + } + } + else + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("vrde=\"off\"\n"); + else + RTPrintf("%-28s disabled\n", "VRDE:"); + } + } + + /* + * USB. + */ + SafeIfaceArray<IUSBController> USBCtlColl; + rc = machine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(USBCtlColl)); + if (SUCCEEDED(rc)) + { + bool fOhciEnabled = false; + bool fEhciEnabled = false; + bool fXhciEnabled = false; + + for (unsigned i = 0; i < USBCtlColl.size(); i++) + { + USBControllerType_T enmType; + + rc = USBCtlColl[i]->COMGETTER(Type)(&enmType); + if (SUCCEEDED(rc)) + { + switch (enmType) + { + case USBControllerType_OHCI: + fOhciEnabled = true; + break; + case USBControllerType_EHCI: + fEhciEnabled = true; + break; + case USBControllerType_XHCI: + fXhciEnabled = true; + break; + default: + break; + } + } + } + + SHOW_BOOL_VALUE("usb", "OHCI USB:", fOhciEnabled); + SHOW_BOOL_VALUE("ehci", "EHCI USB:", fEhciEnabled); + SHOW_BOOL_VALUE("xhci", "xHCI USB:", fXhciEnabled); + } + + ComPtr<IUSBDeviceFilters> USBFlts; + rc = machine->COMGETTER(USBDeviceFilters)(USBFlts.asOutParam()); + if (SUCCEEDED(rc)) + { + SafeIfaceArray <IUSBDeviceFilter> Coll; + rc = USBFlts->COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(Coll)); + if (SUCCEEDED(rc)) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\nUSB Device Filters:\n\n"); + + if (Coll.size() == 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("<none>\n\n"); + } + else + { + for (size_t index = 0; index < Coll.size(); ++index) + { + ComPtr<IUSBDeviceFilter> DevPtr = Coll[index]; + + if (details != VMINFO_MACHINEREADABLE) + SHOW_UTF8_STRING("index", "Index:", FmtNm(szNm, "%zu", index)); + SHOW_BOOLEAN_PROP_EX(DevPtr, Active, FmtNm(szNm, "USBFilterActive%zu", index + 1), "Active:", "yes", "no"); + SHOW_STRING_PROP(DevPtr, Name, FmtNm(szNm, "USBFilterName%zu", index + 1), "Name:"); + SHOW_STRING_PROP(DevPtr, VendorId, FmtNm(szNm, "USBFilterVendorId%zu", index + 1), "VendorId:"); + SHOW_STRING_PROP(DevPtr, ProductId, FmtNm(szNm, "USBFilterProductId%zu", index + 1), "ProductId:"); + SHOW_STRING_PROP(DevPtr, Revision, FmtNm(szNm, "USBFilterRevision%zu", index + 1), "Revision:"); + SHOW_STRING_PROP(DevPtr, Manufacturer, FmtNm(szNm, "USBFilterManufacturer%zu", index + 1), "Manufacturer:"); + SHOW_STRING_PROP(DevPtr, Product, FmtNm(szNm, "USBFilterProduct%zu", index + 1), "Product:"); + SHOW_STRING_PROP(DevPtr, Remote, FmtNm(szNm, "USBFilterRemote%zu", index + 1), "Remote:"); + SHOW_STRING_PROP(DevPtr, SerialNumber, FmtNm(szNm, "USBFilterSerialNumber%zu", index + 1), "Serial Number:"); + if (details != VMINFO_MACHINEREADABLE) + { + ULONG fMaskedIfs; + CHECK_ERROR_RET(DevPtr, COMGETTER(MaskedInterfaces)(&fMaskedIfs), rc); + if (fMaskedIfs) + RTPrintf("%-28s %#010x\n", "Masked Interfaces:", fMaskedIfs); + RTPrintf("\n"); + } + } + } + } + + if (pConsole) + { + /* scope */ + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Available remote USB devices:\n\n"); + + SafeIfaceArray <IHostUSBDevice> coll; + CHECK_ERROR_RET(pConsole, COMGETTER(RemoteUSBDevices)(ComSafeArrayAsOutParam(coll)), rc); + + if (coll.size() == 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("<none>\n\n"); + } + else + { + /* This code is duplicated below, with USBAttach as prefix. */ + const char *pszPfx = "USBRemote"; + for (size_t i = 0; i < coll.size(); ++i) + { + ComPtr<IHostUSBDevice> dev = coll[i]; + + SHOW_STRING_PROP(dev, Id, FmtNm(szNm, "%sActive%zu", pszPfx, i + 1), "UUID:"); + SHOW_USHORT_PROP_EX2(dev, VendorId, FmtNm(szNm, "%sVendorId%zu", pszPfx, i + 1), "VendorId:", "", "%#06x", "%#06x (%04X)"); + SHOW_USHORT_PROP_EX2(dev, ProductId, FmtNm(szNm, "%sProductId%zu", pszPfx, i + 1), "ProductId:", "", "%#06x", "%#06x (%04X)"); + + USHORT bcdRevision; + CHECK_ERROR_RET(dev, COMGETTER(Revision)(&bcdRevision), rc); + if (details == VMINFO_MACHINEREADABLE) + RTStrPrintf(szValue, sizeof(szValue), "%#04x%02x", bcdRevision >> 8, bcdRevision & 0xff); + else + RTStrPrintf(szValue, sizeof(szValue), "%u.%u (%02u%02u)\n", + bcdRevision >> 8, bcdRevision & 0xff, bcdRevision >> 8, bcdRevision & 0xff); + SHOW_UTF8_STRING(FmtNm(szNm, "%sRevision%zu", pszPfx, i + 1), "Revision:", szValue); + + SHOW_STRING_PROP_NOT_EMPTY(dev, Manufacturer, FmtNm(szNm, "%sManufacturer%zu", pszPfx, i + 1), "Manufacturer:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, Product, FmtNm(szNm, "%sProduct%zu", pszPfx, i + 1), "Product:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, SerialNumber, FmtNm(szNm, "%sSerialNumber%zu", pszPfx, i + 1), "SerialNumber:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, Address, FmtNm(szNm, "%sAddress%zu", pszPfx, i + 1), "Address:"); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + } + } + } + + /* scope */ + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Currently Attached USB Devices:\n\n"); + + SafeIfaceArray <IUSBDevice> coll; + CHECK_ERROR_RET(pConsole, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)), rc); + + if (coll.size() == 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("<none>\n\n"); + } + else + { + /* This code is duplicated below, with USBAttach as prefix. */ + const char *pszPfx = "USBAttach"; + for (size_t i = 0; i < coll.size(); ++i) + { + ComPtr<IHostUSBDevice> dev = coll[i]; + + SHOW_STRING_PROP(dev, Id, FmtNm(szNm, "%sActive%zu", pszPfx, i + 1), "UUID:"); + SHOW_USHORT_PROP_EX2(dev, VendorId, FmtNm(szNm, "%sVendorId%zu", pszPfx, i + 1), "VendorId:", "", "%#06x", "%#06x (%04X)"); + SHOW_USHORT_PROP_EX2(dev, ProductId, FmtNm(szNm, "%sProductId%zu", pszPfx, i + 1), "ProductId:", "", "%#06x", "%#06x (%04X)"); + + USHORT bcdRevision; + CHECK_ERROR_RET(dev, COMGETTER(Revision)(&bcdRevision), rc); + if (details == VMINFO_MACHINEREADABLE) + RTStrPrintf(szValue, sizeof(szValue), "%#04x%02x", bcdRevision >> 8, bcdRevision & 0xff); + else + RTStrPrintf(szValue, sizeof(szValue), "%u.%u (%02u%02u)\n", + bcdRevision >> 8, bcdRevision & 0xff, bcdRevision >> 8, bcdRevision & 0xff); + SHOW_UTF8_STRING(FmtNm(szNm, "%sRevision%zu", pszPfx, i + 1), "Revision:", szValue); + + SHOW_STRING_PROP_NOT_EMPTY(dev, Manufacturer, FmtNm(szNm, "%sManufacturer%zu", pszPfx, i + 1), "Manufacturer:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, Product, FmtNm(szNm, "%sProduct%zu", pszPfx, i + 1), "Product:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, SerialNumber, FmtNm(szNm, "%sSerialNumber%zu", pszPfx, i + 1), "SerialNumber:"); + SHOW_STRING_PROP_NOT_EMPTY(dev, Address, FmtNm(szNm, "%sAddress%zu", pszPfx, i + 1), "Address:"); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + } + } + } + } + } /* USB */ + +#ifdef VBOX_WITH_PCI_PASSTHROUGH + /* Host PCI passthrough devices */ + { + SafeIfaceArray <IPCIDeviceAttachment> assignments; + rc = machine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments)); + if (SUCCEEDED(rc)) + { + if (assignments.size() > 0 && (details != VMINFO_MACHINEREADABLE)) + { + RTPrintf("\nAttached physical PCI devices:\n\n"); + } + + for (size_t index = 0; index < assignments.size(); ++index) + { + ComPtr<IPCIDeviceAttachment> Assignment = assignments[index]; + char szHostPCIAddress[32], szGuestPCIAddress[32]; + LONG iHostPCIAddress = -1, iGuestPCIAddress = -1; + Bstr DevName; + + Assignment->COMGETTER(Name)(DevName.asOutParam()); + Assignment->COMGETTER(HostAddress)(&iHostPCIAddress); + Assignment->COMGETTER(GuestAddress)(&iGuestPCIAddress); + PCIBusAddress().fromLong(iHostPCIAddress).format(szHostPCIAddress, sizeof(szHostPCIAddress)); + PCIBusAddress().fromLong(iGuestPCIAddress).format(szGuestPCIAddress, sizeof(szGuestPCIAddress)); + + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("AttachedHostPCI=%s,%s\n", szHostPCIAddress, szGuestPCIAddress); + else + RTPrintf(" Host device %ls at %s attached as %s\n", DevName.raw(), szHostPCIAddress, szGuestPCIAddress); + } + + if (assignments.size() > 0 && (details != VMINFO_MACHINEREADABLE)) + { + RTPrintf("\n"); + } + } + } + /* Host PCI passthrough devices */ +#endif + + /* + * Bandwidth groups + */ + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Bandwidth groups: "); + { + ComPtr<IBandwidthControl> bwCtrl; + CHECK_ERROR_RET(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()), rc); + + rc = showBandwidthGroups(bwCtrl, details); + } + + + /* + * Shared folders + */ + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Shared folders:"); + uint32_t numSharedFolders = 0; +#if 0 // not yet implemented + /* globally shared folders first */ + { + SafeIfaceArray <ISharedFolder> sfColl; + CHECK_ERROR_RET(pVirtualBox, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(sfColl)), rc); + for (size_t i = 0; i < sfColl.size(); ++i) + { + ComPtr<ISharedFolder> sf = sfColl[i]; + showSharedFolder(sf, details, "global mapping", "GlobalMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } +#endif + /* now VM mappings */ + { + com::SafeIfaceArray <ISharedFolder> folders; + CHECK_ERROR_RET(machine, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), rc); + for (size_t i = 0; i < folders.size(); ++i) + { + ComPtr<ISharedFolder> sf = folders[i]; + showSharedFolder(sf, details, "machine mapping", "MachineMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } + /* transient mappings */ + if (pConsole) + { + com::SafeIfaceArray <ISharedFolder> folders; + CHECK_ERROR_RET(pConsole, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), rc); + for (size_t i = 0; i < folders.size(); ++i) + { + ComPtr<ISharedFolder> sf = folders[i]; + showSharedFolder(sf, details, "transient mapping", "TransientMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } + if (!numSharedFolders && details != VMINFO_MACHINEREADABLE) + RTPrintf("<none>\n"); + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + + if (pConsole) + { + /* + * Live VRDE info. + */ + ComPtr<IVRDEServerInfo> vrdeServerInfo; + CHECK_ERROR_RET(pConsole, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), rc); + BOOL fActive = FALSE; + ULONG cNumberOfClients = 0; + LONG64 BeginTime = 0; + LONG64 EndTime = 0; + LONG64 BytesSent = 0; + LONG64 BytesSentTotal = 0; + LONG64 BytesReceived = 0; + LONG64 BytesReceivedTotal = 0; + Bstr User; + Bstr Domain; + Bstr ClientName; + Bstr ClientIP; + ULONG ClientVersion = 0; + ULONG EncryptionStyle = 0; + + if (!vrdeServerInfo.isNull()) + { + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(Active)(&fActive), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(NumberOfClients)(&cNumberOfClients), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BeginTime)(&BeginTime), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EndTime)(&EndTime), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSent)(&BytesSent), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSentTotal)(&BytesSentTotal), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceived)(&BytesReceived), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceivedTotal)(&BytesReceivedTotal), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(User)(User.asOutParam()), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(Domain)(Domain.asOutParam()), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientName)(ClientName.asOutParam()), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientIP)(ClientIP.asOutParam()), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientVersion)(&ClientVersion), rc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EncryptionStyle)(&EncryptionStyle), rc); + } + + SHOW_BOOL_VALUE_EX("VRDEActiveConnection", "VRDE Connection:", fActive, "active", "not active"); + SHOW_ULONG_VALUE("VRDEClients=", "Clients so far:", cNumberOfClients, ""); + + if (cNumberOfClients > 0) + { + char szTimeValue[128]; + makeTimeStr(szTimeValue, sizeof(szTimeValue), BeginTime); + if (fActive) + SHOW_UTF8_STRING("VRDEStartTime", "Start time:", szTimeValue); + else + { + SHOW_UTF8_STRING("VRDELastStartTime", "Last started:", szTimeValue); + makeTimeStr(szTimeValue, sizeof(szTimeValue), EndTime); + SHOW_UTF8_STRING("VRDELastEndTime", "Last ended:", szTimeValue); + } + + int64_t ThroughputSend = 0; + int64_t ThroughputReceive = 0; + if (EndTime != BeginTime) + { + ThroughputSend = (BytesSent * 1000) / (EndTime - BeginTime); + ThroughputReceive = (BytesReceived * 1000) / (EndTime - BeginTime); + } + SHOW_LONG64_VALUE("VRDEBytesSent", "Sent:", BytesSent, "Bytes"); + SHOW_LONG64_VALUE("VRDEThroughputSend", "Average speed:", ThroughputSend, "B/s"); + SHOW_LONG64_VALUE("VRDEBytesSentTotal", "Sent total:", BytesSentTotal, "Bytes"); + + SHOW_LONG64_VALUE("VRDEBytesReceived", "Received:", BytesReceived, "Bytes"); + SHOW_LONG64_VALUE("VRDEThroughputReceive", "Speed:", ThroughputReceive, "B/s"); + SHOW_LONG64_VALUE("VRDEBytesReceivedTotal", "Received total:", BytesReceivedTotal, "Bytes"); + + if (fActive) + { + SHOW_BSTR_STRING("VRDEUserName", "User name:", User); + SHOW_BSTR_STRING("VRDEDomain", "Domain:", Domain); + SHOW_BSTR_STRING("VRDEClientName", "Client name:", ClientName); + SHOW_BSTR_STRING("VRDEClientIP", "Client IP:", ClientIP); + SHOW_ULONG_VALUE("VRDEClientVersion", "Client version:", ClientVersion, ""); + SHOW_UTF8_STRING("VRDEEncryption", "Encryption:", EncryptionStyle == 0 ? "RDP4" : "RDP5 (X.509)"); + } + } + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + } + +#ifdef VBOX_WITH_RECORDING + { + /* Video capture */ + BOOL fCaptureVideo = FALSE; +# ifdef VBOX_WITH_AUDIO_RECORDING + BOOL fCaptureAudio = FALSE; +# endif + + ComPtr<IRecordingSettings> recordingSettings; + CHECK_ERROR_RET(machine, COMGETTER(RecordingSettings)(recordingSettings.asOutParam()), rc); + + SafeIfaceArray <IRecordingScreenSettings> saRecordingScreenScreens; + CHECK_ERROR_RET(recordingSettings, COMGETTER(Screens)(ComSafeArrayAsOutParam(saRecordingScreenScreens)), rc); + + /* For now all screens have the same configuration; so take screen 0 and work with that. */ + ULONG fFeatures; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(Features)(&fFeatures), rc); + ULONG Width; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(VideoWidth)(&Width), rc); + ULONG Height; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(VideoHeight)(&Height), rc); + ULONG Rate; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(VideoRate)(&Rate), rc); + ULONG Fps; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(VideoFPS)(&Fps), rc); + Bstr bstrFile; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(Filename)(bstrFile.asOutParam()), rc); + Bstr bstrOptions; + CHECK_ERROR_RET(saRecordingScreenScreens[0], COMGETTER(Options)(bstrOptions.asOutParam()), rc); + + Utf8Str strOptions(bstrOptions); + size_t pos = 0; + com::Utf8Str key, value; + while ((pos = strOptions.parseKeyValue(key, value, pos)) != com::Utf8Str::npos) + { + if (key.compare("vc_enabled", Utf8Str::CaseInsensitive) == 0) + { + fCaptureVideo = value.compare("true", Utf8Str::CaseInsensitive) == 0; + } + else if (key.compare("ac_enabled", Utf8Str::CaseInsensitive) == 0) + { +# ifdef VBOX_WITH_AUDIO_RECORDING + fCaptureAudio = value.compare("true", Utf8Str::CaseInsensitive) == 0; +# endif + } + } + + SHOW_BOOL_VALUE_EX("videocap", "Capturing:", fCaptureVideo, "active", "not active"); +# ifdef VBOX_WITH_AUDIO_RECORDING + SHOW_BOOL_VALUE_EX("videocapaudio", "Capture audio:", fCaptureAudio, "active", "not active"); +# endif + szValue[0] = '\0'; + for (size_t i = 0, off = 0; i < saRecordingScreenScreens.size(); i++) + { + BOOL fEnabled; + CHECK_ERROR_RET(saRecordingScreenScreens[i], COMGETTER(Enabled)(&fEnabled), rc); + if (fEnabled && off < sizeof(szValue) - 3) + off += RTStrPrintf(&szValue[off], sizeof(szValue) - off, off ? ",%zu" : "%zu", i); + } + SHOW_UTF8_STRING("capturescreens", "Capture screens:", szValue); + SHOW_BSTR_STRING("capturefilename", "Capture file:", bstrFile); + RTStrPrintf(szValue, sizeof(szValue), "%ux%u", Width, Height); + SHOW_UTF8_STRING("captureres", "Capture dimensions:", szValue); + SHOW_ULONG_VALUE("capturevideorate", "Capture rate:", Rate, "kbps"); + SHOW_ULONG_VALUE("capturevideofps", "Capture FPS:", Fps, "kbps"); + SHOW_BSTR_STRING("captureopts", "Capture options:", bstrOptions); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + /** @todo Add more audio capturing profile / information here. */ + } +#endif /* VBOX_WITH_RECORDING */ + + if ( details == VMINFO_STANDARD + || details == VMINFO_FULL + || details == VMINFO_MACHINEREADABLE) + { + Bstr description; + machine->COMGETTER(Description)(description.asOutParam()); + if (!description.isEmpty()) + { + if (details == VMINFO_MACHINEREADABLE) + outputMachineReadableString("description", &description); + else + RTPrintf("Description:\n%ls\n", description.raw()); + } + } + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Guest:\n\n"); + + SHOW_ULONG_PROP(machine, MemoryBalloonSize, "GuestMemoryBalloon", "Configured memory balloon size:", "MB"); + + if (pConsole) + { + ComPtr<IGuest> guest; + rc = pConsole->COMGETTER(Guest)(guest.asOutParam()); + if (SUCCEEDED(rc) && !guest.isNull()) + { + SHOW_STRING_PROP_NOT_EMPTY(guest, OSTypeId, "GuestOSType", "OS type:"); + + AdditionsRunLevelType_T guestRunLevel; /** @todo Add a runlevel-to-string (e.g. 0 = "None") method? */ + rc = guest->COMGETTER(AdditionsRunLevel)(&guestRunLevel); + if (SUCCEEDED(rc)) + SHOW_ULONG_VALUE("GuestAdditionsRunLevel", "Additions run level:", (ULONG)guestRunLevel, ""); + + Bstr guestString; + rc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam()); + if ( SUCCEEDED(rc) + && !guestString.isEmpty()) + { + ULONG uRevision; + rc = guest->COMGETTER(AdditionsRevision)(&uRevision); + if (FAILED(rc)) + uRevision = 0; + RTStrPrintf(szValue, sizeof(szValue), "%ls r%u", guestString.raw(), uRevision); + SHOW_UTF8_STRING("GuestAdditionsVersion", "Additions version", szValue); + } + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\nGuest Facilities:\n\n"); + + /* Print information about known Guest Additions facilities: */ + SafeIfaceArray <IAdditionsFacility> collFac; + CHECK_ERROR_RET(guest, COMGETTER(Facilities)(ComSafeArrayAsOutParam(collFac)), rc); + LONG64 lLastUpdatedMS; + char szLastUpdated[32]; + AdditionsFacilityStatus_T curStatus; + for (size_t index = 0; index < collFac.size(); ++index) + { + ComPtr<IAdditionsFacility> fac = collFac[index]; + if (fac) + { + CHECK_ERROR_RET(fac, COMGETTER(Name)(guestString.asOutParam()), rc); + if (!guestString.isEmpty()) + { + CHECK_ERROR_RET(fac, COMGETTER(Status)(&curStatus), rc); + CHECK_ERROR_RET(fac, COMGETTER(LastUpdated)(&lLastUpdatedMS), rc); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("GuestAdditionsFacility_%ls=%u,%lld\n", + guestString.raw(), curStatus, lLastUpdatedMS); + else + { + makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS); + RTPrintf("Facility \"%ls\": %s (last update: %s)\n", + guestString.raw(), facilityStateToName(curStatus, false /* No short naming */), szLastUpdated); + } + } + else + AssertMsgFailed(("Facility with undefined name retrieved!\n")); + } + else + AssertMsgFailed(("Invalid facility returned!\n")); + } + if (!collFac.size() && details != VMINFO_MACHINEREADABLE) + RTPrintf("No active facilities.\n"); + } + } + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + + /* + * snapshots + */ + ComPtr<ISnapshot> snapshot; + rc = machine->FindSnapshot(Bstr().raw(), snapshot.asOutParam()); + if (SUCCEEDED(rc) && snapshot) + { + ComPtr<ISnapshot> currentSnapshot; + rc = machine->COMGETTER(CurrentSnapshot)(currentSnapshot.asOutParam()); + if (SUCCEEDED(rc)) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("Snapshots:\n\n"); + showSnapshots(snapshot, currentSnapshot, details); + } + } + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + return S_OK; +} + +#if defined(_MSC_VER) +# pragma optimize("", on) +# pragma warning(pop) +#endif + +static const RTGETOPTDEF g_aShowVMInfoOptions[] = +{ + { "--details", 'D', RTGETOPT_REQ_NOTHING }, + { "-details", 'D', RTGETOPT_REQ_NOTHING }, // deprecated + { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING }, + { "-machinereadable", 'M', RTGETOPT_REQ_NOTHING }, // deprecated + { "--log", 'l', RTGETOPT_REQ_UINT32 }, +}; + +RTEXITCODE handleShowVMInfo(HandlerArg *a) +{ + HRESULT rc; + const char *VMNameOrUuid = NULL; + bool fLog = false; + uint32_t uLogIdx = 0; + bool fDetails = false; + bool fMachinereadable = 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_aShowVMInfoOptions, RT_ELEMENTS(g_aShowVMInfoOptions), + 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + while ((c = RTGetOpt(&GetState, &ValueUnion))) + { + switch (c) + { + case 'D': // --details + fDetails = true; + break; + + case 'M': // --machinereadable + fMachinereadable = true; + break; + + case 'l': // --log + fLog = true; + uLogIdx = ValueUnion.u32; + break; + + case VINF_GETOPT_NOT_OPTION: + if (!VMNameOrUuid) + VMNameOrUuid = ValueUnion.psz; + else + return errorSyntax(USAGE_SHOWVMINFO, "Invalid parameter '%s'", ValueUnion.psz); + break; + + default: + return errorGetOpt(USAGE_SHOWVMINFO, c, &ValueUnion); + } + } + + /* check for required options */ + if (!VMNameOrUuid) + return errorSyntax(USAGE_SHOWVMINFO, "VM name or UUID required"); + + /* try to find the given machine */ + ComPtr<IMachine> machine; + CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMNameOrUuid).raw(), + machine.asOutParam())); + if (FAILED(rc)) + return RTEXITCODE_FAILURE; + + /* Printing the log is exclusive. */ + if (fLog && (fMachinereadable || fDetails)) + return errorSyntax(USAGE_SHOWVMINFO, "Option --log is exclusive"); + + if (fLog) + { + ULONG64 uOffset = 0; + SafeArray<BYTE> aLogData; + size_t cbLogData; + while (true) + { + /* Reset the array */ + aLogData.setNull(); + /* Fetch a chunk of the log file */ + CHECK_ERROR_BREAK(machine, ReadLog(uLogIdx, uOffset, _1M, + ComSafeArrayAsOutParam(aLogData))); + cbLogData = aLogData.size(); + if (cbLogData == 0) + break; + /* aLogData has a platform dependent line ending, standardize on + * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on + * Windows. Otherwise we end up with CR/CR/LF on Windows. */ + size_t cbLogDataPrint = cbLogData; + for (BYTE *s = aLogData.raw(), *d = s; + s - aLogData.raw() < (ssize_t)cbLogData; + s++, d++) + { + if (*s == '\r') + { + /* skip over CR, adjust destination */ + d--; + cbLogDataPrint--; + } + else if (s != d) + *d = *s; + } + RTStrmWrite(g_pStdOut, aLogData.raw(), cbLogDataPrint); + uOffset += cbLogData; + } + } + else + { + /* 2nd option can be -details or -argdump */ + VMINFO_DETAILS details = VMINFO_NONE; + if (fMachinereadable) + details = VMINFO_MACHINEREADABLE; + else if (fDetails) + details = VMINFO_FULL; + else + details = VMINFO_STANDARD; + + /* open an existing session for the VM */ + rc = machine->LockMachine(a->session, LockType_Shared); + if (SUCCEEDED(rc)) + /* get the session machine */ + rc = a->session->COMGETTER(Machine)(machine.asOutParam()); + + rc = showVMInfo(a->virtualBox, machine, a->session, details); + + a->session->UnlockMachine(); + } + + return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; +} + +#endif /* !VBOX_ONLY_DOCS */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ |