VBoxManageSnapshot.cpp revision 2b114c590cf5a19f8047cd7bde9c7e5ae00aa22b
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/* $Id$ */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/** @file
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * VBoxManage - The 'snapshot' command.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/*
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Copyright (C) 2006-2014 Oracle Corporation
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync *
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * available from http://www.virtualbox.org. This file is free software;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * you can redistribute it and/or modify it under the terms of the GNU
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * General Public License (GPL) as published by the Free Software
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/*******************************************************************************
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync* Header Files *
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync*******************************************************************************/
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/com.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/string.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/array.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/ErrorInfo.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/errorprint.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <VBox/com/VirtualBox.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <iprt/stream.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include <iprt/getopt.h>
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#include "VBoxManage.h"
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncusing namespace com;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/**
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Helper function used with "VBoxManage snapshot ... dump". Gets called to find the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * snapshot in the machine's snapshot tree that uses a particular diff image child of
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * a medium.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Horribly inefficient since we keep re-querying the snapshots tree for each image,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * but this is for quick debugging only.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pMedium
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pThisSnapshot
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pCurrentSnapshot
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param uMediumLevel
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param uSnapshotLevel
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @return
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncbool FindAndPrintSnapshotUsingMedium(ComPtr<IMedium> &pMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> &pThisSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> &pCurrentSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uint32_t uMediumLevel,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uint32_t uSnapshotLevel)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync{
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync HRESULT rc;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync do
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get snapshot machine so we can figure out which diff image this created
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMachine> pSnapshotMachine;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Machine)(pSnapshotMachine.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get media attachments
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync SafeIfaceArray<IMediumAttachment> aAttachments;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pSnapshotMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync for (uint32_t i = 0;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync i < aAttachments.size();
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ++i)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync DeviceType_T type;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (type == DeviceType_HardDisk)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMedium> pMediumInSnapshot;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pMediumInSnapshot.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (pMediumInSnapshot == pMedium)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get snapshot name
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr bstrSnapshotName;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Name)(bstrSnapshotName.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTPrintf("%*s \"%ls\"%s\n",
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync 50 + uSnapshotLevel * 2, "", // indent
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync bstrSnapshotName.raw(),
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync (pThisSnapshot == pCurrentSnapshot) ? " (CURSNAP)" : "");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return true; // found
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // not found: then recurse into child snapshots
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync SafeIfaceArray<ISnapshot> aSnapshots;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Children)(ComSafeArrayAsOutParam(aSnapshots)));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync for (uint32_t i = 0;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync i < aSnapshots.size();
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ++i)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> pChild(aSnapshots[i]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (FindAndPrintSnapshotUsingMedium(pMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pChild,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pCurrentSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uMediumLevel,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uSnapshotLevel + 1))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // found:
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync break;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync } while (0);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return false;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync}
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/**
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Helper function used with "VBoxManage snapshot ... dump". Called from DumpSnapshot()
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * for each hard disk attachment found in a virtual machine. This then writes out the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * root (base) medium for that hard disk attachment and recurses into the children
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * tree of that medium, correlating it with the snapshots of the machine.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pCurrentStateMedium constant, the medium listed in the current machine data (latest diff image).
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pMedium variant, initially the base medium, then a child of the base medium when recursing.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pRootSnapshot constant, the root snapshot of the machine, if any; this then looks into the child snapshots.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pCurrentSnapshot constant, the machine's current snapshot (so we can mark it in the output).
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param uLevel variant, the recursion level for output indentation.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncvoid DumpMediumWithChildren(ComPtr<IMedium> &pCurrentStateMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMedium> &pMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> &pRootSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> &pCurrentSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uint32_t uLevel)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync{
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync HRESULT rc;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync do
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // print this medium
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr bstrMediumName;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pMedium, COMGETTER(Name)(bstrMediumName.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTPrintf("%*s \"%ls\"%s\n",
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync uLevel * 2, "", // indent
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync bstrMediumName.raw(),
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync (pCurrentStateMedium == pMedium) ? " (CURSTATE)" : "");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // find and print the snapshot that uses this particular medium (diff image)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync FindAndPrintSnapshotUsingMedium(pMedium, pRootSnapshot, pCurrentSnapshot, uLevel, 0);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // recurse into children
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync SafeIfaceArray<IMedium> aChildren;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(aChildren)));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync for (uint32_t i = 0;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync i < aChildren.size();
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ++i)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMedium> pChild(aChildren[i]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync DumpMediumWithChildren(pCurrentStateMedium, pChild, pRootSnapshot, pCurrentSnapshot, uLevel + 1);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync } while (0);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync}
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/**
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Handles the 'snapshot myvm list' sub-command.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @returns Exit code.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pArgs The handler argument package.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pMachine Reference to the VM (locked) we're operating on.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic RTEXITCODE handleSnapshotList(HandlerArg *pArgs, ComPtr<IMachine> &pMachine)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync{
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync static const RTGETOPTDEF g_aOptions[] =
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "--details", 'D', RTGETOPT_REQ_NOTHING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync };
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync VMINFO_DETAILS enmDetails = VMINFO_STANDARD;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync int c;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGETOPTUNION ValueUnion;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGETOPTSTATE GetState;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, g_aOptions, RT_ELEMENTS(g_aOptions), 2 /*iArg*/, 0 /*fFlags*/);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync while ((c = RTGetOpt(&GetState, &ValueUnion)))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync switch (c)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync case 'D': enmDetails = VMINFO_FULL; break;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync case 'M': enmDetails = VMINFO_MACHINEREADABLE; break;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync default: return errorGetOpt(USAGE_SNAPSHOT, c, &ValueUnion);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> pSnapshot;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync HRESULT hrc = pMachine->FindSnapshot(Bstr().raw(), pSnapshot.asOutParam());
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (FAILED(hrc))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTPrintf("This machine does not have any snapshots\n");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return RTEXITCODE_FAILURE;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (pSnapshot)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> pCurrentSnapshot;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR2_RET(pMachine,COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()), RTEXITCODE_FAILURE);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync hrc = showSnapshots(pSnapshot, pCurrentSnapshot, enmDetails);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (FAILED(hrc))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return RTEXITCODE_FAILURE;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return RTEXITCODE_SUCCESS;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync}
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/**
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Implementation for "VBoxManage snapshot ... dump". This goes thru the machine's
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * medium attachments and calls DumpMediumWithChildren() for each hard disk medium found,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * which then dumps the parent/child tree of that medium together with the corresponding
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * snapshots.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param pMachine Machine to dump snapshots for.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncvoid DumpSnapshot(ComPtr<IMachine> &pMachine)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync{
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync HRESULT rc;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync do
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get root snapshot
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> pSnapshot;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr("").raw(), pSnapshot.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get current snapshot
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<ISnapshot> pCurrentSnapshot;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync // get media attachments
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync SafeIfaceArray<IMediumAttachment> aAttachments;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync for (uint32_t i = 0;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync i < aAttachments.size();
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ++i)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync DeviceType_T type;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (type == DeviceType_HardDisk)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMedium> pCurrentStateMedium;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pCurrentStateMedium.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMedium> pBaseMedium;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pCurrentStateMedium, COMGETTER(Base)(pBaseMedium.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr bstrBaseMediumName;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(pBaseMedium, COMGETTER(Name)(bstrBaseMediumName.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTPrintf("[%RI32] Images and snapshots for medium \"%ls\"\n", i, bstrBaseMediumName.raw());
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync DumpMediumWithChildren(pCurrentStateMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pBaseMedium,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pCurrentSnapshot,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync 0);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync } while (0);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync}
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/**
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Implementation for all VBoxManage snapshot ... subcommands.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @param a
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @return
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncint handleSnapshot(HandlerArg *a)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync{
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync HRESULT rc;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* we need at least a VM and a command */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (a->argc < 2)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return errorSyntax(USAGE_SNAPSHOT, "Not enough parameters");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* the first argument must be the VM */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr bstrMachine(a->argv[0]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IMachine> pMachine;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR(a->virtualBox, FindMachine(bstrMachine.raw(),
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pMachine.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (!pMachine)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync return 1;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync do
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* we have to open a session for this task (new or shared) */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync rc = pMachine->LockMachine(a->session, LockType_Shared);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ComPtr<IConsole> pConsole;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(pConsole.asOutParam()));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* switch based on the command */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync bool fDelete = false,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync fRestore = false,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync fRestoreCurrent = false;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (!strcmp(a->argv[1], "take"))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* there must be a name */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync if (a->argc < 3)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync rc = E_FAIL;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync break;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr name(a->argv[2]);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* parse the optional arguments */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync Bstr desc;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync bool fPause = true; /* default is NO live snapshot */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync static const RTGETOPTDEF s_aTakeOptions[] =
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "--description", 'd', RTGETOPT_REQ_STRING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "-description", 'd', RTGETOPT_REQ_STRING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "-desc", 'd', RTGETOPT_REQ_STRING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "--pause", 'p', RTGETOPT_REQ_NOTHING },
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync { "--live", 'l', RTGETOPT_REQ_NOTHING }
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync };
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGETOPTSTATE GetOptState;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTakeOptions, RT_ELEMENTS(s_aTakeOptions),
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync 3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync int ch;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync RTGETOPTUNION Value;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync while ( SUCCEEDED(rc)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync && (ch = RTGetOpt(&GetOptState, &Value)))
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync switch (ch)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync {
case 'p':
fPause = true;
break;
case 'l':
fPause = false;
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(pConsole, COMGETTER(State)(&machineState));
if (machineState == MachineState_Running)
CHECK_ERROR_BREAK(pConsole, Pause());
else
fPause = false;
}
ComPtr<IProgress> progress;
CHECK_ERROR_BREAK(pConsole, TakeSnapshot(name.raw(), desc.raw(),
progress.asOutParam()));
rc = showProgress(progress);
CHECK_PROGRESS_ERROR(progress, ("Failed to take snapshot"));
if (fPause)
{
MachineState_T machineState;
CHECK_ERROR_BREAK(pConsole, COMGETTER(State)(&machineState));
if (machineState == MachineState_Paused)
{
if (SUCCEEDED(rc))
CHECK_ERROR_BREAK(pConsole, Resume());
else
pConsole->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()));
}
else
{
// restore or delete snapshot: then resolve cmd line argument to snapshot instance
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
pSnapshot.asOutParam()));
}
CHECK_ERROR_BREAK(pSnapshot, COMGETTER(Id)(bstrSnapGuid.asOutParam()));
if (fDelete)
{
CHECK_ERROR_BREAK(pConsole, DeleteSnapshot(bstrSnapGuid.raw(),
pProgress.asOutParam()));
}
else
{
// restore or restore current
RTPrintf("Restoring snapshot %ls\n", bstrSnapGuid.raw());
CHECK_ERROR_BREAK(pConsole, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
}
rc = showProgress(pProgress);
CHECK_PROGRESS_ERROR(pProgress, ("Snapshot operation failed"));
}
else if (!strcmp(a->argv[1], "edit"))
{
if (a->argc < 3)
{
errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
rc = E_FAIL;
break;
}
ComPtr<ISnapshot> pSnapshot;
if ( !strcmp(a->argv[2], "--current")
|| !strcmp(a->argv[2], "-current"))
{
CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pSnapshot.asOutParam()));
}
else
{
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
pSnapshot.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++;
pSnapshot->COMSETTER(Name)(Bstr(a->argv[i]).raw());
}
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++;
pSnapshot->COMSETTER(Description)(Bstr(a->argv[i]).raw());
}
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> pSnapshot;
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
pSnapshot.asOutParam()));
/* get the machine of the given snapshot */
ComPtr<IMachine> pMachine2;
pSnapshot->COMGETTER(Machine)(pMachine2.asOutParam());
showVMInfo(a->virtualBox, pMachine2, NULL, VMINFO_NONE);
}
else if (!strcmp(a->argv[1], "list"))
rc = handleSnapshotList(a, pMachine) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
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;
}