diff options
Diffstat (limited to 'src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp')
-rw-r--r-- | src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp b/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp new file mode 100644 index 00000000..bb49867c --- /dev/null +++ b/src/VBox/ImageMounter/vboximg-mount/vboximgMedia.cpp @@ -0,0 +1,409 @@ +/* $Id: vboximgMedia.cpp $ */ +/** @file + * vboximgMedia.cpp - Disk Image Flattening FUSE Program. + */ + +/* + * Copyright (C) 2009-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 <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include <VirtualBox_XPCOM.h> +#include <VBox/com/VirtualBox.h> +#include <VBox/vd.h> +#include <VBox/vd-ifs.h> +#include <VBox/log.h> +#include <iprt/errcore.h> +#include <VBox/com/ErrorInfo.h> +#include <VBox/com/NativeEventQueue.h> +#include <VBox/com/com.h> +#include <VBox/com/string.h> +#include <VBox/com/Guid.h> +#include <VBox/com/array.h> +#include <VBox/com/errorprint.h> +#include <VBox/vd-plugin.h> +#include <iprt/initterm.h> +#include <iprt/assert.h> +#include <iprt/message.h> +#include <iprt/critsect.h> +#include <iprt/asm.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/types.h> +#include <iprt/path.h> +#include <iprt/utf16.h> +#include <math.h> +#include "vboximgOpts.h" + +using namespace com; + +extern VBOXIMGOPTS g_vboximgOpts; + +#define SAFENULL(strPtr) (strPtr ? strPtr : "") /** Makes null harmless to print */ +#define CSTR(arg) Utf8Str(arg).c_str() /** Converts XPCOM string type to C string type */ +#define MAX_UUID_LEN 256 /** Max length of a UUID */ +#define VM_MAX_NAME 32 /** Max length of VM name we handle */ + +typedef struct MEDIUMINFO +{ + char *pszName; + char *pszUuid; + char *pszBaseUuid; + char *pszPath; + char *pszDescription; + char *pszState; + char *pszType; + char *pszFormat; + bool fSnapshot; + PRInt64 cbSize; + MediumType_T type; + MediumState_T state; + ~MEDIUMINFO() + { + RTMemFree(pszName); + RTMemFree(pszUuid); + RTMemFree(pszPath); + RTMemFree(pszDescription); + RTMemFree(pszFormat); + } +} MEDIUMINFO; + + +char *vboximgScaledSize(size_t size) +{ + uint64_t exp = 0; + if (size > 0) + exp = log2((double)size); + char scaledMagnitude = ((char []){ ' ', 'K', 'M', 'G', 'T', 'P' })[exp / 10]; + /* This workaround is because IPRT RT*Printf* funcs don't handle floating point format specifiers */ + double cbScaled = (double)size / pow(2, (double)(((uint64_t)(exp / 10)) * 10)); + uint64_t intPart = cbScaled; + uint64_t fracPart = (cbScaled - (double)intPart) * 10; + char tmp[256]; + RTStrPrintf(tmp, sizeof (tmp), "%d.%d%c", intPart, fracPart, scaledMagnitude); + return RTStrDup(tmp); +} + +static int getMediumInfo(IMachine *pMachine, IMedium *pMedium, MEDIUMINFO **ppMediumInfo) +{ + RT_NOREF(pMachine); + + MEDIUMINFO *info = new MEDIUMINFO(); + *ppMediumInfo = info; + + Bstr name; + Bstr uuid; + Bstr baseUuid; + Bstr path; + Bstr description; + Bstr format; + PRInt64 *pSize = &info->cbSize; + ComPtr<IMedium> pBase; + MediumType_T *pType = &info->type; + MediumState_T *pState = &info->state; + + *pState = MediumState_NotCreated; + + HRESULT hrc; + + CHECK_ERROR(pMedium, RefreshState(pState)); + CHECK_ERROR(pMedium, COMGETTER(Id)(uuid.asOutParam())); + CHECK_ERROR(pMedium, COMGETTER(Base)(pBase.asOutParam())); + CHECK_ERROR(pBase, COMGETTER(Id)(baseUuid.asOutParam())); + + CHECK_ERROR(pMedium, COMGETTER(State)(pState)); + + CHECK_ERROR(pMedium, COMGETTER(Location)(path.asOutParam())); + CHECK_ERROR(pMedium, COMGETTER(Format)(format.asOutParam())); + CHECK_ERROR(pMedium, COMGETTER(Type)(pType)); + CHECK_ERROR(pMedium, COMGETTER(Size)(pSize)); + + info->pszUuid = RTStrDup((char *)CSTR(uuid)); + info->pszBaseUuid = RTStrDup((char *)CSTR(baseUuid)); + info->pszPath = RTStrDup((char *)CSTR(path)); + info->pszFormat = RTStrDup((char *)CSTR(format)); + info->fSnapshot = RTStrCmp(CSTR(uuid), CSTR(baseUuid)) != 0; + + if (info->fSnapshot) + { + /** @todo Determine the VM snapshot this and set name and description + * to the snapshot name/description + */ + CHECK_ERROR(pMedium, COMGETTER(Name)(name.asOutParam())); + CHECK_ERROR(pMedium, COMGETTER(Description)(description.asOutParam())); + } + else + { + CHECK_ERROR(pMedium, COMGETTER(Name)(name.asOutParam())); + CHECK_ERROR(pMedium, COMGETTER(Description)(description.asOutParam())); + } + + info->pszName = RTStrDup((char *)CSTR(name)); + info->pszDescription = RTStrDup((char *)CSTR(description)); + + switch(*pType) + { + case MediumType_Normal: + info->pszType = (char *)"normal"; + break; + case MediumType_Immutable: + info->pszType = (char *)"immutable"; + break; + case MediumType_Writethrough: + info->pszType = (char *)"writethrough"; + break; + case MediumType_Shareable: + info->pszType = (char *)"shareable"; + break; + case MediumType_Readonly: + info->pszType = (char *)"readonly"; + break; + case MediumType_MultiAttach: + info->pszType = (char *)"multiattach"; + break; + default: + info->pszType = (char *)"?"; + } + + switch(*pState) + { + case MediumState_NotCreated: + info->pszState = (char *)"uncreated"; + break; + case MediumState_Created: + info->pszState = (char *)"created"; + break; + case MediumState_LockedRead: + info->pszState = (char *)"rlock"; + break; + case MediumState_LockedWrite: + info->pszState = (char *)"wlock"; + break; + case MediumState_Inaccessible: + info->pszState = (char *)"no access"; + break; + case MediumState_Creating: + info->pszState = (char *)"creating"; + break; + case MediumState_Deleting: + info->pszState = (char *)"deleting"; + break; + default: + info->pszState = (char *)"?"; + } + return VINF_SUCCESS; +} + +static void displayMediumInfo(MEDIUMINFO *pInfo, int nestLevel, bool fLast) +{ + char *pszSzScaled = vboximgScaledSize(pInfo->cbSize); + int cPad = nestLevel * 2; + if (g_vboximgOpts.fWide && !g_vboximgOpts.fVerbose) + { + RTPrintf("%3s %-*s %7s %-9s %9s %-*s %s\n", + !fLast ? (pInfo->fSnapshot ? " | " : " +-") : (pInfo->fSnapshot ? " " : " +-"), + VM_MAX_NAME, pInfo->fSnapshot ? "+- <snapshot>" : pInfo->pszName, + pszSzScaled, + pInfo->pszFormat, + pInfo->pszState, + cPad, "", pInfo->pszUuid); + } + else + { + if (!pInfo->fSnapshot) + { + RTPrintf(" Image: %s\n", pInfo->pszName); + if (pInfo->pszDescription && RTStrNLen(pInfo->pszDescription, 256) > 0) + RTPrintf("Desc: %s\n", pInfo->pszDescription); + RTPrintf(" UUID: %s\n", pInfo->pszUuid); + if (g_vboximgOpts.fVerbose) + { + RTPrintf(" Path: %s\n", pInfo->pszPath); + RTPrintf(" Format: %s\n", pInfo->pszFormat); + RTPrintf(" Size: %s\n", pszSzScaled); + RTPrintf(" State: %s\n", pInfo->pszState); + RTPrintf(" Type: %s\n", pInfo->pszType); + } + RTPrintf("\n"); + } + else + { + RTPrintf(" Snapshot: %s\n", pInfo->pszUuid); + if (g_vboximgOpts.fVerbose) + { + RTPrintf(" Name: %s\n", pInfo->pszName); + RTPrintf(" Desc: %s\n", pInfo->pszDescription); + } + RTPrintf(" Size: %s\n", pszSzScaled); + if (g_vboximgOpts.fVerbose) + RTPrintf(" Path: %s\n", pInfo->pszPath); + RTPrintf("\n"); + } + } + RTMemFree(pszSzScaled); +} + +static int vboximgListBranch(IMachine *pMachine, IMedium *pMedium, uint8_t nestLevel, bool fLast) +{ + MEDIUMINFO *pMediumInfo; + int vrc = getMediumInfo(pMachine, pMedium, &pMediumInfo); + if (RT_FAILURE(vrc)) + return vrc; + + displayMediumInfo(pMediumInfo, nestLevel, fLast); + + HRESULT hrc; + com::SafeIfaceArray<IMedium> pChildren; + CHECK_ERROR_RET(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(pChildren)), VERR_NOT_FOUND); /** @todo r=andy Find a better rc. */ + + for (size_t i = 0; i < pChildren.size(); i++) + vboximgListBranch(pMachine, pChildren[i], nestLevel + 1, fLast); + + delete pMediumInfo; + + return VINF_SUCCESS; +} + +static int listMedia(IVirtualBox *pVirtualBox, IMachine *pMachine, char *vmName, char *vmUuid) +{ + RT_NOREF(pVirtualBox); + RT_NOREF(vmName); + RT_NOREF(vmUuid); + + int vrc = VINF_SUCCESS; + + com::SafeIfaceArray<IMediumAttachment> pMediumAttachments; + + HRESULT hrc; + CHECK_ERROR(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(pMediumAttachments))); + + for (size_t i = 0; i < pMediumAttachments.size(); i++) + { + bool fLast = (i == pMediumAttachments.size() - 1); + DeviceType_T deviceType; + + CHECK_ERROR(pMediumAttachments[i], COMGETTER(Type)(&deviceType)); + if (deviceType != DeviceType_HardDisk) + continue; + + ComPtr<IMedium> pMedium; + CHECK_ERROR(pMediumAttachments[i], COMGETTER(Medium)(pMedium.asOutParam())); + + ComPtr<IMedium> pBase; + CHECK_ERROR(pMedium, COMGETTER(Base)(pBase.asOutParam())); + if (g_vboximgOpts.fWide && !g_vboximgOpts.fVerbose) + RTPrintf(" |\n"); + else + RTPrintf("\n"); + + vrc = vboximgListBranch(pMachine, pBase, 0, fLast); + if (RT_FAILURE(vrc)) + { + RTPrintf("vboximgListBranch failed with %Rrc\n", vrc); + break; + } + } + + return vrc; +} +/** + * Display all registered VMs on the screen with some information about each + * + * @param virtualBox VirtualBox instance object. + */ +int vboximgListVMs(IVirtualBox *pVirtualBox) +{ + HRESULT hrc; + com::SafeIfaceArray<IMachine> pMachines; + CHECK_ERROR(pVirtualBox, COMGETTER(Machines)(ComSafeArrayAsOutParam(pMachines))); + + if (g_vboximgOpts.fWide) + { + RTPrintf("\n"); + RTPrintf("VM Image Size Type State UUID (hierarchy)\n"); + } + + int vrc = VINF_SUCCESS; + + for (size_t i = 0; i < pMachines.size(); ++i) + { + ComPtr<IMachine> pMachine = pMachines[i]; + if (pMachine) + { + BOOL fAccessible; + CHECK_ERROR(pMachines[i], COMGETTER(Accessible)(&fAccessible)); + if (fAccessible) + { + Bstr machineName; + Bstr machineUuid; + Bstr description; + Bstr machineLocation; + + CHECK_ERROR(pMachine, COMGETTER(Name)(machineName.asOutParam())); + CHECK_ERROR(pMachine, COMGETTER(Id)(machineUuid.asOutParam())); + CHECK_ERROR(pMachine, COMGETTER(Description)(description.asOutParam())); + CHECK_ERROR(pMachine, COMGETTER(SettingsFilePath)(machineLocation.asOutParam())); + + + if ( g_vboximgOpts.pszVm == NULL + || RTStrNCmp(CSTR(machineUuid), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0 + || RTStrNCmp((const char *)machineName.raw(), g_vboximgOpts.pszVm, MAX_UUID_LEN) == 0) + { + if (g_vboximgOpts.fVerbose) + { + RTPrintf("-----------------------------------------------------------------\n"); + RTPrintf("VM Name: \"%s\"\n", CSTR(machineName)); + RTPrintf("UUID: %s\n", CSTR(machineUuid)); + if (*description.raw() != '\0') + RTPrintf("Desc: %s\n", CSTR(description)); + RTPrintf("Path: %s\n", CSTR(machineLocation)); + } + else + { + if (g_vboximgOpts.fWide & !g_vboximgOpts.fVerbose) + { + RTPrintf("----------------------------------------------------------------- " + "------------------------------------\n"); + RTPrintf("%-*s %*s %s\n", VM_MAX_NAME, CSTR(machineName), 33, "", CSTR(machineUuid)); + } + else + { + RTPrintf("-----------------------------------------------------------------\n"); + RTPrintf("VM: %s\n", CSTR(machineName)); + RTPrintf("UUID: %s\n", CSTR(machineUuid)); + } + } + + int vrc2 = listMedia(pVirtualBox, pMachine, + RTStrDup(CSTR(machineName)), RTStrDup(CSTR(machineUuid))); + if (RT_SUCCESS(vrc)) + vrc = vrc2; + + RTPrintf("\n"); + } + } + } + } + + return vrc; +} + |