VBoxManageDisk.cpp revision 51fb8ccc0277c4647c6133d228525431bc1a1a61
/* $Id$ */
/** @file
* VBoxManage - The disk delated commands.
*/
/*
* Copyright (C) 2006-2010 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 *
*******************************************************************************/
#include "VBoxManage.h"
using namespace com;
// funcs
///////////////////////////////////////////////////////////////////////////////
static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
{
RTPrintf("ERROR: ");
RTPrintf("\n");
}
{
int rc = VINF_SUCCESS;
unsigned DiskVariant = (unsigned)(*pDiskVariant);
{
if (pszComma)
else
if (len > 0)
{
// Parsing is intentionally inconsistent: "standard" resets the
// variant, whereas the other flags are cumulative.
else
}
if (pszComma)
else
}
if (RT_SUCCESS(rc))
return rc;
}
{
int rc = VINF_SUCCESS;
else
if (RT_SUCCESS(rc))
return rc;
}
/** @todo move this into getopt, as getting bool values is generic */
{
int rc = VINF_SUCCESS;
{
*pb = true;
}
{
*pb = false;
}
else
return rc;
}
static const RTGETOPTDEF g_aCreateHardDiskOptions[] =
{
};
int handleCreateHardDisk(HandlerArg *a)
{
int vrc;
bool fRemember = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateHardDiskOptions, RT_ELEMENTS(g_aCreateHardDiskOptions),
{
switch (c)
{
case 'f': // --filename
break;
case 's': // --size
break;
case 'o': // --format
break;
case 'F': // --static ("fixed"/"flat")
{
unsigned uDiskVariant = (unsigned)DiskVariant;
break;
}
case 'm': // --variant
if (RT_FAILURE(vrc))
break;
case 'c': // --comment
break;
case 'r': // --remember
fRemember = true;
break;
case 't': // --type
if ( RT_FAILURE(vrc)
|| ( DiskType != MediumType_Normal
&& DiskType != MediumType_Shareable))
break;
case VINF_GETOPT_NOT_OPTION:
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
/* check the outcome */
if ( !filename
|| sizeMB == 0)
/* check for filename extension */
{
else
}
{
/* we will close the hard disk after the storage has been successfully
* created unless fRemember is set */
bool doClose = false;
{
}
{
{
if (info.isBasicAvailable())
else
RTPrintf("Error: failed to create hard disk. No error message available!\n");
}
else
{
if (DiskType == MediumType_Writethrough)
{
}
}
}
if (doClose)
{
}
}
}
#if 0 /* disabled until disk shrinking is implemented based on VBoxHDD */
{
{
RTPrintf(".");
}
return VINF_SUCCESS;
}
#endif
static const RTGETOPTDEF g_aModifyHardDiskOptions[] =
{
};
int handleModifyHardDisk(HandlerArg *a)
{
int vrc;
bool AutoReset = false;
const char *FilenameOrUuid = NULL;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyHardDiskOptions, RT_ELEMENTS(g_aModifyHardDiskOptions),
{
switch (c)
{
case 't': // --type
if (RT_FAILURE(vrc))
fModifyDiskType = true;
break;
case 'z': // --autoreset
if (RT_FAILURE(vrc))
fModifyAutoReset = true;
break;
case 'c': // --compact
fModifyCompact = true;
break;
case VINF_GETOPT_NOT_OPTION:
if (!FilenameOrUuid)
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 (!FilenameOrUuid)
/* first guess is that it's a UUID */
/* no? then it must be a filename */
if (!hardDisk)
{
return 1;
}
if (fModifyDiskType)
{
/* hard disk must be registered */
{
}
else
return errorArgument("Hard disk image not registered");
}
if (fModifyAutoReset)
{
}
if (fModifyCompact)
{
bool unknown = false;
/* the hard disk image might not be registered */
if (!hardDisk)
{
unknown = true;
rc = a->virtualBox->OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam());
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam()));
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam()));
}
{
{
{
RTPrintf("Error: Compact hard disk operation is not implemented!\n");
RTPrintf("The functionality will be restored later.\n");
}
else if (rc == VBOX_E_NOT_SUPPORTED)
{
RTPrintf("Error: Compact hard disk operation for this format is not implemented yet!\n");
}
else
}
if (unknown)
}
}
}
static const RTGETOPTDEF g_aCloneHardDiskOptions[] =
{
};
int handleCloneHardDisk(HandlerArg *a)
{
int vrc;
bool fExisting = false;
bool fRemember = false;
bool fSetDiskType = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions),
{
switch (c)
{
case 'o': // --format
break;
case 'F': // --static
{
unsigned uDiskVariant = (unsigned)DiskVariant;
break;
}
case 'E': // --existing
fExisting = true;
break;
case 'm': // --variant
if (RT_FAILURE(vrc))
break;
case 'r': // --remember
fRemember = true;
break;
case 't': // --type
if (RT_FAILURE(vrc))
fSetDiskType = true;
break;
case VINF_GETOPT_NOT_OPTION:
else
break;
default:
if (c > 0)
{
if (RT_C_IS_GRAPH(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
bool fSrcUnknown = false;
bool fDstUnknown = false;
/* first guess is that it's a UUID */
/* no? then it must be a filename */
/* no? well, then it's an unknown image */
{
rc = a->virtualBox->OpenHardDisk(src, AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), srcDisk.asOutParam());
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), srcDisk.asOutParam()));
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), srcDisk.asOutParam()));
fSrcUnknown = true;
}
do
{
break;
if (fExisting)
{
/* first guess is that it's a UUID */
/* no? then it must be a filename */
/* no? well, then it's an unknown image */
{
rc = a->virtualBox->OpenHardDisk(dst, AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), dstDisk.asOutParam());
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
CHECK_ERROR_BREAK(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), dstDisk.asOutParam()));
}
CHECK_ERROR_BREAK(a->virtualBox, OpenHardDisk(dst, AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), dstDisk.asOutParam()));
fDstUnknown = true;
}
else
fRemember = true;
{
/* Perform accessibility check now. */
}
}
else
{
/* use the format of the source hard disk if unspecified */
}
{
if (info.isBasicAvailable())
else
RTPrintf("Error: failed to clone hard disk. No error message available!\n");
break;
}
RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
}
while (0);
{
/* forget the created clone */
}
else if (fSetDiskType)
{
}
if (fSrcUnknown)
{
/* close the unknown hard disk to forget it again */
}
}
static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
{
};
{
int rc = VINF_SUCCESS;
bool fReadFromStdIn = false;
const char *format = "VDI";
const char *srcfilename = NULL;
const char *dstfilename = NULL;
unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions),
{
switch (c)
{
case 'o': // --format
break;
case 'm': // --variant
if (RT_FAILURE(rc))
/// @todo cleaner solution than assuming 1:1 mapping?
uImageFlags = (unsigned)DiskVariant;
break;
case VINF_GETOPT_NOT_OPTION:
if (!srcfilename)
{
#endif
}
else if (!dstfilename)
else if (fReadFromStdIn && !filesize)
else
break;
default:
}
}
RTPrintf("Converting from raw image file=\"%s\" to file=\"%s\"...\n",
/* open raw image file. */
if (fReadFromStdIn)
File = 0;
else
if (RT_FAILURE(rc))
{
goto out;
}
/* get image size. */
if (fReadFromStdIn)
else
if (RT_FAILURE(rc))
{
goto out;
}
RTPrintf("Creating %s image with size %RU64 bytes (%RU64MB)...\n", (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
char pszComment[256];
if (RT_FAILURE(rc))
{
goto out;
}
LCHS.cCylinders = 0;
if (RT_FAILURE(rc))
{
goto out;
}
if (!pvBuf)
{
rc = VERR_NO_MEMORY;
goto out;
}
offFile = 0;
{
cbRead = 0;
break;
if (RT_FAILURE(rc))
{
goto out;
}
}
out:
if (pvBuf)
if (pDisk)
if (File != NIL_RTFILE)
return RT_FAILURE(rc);
}
static const RTGETOPTDEF g_aAddiSCSIDiskOptions[] =
{
};
int handleAddiSCSIDisk(HandlerArg *a)
{
int vrc;
bool fIntNet = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aAddiSCSIDiskOptions, RT_ELEMENTS(g_aAddiSCSIDiskOptions),
{
switch (c)
{
case 's': // --server
break;
case 'T': // --target
break;
case 'p': // --port
break;
case 'l': // --lun
break;
case 'L': // --encodedlun
break;
case 'u': // --username
break;
case 'P': // --password
break;
case 't': // --type
if (RT_FAILURE(vrc))
break;
case 'I': // --intnet
fIntNet = true;
break;
case VINF_GETOPT_NOT_OPTION:
default:
if (c > 0)
{
if (RT_C_IS_PRINT(c))
else
}
else if (c == VERR_GETOPT_UNKNOWN_OPTION)
else if (ValueUnion.pDef)
else
}
}
/* check for required options */
do
{
/** @todo move the location stuff to Main, which can use pfnComposeName
* from the disk backends to construct the location properly. Also do
* not use slashes to separate the parts, as otherwise only the last
* element comtaining information will be shown. */
{
hardDisk.asOutParam()));
}
else
{
hardDisk.asOutParam()));
}
{
}
{
}
{
}
/// @todo add --initiator option - until that happens rely on the
// defaults of the iSCSI initiator code. Setting it to a constant
// value does more harm than good, as the initiator name is supposed
// to identify a particular initiator uniquely.
// Bstr ("InitiatorName").detachTo (names.appendedRaw());
// Bstr ("iqn.2008-04.com.sun.virtualbox.initiator").detachTo (values.appendedRaw());
/// @todo add --targetName and --targetPassword options
if (fIntNet)
{
}
if (DiskType != MediumType_Normal)
{
}
}
while (0);
}
static const RTGETOPTDEF g_aShowHardDiskInfoOptions[] =
{
};
int handleShowHardDiskInfo(HandlerArg *a)
{
const char *FilenameOrUuid = NULL;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aShowHardDiskInfoOptions, RT_ELEMENTS(g_aShowHardDiskInfoOptions),
{
switch (c)
{
case VINF_GETOPT_NOT_OPTION:
if (!FilenameOrUuid)
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
}
}
/* check for required options */
if (!FilenameOrUuid)
bool unknown = false;
/* first guess is that it's a UUID */
/* no? then it must be a filename */
{
/* no? well, then it's an unkwnown image */
{
rc = a->virtualBox->OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam());
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(vrc))
{
return 1;
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam()));
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, false, Bstr(""), false, Bstr(""), hardDisk.asOutParam()));
{
unknown = true;
}
}
}
do
{
break;
/* check for accessibility */
/// @todo NEWMEDIA check accessibility of all parents
/// @todo NEWMEDIA print the full state value
if (state == MediumState_Inaccessible)
{
}
if (description)
{
}
const char *typeStr = "unknown";
switch (type)
{
case MediumType_Normal:
typeStr = "normal (differencing)";
else
typeStr = "normal (base)";
break;
case MediumType_Immutable:
typeStr = "immutable";
break;
case MediumType_Writethrough:
typeStr = "writethrough";
break;
case MediumType_Shareable:
typeStr = "shareable";
break;
}
if (!unknown)
{
{
RTPrintf("%s%lS (UUID: %lS)\n",
j == 0 ? "In use by VMs: " : " ",
}
/// @todo NEWMEDIA check usage in snapshots too
/// @todo NEWMEDIA also list children
}
/* print out information specific for differencing hard disks */
{
}
}
while (0);
if (unknown)
{
/* close the unknown hard disk to forget it again */
}
}
static const RTGETOPTDEF g_aOpenMediumOptions[] =
{
};
int handleOpenMedium(HandlerArg *a)
{
int vrc;
enum {
bool fDiskType = false;
bool fSetImageId = false;
bool fSetParentId = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
{
switch (c)
{
case 'd': // disk
break;
case 'D': // DVD
break;
case 'f': // floppy
cmd = CMD_FLOPPY;
break;
case 't': // --type
if (RT_FAILURE(vrc))
fDiskType = true;
break;
case 'u': // --uuid
fSetImageId = true;
break;
case 'p': // --parentuuid
fSetParentId = true;
break;
case VINF_GETOPT_NOT_OPTION:
if (!Filename)
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
}
}
/* check for required options */
if (!Filename)
/** @todo remove this hack!
* First try opening the image as is (using the regular API semantics for
* images with relative path or without path), and if that fails with a
* file related error then try it again with what the client thinks the
* relative path would mean. Requires doing the command twice in certain
* cases. This is an ugly hack and needs to be removed whevever we have a
* chance to clean up the API semantics. */
{
rc = a->virtualBox->OpenHardDisk(Bstr(Filename), AccessMode_ReadWrite, fSetImageId, ImageIdStr, fSetParentId, ParentIdStr, hardDisk.asOutParam());
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, fSetImageId, ImageIdStr, fSetParentId, ParentIdStr, hardDisk.asOutParam()));
}
CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(Filename), AccessMode_ReadWrite, fSetImageId, ImageIdStr, fSetParentId, ParentIdStr, hardDisk.asOutParam()));
{
/* change the type if requested */
if (DiskType != MediumType_Normal)
{
}
}
}
{
if (fDiskType || fSetParentId)
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
}
}
else if (cmd == CMD_FLOPPY)
{
if (rc == VBOX_E_FILE_ERROR)
{
if (RT_FAILURE(irc))
{
return 1;
}
CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(szFilenameAbs), ImageIdStr, floppyImage.asOutParam()));
}
}
}
static const RTGETOPTDEF g_aCloseMediumOptions[] =
{
};
int handleCloseMedium(HandlerArg *a)
{
enum {
const char *FilenameOrUuid = NULL;
bool fDelete = false;
int c;
// start at 0 because main() has hacked both the argc and argv given to us
RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions),
{
switch (c)
{
case 'd': // disk
break;
case 'D': // DVD
break;
case 'f': // floppy
cmd = CMD_FLOPPY;
break;
case 'r': // --delete
fDelete = true;
break;
case VINF_GETOPT_NOT_OPTION:
if (!FilenameOrUuid)
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
}
}
/* check for required options */
if (!FilenameOrUuid)
/* first guess is that it's a UUID */
{
/* not a UUID or not registered? Then it must be a filename */
if (!medium)
{
}
}
else
{
/* not a UUID or not registered? Then it must be a filename */
if (!medium)
{
}
}
else
if (cmd == CMD_FLOPPY)
{
/* not a UUID or not registered? Then it must be a filename */
if (!medium)
{
}
}
{
if (fDelete)
{
{
{
if (info.isBasicAvailable())
else
RTPrintf("Error: failed to delete medium. No error message available!\n");
}
}
else
}
}
}
#endif /* !VBOX_ONLY_DOCS */