VBoxManageAppliance.cpp revision 53f00ea4ead24f9c67605be59dbc0067a810415d
/* $Id$ */
/** @file
* VBoxManage - The appliance-related commands.
*/
/*
* Copyright (C) 2009-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef VBOX_ONLY_DOCS
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifndef VBOX_ONLY_DOCS
#include <list>
#include <map>
#endif /* !VBOX_ONLY_DOCS */
#include "VBoxManage.h"
using namespace com;
// funcs
///////////////////////////////////////////////////////////////////////////////
typedef std::map<uint32_t, ArgsMap> ArgsMapsMap; // map of maps, one for each virtual system, sorted by index
typedef std::map<uint32_t, IgnoresMap> IgnoresMapsMap; // map of maps, one for each virtual system, sorted by index
{
if (pmapArgs)
{
{
return true;
}
}
return false;
}
{
int rc = VINF_SUCCESS;
{
if (pszComma)
else
if (len > 0)
{
else
}
if (pszComma)
else
}
return rc;
}
static const RTGETOPTDEF g_aImportApplianceOptions[] =
{
#if 0 /* Changing the controller is fully valid, but the current design on how
the params are evaluated here doesn't allow two parameter for one
unit. The target disk path is more important. I leave it for future
improvments. */
#endif
};
{
bool fExecute = true; // if true, then we actually do the import
// for each --vsys X command, maintain a map of command line items
// (we'll parse them later after interpreting the OVF, when we can
// actually check whether they make sense semantically)
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, arg->argc, arg->argv, g_aImportApplianceOptions, RT_ELEMENTS(g_aImportApplianceOptions),
{
switch (c)
{
case 'n': // --dry-run
fExecute = false;
break;
case 'P': // --detailed-progress
g_fDetailedProgress = true;
break;
case 's': // --vsys
break;
case 'o': // --ostype
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'V': // --vmname
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'd': // --description
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'L': // --eula
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'm': // --memory
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'c': // --cpus
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'u': // --unit
break;
case 'x': // --ignore
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --unit argument.", GetState.pDef->pszLong);
break;
case 'T': // --scsitype
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --unit argument.", GetState.pDef->pszLong);
break;
case 'C': // --controller
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --unit argument.", GetState.pDef->pszLong);
break;
case 'D': // --disk
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
return errorSyntax(USAGE_IMPORTAPPLIANCE, "Option \"%s\" requires preceding --unit argument.", GetState.pDef->pszLong);
break;
case 'O': // --options
break;
case VINF_GETOPT_NOT_OPTION:
if (strOvfFilename.isEmpty())
else
break;
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
if (strOvfFilename.isEmpty())
do
{
char *pszAbsFilePath;
else
progressRead.asOutParam()));
// call interpret(); this can yield both warnings and errors, so we need
// to tinker with the error info a bit
{
for (unsigned i = 0; i < cWarnings; ++i)
{
}
}
{
break;
}
// fetch all disks
{
RTPrintf("Disks:\n");
RTPrintf("\n");
}
// fetch virtual system descriptions
// match command line arguments with virtual system descriptions;
// this is only to sort out invalid indices at this time
++it)
{
if (ulVsys >= cVirtualSystemDescriptions)
return errorSyntax(USAGE_IMPORTAPPLIANCE,
"Invalid index %RI32 with -vsys option; the OVF contains only %zu virtual system(s).",
}
// dump virtual system descriptions and match command-line arguments
if (cVirtualSystemDescriptions > 0)
{
for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
{
RTPrintf("Virtual system %u:\n", i);
// look up the corresponding command line options, if any
// this collects the final values for setFinalValues()
{
bool fIgnoreThis = mapIgnoresMapsPerVsys[i][a];
aEnabled[a] = true;
switch (t)
{
{
RTPrintf("%2u: OS type specified with --ostype: \"%ls\"\n",
a, bstrFinalValue.raw());
}
else
RTPrintf("%2u: Suggested OS type: \"%ls\""
"\n (change with \"--vsys %u --ostype <type>\"; use \"list ostypes\" to list all possible values)\n",
a, bstrFinalValue.raw(), i);
break;
{
RTPrintf("%2u: VM name specified with --vmname: \"%ls\"\n",
a, bstrFinalValue.raw());
}
else
RTPrintf("%2u: Suggested VM name \"%ls\""
"\n (change with \"--vsys %u --vmname <name>\")\n",
a, bstrFinalValue.raw(), i);
break;
RTPrintf("%2u: Product (ignored): %ls\n",
a, aVBoxValues[a]);
break;
RTPrintf("%2u: ProductUrl (ignored): %ls\n",
a, aVBoxValues[a]);
break;
RTPrintf("%2u: Vendor (ignored): %ls\n",
a, aVBoxValues[a]);
break;
RTPrintf("%2u: VendorUrl (ignored): %ls\n",
a, aVBoxValues[a]);
break;
RTPrintf("%2u: Version (ignored): %ls\n",
a, aVBoxValues[a]);
break;
{
RTPrintf("%2u: Description specified with --description: \"%ls\"\n",
a, bstrFinalValue.raw());
}
else
RTPrintf("%2u: Description \"%ls\""
"\n (change with \"--vsys %u --description <desc>\")\n",
a, bstrFinalValue.raw(), i);
break;
{
if (strOverride == "show")
{
RTPrintf("%2u: End-user license agreement"
"\n (accept with \"--vsys %u --eula accept\"):"
"\n\n%ls\n\n",
a, i, bstrFinalValue.raw());
}
else if (strOverride == "accept")
{
RTPrintf("%2u: End-user license agreement (accepted)\n",
a);
}
else
return errorSyntax(USAGE_IMPORTAPPLIANCE,
"Argument to --eula must be either \"show\" or \"accept\".");
}
else
RTPrintf("%2u: End-user license agreement"
"\n (display with \"--vsys %u --eula show\";"
"\n accept with \"--vsys %u --eula accept\")\n",
a, i, i);
break;
{
&& cCPUs >= VMM_MIN_CPU_COUNT
&& cCPUs <= VMM_MAX_CPU_COUNT
)
{
RTPrintf("%2u: No. of CPUs specified with --cpus: %ls\n",
a, bstrFinalValue.raw());
}
else
return errorSyntax(USAGE_IMPORTAPPLIANCE,
"Argument to --cpus option must be a number greater than %d and less than %d.",
}
else
RTPrintf("%2u: Number of CPUs: %ls\n (change with \"--vsys %u --cpus <n>\")\n",
a, bstrFinalValue.raw(), i);
break;
{
{
{
RTPrintf("%2u: Guest memory specified with --memory: %ls MB\n",
a, bstrFinalValue.raw());
}
else
return errorSyntax(USAGE_IMPORTAPPLIANCE,
"Argument to --memory option must be a non-negative number.");
}
else
RTPrintf("%2u: Guest memory: %ls MB\n (change with \"--vsys %u --memory <MB>\")\n",
a, bstrFinalValue.raw(), i);
}
break;
if (fIgnoreThis)
{
RTPrintf("%2u: IDE controller, type %ls -- disabled\n",
a,
aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: IDE controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aVBoxValues[a],
i, a);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: SATA controller, type %ls -- disabled\n",
a,
aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: SATA controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aVBoxValues[a],
i, a);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: SAS controller, type %ls -- disabled\n",
a,
aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: SAS controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aVBoxValues[a],
i, a);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: SCSI controller, type %ls -- disabled\n",
a,
aVBoxValues[a]);
aEnabled[a] = false;
}
else
{
{
RTPrintf("%2u: SCSI controller, type set with --unit %u --scsitype: \"%ls\"\n",
a,
a,
bstrFinalValue.raw());
}
else
RTPrintf("%2u: SCSI controller, type %ls"
"\n (change with \"--vsys %u --unit %u --scsitype {BusLogic|LsiLogic}\";"
"\n disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aVBoxValues[a],
i, a, i, a);
}
break;
if (fIgnoreThis)
{
RTPrintf("%2u: Hard disk image: source image=%ls -- disabled\n",
a,
aOvfValues[a]);
aEnabled[a] = false;
}
else
{
bstrFinalValue = aVBoxValues[a];
{
{
/* Check if this is a uuid. If so, don't touch. */
if (vrc != VINF_SUCCESS)
{
/* Make the path absolute. */
{
char pszPwd[RTPATH_MAX];
if (RT_SUCCESS(vrc))
}
}
}
else
{
//print some error about incompatible command-line arguments
return errorSyntax(USAGE_IMPORTAPPLIANCE,
"Option --ImportToVDI shall not be used together with "
"manually set target path.");
}
RTPrintf("%2u: Hard disk image: source image=%ls, target path=%ls, %ls\n",
a,
aOvfValues[a],
aExtraConfigValues[a]);
}
#if 0 /* Changing the controller is fully valid, but the current design on how
the params are evaluated here doesn't allow two parameter for one
unit. The target disk path is more important I leave it for future
improvments. */
{
// strOverride now has the controller index as a number, but we
// need a "controller=X" format string
RTPrintf("%2u: Hard disk image: source image=%ls, target path=%ls, %ls\n",
a,
aOvfValues[a],
aVBoxValues[a],
aExtraConfigValues[a]);
}
#endif
else
{
strOverride = aVBoxValues[a];
/*
* Current solution isn't optimal.
* Better way is to provide API call for function
* Appliance::i_findMediumFormatFromDiskImage()
* and creating one new function which returns
* struct ovf::DiskImage for currently processed disk.
*/
/*
* if user wants to convert all imported disks to VDI format
* we need to replace files extensions to "vdi"
*/
{
/* go through all supported media formats and store files extensions only for RAW */
for (unsigned i = 0; i < mediumFormats.size(); ++i)
{
{
/* getting files extensions for "RAW" format */
break;
}
}
/* go through files extensions for RAW format and compare them with
* extension of current file
*/
bool b_replace = true;
if (pszExtension)
pszExtension++;
for (unsigned i = 0; i < extensions.size(); ++i)
{
{
b_replace = false;
break;
}
}
if (b_replace==true)
{
}
}
RTPrintf("%2u: Hard disk image: source image=%ls, target path=%ls, %ls"
"\n (change target path with \"--vsys %u --unit %u --disk path\";"
"\n disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aOvfValues[a],
i, a, i, a);
}
}
break;
if (fIgnoreThis)
{
RTPrintf("%2u: CD-ROM -- disabled\n",
a);
aEnabled[a] = false;
}
else
RTPrintf("%2u: CD-ROM"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a, i, a);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: Floppy -- disabled\n",
a);
aEnabled[a] = false;
}
else
RTPrintf("%2u: Floppy"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a, i, a);
break;
RTPrintf("%2u: Network adapter: orig %ls, config %ls, extra %ls\n", // @todo implement once we have a plan for the back-end
a,
aOvfValues[a],
aVBoxValues[a],
aExtraConfigValues[a]);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: USB controller -- disabled\n",
a);
aEnabled[a] = false;
}
else
RTPrintf("%2u: USB controller"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a, i, a);
break;
if (fIgnoreThis)
{
RTPrintf("%2u: Sound card \"%ls\" -- disabled\n",
a,
aOvfValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: Sound card (appliance expects \"%ls\", can change on import)"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aOvfValues[a],
i,
a);
break;
}
}
if (fExecute)
} // for (unsigned i = 0; i < cVirtualSystemDescriptions; ++i)
if (cLicensesInTheWay == 1)
RTMsgError("Cannot import until the license agreement listed above is accepted.");
else if (cLicensesInTheWay > 1)
RTMsgError("Cannot import until the %c license agreements listed above are accepted.", cLicensesInTheWay);
if (!cLicensesInTheWay && fExecute)
{
// go!
RTPrintf("Successfully imported the appliance.\n");
}
} // end if (aVirtualSystemDescriptions.size() > 0)
} while (0);
}
{
int rc = VINF_SUCCESS;
{
if (pszComma)
else
if (len > 0)
{
else
}
if (pszComma)
else
}
return rc;
}
static const RTGETOPTDEF g_aExportOptions[] =
{
};
int handleExportAppliance(HandlerArg *a)
{
bool fManifest = false; // the default
bool fExportISOImages = false; // the default
// for each --vsys X command, maintain a map of command line items
do
{
int c;
// start at 0 because main() has hacked both the argc and argv given to us
{
switch (c)
{
case 'o': // --output
if (strOutputFile.length())
else
break;
case 'l': // --legacy09/--ovf09
strOvfFormat = "ovf-0.9";
break;
case '1': // --ovf10
strOvfFormat = "ovf-1.0";
break;
case '2': // --ovf20
strOvfFormat = "ovf-2.0";
break;
case 'I': // --iso
fExportISOImages = true;
break;
case 'm': // --manifest
fManifest = true;
break;
case 's': // --vsys
break;
case 'p': // --product
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'P': // --producturl
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'n': // --vendor
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'N': // --vendorurl
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'v': // --version
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'd': // --description
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'e': // --eula
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'E': // --eulafile
return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
break;
case 'O': // --options
break;
case VINF_GETOPT_NOT_OPTION:
{
// must be machine: try UUID or name
machine.asOutParam()));
if (machine)
break;
}
default:
if (c > 0)
{
if (RT_C_IS_GRAPH(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
break;
}
break;
if (llMachines.size() == 0)
return errorSyntax(USAGE_EXPORTAPPLIANCE, "At least one machine must be specified with the export command.");
if (!strOutputFile.length())
// match command line arguments with the machines count
// this is only to sort out invalid indices at this time
++it)
{
return errorSyntax(USAGE_EXPORTAPPLIANCE,
"Invalid index %RI32 with -vsys option; you specified only %zu virtual system(s).",
}
char *pszAbsFilePath = 0;
else
uint32_t i=0;
++itM, ++i)
{
// Add additional info to the virtual system description if the user wants so
if (pmapArgs)
{
++itD)
{
{
void *pvFile;
if (RT_SUCCESS(irc))
{
bstrContent.raw(),
bstrContent.raw());
}
else
{
RTMsgError("Cannot read license file \"%s\" which should be included in the virtual system %u.",
return 1;
}
}
}
}
}
break;
if (fManifest)
if (fExportISOImages)
progress.asOutParam()));
} while (0);
}
#endif /* !VBOX_ONLY_DOCS */