VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
RevLine 
[12599]1/* $Id: VBoxManageSnapshot.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
[1]2/** @file
[17102]3 * VBoxManage - The 'snapshot' command.
[1]4 */
5
6/*
[76553]7 * Copyright (C) 2006-2019 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
[57358]18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[1]22#include <VBox/com/com.h>
23#include <VBox/com/string.h>
[24081]24#include <VBox/com/array.h>
[1]25#include <VBox/com/ErrorInfo.h>
[20928]26#include <VBox/com/errorprint.h>
[1]27
28#include <VBox/com/VirtualBox.h>
29
[76366]30#include <iprt/getopt.h>
[1]31#include <iprt/stream.h>
[55977]32#include <iprt/time.h>
[1]33
34#include "VBoxManage.h"
35using namespace com;
36
[24081]37/**
[24084]38 * Helper function used with "VBoxManage snapshot ... dump". Gets called to find the
39 * snapshot in the machine's snapshot tree that uses a particular diff image child of
40 * a medium.
41 * Horribly inefficient since we keep re-querying the snapshots tree for each image,
42 * but this is for quick debugging only.
[24081]43 * @param pMedium
44 * @param pThisSnapshot
45 * @param pCurrentSnapshot
46 * @param uMediumLevel
47 * @param uSnapshotLevel
48 * @return
49 */
50bool FindAndPrintSnapshotUsingMedium(ComPtr<IMedium> &pMedium,
51 ComPtr<ISnapshot> &pThisSnapshot,
52 ComPtr<ISnapshot> &pCurrentSnapshot,
53 uint32_t uMediumLevel,
54 uint32_t uSnapshotLevel)
55{
56 HRESULT rc;
57
58 do
59 {
60 // get snapshot machine so we can figure out which diff image this created
61 ComPtr<IMachine> pSnapshotMachine;
62 CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Machine)(pSnapshotMachine.asOutParam()));
63
64 // get media attachments
65 SafeIfaceArray<IMediumAttachment> aAttachments;
66 CHECK_ERROR_BREAK(pSnapshotMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
67
68 for (uint32_t i = 0;
69 i < aAttachments.size();
70 ++i)
71 {
72 ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
73 DeviceType_T type;
74 CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
75 if (type == DeviceType_HardDisk)
76 {
77 ComPtr<IMedium> pMediumInSnapshot;
78 CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pMediumInSnapshot.asOutParam()));
79
80 if (pMediumInSnapshot == pMedium)
81 {
82 // get snapshot name
83 Bstr bstrSnapshotName;
84 CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Name)(bstrSnapshotName.asOutParam()));
85
[24084]86 RTPrintf("%*s \"%ls\"%s\n",
[24081]87 50 + uSnapshotLevel * 2, "", // indent
[24084]88 bstrSnapshotName.raw(),
89 (pThisSnapshot == pCurrentSnapshot) ? " (CURSNAP)" : "");
[24081]90 return true; // found
91 }
92 }
93 }
94
[24084]95 // not found: then recurse into child snapshots
96 SafeIfaceArray<ISnapshot> aSnapshots;
97 CHECK_ERROR_BREAK(pThisSnapshot, COMGETTER(Children)(ComSafeArrayAsOutParam(aSnapshots)));
98
99 for (uint32_t i = 0;
100 i < aSnapshots.size();
101 ++i)
[24081]102 {
[24084]103 ComPtr<ISnapshot> pChild(aSnapshots[i]);
104 if (FindAndPrintSnapshotUsingMedium(pMedium,
105 pChild,
106 pCurrentSnapshot,
107 uMediumLevel,
108 uSnapshotLevel + 1))
109 // found:
110 break;
[24081]111 }
112 } while (0);
113
114 return false;
115}
116
117/**
118 * Helper function used with "VBoxManage snapshot ... dump". Called from DumpSnapshot()
119 * for each hard disk attachment found in a virtual machine. This then writes out the
120 * root (base) medium for that hard disk attachment and recurses into the children
121 * tree of that medium, correlating it with the snapshots of the machine.
122 * @param pCurrentStateMedium constant, the medium listed in the current machine data (latest diff image).
123 * @param pMedium variant, initially the base medium, then a child of the base medium when recursing.
124 * @param pRootSnapshot constant, the root snapshot of the machine, if any; this then looks into the child snapshots.
125 * @param pCurrentSnapshot constant, the machine's current snapshot (so we can mark it in the output).
126 * @param uLevel variant, the recursion level for output indentation.
127 */
128void DumpMediumWithChildren(ComPtr<IMedium> &pCurrentStateMedium,
129 ComPtr<IMedium> &pMedium,
130 ComPtr<ISnapshot> &pRootSnapshot,
131 ComPtr<ISnapshot> &pCurrentSnapshot,
132 uint32_t uLevel)
133{
134 HRESULT rc;
135 do
136 {
137 // print this medium
138 Bstr bstrMediumName;
139 CHECK_ERROR_BREAK(pMedium, COMGETTER(Name)(bstrMediumName.asOutParam()));
140 RTPrintf("%*s \"%ls\"%s\n",
141 uLevel * 2, "", // indent
142 bstrMediumName.raw(),
[24084]143 (pCurrentStateMedium == pMedium) ? " (CURSTATE)" : "");
[24081]144
145 // find and print the snapshot that uses this particular medium (diff image)
146 FindAndPrintSnapshotUsingMedium(pMedium, pRootSnapshot, pCurrentSnapshot, uLevel, 0);
147
148 // recurse into children
149 SafeIfaceArray<IMedium> aChildren;
150 CHECK_ERROR_BREAK(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(aChildren)));
151 for (uint32_t i = 0;
152 i < aChildren.size();
153 ++i)
154 {
155 ComPtr<IMedium> pChild(aChildren[i]);
156 DumpMediumWithChildren(pCurrentStateMedium, pChild, pRootSnapshot, pCurrentSnapshot, uLevel + 1);
157 }
158 } while (0);
159}
160
[39119]161
[24081]162/**
[39119]163 * Handles the 'snapshot myvm list' sub-command.
164 * @returns Exit code.
165 * @param pArgs The handler argument package.
[53266]166 * @param pMachine Reference to the VM (locked) we're operating on.
[39119]167 */
[53266]168static RTEXITCODE handleSnapshotList(HandlerArg *pArgs, ComPtr<IMachine> &pMachine)
[39119]169{
170 static const RTGETOPTDEF g_aOptions[] =
171 {
172 { "--details", 'D', RTGETOPT_REQ_NOTHING },
173 { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
174 };
175
176 VMINFO_DETAILS enmDetails = VMINFO_STANDARD;
177
178 int c;
179 RTGETOPTUNION ValueUnion;
180 RTGETOPTSTATE GetState;
181 RTGetOptInit(&GetState, pArgs->argc, pArgs->argv, g_aOptions, RT_ELEMENTS(g_aOptions), 2 /*iArg*/, 0 /*fFlags*/);
182 while ((c = RTGetOpt(&GetState, &ValueUnion)))
183 {
184 switch (c)
185 {
186 case 'D': enmDetails = VMINFO_FULL; break;
187 case 'M': enmDetails = VMINFO_MACHINEREADABLE; break;
188 default: return errorGetOpt(USAGE_SNAPSHOT, c, &ValueUnion);
189 }
190 }
191
[53266]192 ComPtr<ISnapshot> pSnapshot;
193 HRESULT hrc = pMachine->FindSnapshot(Bstr().raw(), pSnapshot.asOutParam());
[43664]194 if (FAILED(hrc))
195 {
196 RTPrintf("This machine does not have any snapshots\n");
197 return RTEXITCODE_FAILURE;
198 }
[53266]199 if (pSnapshot)
[39119]200 {
[53266]201 ComPtr<ISnapshot> pCurrentSnapshot;
[56118]202 CHECK_ERROR2I_RET(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()), RTEXITCODE_FAILURE);
[53266]203 hrc = showSnapshots(pSnapshot, pCurrentSnapshot, enmDetails);
[39119]204 if (FAILED(hrc))
205 return RTEXITCODE_FAILURE;
206 }
207 return RTEXITCODE_SUCCESS;
208}
209
210/**
[24081]211 * Implementation for "VBoxManage snapshot ... dump". This goes thru the machine's
212 * medium attachments and calls DumpMediumWithChildren() for each hard disk medium found,
213 * which then dumps the parent/child tree of that medium together with the corresponding
214 * snapshots.
215 * @param pMachine Machine to dump snapshots for.
216 */
217void DumpSnapshot(ComPtr<IMachine> &pMachine)
218{
219 HRESULT rc;
220
221 do
222 {
223 // get root snapshot
224 ComPtr<ISnapshot> pSnapshot;
[33300]225 CHECK_ERROR_BREAK(pMachine, FindSnapshot(Bstr("").raw(), pSnapshot.asOutParam()));
[24081]226
227 // get current snapshot
228 ComPtr<ISnapshot> pCurrentSnapshot;
229 CHECK_ERROR_BREAK(pMachine, COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam()));
230
231 // get media attachments
232 SafeIfaceArray<IMediumAttachment> aAttachments;
233 CHECK_ERROR_BREAK(pMachine, COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(aAttachments)));
234 for (uint32_t i = 0;
235 i < aAttachments.size();
236 ++i)
237 {
238 ComPtr<IMediumAttachment> pAttach(aAttachments[i]);
239 DeviceType_T type;
240 CHECK_ERROR_BREAK(pAttach, COMGETTER(Type)(&type));
241 if (type == DeviceType_HardDisk)
242 {
243 ComPtr<IMedium> pCurrentStateMedium;
244 CHECK_ERROR_BREAK(pAttach, COMGETTER(Medium)(pCurrentStateMedium.asOutParam()));
245
246 ComPtr<IMedium> pBaseMedium;
247 CHECK_ERROR_BREAK(pCurrentStateMedium, COMGETTER(Base)(pBaseMedium.asOutParam()));
248
249 Bstr bstrBaseMediumName;
250 CHECK_ERROR_BREAK(pBaseMedium, COMGETTER(Name)(bstrBaseMediumName.asOutParam()));
251
252 RTPrintf("[%RI32] Images and snapshots for medium \"%ls\"\n", i, bstrBaseMediumName.raw());
253
254 DumpMediumWithChildren(pCurrentStateMedium,
255 pBaseMedium,
256 pSnapshot,
257 pCurrentSnapshot,
258 0);
259 }
260 }
261 } while (0);
262}
263
[55977]264typedef enum SnapshotUniqueFlags
265{
266 SnapshotUniqueFlags_Null = 0,
267 SnapshotUniqueFlags_Number = RT_BIT(1),
268 SnapshotUniqueFlags_Timestamp = RT_BIT(2),
269 SnapshotUniqueFlags_Space = RT_BIT(16),
270 SnapshotUniqueFlags_Force = RT_BIT(30)
271} SnapshotUniqueFlags;
272
273static int parseSnapshotUniqueFlags(const char *psz, SnapshotUniqueFlags *pUnique)
274{
275 int rc = VINF_SUCCESS;
276 unsigned uUnique = 0;
277 while (psz && *psz && RT_SUCCESS(rc))
278 {
279 size_t len;
280 const char *pszComma = strchr(psz, ',');
281 if (pszComma)
282 len = pszComma - psz;
283 else
284 len = strlen(psz);
285 if (len > 0)
286 {
287 if (!RTStrNICmp(psz, "number", len))
288 uUnique |= SnapshotUniqueFlags_Number;
289 else if (!RTStrNICmp(psz, "timestamp", len))
290 uUnique |= SnapshotUniqueFlags_Timestamp;
291 else if (!RTStrNICmp(psz, "space", len))
292 uUnique |= SnapshotUniqueFlags_Space;
293 else if (!RTStrNICmp(psz, "force", len))
294 uUnique |= SnapshotUniqueFlags_Force;
295 else
296 rc = VERR_PARSE_ERROR;
297 }
298 if (pszComma)
299 psz += len + 1;
300 else
301 psz += len;
302 }
303
304 if (RT_SUCCESS(rc))
305 *pUnique = (SnapshotUniqueFlags)uUnique;
306 return rc;
307}
308
[24081]309/**
310 * Implementation for all VBoxManage snapshot ... subcommands.
311 * @param a
312 * @return
313 */
[56118]314RTEXITCODE handleSnapshot(HandlerArg *a)
[1]315{
[5280]316 HRESULT rc;
[1]317
318 /* we need at least a VM and a command */
[16052]319 if (a->argc < 2)
[1]320 return errorSyntax(USAGE_SNAPSHOT, "Not enough parameters");
321
322 /* the first argument must be the VM */
[24081]323 Bstr bstrMachine(a->argv[0]);
[53266]324 ComPtr<IMachine> pMachine;
[33294]325 CHECK_ERROR(a->virtualBox, FindMachine(bstrMachine.raw(),
[53266]326 pMachine.asOutParam()));
327 if (!pMachine)
[56118]328 return RTEXITCODE_FAILURE;
[1]329
[55214]330 /* we have to open a session for this task (new or shared) */
[56118]331 CHECK_ERROR_RET(pMachine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[1]332 do
333 {
[55214]334 /* replace the (read-only) IMachine object by a writable one */
[55234]335 ComPtr<IMachine> sessionMachine;
336 CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
[1]337
338 /* switch based on the command */
[25755]339 bool fDelete = false,
340 fRestore = false,
341 fRestoreCurrent = false;
342
[18777]343 if (!strcmp(a->argv[1], "take"))
[1]344 {
345 /* there must be a name */
[16052]346 if (a->argc < 3)
[1]347 {
348 errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
349 rc = E_FAIL;
350 break;
351 }
[16052]352 Bstr name(a->argv[2]);
[23569]353
354 /* parse the optional arguments */
355 Bstr desc;
[47544]356 bool fPause = true; /* default is NO live snapshot */
[55977]357 SnapshotUniqueFlags enmUnique = SnapshotUniqueFlags_Null;
[23569]358 static const RTGETOPTDEF s_aTakeOptions[] =
[1]359 {
[23569]360 { "--description", 'd', RTGETOPT_REQ_STRING },
361 { "-description", 'd', RTGETOPT_REQ_STRING },
362 { "-desc", 'd', RTGETOPT_REQ_STRING },
[47544]363 { "--pause", 'p', RTGETOPT_REQ_NOTHING },
[55977]364 { "--live", 'l', RTGETOPT_REQ_NOTHING },
365 { "--uniquename", 'u', RTGETOPT_REQ_STRING }
[23569]366 };
367 RTGETOPTSTATE GetOptState;
[26517]368 RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTakeOptions, RT_ELEMENTS(s_aTakeOptions),
369 3, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
[23569]370 int ch;
371 RTGETOPTUNION Value;
[55977]372 int vrc;
[23569]373 while ( SUCCEEDED(rc)
374 && (ch = RTGetOpt(&GetOptState, &Value)))
375 {
376 switch (ch)
377 {
378 case 'p':
379 fPause = true;
380 break;
381
[47544]382 case 'l':
383 fPause = false;
384 break;
385
[23569]386 case 'd':
387 desc = Value.psz;
388 break;
389
[55977]390 case 'u':
391 vrc = parseSnapshotUniqueFlags(Value.psz, &enmUnique);
392 if (RT_FAILURE(vrc))
393 return errorArgument("Invalid unique name description '%s'", Value.psz);
394 break;
395
[23569]396 default:
397 errorGetOpt(USAGE_SNAPSHOT, ch, &Value);
398 rc = E_FAIL;
399 break;
400 }
401 }
402 if (FAILED(rc))
[1]403 break;
[23569]404
[55977]405 if (enmUnique & (SnapshotUniqueFlags_Number | SnapshotUniqueFlags_Timestamp))
406 {
407 ComPtr<ISnapshot> pSnapshot;
408 rc = sessionMachine->FindSnapshot(name.raw(),
409 pSnapshot.asOutParam());
410 if (SUCCEEDED(rc) || (enmUnique & SnapshotUniqueFlags_Force))
411 {
412 /* there is a duplicate, need to create a unique name */
413 uint32_t count = 0;
414 RTTIMESPEC now;
415
416 if (enmUnique & SnapshotUniqueFlags_Number)
417 {
418 if (enmUnique & SnapshotUniqueFlags_Force)
419 count = 1;
420 else
421 count = 2;
[63300]422 RTTimeSpecSetNano(&now, 0); /* Shut up MSC */
[55977]423 }
424 else
425 RTTimeNow(&now);
426
427 while (count < 500)
428 {
429 Utf8Str suffix;
430 if (enmUnique & SnapshotUniqueFlags_Number)
431 suffix = Utf8StrFmt("%u", count);
432 else
433 {
434 RTTIMESPEC nowplus = now;
435 RTTimeSpecAddSeconds(&nowplus, count);
436 RTTIME stamp;
437 RTTimeExplode(&stamp, &nowplus);
438 suffix = Utf8StrFmt("%04u-%02u-%02uT%02u:%02u:%02uZ", stamp.i32Year, stamp.u8Month, stamp.u8MonthDay, stamp.u8Hour, stamp.u8Minute, stamp.u8Second);
439 }
440 Bstr tryName = name;
441 if (enmUnique & SnapshotUniqueFlags_Space)
442 tryName = BstrFmt("%ls %s", name.raw(), suffix.c_str());
443 else
444 tryName = BstrFmt("%ls%s", name.raw(), suffix.c_str());
445 count++;
446 rc = sessionMachine->FindSnapshot(tryName.raw(),
447 pSnapshot.asOutParam());
448 if (FAILED(rc))
449 {
450 name = tryName;
451 break;
452 }
453 }
454 if (SUCCEEDED(rc))
455 {
456 errorArgument("Failed to generate a unique snapshot name");
457 rc = E_FAIL;
458 break;
459 }
460 }
461 rc = S_OK;
462 }
463
[53267]464 ComPtr<IProgress> progress;
[55977]465 Bstr snapId;
[55234]466 CHECK_ERROR_BREAK(sessionMachine, TakeSnapshot(name.raw(), desc.raw(),
[55977]467 fPause, snapId.asOutParam(),
[55234]468 progress.asOutParam()));
[53267]469
470 rc = showProgress(progress);
[55977]471 if (SUCCEEDED(rc))
472 RTPrintf("Snapshot taken. UUID: %ls\n", snapId.raw());
473 else
474 CHECK_PROGRESS_ERROR(progress, ("Failed to take snapshot"));
[1]475 }
[23882]476 else if ( (fDelete = !strcmp(a->argv[1], "delete"))
477 || (fRestore = !strcmp(a->argv[1], "restore"))
[25755]478 || (fRestoreCurrent = !strcmp(a->argv[1], "restorecurrent"))
[23882]479 )
[1]480 {
[25755]481 if (fRestoreCurrent)
482 {
483 if (a->argc > 2)
484 {
485 errorSyntax(USAGE_SNAPSHOT, "Too many arguments");
486 rc = E_FAIL;
487 break;
488 }
489 }
[1]490 /* exactly one parameter: snapshot name */
[25755]491 else if (a->argc != 3)
[1]492 {
493 errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
494 rc = E_FAIL;
495 break;
496 }
497
[23882]498 ComPtr<ISnapshot> pSnapshot;
[1]499
[25755]500 if (fRestoreCurrent)
[1]501 {
[55234]502 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(CurrentSnapshot)(pSnapshot.asOutParam()));
[58410]503 if (pSnapshot.isNull())
504 {
505 RTPrintf("This machine does not have any snapshots\n");
506 return RTEXITCODE_FAILURE;
507 }
[1]508 }
509 else
510 {
[25755]511 // restore or delete snapshot: then resolve cmd line argument to snapshot instance
[55234]512 CHECK_ERROR_BREAK(sessionMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
[55977]513 pSnapshot.asOutParam()));
[1]514 }
515
[63751]516 Bstr bstrSnapGuid;
[33425]517 CHECK_ERROR_BREAK(pSnapshot, COMGETTER(Id)(bstrSnapGuid.asOutParam()));
518
[63751]519 Bstr bstrSnapName;
520 CHECK_ERROR_BREAK(pSnapshot, COMGETTER(Name)(bstrSnapName.asOutParam()));
521
522 ComPtr<IProgress> pProgress;
523
524 RTPrintf("%s snapshot '%ls' (%ls)\n",
525 fDelete ? "Deleting" : "Restoring", bstrSnapName.raw(), bstrSnapGuid.raw());
526
[23882]527 if (fDelete)
[1]528 {
[55234]529 CHECK_ERROR_BREAK(sessionMachine, DeleteSnapshot(bstrSnapGuid.raw(),
[55977]530 pProgress.asOutParam()));
[1]531 }
[23882]532 else
[1]533 {
[25755]534 // restore or restore current
[55234]535 CHECK_ERROR_BREAK(sessionMachine, RestoreSnapshot(pSnapshot, pProgress.asOutParam()));
[1]536 }
537
[24879]538 rc = showProgress(pProgress);
[38525]539 CHECK_PROGRESS_ERROR(pProgress, ("Snapshot operation failed"));
[1]540 }
[18777]541 else if (!strcmp(a->argv[1], "edit"))
[1]542 {
[16052]543 if (a->argc < 3)
[1]544 {
545 errorSyntax(USAGE_SNAPSHOT, "Missing snapshot name");
546 rc = E_FAIL;
547 break;
548 }
549
[53266]550 ComPtr<ISnapshot> pSnapshot;
[1]551
[18777]552 if ( !strcmp(a->argv[2], "--current")
553 || !strcmp(a->argv[2], "-current"))
[1]554 {
[55234]555 CHECK_ERROR_BREAK(sessionMachine, COMGETTER(CurrentSnapshot)(pSnapshot.asOutParam()));
[58410]556 if (pSnapshot.isNull())
557 {
558 RTPrintf("This machine does not have any snapshots\n");
559 return RTEXITCODE_FAILURE;
560 }
[1]561 }
562 else
563 {
[55234]564 CHECK_ERROR_BREAK(sessionMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
[55977]565 pSnapshot.asOutParam()));
[1]566 }
567
568 /* parse options */
[16052]569 for (int i = 3; i < a->argc; i++)
[1]570 {
[18777]571 if ( !strcmp(a->argv[i], "--name")
572 || !strcmp(a->argv[i], "-name")
573 || !strcmp(a->argv[i], "-newname"))
[1]574 {
[16052]575 if (a->argc <= i + 1)
[1]576 {
[16052]577 errorArgument("Missing argument to '%s'", a->argv[i]);
[1]578 rc = E_FAIL;
579 break;
580 }
581 i++;
[53266]582 pSnapshot->COMSETTER(Name)(Bstr(a->argv[i]).raw());
[1]583 }
[18777]584 else if ( !strcmp(a->argv[i], "--description")
585 || !strcmp(a->argv[i], "-description")
586 || !strcmp(a->argv[i], "-newdesc"))
[1]587 {
[16052]588 if (a->argc <= i + 1)
[1]589 {
[16052]590 errorArgument("Missing argument to '%s'", a->argv[i]);
[1]591 rc = E_FAIL;
592 break;
593 }
594 i++;
[53266]595 pSnapshot->COMSETTER(Description)(Bstr(a->argv[i]).raw());
[1]596 }
597 else
598 {
[31539]599 errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
[1]600 rc = E_FAIL;
601 break;
602 }
603 }
604
605 }
[18777]606 else if (!strcmp(a->argv[1], "showvminfo"))
[1]607 {
608 /* exactly one parameter: snapshot name */
[16052]609 if (a->argc != 3)
[1]610 {
611 errorSyntax(USAGE_SNAPSHOT, "Expecting snapshot name only");
612 rc = E_FAIL;
613 break;
614 }
615
[53266]616 ComPtr<ISnapshot> pSnapshot;
[1]617
[55234]618 CHECK_ERROR_BREAK(sessionMachine, FindSnapshot(Bstr(a->argv[2]).raw(),
619 pSnapshot.asOutParam()));
[1]620
621 /* get the machine of the given snapshot */
[53266]622 ComPtr<IMachine> pMachine2;
623 pSnapshot->COMGETTER(Machine)(pMachine2.asOutParam());
624 showVMInfo(a->virtualBox, pMachine2, NULL, VMINFO_NONE);
[1]625 }
[39119]626 else if (!strcmp(a->argv[1], "list"))
[55234]627 rc = handleSnapshotList(a, sessionMachine) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
[24081]628 else if (!strcmp(a->argv[1], "dump")) // undocumented parameter to debug snapshot info
[55234]629 DumpSnapshot(sessionMachine);
[1]630 else
631 {
[31539]632 errorSyntax(USAGE_SNAPSHOT, "Invalid parameter '%s'", Utf8Str(a->argv[1]).c_str());
[1]633 rc = E_FAIL;
634 }
635 } while (0);
636
[31070]637 a->session->UnlockMachine();
[1]638
[56118]639 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[1]640}
641
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use