35
36
#include "VBoxManage.h"
36
37
using namespace com;
40
* Helper function used with "VBoxManage snapshot ... dump". Gets called to find the
41
* snapshot in the machine's snapshot tree that uses a particular diff image child of
43
* Horribly inefficient since we keep re-querying the snapshots tree for each image,
44
* but this is for quick debugging only.
46
* @param pThisSnapshot
47
* @param pCurrentSnapshot
49
* @param uSnapshotLevel
52
bool FindAndPrintSnapshotUsingMedium(ComPtr<IMedium> &pMedium,
53
ComPtr<ISnapshot> &pThisSnapshot,
54
ComPtr<ISnapshot> &pCurrentSnapshot,
55
uint32_t uMediumLevel,
56
uint32_t uSnapshotLevel)
62
// get snapshot machine so we can figure out which diff image this created
63
ComPtr<IMachine> pSnapshotMachine;
64
CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Machine)(pSnapshotMachine.asOutParam()));
66
// get media attachments
67
SafeIfaceArray<IMediumAttachment> aAttachments;
68
CHECK_ERROR_BREAK(pSnapshotMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
71
i < aAttachments.size();
74
ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
76
CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
77
if (type == DeviceType_HardDisk)
79
ComPtr<IMedium> pMediumInSnapshot;
80
CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pMediumInSnapshot.asOutParam()));
82
if (pMediumInSnapshot == pMedium)
85
Bstr bstrSnapshotName;
86
CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Name)(bstrSnapshotName.asOutParam()));
88
RTPrintf("%*s \"%ls\"%s\n",
89
50 + uSnapshotLevel * 2, "", // indent
90
bstrSnapshotName.raw(),
91
(pThisSnapshot == pCurrentSnapshot) ? " (CURSNAP)" : "");
97
// not found: then recurse into child snapshots
98
SafeIfaceArray<ISnapshot> aSnapshots;
99
CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Children)(ComSafeArrayAsOutParam(aSnapshots)));
102
i < aSnapshots.size();
105
ComPtr<ISnapshot> pChild(aSnapshots[i]);
106
if (FindAndPrintSnapshotUsingMedium(pMedium,
120
* Helper function used with "VBoxManage snapshot ... dump". Called from DumpSnapshot()
121
* for each hard disk attachment found in a virtual machine. This then writes out the
122
* root (base) medium for that hard disk attachment and recurses into the children
123
* tree of that medium, correlating it with the snapshots of the machine.
124
* @param pCurrentStateMedium constant, the medium listed in the current machine data (latest diff image).
125
* @param pMedium variant, initially the base medium, then a child of the base medium when recursing.
126
* @param pRootSnapshot constant, the root snapshot of the machine, if any; this then looks into the child snapshots.
127
* @param pCurrentSnapshot constant, the machine's current snapshot (so we can mark it in the output).
128
* @param uLevel variant, the recursion level for output indentation.
130
void DumpMediumWithChildren(ComPtr<IMedium> &pCurrentStateMedium,
131
ComPtr<IMedium> &pMedium,
132
ComPtr<ISnapshot> &pRootSnapshot,
133
ComPtr<ISnapshot> &pCurrentSnapshot,
141
CHECK_ERROR_BREAK(pMedium, COMGETTER(Name)(bstrMediumName.asOutParam()));
142
RTPrintf("%*s \"%ls\"%s\n",
143
uLevel * 2, "", // indent
144
bstrMediumName.raw(),
145
(pCurrentStateMedium == pMedium) ? " (CURSTATE)" : "");
147
// find and print the snapshot that uses this particular medium (diff image)
148
FindAndPrintSnapshotUsingMedium(pMedium, pRootSnapshot, pCurrentSnapshot, uLevel, 0);
150
// recurse into children
151
SafeIfaceArray<IMedium> aChildren;
152
CHECK_ERROR_BREAK(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(aChildren)));
154
i < aChildren.size();
157
ComPtr<IMedium> pChild(aChildren[i]);
158
DumpMediumWithChildren(pCurrentStateMedium, pChild, pRootSnapshot, pCurrentSnapshot, uLevel + 1);
164
* Implementation for "VBoxManage snapshot ... dump". This goes thru the machine's
165
* medium attachments and calls DumpMediumWithChildren() for each hard disk medium found,
166
* which then dumps the parent/child tree of that medium together with the corresponding
168
* @param pMachine Machine to dump snapshots for.
170
void DumpSnapshot(ComPtr<IMachine> &pMachine)
177
ComPtr<ISnapshot> pSnapshot;
178
CHECK_ERROR_BREAK(pMachine, GetSnapshot(Bstr(""), pSnapshot.asOutParam()));
180
// get current snapshot
181
ComPtr<ISnapshot> pCurrentSnapshot;
182
CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()));
184
// get media attachments
185
SafeIfaceArray<IMediumAttachment> aAttachments;
186
CHECK_ERROR_BREAK(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
188
i < aAttachments.size();
191
ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
193
CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
194
if (type == DeviceType_HardDisk)
196
ComPtr<IMedium> pCurrentStateMedium;
197
CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pCurrentStateMedium.asOutParam()));
199
ComPtr<IMedium> pBaseMedium;
200
CHECK_ERROR_BREAK(pCurrentStateMedium, COMGETTER(Base)(pBaseMedium.asOutParam()));
202
Bstr bstrBaseMediumName;
203
CHECK_ERROR_BREAK(pBaseMedium, COMGETTER(Name)(bstrBaseMediumName.asOutParam()));
205
RTPrintf("[%RI32] Images and snapshots for medium \"%ls\"\n", i, bstrBaseMediumName.raw());
207
DumpMediumWithChildren(pCurrentStateMedium,
218
* Implementation for all VBoxManage snapshot ... subcommands.
38
222
int handleSnapshot(HandlerArg *a)
44
228
return errorSyntax(USAGE_SNAPSHOT, "Not enough parameters");
46
230
/* the first argument must be the VM */
47
ComPtr<IMachine> machine;
231
Bstr bstrMachine(a->argv[0]);
232
ComPtr<IMachine> pMachine;
48
233
/* assume it's a UUID */
49
rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
50
if (FAILED(rc) || !machine)
234
rc = a->virtualBox->GetMachine(bstrMachine, pMachine.asOutParam());
235
if (FAILED(rc) || !pMachine)
52
237
/* must be a name */
53
CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
238
CHECK_ERROR(a->virtualBox, FindMachine(bstrMachine, pMachine.asOutParam()));
58
machine->COMGETTER(Id)(guid.asOutParam());
243
pMachine->COMGETTER(Id)(guidMachine.asOutParam());
62
247
/* we have to open a session for this task. First try an existing session */
63
rc = a->virtualBox->OpenExistingSession(a->session, guid);
248
rc = a->virtualBox->OpenExistingSession(a->session, guidMachine);
65
CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guid));
250
CHECK_ERROR_BREAK(a->virtualBox, OpenSession(a->session, guidMachine));
66
251
ComPtr<IConsole> console;
67
252
CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
69
254
/* switch based on the command */
255
bool fDelete = false, fRestore = false;
70
256
if (!strcmp(a->argv[1], "take"))
72
258
/* there must be a name */
79
265
Bstr name(a->argv[2]);
80
if ((a->argc > 3) && ( (a->argc != 5)
81
|| ( strcmp(a->argv[3], "--description")
82
&& strcmp(a->argv[3], "-description")
83
&& strcmp(a->argv[3], "-desc"))))
85
errorSyntax(USAGE_SNAPSHOT, "Incorrect description format");
267
/* parse the optional arguments */
270
static const RTGETOPTDEF s_aTakeOptions[] =
272
{ "--description", 'd', RTGETOPT_REQ_STRING },
273
{ "-description", 'd', RTGETOPT_REQ_STRING },
274
{ "-desc", 'd', RTGETOPT_REQ_STRING },
275
{ "--pause", 'p', RTGETOPT_REQ_NOTHING }
277
RTGETOPTSTATE GetOptState;
278
RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTakeOptions, RT_ELEMENTS(s_aTakeOptions), 3, 0 /*fFlags*/);
281
while ( SUCCEEDED(rc)
282
&& (ch = RTGetOpt(&GetOptState, &Value)))
295
errorGetOpt(USAGE_SNAPSHOT, ch, &Value);
305
MachineState_T machineState;
306
CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
307
if (machineState == MachineState_Running)
308
CHECK_ERROR_BREAK(console, Pause());
92
313
ComPtr<IProgress> progress;
93
314
CHECK_ERROR_BREAK(console, TakeSnapshot(name, desc, progress.asOutParam()));
95
showProgress(progress);
97
progress->COMGETTER(ResultCode)(&iRc);
316
rc = showProgress(progress);
101
319
com::ProgressErrorInfo info(progress);
118
ComPtr<ISnapshot> snapshot;
351
ComPtr<ISnapshot> pSnapshot;
120
353
/* assume it's a UUID */
121
Bstr guid(a->argv[2]);
354
Bstr guidSnap(a->argv[2]);
355
if (!guidSnap.isEmpty())
124
CHECK_ERROR_BREAK(machine, GetSnapshot(guid, snapshot.asOutParam()));
357
CHECK_ERROR_BREAK(pMachine, GetSnapshot(guidSnap, pSnapshot.asOutParam()));
128
361
/* then it must be a name */
129
CHECK_ERROR_BREAK(machine, FindSnapshot(Bstr(a->argv[2]), snapshot.asOutParam()));
132
snapshot->COMGETTER(Id)(guid.asOutParam());
134
ComPtr<IProgress> progress;
135
CHECK_ERROR_BREAK(console, DiscardSnapshot(guid, progress.asOutParam()));
137
showProgress(progress);
139
progress->COMGETTER(ResultCode)(&iRc);
143
com::ProgressErrorInfo info(progress);
144
if (info.isBasicAvailable())
145
RTPrintf("Error: failed to discard snapshot. Error message: %lS\n", info.getText().raw());
147
RTPrintf("Error: failed to discard snapshot. No error message available!\n");
150
else if (!strcmp(a->argv[1], "discardcurrent"))
153
|| ( strcmp(a->argv[2], "--state")
154
&& strcmp(a->argv[2], "-state")
155
&& strcmp(a->argv[2], "--all")
156
&& strcmp(a->argv[2], "-all")))
158
errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(a->argv[2]).raw());
163
if ( !strcmp(a->argv[2], "--all")
164
|| !strcmp(a->argv[2], "-all"))
167
ComPtr<IProgress> progress;
171
CHECK_ERROR_BREAK(console, DiscardCurrentSnapshotAndState(progress.asOutParam()));
362
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]), pSnapshot.asOutParam()));
363
pSnapshot->COMGETTER(Id)(guidSnap.asOutParam());
366
ComPtr<IProgress> pProgress;
369
CHECK_ERROR_BREAK(console, DeleteSnapshot(guidSnap, pProgress.asOutParam()));
175
CHECK_ERROR_BREAK(console, DiscardCurrentState(progress.asOutParam()));
374
CHECK_ERROR_BREAK(console, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
178
showProgress(progress);
180
progress->COMGETTER(ResultCode)(&iRc);
377
rc = showProgress(pProgress);
184
com::ProgressErrorInfo info(progress);
380
com::ProgressErrorInfo info(pProgress);
185
381
if (info.isBasicAvailable())
186
RTPrintf("Error: failed to discard. Error message: %lS\n", info.getText().raw());
382
RTPrintf("Error: snapshot operation failed. Error message: %lS\n", info.getText().raw());
188
RTPrintf("Error: failed to discard. No error message available!\n");
384
RTPrintf("Error: snapshot operation failed. No error message available!\n");
192
387
else if (!strcmp(a->argv[1], "edit"))
271
466
ComPtr<ISnapshot> snapshot;
273
468
/* assume it's a UUID */
274
Bstr guid(a->argv[2]);
469
Bstr guidSnap(a->argv[2]);
470
if (!guidSnap.isEmpty())
277
CHECK_ERROR_BREAK(machine, GetSnapshot(guid, snapshot.asOutParam()));
472
CHECK_ERROR_BREAK(pMachine, GetSnapshot(guidSnap, snapshot.asOutParam()));
281
476
/* then it must be a name */
282
CHECK_ERROR_BREAK(machine, FindSnapshot(Bstr(a->argv[2]), snapshot.asOutParam()));
477
CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr(a->argv[2]), snapshot.asOutParam()));
285
480
/* get the machine of the given snapshot */
286
ComPtr<IMachine> machine;
287
snapshot->COMGETTER(Machine)(machine.asOutParam());
288
showVMInfo(a->virtualBox, machine, VMINFO_NONE, console);
481
ComPtr<IMachine> pMachine2;
482
snapshot->COMGETTER(Machine)(pMachine2.asOutParam());
483
showVMInfo(a->virtualBox, pMachine2, VMINFO_NONE, console);
485
else if (!strcmp(a->argv[1], "dump")) // undocumented parameter to debug snapshot info
487
DumpSnapshot(pMachine);