From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp | 3231 ++++++++++++++++++++++ 1 file changed, 3231 insertions(+) create mode 100644 src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp (limited to 'src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp') diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp new file mode 100644 index 00000000..524c1be2 --- /dev/null +++ b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp @@ -0,0 +1,3231 @@ +/* $Id: VBoxManageInfo.cpp $ */ +/** @file + * VBoxManage - The 'showvminfo' command and helper routines. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include + +#ifdef VBOX_WITH_PCI_PASSTHROUGH +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "VBoxManage.h" +#include "VBoxManageUtils.h" + +using namespace com; + +DECLARE_TRANSLATION_CONTEXT(Info); + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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, Info::tr("enabled"), Info::tr("disabled")) + +#define SHOW_ULONG_VALUE(a_pszMachine, a_pszHuman, a_uValue, a_pszUnit) \ + do \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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, Info::tr("enabled"), Info::tr("disabled")) + +#define SHOW_BOOLEAN_PROP_EX(a_pObj, a_Prop, a_pszMachine, a_pszHuman, a_szTrue, a_szFalse) \ + do \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 ? Info::tr("enabled") : Info::tr("disabled")); \ + } while (0) + +#define SHOW_STRING_PROP(a_pObj, a_Prop, a_pszMachine, a_pszHuman) \ + do \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + SafeArray 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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 \ + { \ + Assert(a_pszHuman[strlen(a_pszHuman) - 1] == ':'); \ + 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) + + +// 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 &rootSnapshot, + ComPtr ¤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(Info::tr(" %sName: %ls (UUID: %s)%s\n"), + prefix.c_str(), + name.raw(), + Utf8Str(uuid).c_str(), + (fCurrent) ? " *" : ""); + if (!description.isEmpty() && RTUtf16Chr(description.raw(), '\n') == NULL) + RTPrintf(Info::tr(" %sDescription: %ls\n"), prefix.c_str(), description.raw()); + else if (!description.isEmpty()) + RTPrintf(Info::tr(" %sDescription:\n%ls\n"), prefix.c_str(), description.raw()); + } + + /* get the children */ + HRESULT hrc = S_OK; + SafeIfaceArray coll; + CHECK_ERROR2I_RET(rootSnapshot,COMGETTER(Children)(ComSafeArrayAsOutParam(coll)), hrcCheck); + if (!coll.isNull()) + { + for (size_t index = 0; index < coll.size(); ++index) + { + ComPtr snapshot = coll[index]; + if (snapshot) + { + Utf8Str newPrefix; + if (details == VMINFO_MACHINEREADABLE) + newPrefix.printf("%s-%d", prefix.c_str(), index + 1); + else + newPrefix.printf("%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" : Info::tr("powered off"); + case MachineState_Saved: + return fShort ? "saved" : Info::tr("saved"); + case MachineState_Teleported: + return fShort ? "teleported" : Info::tr("teleported"); + case MachineState_Aborted: + return fShort ? "aborted" : Info::tr("aborted"); + case MachineState_AbortedSaved: + return fShort ? "aborted-saved" : Info::tr("aborted-saved"); + case MachineState_Running: + return fShort ? "running" : Info::tr("running"); + case MachineState_Paused: + return fShort ? "paused" : Info::tr("paused"); + case MachineState_Stuck: + return fShort ? "gurumeditation" : Info::tr("guru meditation"); + case MachineState_Teleporting: + return fShort ? "teleporting" : Info::tr("teleporting"); + case MachineState_LiveSnapshotting: + return fShort ? "livesnapshotting" : Info::tr("live snapshotting"); + case MachineState_Starting: + return fShort ? "starting" : Info::tr("starting"); + case MachineState_Stopping: + return fShort ? "stopping" : Info::tr("stopping"); + case MachineState_Saving: + return fShort ? "saving" : Info::tr("saving"); + case MachineState_Restoring: + return fShort ? "restoring" : Info::tr("restoring"); + case MachineState_TeleportingPausedVM: + return fShort ? "teleportingpausedvm" : Info::tr("teleporting paused vm"); + case MachineState_TeleportingIn: + return fShort ? "teleportingin" : Info::tr("teleporting (incoming)"); + case MachineState_DeletingSnapshotOnline: + return fShort ? "deletingsnapshotlive" : Info::tr("deleting snapshot live"); + case MachineState_DeletingSnapshotPaused: + return fShort ? "deletingsnapshotlivepaused" : Info::tr("deleting snapshot live paused"); + case MachineState_OnlineSnapshotting: + return fShort ? "onlinesnapshotting" : Info::tr("online snapshotting"); + case MachineState_RestoringSnapshot: + return fShort ? "restoringsnapshot" : Info::tr("restoring snapshot"); + case MachineState_DeletingSnapshot: + return fShort ? "deletingsnapshot" : Info::tr("deleting snapshot"); + case MachineState_SettingUp: + return fShort ? "settingup" : Info::tr("setting up"); + case MachineState_Snapshotting: + return fShort ? "snapshotting" : Info::tr("offline snapshotting"); + default: + break; + } + return Info::tr("unknown"); +} + +const char *facilityStateToName(AdditionsFacilityStatus_T faStatus, bool fShort) +{ + switch (faStatus) + { + case AdditionsFacilityStatus_Inactive: + return fShort ? "inactive" : Info::tr("not active"); + case AdditionsFacilityStatus_Paused: + return fShort ? "paused" : Info::tr("paused"); + case AdditionsFacilityStatus_PreInit: + return fShort ? "preinit" : Info::tr("pre-initializing"); + case AdditionsFacilityStatus_Init: + return fShort ? "init" : Info::tr("initializing"); + case AdditionsFacilityStatus_Active: + return fShort ? "active" : Info::tr("active/running"); + case AdditionsFacilityStatus_Terminating: + return fShort ? "terminating" : Info::tr("terminating"); + case AdditionsFacilityStatus_Terminated: + return fShort ? "terminated" : Info::tr("terminated"); + case AdditionsFacilityStatus_Failed: + return fShort ? "failed" : Info::tr("failed"); + case AdditionsFacilityStatus_Unknown: + default: + break; + } + return Info::tr("unknown"); +} + +static const char *storageControllerTypeToName(StorageControllerType_T enmCtlType, bool fMachineReadable = false) +{ + switch (enmCtlType) + { + case StorageControllerType_LsiLogic: + return "LsiLogic"; + case StorageControllerType_LsiLogicSas: + return "LsiLogicSas"; + case StorageControllerType_BusLogic: + return "BusLogic"; + case StorageControllerType_IntelAhci: + return "IntelAhci"; + case StorageControllerType_PIIX3: + return "PIIX3"; + case StorageControllerType_PIIX4: + return "PIIX4"; + case StorageControllerType_ICH6: + return "ICH6"; + case StorageControllerType_I82078: + return "I82078"; + case StorageControllerType_USB: + return "USB"; + case StorageControllerType_NVMe: + return "NVMe"; + case StorageControllerType_VirtioSCSI: + return "VirtioSCSI"; + default: + return fMachineReadable ? "unknown" : Info::tr("unknown"); + } +} + + +DECLINLINE(bool) doesMachineReadableStringNeedEscaping(const char *psz) +{ + return psz == NULL + || *psz == '\0' + || strchr(psz, '"') != NULL + || strchr(psz, '\\') != NULL; +} + + +/** + * This simply outputs the string adding necessary escaping and nothing else. + */ +void outputMachineReadableStringWorker(const char *psz) +{ + for (;;) + { + const char *pszDoubleQuote = strchr(psz, '"'); + const char *pszSlash = strchr(psz, '\\'); + const char *pszNext; + if (pszSlash) + pszNext = !pszDoubleQuote || (uintptr_t)pszSlash < (uintptr_t)pszDoubleQuote ? pszSlash : pszDoubleQuote; + else if (pszDoubleQuote) + pszNext = pszDoubleQuote; + else + { + RTStrmWrite(g_pStdOut, psz, strlen(psz)); + break; + } + RTStrmWrite(g_pStdOut, psz, pszNext - psz); + char const szTmp[2] = { '\\', *pszNext }; + RTStrmWrite(g_pStdOut, szTmp, sizeof(szTmp)); + + psz = pszNext + 1; + } +} + + +/** + * This takes care of escaping double quotes and slashes that the string might + * contain. + * + * @param pszName The variable name. + * @param pszValue The value. + * @param fQuoteName Whether to unconditionally quote the name or not. + * @param fNewline Whether to automatically add a newline after the value. + */ +void outputMachineReadableString(const char *pszName, const char *pszValue, bool fQuoteName /*=false*/, bool fNewline /*=true*/) +{ + if (!fQuoteName) + fQuoteName = strchr(pszName, '=') != NULL; + bool const fEscapeName = doesMachineReadableStringNeedEscaping(pszName); + bool const fEscapeValue = doesMachineReadableStringNeedEscaping(pszValue); + if (!fEscapeName && !fEscapeValue) + { + if (fNewline) + RTPrintf(!fQuoteName ? "%s=\"%s\"\n" : "\"%s\"=\"%s\"\n", pszName, pszValue); + else + RTPrintf(!fQuoteName ? "%s=\"%s\"" : "\"%s\"=\"%s\"", pszName, pszValue); + } + else + { + /* The name and string quotation: */ + if (!fEscapeName) + RTPrintf(fQuoteName ? "\"%s\"=\"" : "%s=\"", pszName); + else + { + if (fQuoteName) + RTStrmWrite(g_pStdOut, RT_STR_TUPLE("\"")); + outputMachineReadableStringWorker(pszName); + if (fQuoteName) + RTStrmWrite(g_pStdOut, RT_STR_TUPLE("\"=\"")); + else + RTStrmWrite(g_pStdOut, RT_STR_TUPLE("=\"")); + } + + /* the value and the closing quotation */ + outputMachineReadableStringWorker(pszValue); + if (fNewline) + RTStrmWrite(g_pStdOut, RT_STR_TUPLE("\"\n")); + else + RTStrmWrite(g_pStdOut, RT_STR_TUPLE("\"")); + } +} + + +/** + * This takes care of escaping double quotes and slashes that the string might + * contain. + * + * @param pszName The variable name. + * @param pbstrValue The value. + * @param fQuoteName Whether to unconditionally quote the name or not. + * @param fNewline Whether to automatically add a newline after the value. + */ +void outputMachineReadableString(const char *pszName, Bstr const *pbstrValue, bool fQuoteName /*=false*/, bool fNewline /*=true*/) +{ + com::Utf8Str strValue(*pbstrValue); + outputMachineReadableString(pszName, strValue.c_str(), fQuoteName, fNewline); +} + + +/** + * Variant that allows formatting the name string, C string value. + * + * @param pszValue The value. + * @param fQuoteName Whether to unconditionally quote the name or not. + * @param pszNameFmt The variable name. + */ +void outputMachineReadableStringWithFmtName(const char *pszValue, bool fQuoteName, const char *pszNameFmt, ...) +{ + com::Utf8Str strName; + va_list va; + va_start(va, pszNameFmt); + strName.printfV(pszNameFmt, va); + va_end(va); + + outputMachineReadableString(strName.c_str(), pszValue, fQuoteName); +} + + +/** + * Variant that allows formatting the name string, Bstr value. + * + * @param pbstrValue The value. + * @param fQuoteName Whether to unconditionally quote the name or not. + * @param pszNameFmt The variable name. + */ +void outputMachineReadableStringWithFmtName(com::Bstr const *pbstrValue, bool fQuoteName, const char *pszNameFmt, ...) +{ + com::Utf8Str strName; + va_list va; + va_start(va, pszNameFmt); + strName.printfV(pszNameFmt, va); + va_end(va); + + outputMachineReadableString(strName.c_str(), pbstrValue, fQuoteName); +} + + +/** + * Machine readable outputting of a boolean value. + */ +void outputMachineReadableBool(const char *pszName, BOOL const *pfValue) +{ + RTPrintf("%s=\"%s\"\n", pszName, *pfValue ? "on" : "off"); +} + + +/** + * Machine readable outputting of a boolean value. + */ +void outputMachineReadableBool(const char *pszName, bool const *pfValue) +{ + RTPrintf("%s=\"%s\"\n", pszName, *pfValue ? "on" : "off"); +} + + +/** + * Machine readable outputting of a ULONG value. + */ +void outputMachineReadableULong(const char *pszName, ULONG *puValue) +{ + RTPrintf("%s=\"%u\"\n", pszName, *puValue); +} + + +/** + * Machine readable outputting of a LONG64 value. + */ +void outputMachineReadableLong64(const char *pszName, LONG64 *puValue) +{ + RTPrintf("%s=\"%llu\"\n", pszName, *puValue); +} + + +/** + * Helper for parsing extra data config. + * @returns true, false, or -1 if invalid. + */ +static int parseCfgmBool(Bstr const *pbstr) +{ + /* GetExtraData returns empty strings if the requested data wasn't + found, so fend that off first: */ + size_t cwcLeft = pbstr->length(); + if (!cwcLeft) + return false; + PCRTUTF16 pwch = pbstr->raw(); + + /* Skip type prefix: */ + if ( cwcLeft >= 8 + && pwch[0] == 'i' + && pwch[1] == 'n' + && pwch[2] == 't' + && pwch[3] == 'e' + && pwch[4] == 'g' + && pwch[5] == 'e' + && pwch[6] == 'r' + && pwch[7] == ':') + { + pwch += 8; + cwcLeft -= 8; + } + + /* Hex prefix? */ + bool fHex = false; + if ( cwcLeft >= 2 + && pwch[0] == '0' + && (pwch[1] == 'x' || pwch[1] == 'X')) + { + pwch += 2; + cwcLeft -= 2; + fHex = true; + } + + /* Empty string is wrong: */ + if (cwcLeft == 0) + return -1; + + /* Check that it's all digits and return when we find a non-zero + one or reaches the end: */ + do + { + RTUTF16 const wc = *pwch++; + if (!RT_C_IS_DIGIT(wc) && (!fHex || !RT_C_IS_XDIGIT(wc))) + return -1; + if (wc != '0') + return true; + } while (--cwcLeft > 0); + return false; +} + + +/** + * 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 Info::tr("Null"); + case BandwidthGroupType_Disk: return Info::tr("Disk"); + case BandwidthGroupType_Network: return Info::tr("Network"); +#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK + case BandwidthGroupType_32BitHack: break; /* Shut up compiler warnings. */ +#endif + } + return Info::tr("unknown"); +} + +HRESULT showBandwidthGroups(ComPtr &bwCtrl, + VMINFO_DETAILS details) +{ + SafeIfaceArray bwGroups; + CHECK_ERROR2I_RET(bwCtrl, GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)), hrcCheck); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(bwGroups.size() != 0 ? "\n" : Info::tr("\n")); + for (size_t i = 0; i < bwGroups.size(); i++) + { + Bstr strName; + CHECK_ERROR2I_RET(bwGroups[i], COMGETTER(Name)(strName.asOutParam()), hrcCheck); + BandwidthGroupType_T enmType; + CHECK_ERROR2I_RET(bwGroups[i], COMGETTER(Type)(&enmType), hrcCheck); + LONG64 cbMaxPerSec; + CHECK_ERROR2I_RET(bwGroups[i], COMGETTER(MaxBytesPerSec)(&cbMaxPerSec), hrcCheck); + + const char *pszType = bwGroupTypeToString(enmType); + if (details == VMINFO_MACHINEREADABLE) + { + /* Complicated condensed format. */ + char szName[64]; + RTStrPrintf(szName, sizeof(szName), "BandwidthGroup%zu", i); + outputMachineReadableString(szName, &strName, false /*fQuoteName*/, false /*fNewline*/); + RTPrintf(",%s,%RI64\n", pszType, cbMaxPerSec); + } + else + { + if (cbMaxPerSec == 0) + { + RTPrintf(Info::tr("#%zu: Name: '%ls', Type: %s, Limit: none (disabled)\n"), i, strName.raw(), pszType); + continue; + } + + /* translate to human readable units.*/ + const char *pszUnit; + LONG64 cUnits; + if (!(cbMaxPerSec % _1G)) + { + cUnits = cbMaxPerSec / _1G; + pszUnit = "GiB/s"; + } + else if (!(cbMaxPerSec % _1M)) + { + cUnits = cbMaxPerSec / _1M; + pszUnit = "MiB/s"; + } + else if (!(cbMaxPerSec % _1K)) + { + cUnits = cbMaxPerSec / _1K; + pszUnit = "KiB/s"; + } + else + { + cUnits = cbMaxPerSec; + pszUnit = "bytes/s"; + } + + /* + * 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. + */ + if ( enmType == BandwidthGroupType_Network + && !(cbMaxPerSec % 125) ) + { + LONG64 cNetUnits = cbMaxPerSec / 125; + const char *pszNetUnit = "kbps"; + if (!(cNetUnits % 1000000)) + { + cNetUnits /= 1000000; + pszNetUnit = "Gbps"; + } + else if (!(cNetUnits % 1000)) + { + cNetUnits /= 1000; + pszNetUnit = "Mbps"; + } + RTPrintf(Info::tr("#%zu: Name: '%ls', Type: %s, Limit: %RI64 %s (%RI64 %s)\n"), + i, strName.raw(), pszType, cNetUnits, pszNetUnit, cUnits, pszUnit); + } + else + RTPrintf(Info::tr("#%zu: Name: '%ls', Type: %s, Limit: %RI64 %s\n"), i, strName.raw(), pszType, cUnits, pszUnit); + } + } + + return VINF_SUCCESS; +} + +/** Shows a shared folder. */ +static HRESULT showSharedFolder(ComPtr &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(Info::tr("Name: '%ls', Host path: '%ls' (%s), %s%s"), + name.raw(), hostPath.raw(), pszDesc, writable ? Info::tr("writable") : Info::tr("readonly"), + fAutoMount ? Info::tr(", auto-mount") : ""); + if (bstrAutoMountPoint.isNotEmpty()) + RTPrintf(Info::tr(", mount-point: '%ls'\n"), bstrAutoMountPoint.raw()); + else + RTPrintf("\n"); + } + return S_OK; +} + +/** Displays a list of IUSBDevices or IHostUSBDevices. */ +template +static HRESULT showUsbDevices(SafeIfaceArray &coll, const char *pszPfx, + const char *pszName, VMINFO_DETAILS details) +{ + if (coll.size() > 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s\n\n", pszName); + for (size_t i = 0; i < coll.size(); ++i) + { + ComPtr dev = coll[i]; + char szValue[128]; + char szNm[80]; + + 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), Info::tr("VendorId:"), "", "%#06x", "%#06x (%04X)"); + SHOW_USHORT_PROP_EX2(dev, ProductId, FmtNm(szNm, "%sProductId%zu", pszPfx, i + 1), Info::tr("ProductId:"), "", "%#06x", "%#06x (%04X)"); + + USHORT bcdRevision; + CHECK_ERROR2I_RET(dev, COMGETTER(Revision)(&bcdRevision), hrcCheck); + 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), Info::tr("Revision:"), szValue); + + SHOW_STRING_PROP_NOT_EMPTY(dev, Manufacturer, FmtNm(szNm, "%sManufacturer%zu", pszPfx, i + 1), Info::tr("Manufacturer:")); + SHOW_STRING_PROP_NOT_EMPTY(dev, Product, FmtNm(szNm, "%sProduct%zu", pszPfx, i + 1), Info::tr("Product:")); + SHOW_STRING_PROP_NOT_EMPTY(dev, SerialNumber, FmtNm(szNm, "%sSerialNumber%zu", pszPfx, i + 1), Info::tr("SerialNumber:")); + SHOW_STRING_PROP_NOT_EMPTY(dev, Address, FmtNm(szNm, "%sAddress%zu", pszPfx, i + 1), Info::tr("Address:")); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("\n"); + } + } + else if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s %s\n", pszName, Info::tr("")); + return S_OK; +} + +/** Displays the medium attachments of the given controller. */ +static HRESULT showMediumAttachments(ComPtr &machine, ComPtr ptrStorageCtl, VMINFO_DETAILS details) +{ + Bstr bstrStorageCtlName; + CHECK_ERROR2I_RET(ptrStorageCtl, COMGETTER(Name)(bstrStorageCtlName.asOutParam()), hrcCheck); + ULONG cDevices; + CHECK_ERROR2I_RET(ptrStorageCtl, COMGETTER(MaxDevicesPerPortCount)(&cDevices), hrcCheck); + ULONG cPorts; + CHECK_ERROR2I_RET(ptrStorageCtl, COMGETTER(PortCount)(&cPorts), hrcCheck); + + for (ULONG i = 0; i < cPorts; ++ i) + { + for (ULONG k = 0; k < cDevices; ++ k) + { + ComPtr mediumAttach; + HRESULT hrc = machine->GetMediumAttachment(bstrStorageCtlName.raw(), i, k, mediumAttach.asOutParam()); + if (!SUCCEEDED(hrc) && hrc != VBOX_E_OBJECT_NOT_FOUND) + { + com::GlueHandleComError(machine, "GetMediumAttachment", hrc, __FILE__, __LINE__); + return hrc; + } + + BOOL fIsEjected = FALSE; + BOOL fTempEject = FALSE; + BOOL fHotPlug = FALSE; + BOOL fNonRotational = FALSE; + BOOL fDiscard = FALSE; + DeviceType_T devType = DeviceType_Null; + if (mediumAttach) + { + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(TemporaryEject)(&fTempEject), hrcCheck); + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(IsEjected)(&fIsEjected), hrcCheck); + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(Type)(&devType), hrcCheck); + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(HotPluggable)(&fHotPlug), hrcCheck); + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(NonRotational)(&fNonRotational), hrcCheck); + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(Discard)(&fDiscard), hrcCheck); + } + + ComPtr medium; + hrc = machine->GetMedium(bstrStorageCtlName.raw(), i, k, medium.asOutParam()); + if (SUCCEEDED(hrc) && medium) + { + BOOL fPassthrough = FALSE; + if (mediumAttach) + { + CHECK_ERROR2I_RET(mediumAttach, COMGETTER(Passthrough)(&fPassthrough), hrcCheck); + } + + Bstr bstrFilePath; + CHECK_ERROR2I_RET(medium, COMGETTER(Location)(bstrFilePath.asOutParam()), hrcCheck); + Bstr bstrUuid; + CHECK_ERROR2I_RET(medium, COMGETTER(Id)(bstrUuid.asOutParam()), hrcCheck); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr(" Port %u, Unit %u: UUID: %ls%s%s%s%s%s%s\n Location: \"%ls\"\n"), + i, k, bstrUuid.raw(), + fPassthrough ? Info::tr(", passthrough enabled") : "", + fTempEject ? Info::tr(", temp eject") : "", + fIsEjected ? Info::tr(", ejected") : "", + fHotPlug ? Info::tr(", hot-pluggable") : "", + fNonRotational ? Info::tr(", non-rotational (SSD)") : "", + fDiscard ? Info::tr(", discards unused blocks") : "", + bstrFilePath.raw()); + else + { + /* Note! dvdpassthough, tempeject and IsEjected was all missed the port + and unit bits prior to VBox 7.0. */ + /** @todo This would look better on the "%ls-%d-%d-{tag}" form! */ + outputMachineReadableStringWithFmtName(&bstrFilePath, + true, "%ls-%d-%d", bstrStorageCtlName.raw(), i, k); + outputMachineReadableStringWithFmtName(&bstrUuid, + true, "%ls-ImageUUID-%d-%d", bstrStorageCtlName.raw(), i, k); + + if (fPassthrough) + outputMachineReadableStringWithFmtName("on", + true, "%ls-dvdpassthrough-%d-%d", bstrStorageCtlName.raw(), i, k); + if (devType == DeviceType_DVD) + { + outputMachineReadableStringWithFmtName(fTempEject ? "on" : "off", + true, "%ls-tempeject-%d-%d", bstrStorageCtlName.raw(), i, k); + outputMachineReadableStringWithFmtName(fIsEjected ? "on" : "off", + true, "%ls-IsEjected-%d-%d", bstrStorageCtlName.raw(), i, k); + } + + if ( bstrStorageCtlName.compare(Bstr("SATA"), Bstr::CaseInsensitive)== 0 + || bstrStorageCtlName.compare(Bstr("USB"), Bstr::CaseInsensitive)== 0) + outputMachineReadableStringWithFmtName(fHotPlug ? "on" : "off", + true, "%ls-hot-pluggable-%d-%d", bstrStorageCtlName.raw(), + i, k); + + outputMachineReadableStringWithFmtName(fNonRotational ? "on" : "off", + true, "%ls-nonrotational-%d-%d", bstrStorageCtlName.raw(), i, k); + outputMachineReadableStringWithFmtName(fDiscard ? "on" : "off", + true, "%ls-discard-%d-%d", bstrStorageCtlName.raw(), i, k); + } + } + else if (SUCCEEDED(hrc)) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr(" Port %u, Unit %u: Empty%s%s\n"), i, k, + fTempEject ? Info::tr(", temp eject") : "", + fIsEjected ? Info::tr(", ejected") : ""); + else + { + outputMachineReadableStringWithFmtName("emptydrive", true, "%ls-%d-%d", bstrStorageCtlName.raw(), i, k); + if (devType == DeviceType_DVD) + outputMachineReadableStringWithFmtName(fIsEjected ? "on" : "off", + true, "%ls-IsEjected-%d-%d", bstrStorageCtlName.raw(), i, k); + } + } + else if (details == VMINFO_MACHINEREADABLE) + outputMachineReadableStringWithFmtName("none", true, "%ls-%d-%d", bstrStorageCtlName.raw(), i, k); + else if (hrc != VBOX_E_OBJECT_NOT_FOUND) + RTPrintf(Info::tr(" Port %u, Unit %u: GetMedium failed: %Rhrc\n"), i, k, hrc); + + } + } + return S_OK; +} + + +#ifdef VBOX_WITH_IOMMU_AMD +static const char *iommuTypeToString(IommuType_T iommuType, VMINFO_DETAILS details) +{ + switch (iommuType) + { + case IommuType_None: + if (details == VMINFO_MACHINEREADABLE) + return "none"; + return Info::tr("None"); + + case IommuType_Automatic: + if (details == VMINFO_MACHINEREADABLE) + return "automatic"; + return Info::tr("Automatic"); + + case IommuType_AMD: + if (details == VMINFO_MACHINEREADABLE) + return "amd"; + return "AMD"; + + case IommuType_Intel: + if (details == VMINFO_MACHINEREADABLE) + return "intel"; + return "Intel"; + + default: + if (details == VMINFO_MACHINEREADABLE) + return "unknown"; + return Info::tr("Unknown"); + } +} +#endif + +static const char *paravirtProviderToString(ParavirtProvider_T provider, VMINFO_DETAILS details) +{ + switch (provider) + { + case ParavirtProvider_None: + if (details == VMINFO_MACHINEREADABLE) + return "none"; + return Info::tr("None"); + + case ParavirtProvider_Default: + if (details == VMINFO_MACHINEREADABLE) + return "default"; + return Info::tr("Default"); + + case ParavirtProvider_Legacy: + if (details == VMINFO_MACHINEREADABLE) + return "legacy"; + return Info::tr("Legacy"); + + case ParavirtProvider_Minimal: + if (details == VMINFO_MACHINEREADABLE) + return "minimal"; + return Info::tr("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 Info::tr("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 pVirtualBox, + ComPtr machine, + ComPtr pSession, + VMINFO_DETAILS details /*= VMINFO_NONE*/) +{ + HRESULT hrc; + ComPtr pConsole; + if (pSession) + pSession->COMGETTER(Console)(pConsole.asOutParam()); + + char szNm[80]; + char szValue[256]; + + /* + * 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(Info::tr("\"\" {%s}\n"), Utf8Str(uuid).c_str()); + else + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("name=\"\"\n"); + else + RTPrintf(Info::tr("Name: \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; + hrc = machine->COMGETTER(SettingsFilePath)(settingsFilePath.asOutParam()); + RTPrintf(Info::tr("Config file: %ls\n"), settingsFilePath.raw()); + + Bstr strCipher; + Bstr strPasswordId; + HRESULT hrc2 = machine->GetEncryptionSettings(strCipher.asOutParam(), strPasswordId.asOutParam()); + if (SUCCEEDED(hrc2)) + { + RTPrintf("Encryption: enabled\n"); + RTPrintf("Cipher: %ls\n", strCipher.raw()); + RTPrintf("Password ID: %ls\n", strPasswordId.raw()); + } + else + RTPrintf("Encryption: disabled\n"); + + ComPtr accessError; + hrc = machine->COMGETTER(AccessError)(accessError.asOutParam()); + RTPrintf(Info::tr("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", Info::tr("Name:")); + { + Bstr strCipher; + Bstr strPasswordId; + HRESULT hrc2 = machine->GetEncryptionSettings(strCipher.asOutParam(), strPasswordId.asOutParam()); + if (SUCCEEDED(hrc2)) + { + RTPrintf("Encryption: enabled\n"); + RTPrintf("Cipher: %ls\n", strCipher.raw()); + RTPrintf("Password ID: %ls\n", strPasswordId.raw()); + } + else + RTPrintf("Encryption: disabled\n"); + } + SHOW_STRINGARRAY_PROP( machine, Groups, "groups", Info::tr("Groups:")); + Bstr osTypeId; + CHECK_ERROR2I_RET(machine, COMGETTER(OSTypeId)(osTypeId.asOutParam()), hrcCheck); + ComPtr osType; + pVirtualBox->GetGuestOSType(osTypeId.raw(), osType.asOutParam()); + if (!osType.isNull()) + SHOW_STRING_PROP( osType, Description, "ostype", Info::tr("Guest OS:")); + else + SHOW_STRING_PROP( machine, OSTypeId, "ostype", Info::tr("Guest OS:")); + SHOW_UUID_PROP( machine, Id, "UUID", "UUID:"); + SHOW_STRING_PROP( machine, SettingsFilePath, "CfgFile", Info::tr("Config file:")); + SHOW_STRING_PROP( machine, SnapshotFolder, "SnapFldr", Info::tr("Snapshot folder:")); + SHOW_STRING_PROP( machine, LogFolder, "LogFldr", Info::tr("Log folder:")); + SHOW_UUID_PROP( machine, HardwareUUID, "hardwareuuid", Info::tr("Hardware UUID:")); + SHOW_ULONG_PROP( machine, MemorySize, "memory", Info::tr("Memory size:"), "MB"); + SHOW_BOOLEAN_PROP( machine, PageFusionEnabled, "pagefusion", Info::tr("Page Fusion:")); + ComPtr pGraphicsAdapter; + machine->COMGETTER(GraphicsAdapter)(pGraphicsAdapter.asOutParam()); + SHOW_ULONG_PROP(pGraphicsAdapter, VRAMSize, "vram", Info::tr("VRAM size:"), "MB"); + SHOW_ULONG_PROP( machine, CPUExecutionCap, "cpuexecutioncap", Info::tr("CPU exec cap:"), "%"); + SHOW_BOOLEAN_PROP( machine, HPETEnabled, "hpet", Info::tr("HPET:")); + SHOW_STRING_PROP_MAJ( machine, CPUProfile, "cpu-profile", Info::tr("CPUProfile:"), "host", 6); + + ChipsetType_T chipsetType; + CHECK_ERROR2I_RET(machine, COMGETTER(ChipsetType)(&chipsetType), hrcCheck); + const char *pszChipsetType; + switch (chipsetType) + { + case ChipsetType_Null: + if (details == VMINFO_MACHINEREADABLE) + pszChipsetType = "invalid"; + else + pszChipsetType = Info::tr("invalid"); + break; + case ChipsetType_PIIX3: pszChipsetType = "piix3"; break; + case ChipsetType_ICH9: pszChipsetType = "ich9"; break; + default: + AssertFailed(); + if (details == VMINFO_MACHINEREADABLE) + pszChipsetType = "unknown"; + else + pszChipsetType = Info::tr("unknown"); + break; + } + SHOW_UTF8_STRING("chipset", Info::tr("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(); + if (details == VMINFO_MACHINEREADABLE) + pszFirmwareType = "unknown"; + else + pszFirmwareType = Info::tr("unknown"); + break; + } + SHOW_UTF8_STRING("firmware", Info::tr("Firmware:"), pszFirmwareType); + + SHOW_ULONG_PROP( machine, CPUCount, "cpus", Info::tr("Number of CPUs:"), ""); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_PAE, &f), "pae", "PAE:"); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_LongMode, &f), "longmode", Info::tr("Long Mode:")); + SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_TripleFaultReset, &f), "triplefaultreset", Info::tr("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", Info::tr("Nested VT-x/AMD-V:")); + SHOW_ULONG_PROP( machine, CPUIDPortabilityLevel, "cpuid-portability-level", Info::tr("CPUID Portability Level:"), ""); + + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s ", Info::tr("CPUID overrides:")); + ULONG uOrdinal = 0; + for (uOrdinal = 0; uOrdinal < _4K; uOrdinal++) + { + ULONG uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX; + hrc = machine->GetCPUIDLeafByOrdinal(uOrdinal, &uLeaf, &uSubLeaf, &uEAX, &uEBX, &uECX, &uEDX); + if (SUCCEEDED(hrc)) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("cpuid=%08x,%08x,%08x,%08x,%08x,%08x", uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX); + else + { + if (!uOrdinal) + RTPrintf(Info::tr("Leaf no. EAX EBX ECX EDX\n")); + RTPrintf("%-28s %08x/%03x %08x %08x %08x %08x\n", "", uLeaf, uSubLeaf, uEAX, uEBX, uECX, uEDX); + } + } + else + { + if (hrc != E_INVALIDARG) + com::GlueHandleComError(machine, "GetCPUIDLeaf", hrc, __FILE__, __LINE__); + break; + } + } + if (!uOrdinal && details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr("None\n")); + + ComPtr biosSettings; + CHECK_ERROR2I_RET(machine, COMGETTER(BIOSSettings)(biosSettings.asOutParam()), hrcCheck); + + ComPtr nvramStore; + CHECK_ERROR2I_RET(machine, COMGETTER(NonVolatileStore)(nvramStore.asOutParam()), hrcCheck); + + BIOSBootMenuMode_T bootMenuMode; + CHECK_ERROR2I_RET(biosSettings, COMGETTER(BootMenuMode)(&bootMenuMode), hrcCheck); + const char *pszBootMenu; + switch (bootMenuMode) + { + case BIOSBootMenuMode_Disabled: + if (details == VMINFO_MACHINEREADABLE) + pszBootMenu = "disabled"; + else + pszBootMenu = Info::tr("disabled"); + break; + case BIOSBootMenuMode_MenuOnly: + if (details == VMINFO_MACHINEREADABLE) + pszBootMenu = "menuonly"; + else + pszBootMenu = Info::tr("menu only"); + break; + default: + if (details == VMINFO_MACHINEREADABLE) + pszBootMenu = "messageandmenu"; + else + pszBootMenu = Info::tr("message and menu"); + } + SHOW_UTF8_STRING("bootmenu", Info::tr("Boot menu mode:"), pszBootMenu); + + ComPtr 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" : Info::tr("Floppy"); + else if (bootOrder == DeviceType_DVD) + pszDevice = details == VMINFO_MACHINEREADABLE ? "dvd" : "DVD"; + else if (bootOrder == DeviceType_HardDisk) + pszDevice = details == VMINFO_MACHINEREADABLE ? "disk" : Info::tr("HardDisk"); + else if (bootOrder == DeviceType_Network) + pszDevice = details == VMINFO_MACHINEREADABLE ? "net" : Info::tr("Network"); + else if (bootOrder == DeviceType_USB) + pszDevice = details == VMINFO_MACHINEREADABLE ? "usb" : "USB"; + else if (bootOrder == DeviceType_SharedFolder) + pszDevice = details == VMINFO_MACHINEREADABLE ? "sharedfolder" : Info::tr("Shared Folder"); + else + pszDevice = details == VMINFO_MACHINEREADABLE ? "none" : Info::tr("Not Assigned"); + SHOW_UTF8_STRING(FmtNm(szNm, "boot%u", i), FmtNm(szNm, Info::tr("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: + if (details == VMINFO_MACHINEREADABLE) + pszAPIC = "disabled"; + else + pszAPIC = Info::tr("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", Info::tr("BIOS APIC mode:"), pszAPIC); + + SHOW_LONG64_PROP(biosSettings, TimeOffset, "biossystemtimeoffset", Info::tr("Time offset:"), Info::tr("ms")); + Bstr bstrNVRAMFile; + CHECK_ERROR2I_RET(nvramStore, COMGETTER(NonVolatileStorageFile)(bstrNVRAMFile.asOutParam()), hrcCheck); + if (bstrNVRAMFile.isNotEmpty()) + SHOW_BSTR_STRING("BIOS NVRAM File", Info::tr("BIOS NVRAM File:"), bstrNVRAMFile); + SHOW_BOOLEAN_PROP_EX(machine, RTCUseUTC, "rtcuseutc", Info::tr("RTC:"), "UTC", Info::tr("local time")); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &f), "hwvirtex", Info::tr("Hardware Virtualization:")); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &f),"nestedpaging", Info::tr("Nested Paging:")); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &f), "largepages", Info::tr("Large Pages:")); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_VPID, &f), "vtxvpid", "VT-x VPID:"); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &f), "vtxux", Info::tr("VT-x Unrestricted Exec.:")); + SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_VirtVmsaveVmload, &f), "virtvmsavevmload", Info::tr("AMD-V Virt. Vmsave/Vmload:")); + +#ifdef VBOX_WITH_IOMMU_AMD + IommuType_T iommuType; + CHECK_ERROR2I_RET(machine, COMGETTER(IommuType)(&iommuType), hrcCheck); + const char *pszIommuType = iommuTypeToString(iommuType, details); + SHOW_UTF8_STRING("iommu", "IOMMU:", pszIommuType); +#endif + + ParavirtProvider_T paravirtProvider; + CHECK_ERROR2I_RET(machine, COMGETTER(ParavirtProvider)(¶virtProvider), hrcCheck); + const char *pszParavirtProvider = paravirtProviderToString(paravirtProvider, details); + SHOW_UTF8_STRING("paravirtprovider", Info::tr("Paravirt. Provider:"), pszParavirtProvider); + + ParavirtProvider_T effParavirtProvider; + CHECK_ERROR2I_RET(machine, GetEffectiveParavirtProvider(&effParavirtProvider), hrcCheck); + const char *pszEffParavirtProvider = paravirtProviderToString(effParavirtProvider, details); + SHOW_UTF8_STRING("effparavirtprovider", Info::tr("Effective Paravirt. Prov.:"), pszEffParavirtProvider); + + Bstr paravirtDebug; + CHECK_ERROR2I_RET(machine, COMGETTER(ParavirtDebug)(paravirtDebug.asOutParam()), hrcCheck); + if (paravirtDebug.isNotEmpty()) + SHOW_BSTR_STRING("paravirtdebug", Info::tr("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(Info::tr("%-28s %s (since %s)\n"), Info::tr("State:"), pszState, pszTime); + + GraphicsControllerType_T enmGraphics; + hrc = pGraphicsAdapter->COMGETTER(GraphicsControllerType)(&enmGraphics); + if (SUCCEEDED(hrc)) + { + const char *pszCtrl; + switch (enmGraphics) + { + case GraphicsControllerType_Null: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "null"; + else + pszCtrl = Info::tr("Null"); + break; + case GraphicsControllerType_VBoxVGA: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "vboxvga"; + else + pszCtrl = "VBoxVGA"; + break; + case GraphicsControllerType_VMSVGA: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "vmsvga"; + else + pszCtrl = "VMSVGA"; + break; + case GraphicsControllerType_VBoxSVGA: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "vboxsvga"; + else + pszCtrl = "VBoxSVGA"; + break; + default: + if (details == VMINFO_MACHINEREADABLE) + pszCtrl = "unknown"; + else + pszCtrl = Info::tr("Unknown"); + break; + } + + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("graphicscontroller=\"%s\"\n", pszCtrl); + else + RTPrintf("%-28s %s\n", Info::tr("Graphics Controller:"), pszCtrl); + } + + SHOW_ULONG_PROP(pGraphicsAdapter, MonitorCount, "monitorcount", Info::tr("Monitor count:"), ""); + SHOW_BOOLEAN_PROP(pGraphicsAdapter, Accelerate3DEnabled, "accelerate3d", Info::tr("3D Acceleration:")); +#ifdef VBOX_WITH_VIDEOHWACCEL + SHOW_BOOLEAN_PROP(pGraphicsAdapter, Accelerate2DVideoEnabled, "accelerate2dvideo", Info::tr("2D Video Acceleration:")); +#endif + SHOW_BOOLEAN_PROP( machine, TeleporterEnabled, "teleporterenabled", Info::tr("Teleporter Enabled:")); + SHOW_ULONG_PROP( machine, TeleporterPort, "teleporterport", Info::tr("Teleporter Port:"), ""); + SHOW_STRING_PROP( machine, TeleporterAddress, "teleporteraddress", Info::tr("Teleporter Address:")); + SHOW_STRING_PROP( machine, TeleporterPassword, "teleporterpassword", Info::tr("Teleporter Password:")); + SHOW_BOOLEAN_PROP( machine, TracingEnabled, "tracing-enabled", Info::tr("Tracing Enabled:")); + SHOW_BOOLEAN_PROP( machine, AllowTracingToAccessVM, "tracing-allow-vm-access", Info::tr("Allow Tracing to Access VM:")); + SHOW_STRING_PROP( machine, TracingConfig, "tracing-config", Info::tr("Tracing Configuration:")); + SHOW_BOOLEAN_PROP( machine, AutostartEnabled, "autostart-enabled", Info::tr("Autostart Enabled:")); + SHOW_ULONG_PROP( machine, AutostartDelay, "autostart-delay", Info::tr("Autostart Delay:"), ""); + SHOW_STRING_PROP( machine, DefaultFrontend, "defaultfrontend", Info::tr("Default Frontend:")); + + VMProcPriority_T enmVMProcPriority; + CHECK_ERROR2I_RET(machine, COMGETTER(VMProcessPriority)(&enmVMProcPriority), hrcCheck); + const char *pszVMProcPriority; + switch (enmVMProcPriority) + { + case VMProcPriority_Flat: + if (details == VMINFO_MACHINEREADABLE) + pszVMProcPriority = "flat"; + else + pszVMProcPriority = Info::tr("flat"); + break; + case VMProcPriority_Low: + if (details == VMINFO_MACHINEREADABLE) + pszVMProcPriority = "low"; + else + pszVMProcPriority = Info::tr("low"); + break; + case VMProcPriority_Normal: + if (details == VMINFO_MACHINEREADABLE) + pszVMProcPriority = "normal"; + else + pszVMProcPriority = Info::tr("normal"); + break; + case VMProcPriority_High: + if (details == VMINFO_MACHINEREADABLE) + pszVMProcPriority = "high"; + else + pszVMProcPriority = Info::tr("high"); + break; + default: + if (details == VMINFO_MACHINEREADABLE) + pszVMProcPriority = "default"; + else + pszVMProcPriority = Info::tr("default"); + break; + } + SHOW_UTF8_STRING("vmprocpriority", Info::tr("VM process priority:"), pszVMProcPriority); + +/** @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 storageCtls; + CHECK_ERROR(machine, COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(storageCtls))); + if (storageCtls.size() > 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%s\n", Info::tr("Storage Controllers:")); + + for (size_t i = 0; i < storageCtls.size(); ++i) + { + ComPtr storageCtl = storageCtls[i]; + + Bstr bstrName; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(Name)(bstrName.asOutParam()), hrcCheck); + StorageControllerType_T enmCtlType = StorageControllerType_Null; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(ControllerType)(&enmCtlType), hrcCheck); + ULONG uInstance = 0; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(Instance)(&uInstance), hrcCheck); + ULONG cMaxPorts = 0; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(MaxPortCount)(&cMaxPorts), hrcCheck); + ULONG cPorts = 0; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(PortCount)(&cPorts), hrcCheck); + BOOL fBootable = FALSE; + CHECK_ERROR2I_RET(storageCtl, COMGETTER(Bootable)(&fBootable), hrcCheck); + if (details == VMINFO_MACHINEREADABLE) + { + outputMachineReadableString(FmtNm(szNm, "storagecontrollername%u", i), &bstrName); + outputMachineReadableString(FmtNm(szNm, "storagecontrollertype%u", i), + storageControllerTypeToName(enmCtlType, true)); + RTPrintf("storagecontrollerinstance%u=\"%u\"\n", i, uInstance); + RTPrintf("storagecontrollermaxportcount%u=\"%u\"\n", i, cMaxPorts); + RTPrintf("storagecontrollerportcount%u=\"%u\"\n", i, cPorts); + RTPrintf("storagecontrollerbootable%u=\"%s\"\n", i, fBootable ? "on" : "off"); + } + else + { + RTPrintf(Info::tr("#%u: '%ls', Type: %s, Instance: %u, Ports: %u (max %u), %s\n"), i, bstrName.raw(), + storageControllerTypeToName(enmCtlType, false), uInstance, cPorts, cMaxPorts, + fBootable ? Info::tr("Bootable") : Info::tr("Not bootable")); + hrc = showMediumAttachments(machine, storageCtl, details); + if (FAILED(hrc)) + return hrc; + } + } + } + else if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s %s\n", Info::tr("Storage Controllers:"), Info::tr("")); + + if (details == VMINFO_MACHINEREADABLE) + for (size_t j = 0; j < storageCtls.size(); ++ j) + { + hrc = showMediumAttachments(machine, storageCtls[j], details); + if (FAILED(hrc)) + return hrc; + } + + /* get the maximum amount of NICS */ + ULONG maxNICs = getMaxNics(pVirtualBox, machine); + + for (ULONG currentNIC = 0; currentNIC < maxNICs; currentNIC++) + { + ComPtr nic; + hrc = machine->GetNetworkAdapter(currentNIC, nic.asOutParam()); + if (SUCCEEDED(hrc) && nic) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "nic%u" : Info::tr("NIC %u:"), currentNIC + 1); + + BOOL fEnabled; + nic->COMGETTER(Enabled)(&fEnabled); + if (!fEnabled) + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("%s=\"none\"\n", szNm); + else + RTPrintf(Info::tr("%-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 = Info::tr("none"); + break; + + case NetworkAttachmentType_NAT: + { + Bstr strNetwork; + ComPtr engine; + nic->COMGETTER(NATEngine)(engine.asOutParam()); + engine->COMGETTER(Network)(strNetwork.asOutParam()); + com::SafeArray 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) + /** @todo r=bird: This probably isn't good enough wrt escaping. */ + strNatForwardings.appendPrintf("Forwarding(%d)=\"%s,%s,%s,%s,%s,%s\"\n", + i, strName.c_str(), strProto.c_str(), + strHostIP.c_str(), strHostPort.c_str(), + strGuestIP.c_str(), strGuestPort.c_str()); + else + strNatForwardings.appendPrintf(Info::tr("NIC %d Rule(%d): name = %s, protocol = %s, host ip = %s, host port = %s, guest ip = %s, guest port = %s\n"), + 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.printf("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.printf(Info::tr("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.printf(Info::tr("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.printf(Info::tr("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.printf(Info::tr("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.printf(Info::tr("Generic '%ls'"), strGenericDriver.raw()); + + // show the generic properties + com::SafeArray aProperties; + com::SafeArray aValues; + hrc = nic->GetProperties(NULL, + ComSafeArrayAsOutParam(aProperties), + ComSafeArrayAsOutParam(aValues)); + if (SUCCEEDED(hrc)) + { + strAttachment += " { "; + for (unsigned i = 0; i < aProperties.size(); ++i) + strAttachment.appendPrintf(!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.printf(Info::tr("NAT Network '%s'"), Utf8Str(strNetwork).c_str()); + break; + } + +#ifdef VBOX_WITH_VMNET + case NetworkAttachmentType_HostOnlyNetwork: + { + Bstr strNetwork; + nic->COMGETTER(HostOnlyNetwork)(strNetwork.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("hostonly-network%d=\"%ls\"\n", currentNIC + 1, strNetwork.raw()); + strAttachment = "hostonlynetwork"; + } + else + strAttachment.printf(Info::tr("Host Only Network '%s'"), Utf8Str(strNetwork).c_str()); + break; + } +#endif /* VBOX_WITH_VMNET */ + +#ifdef VBOX_WITH_CLOUD_NET + case NetworkAttachmentType_Cloud: + { + Bstr strNetwork; + nic->COMGETTER(CloudNetwork)(strNetwork.asOutParam()); + if (details == VMINFO_MACHINEREADABLE) + { + RTPrintf("cloud-network%d=\"%ls\"\n", currentNIC + 1, strNetwork.raw()); + strAttachment = "cloudnetwork"; + } + else + strAttachment.printf(Info::tr("Cloud Network '%s'"), Utf8Str(strNetwork).c_str()); + break; + } +#endif /* VBOX_WITH_CLOUD_NET */ + + default: + if (details == VMINFO_MACHINEREADABLE) + strAttachment = "unknown"; + else + strAttachment = Info::tr("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 = Info::tr("deny"); break; + case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = Info::tr("allow-vms"); break; + case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = Info::tr("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; + case NetworkAdapterType_Am79C960: pszNICType = "Am79C960"; 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 + case NetworkAdapterType_NE1000: pszNICType = "NE1000"; break; + case NetworkAdapterType_NE2000: pszNICType = "NE2000"; break; + case NetworkAdapterType_WD8003: pszNICType = "WD8003"; break; + case NetworkAdapterType_WD8013: pszNICType = "WD8013"; break; + case NetworkAdapterType_ELNK2: pszNICType = "3C503"; break; + case NetworkAdapterType_ELNK1: pszNICType = "3C501"; break; + default: + AssertFailed(); + if (details == VMINFO_MACHINEREADABLE) + pszNICType = "unknown"; + else + pszNICType = Info::tr("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 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(Info::tr("%-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 ? Info::tr("on") : Info::tr("off"), + fTraceEnabled ? Info::tr("on") : Info::tr("off"), + traceFile.isEmpty() ? Bstr(Info::tr("none")).raw() : traceFile.raw(), + pszNICType, + ulLineSpeed / 1000, + (int)ulBootPriority, + pszPromiscuousGuestPolicy, + strBwGroup.isEmpty() ? Bstr(Info::tr("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 = Info::tr("Unknown"); + const char *pszMrHID = "unknown"; + machine->COMGETTER(PointingHIDType)(&aPointingHID); + switch (aPointingHID) + { + case PointingHIDType_None: + pszHID = Info::tr("None"); + pszMrHID = "none"; + break; + case PointingHIDType_PS2Mouse: + pszHID = Info::tr("PS/2 Mouse"); + pszMrHID = "ps2mouse"; + break; + case PointingHIDType_USBMouse: + pszHID = Info::tr("USB Mouse"); + pszMrHID = "usbmouse"; + break; + case PointingHIDType_USBTablet: + pszHID = Info::tr("USB Tablet"); + pszMrHID = "usbtablet"; + break; + case PointingHIDType_ComboMouse: + pszHID = Info::tr("USB Tablet and PS/2 Mouse"); + pszMrHID = "combomouse"; + break; + case PointingHIDType_USBMultiTouch: + pszHID = Info::tr("USB Multi-Touch"); + pszMrHID = "usbmultitouch"; + break; + default: + break; + } + SHOW_UTF8_STRING("hidpointing", Info::tr("Pointing Device:"), details == VMINFO_MACHINEREADABLE ? pszMrHID : pszHID); + + /* Keyboard device information */ + KeyboardHIDType_T aKeyboardHID; + machine->COMGETTER(KeyboardHIDType)(&aKeyboardHID); + pszHID = Info::tr("Unknown"); + pszMrHID = "unknown"; + switch (aKeyboardHID) + { + case KeyboardHIDType_None: + pszHID = Info::tr("None"); + pszMrHID = "none"; + break; + case KeyboardHIDType_PS2Keyboard: + pszHID = Info::tr("PS/2 Keyboard"); + pszMrHID = "ps2kbd"; + break; + case KeyboardHIDType_USBKeyboard: + pszHID = Info::tr("USB Keyboard"); + pszMrHID = "usbkbd"; + break; + case KeyboardHIDType_ComboKeyboard: + pszHID = Info::tr("USB and PS/2 Keyboard"); + pszMrHID = "combokbd"; + break; + default: + break; + } + SHOW_UTF8_STRING("hidkeyboard", Info::tr("Keyboard Device:"), details == VMINFO_MACHINEREADABLE ? pszMrHID : pszHID); + + ComPtr 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 uart; + hrc = machine->GetSerialPort(currentUART, uart.asOutParam()); + if (SUCCEEDED(hrc) && uart) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "uart%u" : Info::tr("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(Info::tr("%-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(Info::tr("%-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(Info::tr(", disconnected")); + break; + case PortMode_RawFile: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"file,%ls\"\n", currentUART + 1, + path.raw()); + else + RTPrintf(Info::tr(", 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(Info::tr(", attached to tcp (%s) '%ls'"), + fServer ? Info::tr("server") : Info::tr("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(Info::tr(", attached to pipe (%s) '%ls'"), + fServer ? Info::tr("server") : Info::tr("client"), path.raw()); + break; + case PortMode_HostDevice: + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("uartmode%d=\"%ls\"\n", currentUART + 1, + path.raw()); + else + RTPrintf(Info::tr(", 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 lpt; + hrc = machine->GetParallelPort(currentLPT, lpt.asOutParam()); + if (SUCCEEDED(hrc) && lpt) + { + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "lpt%u" : Info::tr("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(Info::tr("%-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(Info::tr("%-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(Info::tr(", attached to device '%ls'\n"), path.raw()); + } + } + } + + ComPtr audioSettings; + ComPtr audioAdapter; + hrc = machine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); + if (SUCCEEDED(hrc)) + hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); + if (SUCCEEDED(hrc)) + { + const char *pszDrv = Info::tr("Unknown"); + const char *pszCtrl = Info::tr("Unknown"); + const char *pszCodec = Info::tr("Unknown"); + BOOL fEnabled; + hrc = audioAdapter->COMGETTER(Enabled)(&fEnabled); + if (SUCCEEDED(hrc) && fEnabled) + { + AudioDriverType_T enmDrvType; + hrc = audioAdapter->COMGETTER(AudioDriver)(&enmDrvType); + switch (enmDrvType) + { + case AudioDriverType_Default: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "default"; + else + pszDrv = Info::tr("Default"); + break; + case AudioDriverType_Null: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "null"; + else + pszDrv = Info::tr("Null"); + 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_WinMM: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "winmm"; + else + pszDrv = "WINMM"; + break; + case AudioDriverType_DirectSound: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "dsound"; + else + pszDrv = "DirectSound"; + break; + case AudioDriverType_WAS: + if (details == VMINFO_MACHINEREADABLE) + pszDrv = "was"; + else + pszDrv = "Windows Audio Session (WAS)"; + 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; + hrc = 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; + hrc = 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", Info::tr("Audio:"), fEnabled ? Info::tr("enabled") : Info::tr("disabled")); + if (fEnabled) + RTPrintf(Info::tr(" (Driver: %s, Controller: %s, Codec: %s)"), pszDrv, pszCtrl, pszCodec); + RTPrintf("\n"); + } + SHOW_BOOLEAN_PROP(audioAdapter, EnabledOut, "audio_out", Info::tr("Audio playback:")); + SHOW_BOOLEAN_PROP(audioAdapter, EnabledIn, "audio_in", Info::tr("Audio capture:")); + + /** @todo Add printing run-time host audio device selection(s) here. */ + } + + /* Shared clipboard */ + { + const char *psz; + ClipboardMode_T enmMode = (ClipboardMode_T)0; + hrc = machine->COMGETTER(ClipboardMode)(&enmMode); + switch (enmMode) + { + case ClipboardMode_Disabled: + psz = "disabled"; + break; + case ClipboardMode_HostToGuest: + psz = details == VMINFO_MACHINEREADABLE ? "hosttoguest" : Info::tr("HostToGuest"); + break; + case ClipboardMode_GuestToHost: + psz = details == VMINFO_MACHINEREADABLE ? "guesttohost" : Info::tr("GuestToHost"); + break; + case ClipboardMode_Bidirectional: + psz = details == VMINFO_MACHINEREADABLE ? "bidirectional" : Info::tr("Bidirectional"); + break; + default: + psz = details == VMINFO_MACHINEREADABLE ? "unknown" : Info::tr("Unknown"); + break; + } + SHOW_UTF8_STRING("clipboard", Info::tr("Clipboard Mode:"), psz); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + SHOW_BOOLEAN_PROP(machine, ClipboardFileTransfersEnabled, "clipboard_file_transfers", Info::tr("Clipboard file transfers:")); +#endif + } + + /* Drag and drop */ + { + const char *psz; + DnDMode_T enmMode; + hrc = machine->COMGETTER(DnDMode)(&enmMode); + switch (enmMode) + { + case DnDMode_Disabled: + psz = "disabled"; + break; + case DnDMode_HostToGuest: + psz = details == VMINFO_MACHINEREADABLE ? "hosttoguest" : Info::tr("HostToGuest"); + break; + case DnDMode_GuestToHost: + psz = details == VMINFO_MACHINEREADABLE ? "guesttohost" : Info::tr("GuestToHost"); + break; + case DnDMode_Bidirectional: + psz = details == VMINFO_MACHINEREADABLE ? "bidirectional" : Info::tr("Bidirectional"); + break; + default: + psz = details == VMINFO_MACHINEREADABLE ? "unknown" : Info::tr("Unknown"); + break; + } + SHOW_UTF8_STRING("draganddrop", Info::tr("Drag and drop Mode:"), psz); + } + + { + SessionState_T sessState; + hrc = machine->COMGETTER(SessionState)(&sessState); + if (SUCCEEDED(hrc) && sessState != SessionState_Unlocked) + { + Bstr sessName; + hrc = machine->COMGETTER(SessionName)(sessName.asOutParam()); + if (SUCCEEDED(hrc) && !sessName.isEmpty()) + SHOW_BSTR_STRING("SessionName", Info::tr("Session name:"), sessName); + } + } + + if (pConsole) + { + do + { + ComPtr display; + hrc = pConsole->COMGETTER(Display)(display.asOutParam()); + if (hrc == E_ACCESSDENIED || display.isNull()) + break; /* VM not powered up */ + if (FAILED(hrc)) + { + com::GlueHandleComError(pConsole, "COMGETTER(Display)(display.asOutParam())", hrc, __FILE__, __LINE__); + return hrc; + } + ULONG xRes, yRes, bpp; + LONG xOrigin, yOrigin; + GuestMonitorStatus_T monitorStatus; + hrc = display->GetScreenResolution(0, &xRes, &yRes, &bpp, &xOrigin, &yOrigin, &monitorStatus); + if (hrc == E_ACCESSDENIED) + break; /* VM not powered up */ + if (FAILED(hrc)) + { + com::ErrorInfo info(display, COM_IIDOF(IDisplay)); + GluePrintErrorInfo(info); + return hrc; + } + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("VideoMode=\"%d,%d,%d\"@%d,%d %d\n", xRes, yRes, bpp, xOrigin, yOrigin, monitorStatus); + else + { + const char *pszMonitorStatus = Info::tr("unknown status"); + switch (monitorStatus) + { + case GuestMonitorStatus_Blank: pszMonitorStatus = Info::tr("blank"); break; + case GuestMonitorStatus_Enabled: pszMonitorStatus = Info::tr("enabled"); break; + case GuestMonitorStatus_Disabled: pszMonitorStatus = Info::tr("disabled"); break; + default: break; + } + RTPrintf("%-28s %dx%dx%d at %d,%d %s\n", Info::tr("Video mode:"), xRes, yRes, bpp, xOrigin, yOrigin, pszMonitorStatus); + } + } + while (0); + } + + /* + * Remote Desktop + */ + ComPtr vrdeServer; + hrc = machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam()); + if (SUCCEEDED(hrc) && 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: + if (details == VMINFO_MACHINEREADABLE) + strAuthType = "null"; + else + strAuthType = Info::tr("null"); + break; + case AuthType_External: + if (details == VMINFO_MACHINEREADABLE) + strAuthType = "external"; + else + strAuthType = Info::tr("external"); + break; + case AuthType_Guest: + if (details == VMINFO_MACHINEREADABLE) + strAuthType = "guest"; + else + strAuthType = Info::tr("guest"); + break; + default: + if (details == VMINFO_MACHINEREADABLE) + strAuthType = "unknown"; + else + strAuthType = Info::tr("unknown"); + break; + } + if (pConsole) + { + ComPtr vrdeServerInfo; + CHECK_ERROR_RET(pConsole, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), hrc); + if (!vrdeServerInfo.isNull()) + { + hrc = vrdeServerInfo->COMGETTER(Port)(¤tPort); + if (hrc == E_ACCESSDENIED) + { + currentPort = -1; /* VM not powered up */ + } + else if (FAILED(hrc)) + { + com::ErrorInfo info(vrdeServerInfo, COM_IIDOF(IVRDEServerInfo)); + GluePrintErrorInfo(info); + return hrc; + } + } + } + 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(Info::tr("%-28s enabled (Address %ls, Ports %ls, MultiConn: %s, ReuseSingleConn: %s, Authentication type: %s)\n"), + "VRDE:", address.raw(), ports.raw(), fMultiCon ? Info::tr("on") : Info::tr("off"), + fReuseCon ? Info::tr("on") : Info::tr("off"), strAuthType); + if (pConsole && currentPort != -1 && currentPort != 0) + RTPrintf("%-28s %d\n", Info::tr("VRDE port:"), currentPort); + if (fVideoChannel) + RTPrintf(Info::tr("%-28s enabled (Quality %ls)\n"), Info::tr("Video redirection:"), videoChannelQuality.raw()); + else + RTPrintf(Info::tr("%-28s disabled\n"), Info::tr("Video redirection:")); + } + com::SafeArray 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]=\n", aProperties[i]); + else + RTPrintf("vrdeproperty[%ls]=\"%ls\"\n", aProperties[i], value.raw()); + } + else + { + if (value.isEmpty()) + RTPrintf(Info::tr("%-28s: %-10lS = \n"), Info::tr("VRDE property"), aProperties[i]); + else + RTPrintf("%-28s: %-10lS = \"%ls\"\n", Info::tr("VRDE property"), aProperties[i], value.raw()); + } + } + } + } + else + { + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("vrde=\"off\"\n"); + else + RTPrintf(Info::tr("%-28s disabled\n"), "VRDE:"); + } + } + + /* + * USB. + */ + SafeIfaceArray USBCtlColl; + hrc = machine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(USBCtlColl)); + if (SUCCEEDED(hrc)) + { + bool fOhciEnabled = false; + bool fEhciEnabled = false; + bool fXhciEnabled = false; + + for (unsigned i = 0; i < USBCtlColl.size(); i++) + { + USBControllerType_T enmType; + + hrc = USBCtlColl[i]->COMGETTER(Type)(&enmType); + if (SUCCEEDED(hrc)) + { + 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 USBFlts; + hrc = machine->COMGETTER(USBDeviceFilters)(USBFlts.asOutParam()); + if (SUCCEEDED(hrc)) + { + SafeIfaceArray Coll; + hrc = USBFlts->COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(Coll)); + if (SUCCEEDED(hrc)) + { + if (Coll.size() > 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr("USB Device Filters:\n")); + for (size_t index = 0; index < Coll.size(); ++index) + { + ComPtr DevPtr = Coll[index]; + + if (details != VMINFO_MACHINEREADABLE) + SHOW_UTF8_STRING("index", Info::tr("Index:"), FmtNm(szNm, "%zu", index)); + SHOW_BOOLEAN_PROP_EX(DevPtr, Active, FmtNm(szNm, "USBFilterActive%zu", index + 1), Info::tr(" Active:"), Info::tr("yes"), Info::tr("no")); + SHOW_STRING_PROP(DevPtr, Name, FmtNm(szNm, "USBFilterName%zu", index + 1), Info::tr(" Name:")); + SHOW_STRING_PROP(DevPtr, VendorId, FmtNm(szNm, "USBFilterVendorId%zu", index + 1), Info::tr(" VendorId:")); + SHOW_STRING_PROP(DevPtr, ProductId, FmtNm(szNm, "USBFilterProductId%zu", index + 1), Info::tr(" ProductId:")); + SHOW_STRING_PROP(DevPtr, Revision, FmtNm(szNm, "USBFilterRevision%zu", index + 1), Info::tr(" Revision:")); + SHOW_STRING_PROP(DevPtr, Manufacturer, FmtNm(szNm, "USBFilterManufacturer%zu", index + 1), Info::tr(" Manufacturer:")); + SHOW_STRING_PROP(DevPtr, Product, FmtNm(szNm, "USBFilterProduct%zu", index + 1), Info::tr(" Product:")); + SHOW_STRING_PROP(DevPtr, Remote, FmtNm(szNm, "USBFilterRemote%zu", index + 1), Info::tr(" Remote:")); + SHOW_STRING_PROP(DevPtr, SerialNumber, FmtNm(szNm, "USBFilterSerialNumber%zu", index + 1), Info::tr(" Serial Number:")); + if (details != VMINFO_MACHINEREADABLE) + { + ULONG fMaskedIfs; + CHECK_ERROR_RET(DevPtr, COMGETTER(MaskedInterfaces)(&fMaskedIfs), hrc); + if (fMaskedIfs) + RTPrintf("%-28s %#010x\n", Info::tr("Masked Interfaces:"), fMaskedIfs); + } + } + } + else if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s %s\n", Info::tr("USB Device Filters:"), Info::tr("")); + } + + if (pConsole) + { + { + SafeIfaceArray coll; + CHECK_ERROR_RET(pConsole, COMGETTER(RemoteUSBDevices)(ComSafeArrayAsOutParam(coll)), hrc); + hrc = showUsbDevices(coll, "USBRemote", Info::tr("Available remote USB devices:"), details); + if (FAILED(hrc)) + return hrc; + } + + { + SafeIfaceArray coll; + CHECK_ERROR_RET(pConsole, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)), hrc); + showUsbDevices(coll, "USBAttach", Info::tr("Currently attached USB devices:"), details); + if (FAILED(hrc)) + return hrc; + } + } + } /* USB */ + +#ifdef VBOX_WITH_PCI_PASSTHROUGH + /* Host PCI passthrough devices */ + { + SafeIfaceArray assignments; + hrc = machine->COMGETTER(PCIDeviceAssignments)(ComSafeArrayAsOutParam(assignments)); + if (SUCCEEDED(hrc)) + { + if (assignments.size() > 0 && (details != VMINFO_MACHINEREADABLE)) + { + RTPrintf(Info::tr("\nAttached physical PCI devices:\n\n")); + } + + for (size_t index = 0; index < assignments.size(); ++index) + { + ComPtr 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(Info::tr(" 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("%-28s ", Info::tr("Bandwidth groups:")); + { + ComPtr bwCtrl; + CHECK_ERROR_RET(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()), hrc); + + hrc = showBandwidthGroups(bwCtrl, details); + } + + + /* + * Shared folders + */ + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s ", Info::tr("Shared folders:")); + uint32_t numSharedFolders = 0; +#if 0 // not yet implemented + /* globally shared folders first */ + { + SafeIfaceArray sfColl; + CHECK_ERROR_RET(pVirtualBox, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(sfColl)), rc); + for (size_t i = 0; i < sfColl.size(); ++i) + { + ComPtr sf = sfColl[i]; + showSharedFolder(sf, details, Info::tr("global mapping"), "GlobalMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } +#endif + /* now VM mappings */ + { + com::SafeIfaceArray folders; + CHECK_ERROR_RET(machine, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), hrc); + for (size_t i = 0; i < folders.size(); ++i) + { + ComPtr sf = folders[i]; + showSharedFolder(sf, details, Info::tr("machine mapping"), "MachineMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } + /* transient mappings */ + if (pConsole) + { + com::SafeIfaceArray folders; + CHECK_ERROR_RET(pConsole, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), hrc); + for (size_t i = 0; i < folders.size(); ++i) + { + ComPtr sf = folders[i]; + showSharedFolder(sf, details, Info::tr("transient mapping"), "TransientMapping", i + 1, numSharedFolders == 0); + ++numSharedFolders; + } + } + if (details != VMINFO_MACHINEREADABLE) + { + if (!numSharedFolders) + RTPrintf(Info::tr("\n")); + else + RTPrintf("\n"); + } + + if (pConsole) + { + /* + * Live VRDE info. + */ + ComPtr vrdeServerInfo; + CHECK_ERROR_RET(pConsole, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), hrc); + 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), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(NumberOfClients)(&cNumberOfClients), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BeginTime)(&BeginTime), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EndTime)(&EndTime), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSent)(&BytesSent), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSentTotal)(&BytesSentTotal), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceived)(&BytesReceived), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceivedTotal)(&BytesReceivedTotal), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(User)(User.asOutParam()), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(Domain)(Domain.asOutParam()), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientName)(ClientName.asOutParam()), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientIP)(ClientIP.asOutParam()), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientVersion)(&ClientVersion), hrc); + CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EncryptionStyle)(&EncryptionStyle), hrc); + } + + SHOW_BOOL_VALUE_EX("VRDEActiveConnection", Info::tr("VRDE Connection:"), fActive, Info::tr("active"), Info::tr("not active")); + SHOW_ULONG_VALUE("VRDEClients=", Info::tr("Clients so far:"), cNumberOfClients, ""); + + if (cNumberOfClients > 0) + { + char szTimeValue[128]; + makeTimeStr(szTimeValue, sizeof(szTimeValue), BeginTime); + if (fActive) + SHOW_UTF8_STRING("VRDEStartTime", Info::tr("Start time:"), szTimeValue); + else + { + SHOW_UTF8_STRING("VRDELastStartTime", Info::tr("Last started:"), szTimeValue); + makeTimeStr(szTimeValue, sizeof(szTimeValue), EndTime); + SHOW_UTF8_STRING("VRDELastEndTime", Info::tr("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", Info::tr("Sent:"), BytesSent, Info::tr("Bytes")); + SHOW_LONG64_VALUE("VRDEThroughputSend", Info::tr("Average speed:"), ThroughputSend, Info::tr("B/s")); + SHOW_LONG64_VALUE("VRDEBytesSentTotal", Info::tr("Sent total:"), BytesSentTotal, Info::tr("Bytes")); + + SHOW_LONG64_VALUE("VRDEBytesReceived", Info::tr("Received:"), BytesReceived, Info::tr("Bytes")); + SHOW_LONG64_VALUE("VRDEThroughputReceive", Info::tr("Speed:"), ThroughputReceive, Info::tr("B/s")); + SHOW_LONG64_VALUE("VRDEBytesReceivedTotal", Info::tr("Received total:"), BytesReceivedTotal, Info::tr("Bytes")); + + if (fActive) + { + SHOW_BSTR_STRING("VRDEUserName", Info::tr("User name:"), User); + SHOW_BSTR_STRING("VRDEDomain", Info::tr("Domain:"), Domain); + SHOW_BSTR_STRING("VRDEClientName", Info::tr("Client name:"), ClientName); + SHOW_BSTR_STRING("VRDEClientIP", Info::tr("Client IP:"), ClientIP); + SHOW_ULONG_VALUE("VRDEClientVersion", Info::tr("Client version:"), ClientVersion, ""); + SHOW_UTF8_STRING("VRDEEncryption", Info::tr("Encryption:"), EncryptionStyle == 0 ? "RDP4" : "RDP5 (X.509)"); + } + } + } + +#ifdef VBOX_WITH_RECORDING + { + ComPtr recordingSettings; + CHECK_ERROR_RET(machine, COMGETTER(RecordingSettings)(recordingSettings.asOutParam()), hrc); + + BOOL fEnabled; + CHECK_ERROR_RET(recordingSettings, COMGETTER(Enabled)(&fEnabled), hrc); + SHOW_BOOL_VALUE_EX("recording_enabled", Info::tr("Recording enabled:"), fEnabled, Info::tr("yes"), Info::tr("no")); + + SafeIfaceArray saScreenSettings; + CHECK_ERROR_RET(recordingSettings, COMGETTER(Screens)(ComSafeArrayAsOutParam(saScreenSettings)), hrc); + + SHOW_ULONG_VALUE("recording_screens", Info::tr("Recording screens:"), saScreenSettings.size(), ""); + + for (size_t i = 0; i < saScreenSettings.size(); ++i) + { + ComPtr screenSettings = saScreenSettings[i]; + + FmtNm(szNm, details == VMINFO_MACHINEREADABLE ? "rec_screen%zu" : Info::tr("Screen %u:"), i); + RTPrintf(Info::tr(" %s\n"), szNm); + + CHECK_ERROR_RET(screenSettings, COMGETTER(Enabled)(&fEnabled), hrc); + ULONG idScreen; + CHECK_ERROR_RET(screenSettings, COMGETTER(Id)(&idScreen), hrc); + com::SafeArray vecFeatures; + CHECK_ERROR_RET(screenSettings, COMGETTER(Features)(ComSafeArrayAsOutParam(vecFeatures)), hrc); + ULONG Width; + CHECK_ERROR_RET(screenSettings, COMGETTER(VideoWidth)(&Width), hrc); + ULONG Height; + CHECK_ERROR_RET(screenSettings, COMGETTER(VideoHeight)(&Height), hrc); + ULONG Rate; + CHECK_ERROR_RET(screenSettings, COMGETTER(VideoRate)(&Rate), hrc); + ULONG Fps; + CHECK_ERROR_RET(screenSettings, COMGETTER(VideoFPS)(&Fps), hrc); + RecordingDestination_T enmDst; + CHECK_ERROR_RET(screenSettings, COMGETTER(Destination)(&enmDst), hrc); + Bstr bstrFile; + CHECK_ERROR_RET(screenSettings, COMGETTER(Filename)(bstrFile.asOutParam()), hrc); + Bstr bstrOptions; + CHECK_ERROR_RET(screenSettings, COMGETTER(Options)(bstrOptions.asOutParam()), hrc); + + BOOL fRecordVideo = FALSE; +# ifdef VBOX_WITH_AUDIO_RECORDING + BOOL fRecordAudio = FALSE; +# endif + for (size_t f = 0; f < vecFeatures.size(); ++f) + { + if (vecFeatures[f] == RecordingFeature_Video) + fRecordVideo = TRUE; +# ifdef VBOX_WITH_AUDIO_RECORDING + else if (vecFeatures[f] == RecordingFeature_Audio) + fRecordAudio = TRUE; +# endif + } + + SHOW_BOOL_VALUE_EX("rec_screen_enabled", Info::tr(" Enabled:"), fEnabled, + Info::tr("yes"), Info::tr("no")); + SHOW_ULONG_VALUE ("rec_screen_id", Info::tr(" ID:"), idScreen, ""); + SHOW_BOOL_VALUE_EX("rec_screen_video_enabled", Info::tr(" Record video:"), fRecordVideo, + Info::tr("yes"), Info::tr("no")); +# ifdef VBOX_WITH_AUDIO_RECORDING + SHOW_BOOL_VALUE_EX("rec_screen_audio_enabled", Info::tr(" Record audio:"), fRecordAudio, + Info::tr("yes"), Info::tr("no")); +# endif + SHOW_UTF8_STRING("rec_screen_dest", Info::tr(" Destination:"), + enmDst == RecordingDestination_File + ? Info::tr("File") : Info::tr("Unknown")); + /** @todo Implement other destinations. */ + if (enmDst == RecordingDestination_File) + SHOW_BSTR_STRING("rec_screen_dest_filename", Info::tr(" File:"), bstrFile); + + SHOW_BSTR_STRING ("rec_screen_opts", Info::tr(" Options:"), bstrOptions); + + /* Video properties. */ + RTStrPrintf(szValue, sizeof(szValue), "%ux%u", Width, Height); + SHOW_UTF8_STRING ("rec_screen_video_res_xy", Info::tr(" Video dimensions:"), szValue); + SHOW_ULONG_VALUE ("rec_screen_video_rate_kbps", Info::tr(" Video rate:"), Rate, Info::tr("kbps")); + SHOW_ULONG_VALUE ("rec_screen_video_fps", Info::tr(" Video FPS:"), Fps, Info::tr("fps")); + + /** @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(Info::tr("Description:\n%ls\n"), description.raw()); + } + } + + /* VMMDev testing config (extra data) */ + if (details != VMINFO_MACHINEREADABLE) + { + Bstr bstr; + CHECK_ERROR2I_RET(machine, GetExtraData(Bstr("VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled").raw(), + bstr.asOutParam()), hrcCheck); + int const fEnabled = parseCfgmBool(&bstr); + + CHECK_ERROR2I_RET(machine, GetExtraData(Bstr("VBoxInternal/Devices/VMMDev/0/Config/TestingMMIO").raw(), + bstr.asOutParam()), hrcCheck); + int const fMmio = parseCfgmBool(&bstr); + if (fEnabled || fMmio) + { + RTPrintf("%-28s %s, %s %s\n", + Info::tr("VMMDev Testing"), + fEnabled > 0 ? Info::tr("enabled") : fEnabled == 0 ? Info::tr("disabled") : Info::tr("misconfigured"), + "MMIO:", + fMmio > 0 ? Info::tr("enabled") : fMmio == 0 ? Info::tr("disabled") : Info::tr("misconfigured")); + for (uint32_t i = 0; i < 10; i++) + { + BstrFmt bstrName("VBoxInternal/Devices/VMMDev/0/Config/TestingCfgDword%u", i); + CHECK_ERROR2I_RET(machine, GetExtraData(bstrName.raw(), bstr.asOutParam()), hrcCheck); + if (bstr.isNotEmpty()) + RTPrintf("%-28s %ls\n", FmtNm(szNm, "VMMDev Testing Cfg Dword%u:", i), bstr.raw()); + } + } + } + + /* + * Snapshots. + */ + ComPtr snapshot; + hrc = machine->FindSnapshot(Bstr().raw(), snapshot.asOutParam()); + if (SUCCEEDED(hrc) && snapshot) + { + ComPtr currentSnapshot; + hrc = machine->COMGETTER(CurrentSnapshot)(currentSnapshot.asOutParam()); + if (SUCCEEDED(hrc)) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr("* Snapshots:\n")); + showSnapshots(snapshot, currentSnapshot, details); + } + } + + /* + * Guest stuff (mainly interesting when running). + */ + if (details != VMINFO_MACHINEREADABLE) + RTPrintf(Info::tr("* Guest:\n")); + + SHOW_ULONG_PROP(machine, MemoryBalloonSize, "GuestMemoryBalloon", + Info::tr("Configured memory balloon:"), Info::tr("MB")); + + if (pConsole) + { + ComPtr guest; + hrc = pConsole->COMGETTER(Guest)(guest.asOutParam()); + if (SUCCEEDED(hrc) && !guest.isNull()) + { + SHOW_STRING_PROP_NOT_EMPTY(guest, OSTypeId, "GuestOSType", Info::tr("OS type:")); + + AdditionsRunLevelType_T guestRunLevel; /** @todo Add a runlevel-to-string (e.g. 0 = "None") method? */ + hrc = guest->COMGETTER(AdditionsRunLevel)(&guestRunLevel); + if (SUCCEEDED(hrc)) + SHOW_ULONG_VALUE("GuestAdditionsRunLevel", Info::tr("Additions run level:"), (ULONG)guestRunLevel, ""); + + Bstr guestString; + hrc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam()); + if ( SUCCEEDED(hrc) + && !guestString.isEmpty()) + { + ULONG uRevision; + hrc = guest->COMGETTER(AdditionsRevision)(&uRevision); + if (FAILED(hrc)) + uRevision = 0; + RTStrPrintf(szValue, sizeof(szValue), "%ls r%u", guestString.raw(), uRevision); + SHOW_UTF8_STRING("GuestAdditionsVersion", Info::tr("Additions version:"), szValue); + } + + /* Print information about known Guest Additions facilities: */ + SafeIfaceArray collFac; + CHECK_ERROR_RET(guest, COMGETTER(Facilities)(ComSafeArrayAsOutParam(collFac)), hrc); + if (collFac.size() > 0) + { + if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%s\n", Info::tr("Guest Facilities:")); + LONG64 lLastUpdatedMS; + char szLastUpdated[32]; + AdditionsFacilityStatus_T curStatus; + for (size_t index = 0; index < collFac.size(); ++index) + { + ComPtr fac = collFac[index]; + if (fac) + { + CHECK_ERROR_RET(fac, COMGETTER(Name)(guestString.asOutParam()), hrc); + if (!guestString.isEmpty()) + { + CHECK_ERROR_RET(fac, COMGETTER(Status)(&curStatus), hrc); + CHECK_ERROR_RET(fac, COMGETTER(LastUpdated)(&lLastUpdatedMS), hrc); + if (details == VMINFO_MACHINEREADABLE) + RTPrintf("GuestAdditionsFacility_%ls=%u,%lld\n", + guestString.raw(), curStatus, lLastUpdatedMS); + else + { + makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS); + RTPrintf(Info::tr("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")); + } + } + else if (details != VMINFO_MACHINEREADABLE) + RTPrintf("%-28s %s\n", Info::tr("Guest Facilities:"), Info::tr("")); + } + } + + 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 }, + { "--password-id", 'i', RTGETOPT_REQ_STRING }, + { "-password-id", 'i', RTGETOPT_REQ_STRING }, + { "--password", 'w', RTGETOPT_REQ_STRING }, + { "-password", 'w', RTGETOPT_REQ_STRING }, +}; + +RTEXITCODE handleShowVMInfo(HandlerArg *a) +{ + HRESULT hrc; + const char *VMNameOrUuid = NULL; + bool fLog = false; + uint32_t uLogIdx = 0; + bool fDetails = false; + bool fMachinereadable = false; + Bstr bstrPasswordId; + const char *pszPassword = NULL; + + 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 'i': // --password-id + bstrPasswordId = ValueUnion.psz; + break; + + case 'w': // --password + pszPassword = ValueUnion.psz; + break; + + case VINF_GETOPT_NOT_OPTION: + if (!VMNameOrUuid) + VMNameOrUuid = ValueUnion.psz; + else + return errorSyntax(Info::tr("Invalid parameter '%s'"), ValueUnion.psz); + break; + + default: + return errorGetOpt(c, &ValueUnion); + } + } + + /* check for required options */ + if (!VMNameOrUuid) + return errorSyntax(Info::tr("VM name or UUID required")); + + /* try to find the given machine */ + ComPtr machine; + CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMNameOrUuid).raw(), + machine.asOutParam())); + if (FAILED(hrc)) + return RTEXITCODE_FAILURE; + + /* Printing the log is exclusive. */ + if (fLog && (fMachinereadable || fDetails)) + return errorSyntax(Info::tr("Option --log is exclusive")); + + /* add VM password if required */ + if (pszPassword && bstrPasswordId.isNotEmpty()) + { + Utf8Str strPassword; + if (!RTStrCmp(pszPassword, "-")) + { + /* Get password from console. */ + RTEXITCODE rcExit = readPasswordFromConsole(&strPassword, "Enter the password:"); + if (rcExit == RTEXITCODE_FAILURE) + return rcExit; + } + else + { + RTEXITCODE rcExit = readPasswordFile(pszPassword, &strPassword); + if (rcExit == RTEXITCODE_FAILURE) + { + RTMsgError("Failed to read new password from file"); + return rcExit; + } + } + CHECK_ERROR(machine, AddEncryptionPassword(bstrPasswordId.raw(), Bstr(strPassword).raw())); + } + + if (fLog) + { + ULONG64 uOffset = 0; + SafeArray 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 */ + hrc = machine->LockMachine(a->session, LockType_Shared); + if (SUCCEEDED(hrc)) + /* get the session machine */ + hrc = a->session->COMGETTER(Machine)(machine.asOutParam()); + + hrc = showVMInfo(a->virtualBox, machine, a->session, details); + + a->session->UnlockMachine(); + } + + return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; +} + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ -- cgit v1.2.3