VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageImport.cpp@ 18709

Last change on this file since 18709 was 18623, checked in by vboxsync, 16 years ago

OVF: add support for writing OVF 0.9 instead of 1.0 and make it the default in front-ends for now

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
Line 
1/* $Id: VBoxManageImport.cpp 18623 2009-04-02 10:00:48Z vboxsync $ */
2/** @file
3 * VBoxManage - The appliance-related commands.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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
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.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#ifndef VBOX_ONLY_DOCS
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#ifndef VBOX_ONLY_DOCS
28#include <VBox/com/com.h>
29#include <VBox/com/string.h>
30#include <VBox/com/Guid.h>
31#include <VBox/com/array.h>
32#include <VBox/com/ErrorInfo.h>
33#include <VBox/com/errorprint2.h>
34#include <VBox/com/EventQueue.h>
35
36#include <VBox/com/VirtualBox.h>
37
38#include <list>
39#include <map>
40#endif /* !VBOX_ONLY_DOCS */
41
42#include <iprt/stream.h>
43#include <iprt/getopt.h>
44#include <iprt/ctype.h>
45
46#include <VBox/log.h>
47
48#include "VBoxManage.h"
49using namespace com;
50
51
52// funcs
53///////////////////////////////////////////////////////////////////////////////
54
55typedef std::map<Utf8Str, Utf8Str> ArgsMap; // pairs of strings like "-vmname" => "newvmname"
56typedef std::map<uint32_t, ArgsMap> ArgsMapsMap; // map of maps, one for each virtual system, sorted by index
57
58typedef std::map<uint32_t, bool> IgnoresMap; // pairs of numeric description entry indices
59typedef std::map<uint32_t, IgnoresMap> IgnoresMapsMap; // map of maps, one for each virtual system, sorted by index
60
61static bool findArgValue(Utf8Str &strOut,
62 ArgsMap *pmapArgs,
63 const Utf8Str &strKey)
64{
65 if (pmapArgs)
66 {
67 ArgsMap::iterator it;
68 it = pmapArgs->find(strKey);
69 if (it != pmapArgs->end())
70 {
71 strOut = it->second;
72 pmapArgs->erase(it);
73 return true;
74 }
75 }
76
77 return false;
78}
79
80int handleImportAppliance(HandlerArg *a)
81{
82 HRESULT rc = S_OK;
83
84 Utf8Str strOvfFilename;
85 bool fExecute = true; // if true, then we actually do the import
86
87 uint32_t ulCurVsys = (uint32_t)-1;
88
89 // for each -vsys X command, maintain a map of command line items
90 // (we'll parse them later after interpreting the OVF, when we can
91 // actually check whether they make sense semantically)
92 ArgsMapsMap mapArgsMapsPerVsys;
93 IgnoresMapsMap mapIgnoresMapsPerVsys;
94
95 for (int i = 0;
96 i < a->argc;
97 ++i)
98 {
99 bool fIsIgnore = false;
100 Utf8Str strThisArg(a->argv[i]);
101 if ( (strThisArg == "--dry-run")
102 || (strThisArg == "-dry-run")
103 || (strThisArg == "-n")
104 )
105 fExecute = false;
106 else if (strThisArg == "--detailed-progress")
107 g_fDetailedProgress = true;
108 else if (strThisArg == "-vsys")
109 {
110 if (++i < a->argc)
111 {
112 uint32_t ulVsys;
113 if (VINF_SUCCESS != (rc = Utf8Str(a->argv[i]).toInt(ulVsys))) // don't use SUCCESS() macro, fail even on warnings
114 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Argument to -vsys option must be a non-negative number.");
115
116 ulCurVsys = ulVsys;
117 }
118 else
119 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Missing argument to -vsys option.");
120 }
121 else if ( (strThisArg == "-ostype")
122 || (strThisArg == "-vmname")
123 || (strThisArg == "-memory")
124 || (strThisArg == "-eula")
125 || (fIsIgnore = (strThisArg == "-ignore"))
126 || (strThisArg.substr(0, 5) == "-type")
127 || (strThisArg.substr(0, 11) == "-controller")
128 )
129 {
130 if (ulCurVsys == (uint32_t)-1)
131 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding -vsys argument.", strThisArg.c_str());
132
133 if (++i < a->argc)
134 if (fIsIgnore)
135 {
136 uint32_t ulItem;
137 if (VINF_SUCCESS != Utf8Str(a->argv[i]).toInt(ulItem))
138 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Argument to -vsys option must be a non-negative number.");
139
140 mapIgnoresMapsPerVsys[ulCurVsys][ulItem] = true;
141 }
142 else
143 {
144 // store both this arg and the next one in the strings map for later parsing
145 mapArgsMapsPerVsys[ulCurVsys][strThisArg] = Utf8Str(a->argv[i]);
146 }
147 else
148 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Missing argument to \"%s\" option.", strThisArg.c_str());
149 }
150 else if (strThisArg[0] == '-')
151 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Unknown option \"%s\".", strThisArg.c_str());
152 else if (!strOvfFilename)
153 strOvfFilename = strThisArg;
154 else
155 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Too many arguments for \"import\" command.");
156 }
157
158 if (!strOvfFilename)
159 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Not enough arguments for \"import\" command.");
160
161 do
162 {
163 Bstr bstrOvfFilename(strOvfFilename);
164 ComPtr<IAppliance> pAppliance;
165 CHECK_ERROR_BREAK(a->virtualBox, CreateAppliance(pAppliance.asOutParam()));
166
167 CHECK_ERROR_BREAK(pAppliance, Read(bstrOvfFilename));
168
169 // call interpret(); this can yield both warnings and errors, so we need
170 // to tinker with the error info a bit
171 RTPrintf("Interpreting %s...\n", strOvfFilename.c_str());
172 rc = pAppliance->Interpret();
173 com::ErrorInfo info0(pAppliance);
174
175 com::SafeArray<BSTR> aWarnings;
176 if (SUCCEEDED(pAppliance->GetWarnings(ComSafeArrayAsOutParam(aWarnings))))
177 {
178 size_t cWarnings = aWarnings.size();
179 for (unsigned i = 0; i < cWarnings; ++i)
180 {
181 Bstr bstrWarning(aWarnings[i]);
182 RTPrintf("WARNING: %ls.\n", bstrWarning.raw());
183 }
184 }
185
186 if (FAILED(rc)) // during interpret, after printing warnings
187 {
188 com::GluePrintErrorInfo(info0);
189 com::GluePrintErrorContext("Interpret", __FILE__, __LINE__);
190 break;
191 }
192
193 RTPrintf("OK.\n");
194
195 // fetch all disks
196 com::SafeArray<BSTR> retDisks;
197 CHECK_ERROR_BREAK(pAppliance,
198 COMGETTER(Disks)(ComSafeArrayAsOutParam(retDisks)));
199 if (retDisks.size() > 0)
200 {
201 RTPrintf("Disks:");
202 for (unsigned i = 0; i < retDisks.size(); i++)
203 RTPrintf(" %ls", retDisks[i]);
204 RTPrintf("\n");
205 }
206
207 // fetch virtual system descriptions
208 com::SafeIfaceArray<IVirtualSystemDescription> aVirtualSystemDescriptions;
209 CHECK_ERROR_BREAK(pAppliance,
210 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(aVirtualSystemDescriptions)));
211
212 size_t cVirtualSystemDescriptions = aVirtualSystemDescriptions.size();
213
214 // match command line arguments with virtual system descriptions;
215 // this is only to sort out invalid indices at this time
216 ArgsMapsMap::const_iterator it;
217 for (it = mapArgsMapsPerVsys.begin();
218 it != mapArgsMapsPerVsys.end();
219 ++it)
220 {
221 uint32_t ulVsys = it->first;
222 if (ulVsys >= cVirtualSystemDescriptions)
223 return errorSyntax(USAGE_IMPORTAPPLIANCE,
224 "Invalid index %RI32 with -vsys option; the OVF contains only %zu virtual system(s).",
225 ulVsys, cVirtualSystemDescriptions);
226 }
227
228 uint32_t cLicensesInTheWay = 0;
229
230 // dump virtual system descriptions and match command-line arguments
231 if (cVirtualSystemDescriptions > 0)
232 {
233 for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
234 {
235 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
236 com::SafeArray<BSTR> aRefs;
237 com::SafeArray<BSTR> aOvfValues;
238 com::SafeArray<BSTR> aVboxValues;
239 com::SafeArray<BSTR> aExtraConfigValues;
240 CHECK_ERROR_BREAK(aVirtualSystemDescriptions[i],
241 GetDescription(ComSafeArrayAsOutParam(retTypes),
242 ComSafeArrayAsOutParam(aRefs),
243 ComSafeArrayAsOutParam(aOvfValues),
244 ComSafeArrayAsOutParam(aVboxValues),
245 ComSafeArrayAsOutParam(aExtraConfigValues)));
246
247 RTPrintf("Virtual system %i:\n", i);
248
249 // look up the corresponding command line options, if any
250 ArgsMap *pmapArgs = NULL;
251 ArgsMapsMap::iterator itm = mapArgsMapsPerVsys.find(i);
252 if (itm != mapArgsMapsPerVsys.end())
253 pmapArgs = &itm->second;
254
255 // this collects the final values for setFinalValues()
256 com::SafeArray<BOOL> aEnabled(retTypes.size());
257 com::SafeArray<BSTR> aFinalValues(retTypes.size());
258
259 for (unsigned a = 0; a < retTypes.size(); ++a)
260 {
261 VirtualSystemDescriptionType_T t = retTypes[a];
262
263 Utf8Str strOverride;
264
265 Bstr bstrFinalValue = aVboxValues[a];
266
267 bool fIgnoreThis = mapIgnoresMapsPerVsys[i][a];
268
269 aEnabled[a] = true;
270
271 switch (t)
272 {
273 case VirtualSystemDescriptionType_Name:
274 if (findArgValue(strOverride, pmapArgs, "-vmname"))
275 {
276 bstrFinalValue = strOverride;
277 RTPrintf("%2d: VM name specified with -vmname: \"%ls\"\n",
278 a, bstrFinalValue.raw());
279 }
280 else
281 RTPrintf("%2d: Suggested VM name \"%ls\""
282 "\n (change with \"-vsys %d -vmname <name>\")\n",
283 a, bstrFinalValue.raw(), i);
284 break;
285
286 case VirtualSystemDescriptionType_OS:
287 if (findArgValue(strOverride, pmapArgs, "-ostype"))
288 {
289 bstrFinalValue = strOverride;
290 RTPrintf("%2d: OS type specified with -ostype: \"%ls\"\n",
291 a, bstrFinalValue.raw());
292 }
293 else
294 RTPrintf("%2d: Suggested OS type: \"%ls\""
295 "\n (change with \"-vsys %d -ostype <type>\"; use \"list ostypes\" to list all)\n",
296 a, bstrFinalValue.raw(), i);
297 break;
298
299 case VirtualSystemDescriptionType_Description:
300 RTPrintf("%2d: Description: \"%ls\"\n",
301 a, bstrFinalValue.raw());
302 break;
303
304 case VirtualSystemDescriptionType_License:
305 ++cLicensesInTheWay;
306 if (findArgValue(strOverride, pmapArgs, "-eula"))
307 {
308 if (strOverride == "show")
309 {
310 RTPrintf("%2d: End-user license agreement"
311 "\n (accept with \"-vsys %d -eula accept\"):"
312 "\n\n%ls\n\n",
313 a, i, bstrFinalValue.raw());
314 }
315 else if (strOverride == "accept")
316 {
317 RTPrintf("%2d: End-user license agreement (accepted)\n",
318 a);
319 --cLicensesInTheWay;
320 }
321 else
322 return errorSyntax(USAGE_IMPORTAPPLIANCE,
323 "Argument to -eula must be either \"show\" or \"accept\".");
324 }
325 else
326 RTPrintf("%2d: End-user license agreement"
327 "\n (display with \"-vsys %d -eula show\";"
328 "\n accept with \"-vsys %d -eula accept\")\n",
329 a, i, i);
330 break;
331
332 case VirtualSystemDescriptionType_CPU:
333 RTPrintf("%2d: Number of CPUs (ignored): %ls\n",
334 a, aVboxValues[a]);
335 break;
336
337 case VirtualSystemDescriptionType_Memory:
338 {
339 if (findArgValue(strOverride, pmapArgs, "-memory"))
340 {
341 uint32_t ulMemMB;
342 if (VINF_SUCCESS == strOverride.toInt(ulMemMB))
343 {
344 bstrFinalValue = strOverride;
345 RTPrintf("%2d: Guest memory specified with -memory: %ls MB\n",
346 a, bstrFinalValue.raw());
347 }
348 else
349 return errorSyntax(USAGE_IMPORTAPPLIANCE,
350 "Argument to -memory option must be a non-negative number.");
351 }
352 else
353 RTPrintf("%2d: Guest memory: %ls MB\n (change with \"-vsys %d -memory <MB>\")\n",
354 a, bstrFinalValue.raw(), i);
355 }
356 break;
357
358 case VirtualSystemDescriptionType_HardDiskControllerIDE:
359 if (fIgnoreThis)
360 {
361 RTPrintf("%2d: IDE controller, type %ls -- disabled\n",
362 a,
363 aVboxValues[a]);
364 aEnabled[a] = false;
365 }
366 else
367 RTPrintf("%2d: IDE controller, type %ls"
368 "\n (disable with \"-vsys %d -ignore %d\")\n",
369 a,
370 aVboxValues[a],
371 i, a);
372 break;
373
374 case VirtualSystemDescriptionType_HardDiskControllerSATA:
375 if (fIgnoreThis)
376 {
377 RTPrintf("%2d: SATA controller, type %ls -- disabled\n",
378 a,
379 aVboxValues[a]);
380 aEnabled[a] = false;
381 }
382 else
383 RTPrintf("%2d: SATA controller, type %ls"
384 "\n (disable with \"-vsys %d -ignore %d\")\n",
385 a,
386 aVboxValues[a],
387 i, a);
388 break;
389
390 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
391 if (fIgnoreThis)
392 {
393 RTPrintf("%2d: SCSI controller, type %ls -- disabled\n",
394 a,
395 aVboxValues[a]);
396 aEnabled[a] = false;
397 }
398 else
399 {
400 Utf8StrFmt strTypeArg("-type%RI16", a);
401 if (findArgValue(strOverride, pmapArgs, strTypeArg))
402 {
403 bstrFinalValue = strOverride;
404 RTPrintf("%2d: SCSI controller, type set with -type%d: %ls\n",
405 a,
406 a,
407 bstrFinalValue.raw());
408 }
409 else
410 RTPrintf("%2d: SCSI controller, type %ls"
411 "\n (change with \"-vsys %d -type%d {BusLogic|LsiLogic}\";"
412 "\n disable with \"-vsys %d -ignore %d\")\n",
413 a,
414 aVboxValues[a],
415 i, a, i, a);
416 }
417 break;
418
419 case VirtualSystemDescriptionType_HardDiskImage:
420 if (fIgnoreThis)
421 {
422 RTPrintf("%2d: Hard disk image: source image=%ls -- disabled\n",
423 a,
424 aOvfValues[a]);
425 aEnabled[a] = false;
426 }
427 else
428 {
429 Utf8StrFmt strTypeArg("-controller%RI16", a);
430 if (findArgValue(strOverride, pmapArgs, strTypeArg))
431 {
432 // strOverride now has the controller index as a number, but we
433 // need a "controller=X" format string
434 strOverride = Utf8StrFmt("controller=%s", strOverride.c_str());
435 Bstr bstrExtraConfigValue = strOverride;
436 bstrExtraConfigValue.detachTo(&aExtraConfigValues[a]);
437 RTPrintf("%2d: Hard disk image: source image=%ls, target path=%ls, %ls\n",
438 a,
439 aOvfValues[a],
440 aVboxValues[a],
441 aExtraConfigValues[a]);
442 }
443 else
444 RTPrintf("%2d: Hard disk image: source image=%ls, target path=%ls, %ls"
445 "\n (change controller with \"-vsys %d -controller%d <id>\";"
446 "\n disable with \"-vsys %d -ignore %d\")\n",
447 a,
448 aOvfValues[a],
449 aVboxValues[a],
450 aExtraConfigValues[a],
451 i, a, i, a);
452 }
453 break;
454
455 case VirtualSystemDescriptionType_CDROM:
456 if (fIgnoreThis)
457 {
458 RTPrintf("%2d: CD-ROM -- disabled\n",
459 a);
460 aEnabled[a] = false;
461 }
462 else
463 RTPrintf("%2d: CD-ROM"
464 "\n (disable with \"-vsys %d -ignore %d\")\n",
465 a, i, a);
466 break;
467
468 case VirtualSystemDescriptionType_Floppy:
469 if (fIgnoreThis)
470 {
471 RTPrintf("%2d: Floppy -- disabled\n",
472 a);
473 aEnabled[a] = false;
474 }
475 else
476 RTPrintf("%2d: Floppy"
477 "\n (disable with \"-vsys %d -ignore %d\")\n",
478 a, i, a);
479 break;
480
481 case VirtualSystemDescriptionType_NetworkAdapter:
482 RTPrintf("%2d: Network adapter: orig %ls, config %ls, extra %ls\n", // @todo implement once we have a plan for the back-end
483 a,
484 aOvfValues[a],
485 aVboxValues[a],
486 aExtraConfigValues[a]);
487 break;
488
489 case VirtualSystemDescriptionType_USBController:
490 if (fIgnoreThis)
491 {
492 RTPrintf("%2d: USB controller -- disabled\n",
493 a);
494 aEnabled[a] = false;
495 }
496 else
497 RTPrintf("%2d: USB controller"
498 "\n (disable with \"-vsys %d -ignore %d\")\n",
499 a, i, a);
500 break;
501
502 case VirtualSystemDescriptionType_SoundCard:
503 if (fIgnoreThis)
504 {
505 RTPrintf("%2d: Sound card \"%ls\" -- disabled\n",
506 a,
507 aOvfValues[a]);
508 aEnabled[a] = false;
509 }
510 else
511 RTPrintf("%2d: Sound card (appliance expects \"%ls\", can change on import)"
512 "\n (disable with \"-vsys %d -ignore %d\")\n",
513 a,
514 aOvfValues[a],
515 i,
516 a);
517 break;
518 }
519
520 bstrFinalValue.detachTo(&aFinalValues[a]);
521 }
522
523 if (fExecute)
524 CHECK_ERROR_BREAK(aVirtualSystemDescriptions[i],
525 SetFinalValues(ComSafeArrayAsInParam(aEnabled),
526 ComSafeArrayAsInParam(aFinalValues),
527 ComSafeArrayAsInParam(aExtraConfigValues)));
528
529 } // for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
530
531 if (cLicensesInTheWay == 1)
532 RTPrintf("ERROR: Cannot import until the license agreement listed above is accepted.\n");
533 else if (cLicensesInTheWay > 1)
534 RTPrintf("ERROR: Cannot import until the %c license agreements listed above are accepted.\n", cLicensesInTheWay);
535
536 if (!cLicensesInTheWay && fExecute)
537 {
538 // go!
539 ComPtr<IProgress> progress;
540 CHECK_ERROR_BREAK(pAppliance,
541 ImportMachines(progress.asOutParam()));
542
543 showProgress(progress);
544
545 if (SUCCEEDED(rc))
546 progress->COMGETTER(ResultCode)(&rc);
547
548 if (FAILED(rc))
549 {
550 com::ProgressErrorInfo info(progress);
551 com::GluePrintErrorInfo(info);
552 com::GluePrintErrorContext("ImportAppliance", __FILE__, __LINE__);
553 }
554 else
555 RTPrintf("Successfully imported the appliance.\n");
556 }
557 } // end if (aVirtualSystemDescriptions.size() > 0)
558 } while (0);
559
560 return SUCCEEDED(rc) ? 0 : 1;
561}
562
563static const RTGETOPTDEF g_aExportOptions[]
564 = {
565 { "--output", 'o', RTGETOPT_REQ_STRING },
566 };
567
568int handleExportAppliance(HandlerArg *a)
569{
570 HRESULT rc = S_OK;
571
572 Utf8Str strOutputFile;
573 std::list< ComPtr<IMachine> > llMachines;
574
575 do
576 {
577 int c;
578
579 RTGETOPTUNION ValueUnion;
580 RTGETOPTSTATE GetState;
581 // start at 0 because main() has hacked both the argc and argv given to us
582 RTGetOptInit(&GetState, a->argc, a->argv, g_aExportOptions,
583 RT_ELEMENTS(g_aExportOptions), 0, 0 /* fFlags */);
584 while ((c = RTGetOpt(&GetState, &ValueUnion)))
585 {
586 switch (c)
587 {
588 case 'o': // --output
589 if (strOutputFile.length())
590 return errorSyntax(USAGE_EXPORTAPPLIANCE, "You can only specify --output once.");
591 else
592 strOutputFile = ValueUnion.psz;
593 break;
594
595 case VINF_GETOPT_NOT_OPTION:
596 {
597 Utf8Str strMachine(ValueUnion.psz);
598 // must be machine: try UUID or name
599 ComPtr<IMachine> machine;
600 /* assume it's a UUID */
601 rc = a->virtualBox->GetMachine(Guid(strMachine), machine.asOutParam());
602 if (FAILED(rc) || !machine)
603 {
604 /* must be a name */
605 CHECK_ERROR_BREAK(a->virtualBox, FindMachine(Bstr(strMachine), machine.asOutParam()));
606 }
607
608 if (machine)
609 llMachines.push_back(machine);
610 }
611 break;
612
613 default:
614 if (c > 0)
615 {
616 if (RT_C_IS_GRAPH(c))
617 return errorSyntax(USAGE_EXPORTAPPLIANCE, "unhandled option: -%c", c);
618 else
619 return errorSyntax(USAGE_EXPORTAPPLIANCE, "unhandled option: %i", c);
620 }
621 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
622 return errorSyntax(USAGE_EXPORTAPPLIANCE, "unknown option: %s", ValueUnion.psz);
623 else if (ValueUnion.pDef)
624 return errorSyntax(USAGE_EXPORTAPPLIANCE, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
625 else
626 return errorSyntax(USAGE_EXPORTAPPLIANCE, "%Rrs", c);
627 }
628
629 if (FAILED(rc))
630 break;
631 }
632
633 if (FAILED(rc))
634 break;
635
636 if (llMachines.size() == 0)
637 return errorSyntax(USAGE_EXPORTAPPLIANCE, "At least one machine must be specified with the export command.");
638 if (!strOutputFile.length())
639 return errorSyntax(USAGE_EXPORTAPPLIANCE, "Missing --output argument with export command.");
640
641 ComPtr<IAppliance> pAppliance;
642 CHECK_ERROR_BREAK(a->virtualBox, CreateAppliance(pAppliance.asOutParam()));
643
644 std::list< ComPtr<IMachine> >::iterator itM;
645 for (itM = llMachines.begin();
646 itM != llMachines.end();
647 ++itM)
648 {
649 ComPtr<IMachine> pMachine = *itM;
650 ComPtr<IVirtualSystemDescription> pVSD;
651 CHECK_ERROR_BREAK(pMachine, Export(pAppliance, pVSD.asOutParam()));
652 }
653
654 if (FAILED(rc))
655 break;
656
657 ComPtr<IProgress> progress;
658 CHECK_ERROR_BREAK(pAppliance, Write(Bstr("ovf-0.9"), Bstr(strOutputFile), progress.asOutParam()));
659
660 showProgress(progress);
661
662 if (SUCCEEDED(rc))
663 progress->COMGETTER(ResultCode)(&rc);
664
665 if (FAILED(rc))
666 {
667 com::ProgressErrorInfo info(progress);
668 com::GluePrintErrorInfo(info);
669 com::GluePrintErrorContext("Write", __FILE__, __LINE__);
670 }
671 else
672 RTPrintf("Successfully exported %d machine(s).\n", llMachines.size());
673
674 } while (0);
675
676 return SUCCEEDED(rc) ? 0 : 1;
677}
678
679#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette