VirtualBox

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

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

OVF: vboxmanage export fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
1/* $Id: VBoxManageImport.cpp 17074 2009-02-24 15:00:32Z 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
44#include <VBox/log.h>
45
46#include "VBoxManage.h"
47using namespace com;
48
49
50// funcs
51///////////////////////////////////////////////////////////////////////////////
52
53typedef std::map<Utf8Str, Utf8Str> ArgsMap; // pairs of strings like "-vmname" => "newvmname"
54typedef std::map<uint32_t, ArgsMap> ArgsMapsMap; // map of maps, one for each virtual system, sorted by index
55
56typedef std::map<uint32_t, bool> IgnoresMap; // pairs of numeric description entry indices
57typedef std::map<uint32_t, IgnoresMap> IgnoresMapsMap; // map of maps, one for each virtual system, sorted by index
58
59static bool findArgValue(Utf8Str &strOut,
60 ArgsMap *pmapArgs,
61 const Utf8Str &strKey)
62{
63 if (pmapArgs)
64 {
65 ArgsMap::iterator it;
66 it = pmapArgs->find(strKey);
67 if (it != pmapArgs->end())
68 {
69 strOut = it->second;
70 pmapArgs->erase(it);
71 return true;
72 }
73 }
74
75 return false;
76}
77
78int handleImportAppliance(HandlerArg *a)
79{
80 HRESULT rc = S_OK;
81
82 Utf8Str strOvfFilename;
83 bool fExecute = true; // if true, then we actually do the import
84
85 uint32_t ulCurVsys = (uint32_t)-1;
86
87 // for each -vsys X command, maintain a map of command line items
88 // (we'll parse them later after interpreting the OVF, when we can
89 // actually check whether they make sense semantically)
90 ArgsMapsMap mapArgsMapsPerVsys;
91 IgnoresMapsMap mapIgnoresMapsPerVsys;
92
93 for (int i = 0;
94 i < a->argc;
95 ++i)
96 {
97 bool fIsIgnore = false;
98 Utf8Str strThisArg(a->argv[i]);
99 if ( (strThisArg == "--dry-run")
100 || (strThisArg == "-dry-run")
101 || (strThisArg == "-n")
102 )
103 fExecute = false;
104 else if (strThisArg == "-vsys")
105 {
106 if (++i < a->argc)
107 {
108 uint32_t ulVsys;
109 if (VINF_SUCCESS != (rc = Utf8Str(a->argv[i]).toInt(ulVsys))) // don't use SUCCESS() macro, fail even on warnings
110 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Argument to -vsys option must be a non-negative number.");
111
112 ulCurVsys = ulVsys;
113 }
114 else
115 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Missing argument to -vsys option.");
116 }
117 else if ( (strThisArg == "-ostype")
118 || (strThisArg == "-vmname")
119 || (strThisArg == "-memory")
120 || (fIsIgnore = (strThisArg == "-ignore"))
121 || (strThisArg.substr(0, 5) == "-type")
122 || (strThisArg.substr(0, 11) == "-controller")
123 )
124 {
125 if (ulCurVsys == (uint32_t)-1)
126 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding -vsys argument.", strThisArg.c_str());
127
128 if (++i < a->argc)
129 if (fIsIgnore)
130 {
131 uint32_t ulItem;
132 if (VINF_SUCCESS != Utf8Str(a->argv[i]).toInt(ulItem))
133 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Argument to -vsys option must be a non-negative number.");
134
135 mapIgnoresMapsPerVsys[ulCurVsys][ulItem] = true;
136 }
137 else
138 {
139 // store both this arg and the next one in the strings map for later parsing
140 mapArgsMapsPerVsys[ulCurVsys][strThisArg] = Utf8Str(a->argv[i]);
141 }
142 else
143 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Missing argument to \"%s\" option.", strThisArg.c_str());
144 }
145 else if (strThisArg[0] == '-')
146 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Unknown option \"%s\".", strThisArg.c_str());
147 else if (!strOvfFilename)
148 strOvfFilename = strThisArg;
149 else
150 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Too many arguments for \"import\" command.");
151 }
152
153 if (!strOvfFilename)
154 return errorSyntax(USAGE_IMPORTAPPLIANCE, "Not enough arguments for \"import\" command.");
155
156 do
157 {
158 Bstr bstrOvfFilename(strOvfFilename);
159 ComPtr<IAppliance> pAppliance;
160 CHECK_ERROR_BREAK(a->virtualBox, CreateAppliance(pAppliance.asOutParam()));
161
162 CHECK_ERROR_BREAK(pAppliance, Read(bstrOvfFilename));
163
164 RTPrintf("Interpreting %s... ", strOvfFilename.c_str());
165 CHECK_ERROR_BREAK(pAppliance, Interpret());
166 RTPrintf("OK.\n");
167
168 // fetch all disks
169 com::SafeArray<BSTR> retDisks;
170 CHECK_ERROR_BREAK(pAppliance,
171 COMGETTER(Disks)(ComSafeArrayAsOutParam(retDisks)));
172 if (retDisks.size() > 0)
173 {
174 RTPrintf("Disks:");
175 for (unsigned i = 0; i < retDisks.size(); i++)
176 RTPrintf(" %ls", retDisks[i]);
177 RTPrintf("\n");
178 }
179
180 // fetch virtual system descriptions
181 com::SafeIfaceArray<IVirtualSystemDescription> aVirtualSystemDescriptions;
182 CHECK_ERROR_BREAK(pAppliance,
183 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(aVirtualSystemDescriptions)));
184
185 uint32_t cVirtualSystemDescriptions = aVirtualSystemDescriptions.size();
186
187 // match command line arguments with virtual system descriptions;
188 // this is only to sort out invalid indices at this time
189 ArgsMapsMap::const_iterator it;
190 for (it = mapArgsMapsPerVsys.begin();
191 it != mapArgsMapsPerVsys.end();
192 ++it)
193 {
194 uint32_t ulVsys = it->first;
195 if (ulVsys >= cVirtualSystemDescriptions)
196 return errorSyntax(USAGE_IMPORTAPPLIANCE,
197 "Invalid index %RI32 with -vsys option; the OVF contains only %RI32 virtual system(s).",
198 ulVsys, cVirtualSystemDescriptions);
199 }
200
201 // dump virtual system descriptions and match command-line arguments
202 if (cVirtualSystemDescriptions > 0)
203 {
204 for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
205 {
206 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
207 com::SafeArray<BSTR> aRefs;
208 com::SafeArray<BSTR> aOrigValues;
209 com::SafeArray<BSTR> aConfigValues;
210 com::SafeArray<BSTR> aExtraConfigValues;
211 CHECK_ERROR_BREAK(aVirtualSystemDescriptions[i],
212 GetDescription(ComSafeArrayAsOutParam(retTypes),
213 ComSafeArrayAsOutParam(aRefs),
214 ComSafeArrayAsOutParam(aOrigValues),
215 ComSafeArrayAsOutParam(aConfigValues),
216 ComSafeArrayAsOutParam(aExtraConfigValues)));
217
218 RTPrintf("Virtual system %i:\n", i);
219
220 // look up the corresponding command line options, if any
221 ArgsMap *pmapArgs = NULL;
222 ArgsMapsMap::iterator itm = mapArgsMapsPerVsys.find(i);
223 if (itm != mapArgsMapsPerVsys.end())
224 pmapArgs = &itm->second;
225
226 // this collects the final values for setFinalValues()
227 com::SafeArray<BOOL> aEnabled(retTypes.size());
228 com::SafeArray<BSTR> aFinalValues(retTypes.size());
229
230 for (unsigned a = 0; a < retTypes.size(); ++a)
231 {
232 VirtualSystemDescriptionType_T t = retTypes[a];
233
234 Utf8Str strOverride;
235
236 Bstr bstrFinalValue = aConfigValues[a];
237
238 bool fIgnoreThis = mapIgnoresMapsPerVsys[i][a];
239
240 aEnabled[a] = true;
241
242 switch (t)
243 {
244 case VirtualSystemDescriptionType_Name:
245 if (findArgValue(strOverride, pmapArgs, "-vmname"))
246 {
247 bstrFinalValue = strOverride;
248 RTPrintf("%2d: VM name specified with -vmname: \"%ls\"\n",
249 a, bstrFinalValue.raw());
250 }
251 else
252 RTPrintf("%2d: Suggested VM name \"%ls\""
253 "\n (change with \"-vsys %d -vmname <name>\")\n",
254 a, bstrFinalValue.raw(), i);
255 break;
256
257 case VirtualSystemDescriptionType_OS:
258 if (findArgValue(strOverride, pmapArgs, "-ostype"))
259 {
260 bstrFinalValue = strOverride;
261 RTPrintf("%2d: OS type specified with -ostype: \"%ls\"\n",
262 a, bstrFinalValue.raw());
263 }
264 else
265 RTPrintf("%2d: Suggested OS type: \"%ls\""
266 "\n (change with \"-vsys %d -ostype <type>\"; use \"list ostypes\" to list all)\n",
267 a, bstrFinalValue.raw(), i);
268 break;
269
270 case VirtualSystemDescriptionType_CPU:
271 RTPrintf("%2d: Number of CPUs (ignored): %ls\n",
272 a, aConfigValues[a]);
273 break;
274
275 case VirtualSystemDescriptionType_Memory:
276 {
277 if (findArgValue(strOverride, pmapArgs, "-memory"))
278 {
279 uint32_t ulMemMB;
280 if (VINF_SUCCESS == strOverride.toInt(ulMemMB))
281 {
282 bstrFinalValue = strOverride;
283 RTPrintf("%2d: Guest memory specified with -memory: %ls MB\n",
284 a, bstrFinalValue.raw());
285 }
286 else
287 return errorSyntax(USAGE_IMPORTAPPLIANCE,
288 "Argument to -memory option must be a non-negative number.");
289 }
290 else
291 RTPrintf("%2d: Guest memory: %ls MB\n (change with \"-vsys %d -memory <MB>\")\n",
292 a, bstrFinalValue.raw(), i);
293 }
294 break;
295
296 case VirtualSystemDescriptionType_HardDiskControllerIDE:
297 if (fIgnoreThis)
298 {
299 RTPrintf("%2d: IDE controller, type %ls -- disabled\n",
300 a,
301 aConfigValues[a]);
302 aEnabled[a] = false;
303 }
304 else
305 RTPrintf("%2d: IDE controller, type %ls"
306 "\n (disable with \"-vsys %d -ignore %d\")\n",
307 a,
308 aConfigValues[a],
309 i, a);
310 break;
311
312 case VirtualSystemDescriptionType_HardDiskControllerSATA:
313 if (fIgnoreThis)
314 {
315 RTPrintf("%2d: SATA controller, type %ls -- disabled\n",
316 a,
317 aConfigValues[a]);
318 aEnabled[a] = false;
319 }
320 else
321 RTPrintf("%2d: SATA controller, type %ls"
322 "\n (disable with \"-vsys %d -ignore %d\")\n",
323 a,
324 aConfigValues[a],
325 i, a);
326 break;
327
328 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
329 if (fIgnoreThis)
330 {
331 RTPrintf("%2d: SCSI controller, type %ls -- disabled\n",
332 a,
333 aConfigValues[a]);
334 aEnabled[a] = false;
335 }
336 else
337 {
338 Utf8StrFmt strTypeArg("-type%RI16", a);
339 if (findArgValue(strOverride, pmapArgs, strTypeArg))
340 {
341 bstrFinalValue = strOverride;
342 RTPrintf("%2d: SCSI controller, type set with -type%d: %ls\n",
343 a,
344 a,
345 bstrFinalValue.raw());
346 }
347 else
348 RTPrintf("%2d: SCSI controller, type %ls"
349 "\n (change with \"-vsys %d -type%d {BusLogic|LsiLogic}\";"
350 "\n disable with \"-vsys %d -ignore %d\")\n",
351 a,
352 aConfigValues[a],
353 i, a, i, a);
354 }
355 break;
356
357 case VirtualSystemDescriptionType_HardDiskImage:
358 if (fIgnoreThis)
359 {
360 RTPrintf("%2d: Hard disk image: source image=%ls -- disabled\n",
361 a,
362 aOrigValues[a]);
363 aEnabled[a] = false;
364 }
365 else
366 {
367 Utf8StrFmt strTypeArg("-controller%RI16", a);
368 if (findArgValue(strOverride, pmapArgs, strTypeArg))
369 {
370 // strOverride now has the controller index as a number, but we
371 // need a "controller=X" format string
372 strOverride = Utf8StrFmt("controller=%s", strOverride.c_str());
373 Bstr bstrExtraConfigValue = strOverride;
374 bstrExtraConfigValue.detachTo(&aExtraConfigValues[a]);
375 RTPrintf("%2d: Hard disk image: source image=%ls, target path=%ls, %ls\n",
376 a,
377 aOrigValues[a],
378 aConfigValues[a],
379 aExtraConfigValues[a]);
380 }
381 else
382 RTPrintf("%2d: Hard disk image: source image=%ls, target path=%ls, %ls"
383 "\n (change controller with \"-vsys %d -controller%d <id>\";"
384 "\n disable with \"-vsys %d -ignore %d\")\n",
385 a,
386 aOrigValues[a],
387 aConfigValues[a],
388 aExtraConfigValues[a],
389 i, a, i, a);
390 }
391 break;
392
393 case VirtualSystemDescriptionType_CDROM:
394 if (fIgnoreThis)
395 {
396 RTPrintf("%2d: CD-ROM -- disabled\n",
397 a);
398 aEnabled[a] = false;
399 }
400 else
401 RTPrintf("%2d: CD-ROM"
402 "\n (disable with \"-vsys %d -ignore %d\")\n",
403 a, i, a);
404 break;
405
406 case VirtualSystemDescriptionType_Floppy:
407 if (fIgnoreThis)
408 {
409 RTPrintf("%2d: Floppy -- disabled\n",
410 a);
411 aEnabled[a] = false;
412 }
413 else
414 RTPrintf("%2d: Floppy"
415 "\n (disable with \"-vsys %d -ignore %d\")\n",
416 a, i, a);
417 break;
418
419 case VirtualSystemDescriptionType_NetworkAdapter:
420 RTPrintf("%2d: Network adapter: orig %ls, config %ls, extra %ls\n", // @todo implement once we have a plan for the back-end
421 a,
422 aOrigValues[a],
423 aConfigValues[a],
424 aExtraConfigValues[a]);
425 break;
426
427 case VirtualSystemDescriptionType_USBController:
428 if (fIgnoreThis)
429 {
430 RTPrintf("%2d: USB controller -- disabled\n",
431 a);
432 aEnabled[a] = false;
433 }
434 else
435 RTPrintf("%2d: USB controller"
436 "\n (disable with \"-vsys %d -ignore %d\")\n",
437 a, i, a);
438 break;
439
440 case VirtualSystemDescriptionType_SoundCard:
441 if (fIgnoreThis)
442 {
443 RTPrintf("%2d: Sound card \"%ls\" -- disabled\n",
444 a,
445 aOrigValues[a]);
446 aEnabled[a] = false;
447 }
448 else
449 RTPrintf("%2d: Sound card (appliance expects \"%ls\", can change on import)"
450 "\n (disable with \"-vsys %d -ignore %d\")\n",
451 a,
452 aOrigValues[a],
453 i,
454 a);
455 break;
456 }
457
458 bstrFinalValue.detachTo(&aFinalValues[a]);
459 }
460
461 if (fExecute)
462 CHECK_ERROR_BREAK(aVirtualSystemDescriptions[i],
463 SetFinalValues(ComSafeArrayAsInParam(aEnabled),
464 ComSafeArrayAsInParam(aFinalValues),
465 ComSafeArrayAsInParam(aExtraConfigValues)));
466
467 } // for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
468
469 if (fExecute)
470 {
471 ComPtr<IProgress> progress;
472 CHECK_ERROR_BREAK(pAppliance,
473 ImportMachines(progress.asOutParam()));
474
475 showProgress(progress);
476
477 if (SUCCEEDED(rc))
478 progress->COMGETTER(ResultCode)(&rc);
479
480 if (FAILED(rc))
481 {
482 com::ProgressErrorInfo info(progress);
483 com::GluePrintErrorInfo(info);
484 com::GluePrintErrorContext("ImportAppliance", __FILE__, __LINE__);
485 }
486 else
487 RTPrintf("Successfully imported the appliance.\n");
488 }
489 } // end if (aVirtualSystemDescriptions.size() > 0)
490 } while (0);
491
492 return SUCCEEDED(rc) ? 0 : 1;
493}
494
495int handleExportAppliance(HandlerArg *a)
496{
497 HRESULT rc = S_OK;
498
499 Utf8Str strOutputFile;
500 std::list< ComPtr<IMachine> > llMachines;
501
502 do
503 {
504 for (int i = 0;
505 i < a->argc;
506 ++i)
507 {
508 Utf8Str strThisArg(a->argv[i]);
509
510 if ( strThisArg == "--output"
511 || strThisArg == "-output"
512 || strThisArg == "-o"
513 )
514 {
515 if (++i < a->argc)
516 {
517 if (strOutputFile.length())
518 return errorSyntax(USAGE_EXPORTAPPLIANCE, "You can only specify --output once.");
519 else
520 strOutputFile = strThisArg;
521 }
522 else
523 return errorSyntax(USAGE_EXPORTAPPLIANCE, "Missing argument to --output option.");
524 }
525 else
526 {
527 // must be machine: try UUID or name
528 ComPtr<IMachine> machine;
529 /* assume it's a UUID */
530 rc = a->virtualBox->GetMachine(Guid(strThisArg), machine.asOutParam());
531 if (FAILED(rc) || !machine)
532 {
533 /* must be a name */
534 CHECK_ERROR_BREAK(a->virtualBox, FindMachine(Bstr(strThisArg), machine.asOutParam()));
535 }
536
537 if (machine)
538 llMachines.push_back(machine);
539 }
540 }
541
542 if (FAILED(rc))
543 break;
544
545 if (llMachines.size() == 0)
546 return errorSyntax(USAGE_EXPORTAPPLIANCE, "Missing arguments to export command.");
547
548 ComPtr<IAppliance> pAppliance;
549 CHECK_ERROR_BREAK(a->virtualBox, CreateAppliance(pAppliance.asOutParam()));
550
551 std::list< ComPtr<IMachine> >::iterator itM;
552 for (itM = llMachines.begin();
553 itM != llMachines.end();
554 ++itM)
555 {
556 ComPtr<IMachine> pMachine = *itM;
557 CHECK_ERROR_BREAK(pMachine, Export(pAppliance));
558 }
559
560 if (FAILED(rc))
561 break;
562
563 CHECK_ERROR_BREAK(pAppliance, Write(Bstr(strOutputFile)));
564
565 } while (0);
566
567 return SUCCEEDED(rc) ? 0 : 1;
568}
569
570#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

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