VBoxManageSnapshot.cpp revision e48239695d41f806ff02d8a60b97dc20d4822d7a
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/* $Id$ */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @file
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * VBoxManage - The 'snapshot' command.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Copyright (C) 2006-2009 Oracle Corporation
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * available from http://www.virtualbox.org. This file is free software;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * General Public License (GPL) as published by the Free Software
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Header Files *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/com.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/string.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/array.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/ErrorInfo.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/errorprint.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <VBox/com/VirtualBox.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/stream.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/getopt.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "VBoxManage.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncusing namespace com;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper function used with "VBoxManage snapshot ... dump". Gets called to find the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * snapshot in the machine's snapshot tree that uses a particular diff image child of
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * a medium.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Horribly inefficient since we keep re-querying the snapshots tree for each image,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * but this is for quick debugging only.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pMedium
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pThisSnapshot
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pCurrentSnapshot
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param uMediumLevel
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param uSnapshotLevel
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @return
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncbool FindAndPrintSnapshotUsingMedium(ComPtr<IMedium> &pMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> &pThisSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> &pCurrentSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t uMediumLevel,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t uSnapshotLevel)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync HRESULT rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync do
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get snapshot machine so we can figure out which diff image this created
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMachine> pSnapshotMachine;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Machine)(pSnapshotMachine.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get media attachments
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync SafeIfaceArray<IMediumAttachment> aAttachments;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pSnapshotMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync i < aAttachments.size();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ++i)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync DeviceType_T type;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (type == DeviceType_HardDisk)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMedium> pMediumInSnapshot;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pMediumInSnapshot.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pMediumInSnapshot == pMedium)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get snapshot name
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr bstrSnapshotName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Name)(bstrSnapshotName.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTPrintf("%*s \"%ls\"%s\n",
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 50 + uSnapshotLevel * 2, "", // indent
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bstrSnapshotName.raw(),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync (pThisSnapshot == pCurrentSnapshot) ? " (CURSNAP)" : "");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return true; // found
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // not found: then recurse into child snapshots
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync SafeIfaceArray<ISnapshot> aSnapshots;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Children)(ComSafeArrayAsOutParam(aSnapshots)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync i < aSnapshots.size();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ++i)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> pChild(aSnapshots[i]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (FindAndPrintSnapshotUsingMedium(pMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChild,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pCurrentSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uMediumLevel,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uSnapshotLevel + 1))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // found:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync } while (0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper function used with "VBoxManage snapshot ... dump". Called from DumpSnapshot()
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * for each hard disk attachment found in a virtual machine. This then writes out the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * root (base) medium for that hard disk attachment and recurses into the children
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * tree of that medium, correlating it with the snapshots of the machine.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pCurrentStateMedium constant, the medium listed in the current machine data (latest diff image).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pMedium variant, initially the base medium, then a child of the base medium when recursing.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pRootSnapshot constant, the root snapshot of the machine, if any; this then looks into the child snapshots.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pCurrentSnapshot constant, the machine's current snapshot (so we can mark it in the output).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param uLevel variant, the recursion level for output indentation.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncvoid DumpMediumWithChildren(ComPtr<IMedium> &pCurrentStateMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMedium> &pMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> &pRootSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> &pCurrentSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t uLevel)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync HRESULT rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync do
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // print this medium
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr bstrMediumName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pMedium, COMGETTER(Name)(bstrMediumName.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTPrintf("%*s \"%ls\"%s\n",
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uLevel * 2, "", // indent
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bstrMediumName.raw(),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync (pCurrentStateMedium == pMedium) ? " (CURSTATE)" : "");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // find and print the snapshot that uses this particular medium (diff image)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync FindAndPrintSnapshotUsingMedium(pMedium, pRootSnapshot, pCurrentSnapshot, uLevel, 0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // recurse into children
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync SafeIfaceArray<IMedium> aChildren;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(aChildren)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync i < aChildren.size();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ++i)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMedium> pChild(aChildren[i]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync DumpMediumWithChildren(pCurrentStateMedium, pChild, pRootSnapshot, pCurrentSnapshot, uLevel + 1);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync } while (0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Implementation for "VBoxManage snapshot ... dump". This goes thru the machine's
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * medium attachments and calls DumpMediumWithChildren() for each hard disk medium found,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * which then dumps the parent/child tree of that medium together with the corresponding
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * snapshots.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pMachine Machine to dump snapshots for.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncvoid DumpSnapshot(ComPtr<IMachine> &pMachine)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync HRESULT rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync do
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get root snapshot
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> pSnapshot;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pMachine, GetSnapshot(Bstr(""), pSnapshot.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get current snapshot
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<ISnapshot> pCurrentSnapshot;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync // get media attachments
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync SafeIfaceArray<IMediumAttachment> aAttachments;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync i < aAttachments.size();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ++i)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync DeviceType_T type;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (type == DeviceType_HardDisk)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMedium> pCurrentStateMedium;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pCurrentStateMedium.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMedium> pBaseMedium;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pCurrentStateMedium, COMGETTER(Base)(pBaseMedium.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr bstrBaseMediumName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(pBaseMedium, COMGETTER(Name)(bstrBaseMediumName.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTPrintf("[%RI32] Images and snapshots for medium \"%ls\"\n", i, bstrBaseMediumName.raw());
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync DumpMediumWithChildren(pCurrentStateMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pBaseMedium,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pCurrentSnapshot,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync } while (0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Implementation for all VBoxManage snapshot ... subcommands.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param a
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @return
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncint handleSnapshot(HandlerArg *a)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync HRESULT rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* we need at least a VM and a command */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (a->argc < 2)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return errorSyntax(USAGE_SNAPSHOT, "Not enough parameters");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* the first argument must be the VM */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr bstrMachine(a->argv[0]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IMachine> pMachine;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* assume it's a UUID */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = a->virtualBox->GetMachine(bstrMachine, pMachine.asOutParam());
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (FAILED(rc) || !pMachine)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* must be a name */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR(a->virtualBox, FindMachine(bstrMachine, pMachine.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pMachine)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync do
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* we have to open a session for this task (new or shared) */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = pMachine->LockMachine(a->session, LockType_Shared);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ComPtr<IConsole> console;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* switch based on the command */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fDelete = false,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fRestore = false,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fRestoreCurrent = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!strcmp(a->argv[1], "take"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* there must be a name */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (a->argc < 3)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = E_FAIL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr name(a->argv[2]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* parse the optional arguments */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Bstr desc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fPause = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync static const RTGETOPTDEF s_aTakeOptions[] =
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
{ "--description", 'd', RTGETOPT_REQ_STRING },
{ "-description", 'd', RTGETOPT_REQ_STRING },
{ "-desc", 'd', RTGETOPT_REQ_STRING },
{ "--pause", 'p', RTGETOPT_REQ_NOTHING }
};
RTGETOPTSTATE GetOptState;
RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTakeOptions, RT_ELEMENTS(s_aTakeOptions),
3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
int ch;
RTGETOPTUNION Value;
while ( SUCCEEDED(rc)
&& (ch = RTGetOpt(&GetOptState, &Value)))
{
switch (ch)
{
case 'p':
fPause = true;
break;
case 'd':
desc = Value.psz;
break;
default:
errorGetOpt(USAGE_SNAPSHOT, ch, &Value);
rc = E_FAIL;
break;
}
}
if (FAILED(rc))
break;
if (fPause)
{
MachineState_T machineState;
CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
if (machineState == MachineState_Running)
CHECK_ERROR_BREAK(console, Pause());
else
fPause = false;
}
ComPtr<IProgress> progress;
CHECK_ERROR_BREAK(console, TakeSnapshot(name, desc, progress.asOutParam()));
rc = showProgress(progress);
if (FAILED(rc))
{
com::ProgressErrorInfo info(progress);
if (info.isBasicAvailable())
RTPrintf("Error: failed to take snapshot. Error message: %lS\n", info.getText().raw());
else
RTPrintf("Error: failed to take snapshot. No error message available!\n");
}
if (fPause)
{
MachineState_T machineState;
CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
if (machineState == MachineState_Paused)
{
if (SUCCEEDED(rc))
CHECK_ERROR_BREAK(console, Resume());
else
console->Resume();
}
}
}
else if ( (fDelete = !strcmp(a->argv[1], "delete"))
|| (fRestore = !strcmp(a->argv[1], "restore"))
|| (fRestoreCurrent = !strcmp(a->argv[1], "restorecurrent"))
)
{
if (fRestoreCurrent)
{
if (a->argc > 2)
{
errorSyntax(USAGE_SNAPSHOT, "Too many arguments");
rc = E_FAIL;
break;
}
}
/* exactly one parameter: snapshot name */
else if (a->argc != 3)
{
errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
rc = E_FAIL;
break;
}
ComPtr<ISnapshot> pSnapshot;
ComPtr<IProgress> pProgress;
Bstr bstrSnapGuid;
if (fRestoreCurrent)
{
CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pSnapshot.asOutParam()));
CHECK_ERROR_BREAK(pSnapshot, COMGETTER(Id)(bstrSnapGuid.asOutParam()));
}
else
{
// restore or delete snapshot: then resolve cmd line argument to snapshot instance
// assume it's a UUID
bstrSnapGuid = a->argv[2];
if (FAILED(pMachine->GetSnapshot(bstrSnapGuid, pSnapshot.asOutParam())))
{
// then it must be a name
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]), pSnapshot.asOutParam()));
CHECK_ERROR_BREAK(pSnapshot, COMGETTER(Id)(bstrSnapGuid.asOutParam()));
}
}
if (fDelete)
{
CHECK_ERROR_BREAK(console, DeleteSnapshot(bstrSnapGuid, pProgress.asOutParam()));
}
else
{
// restore or restore current
RTPrintf("Restoring snapshot %ls\n", bstrSnapGuid.raw());
CHECK_ERROR_BREAK(console, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
}
rc = showProgress(pProgress);
if (FAILED(rc))
{
com::ProgressErrorInfo info(pProgress);
if (info.isBasicAvailable())
RTPrintf("Error: snapshot operation failed. Error message: %lS\n", info.getText().raw());
else
RTPrintf("Error: snapshot operation failed. No error message available!\n");
}
}
else if (!strcmp(a->argv[1], "edit"))
{
if (a->argc < 3)
{
errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
rc = E_FAIL;
break;
}
ComPtr<ISnapshot> snapshot;
if ( !strcmp(a->argv[2], "--current")
|| !strcmp(a->argv[2], "-current"))
{
CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(snapshot.asOutParam()));
}
else
{
/* assume it's a UUID */
rc = pMachine->GetSnapshot(Bstr(a->argv[2]), snapshot.asOutParam());
if (FAILED(rc) || !snapshot)
{
/* then it must be a name */
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]), snapshot.asOutParam()));
}
}
/* parse options */
for (int i = 3; i < a->argc; i++)
{
if ( !strcmp(a->argv[i], "--name")
|| !strcmp(a->argv[i], "-name")
|| !strcmp(a->argv[i], "-newname"))
{
if (a->argc <= i + 1)
{
errorArgument("Missing argument to '%s'", a->argv[i]);
rc = E_FAIL;
break;
}
i++;
snapshot->COMSETTER(Name)(Bstr(a->argv[i]));
}
else if ( !strcmp(a->argv[i], "--description")
|| !strcmp(a->argv[i], "-description")
|| !strcmp(a->argv[i], "-newdesc"))
{
if (a->argc <= i + 1)
{
errorArgument("Missing argument to '%s'", a->argv[i]);
rc = E_FAIL;
break;
}
i++;
snapshot->COMSETTER(Description)(Bstr(a->argv[i]));
}
else
{
errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
rc = E_FAIL;
break;
}
}
}
else if (!strcmp(a->argv[1], "showvminfo"))
{
/* exactly one parameter: snapshot name */
if (a->argc != 3)
{
errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
rc = E_FAIL;
break;
}
ComPtr<ISnapshot> snapshot;
/* assume it's a UUID */
rc = pMachine->GetSnapshot(Bstr(a->argv[2]), snapshot.asOutParam());
if (FAILED(rc) || !snapshot)
{
/* then it must be a name */
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]), snapshot.asOutParam()));
}
/* get the machine of the given snapshot */
ComPtr<IMachine> pMachine2;
snapshot->COMGETTER(Machine)(pMachine2.asOutParam());
showVMInfo(a->virtualBox, pMachine2, VMINFO_NONE, console);
}
else if (!strcmp(a->argv[1], "dump")) // undocumented parameter to debug snapshot info
DumpSnapshot(pMachine);
else
{
errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(a->argv[1]).c_str());
rc = E_FAIL;
}
} while (0);
a->session->UnlockMachine();
return SUCCEEDED(rc) ? 0 : 1;
}