[23802] | 1 | /* $Id: VBoxManageStorageController.cpp 35241 2010-12-20 13:14:55Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * VBoxManage - The storage controller related commands.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[32718] | 7 | * Copyright (C) 2006-2010 Oracle Corporation
|
---|
[23802] | 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 |
|
---|
| 18 | #ifndef VBOX_ONLY_DOCS
|
---|
| 19 |
|
---|
| 20 | /*******************************************************************************
|
---|
| 21 | * Header Files *
|
---|
| 22 | *******************************************************************************/
|
---|
| 23 | #include <VBox/com/com.h>
|
---|
| 24 | #include <VBox/com/array.h>
|
---|
| 25 | #include <VBox/com/ErrorInfo.h>
|
---|
| 26 | #include <VBox/com/errorprint.h>
|
---|
| 27 | #include <VBox/com/VirtualBox.h>
|
---|
| 28 |
|
---|
| 29 | #include <iprt/path.h>
|
---|
| 30 | #include <iprt/param.h>
|
---|
| 31 | #include <iprt/string.h>
|
---|
| 32 | #include <iprt/ctype.h>
|
---|
| 33 | #include <iprt/stream.h>
|
---|
| 34 | #include <iprt/getopt.h>
|
---|
| 35 | #include <VBox/log.h>
|
---|
| 36 |
|
---|
| 37 | #include "VBoxManage.h"
|
---|
| 38 | using namespace com;
|
---|
| 39 |
|
---|
| 40 |
|
---|
| 41 | // funcs
|
---|
| 42 | ///////////////////////////////////////////////////////////////////////////////
|
---|
| 43 |
|
---|
| 44 |
|
---|
[23902] | 45 | static const RTGETOPTDEF g_aStorageAttachOptions[] =
|
---|
[23802] | 46 | {
|
---|
[34634] | 47 | { "--storagectl", 's', RTGETOPT_REQ_STRING },
|
---|
| 48 | { "--port", 'p', RTGETOPT_REQ_UINT32 },
|
---|
| 49 | { "--device", 'd', RTGETOPT_REQ_UINT32 },
|
---|
| 50 | { "--type", 't', RTGETOPT_REQ_STRING },
|
---|
| 51 | { "--medium", 'm', RTGETOPT_REQ_STRING },
|
---|
| 52 | { "--mtype", 'M', RTGETOPT_REQ_STRING },
|
---|
| 53 | { "--passthrough", 'h', RTGETOPT_REQ_STRING },
|
---|
| 54 | { "--bandwidthgroup", 'b', RTGETOPT_REQ_STRING },
|
---|
| 55 | { "--forceunmount", 'f', RTGETOPT_REQ_NOTHING },
|
---|
| 56 | { "--comment", 'C', RTGETOPT_REQ_STRING },
|
---|
| 57 | // iSCSI options
|
---|
| 58 | { "--server", 'S', RTGETOPT_REQ_STRING },
|
---|
| 59 | { "--target", 'T', RTGETOPT_REQ_STRING },
|
---|
| 60 | { "--port", 'P', RTGETOPT_REQ_STRING },
|
---|
| 61 | { "--lun", 'L', RTGETOPT_REQ_STRING },
|
---|
| 62 | { "--encodedlun", 'E', RTGETOPT_REQ_STRING },
|
---|
| 63 | { "--username", 'U', RTGETOPT_REQ_STRING },
|
---|
| 64 | { "--password", 'W', RTGETOPT_REQ_STRING },
|
---|
| 65 | { "--intnet", 'I', RTGETOPT_REQ_NOTHING },
|
---|
[23802] | 66 | };
|
---|
| 67 |
|
---|
[23902] | 68 | int handleStorageAttach(HandlerArg *a)
|
---|
[23802] | 69 | {
|
---|
[24678] | 70 | int c = VERR_INTERNAL_ERROR; /* initialized to shut up gcc */
|
---|
[23802] | 71 | HRESULT rc = S_OK;
|
---|
[23902] | 72 | ULONG port = ~0U;
|
---|
| 73 | ULONG device = ~0U;
|
---|
[24504] | 74 | bool fForceUnmount = false;
|
---|
[35136] | 75 | bool fSetMediumType = false;
|
---|
[34634] | 76 | MediumType_T mediumType = MediumType_Normal;
|
---|
| 77 | Bstr bstrComment;
|
---|
[23802] | 78 | const char *pszCtl = NULL;
|
---|
[34634] | 79 | DeviceType_T devTypeRequested = DeviceType_Null;
|
---|
[23902] | 80 | const char *pszMedium = NULL;
|
---|
| 81 | const char *pszPassThrough = NULL;
|
---|
[34587] | 82 | const char *pszBandwidthGroup = NULL;
|
---|
[34634] | 83 | // iSCSI options
|
---|
| 84 | Bstr bstrServer;
|
---|
| 85 | Bstr bstrTarget;
|
---|
| 86 | Bstr bstrPort;
|
---|
| 87 | Bstr bstrLun;
|
---|
| 88 | Bstr bstrUsername;
|
---|
| 89 | Bstr bstrPassword;
|
---|
| 90 | bool fIntNet = false;
|
---|
| 91 |
|
---|
[23802] | 92 | RTGETOPTUNION ValueUnion;
|
---|
| 93 | RTGETOPTSTATE GetState;
|
---|
| 94 | ComPtr<IMachine> machine;
|
---|
| 95 | ComPtr<IStorageController> storageCtl;
|
---|
[24346] | 96 | ComPtr<ISystemProperties> systemProperties;
|
---|
[23802] | 97 |
|
---|
[23934] | 98 | RTGetOptInit(&GetState, a->argc, a->argv, g_aStorageAttachOptions,
|
---|
[26517] | 99 | RT_ELEMENTS(g_aStorageAttachOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
|
---|
[23802] | 100 |
|
---|
| 101 | while ( SUCCEEDED(rc)
|
---|
| 102 | && (c = RTGetOpt(&GetState, &ValueUnion)))
|
---|
| 103 | {
|
---|
| 104 | switch (c)
|
---|
| 105 | {
|
---|
[23902] | 106 | case 's': // storage controller name
|
---|
[23802] | 107 | {
|
---|
| 108 | if (ValueUnion.psz)
|
---|
[23902] | 109 | pszCtl = ValueUnion.psz;
|
---|
[23802] | 110 | else
|
---|
| 111 | rc = E_FAIL;
|
---|
| 112 | break;
|
---|
| 113 | }
|
---|
| 114 |
|
---|
[23902] | 115 | case 'p': // port
|
---|
[23802] | 116 | {
|
---|
[23902] | 117 | port = ValueUnion.u32;
|
---|
[23802] | 118 | break;
|
---|
| 119 | }
|
---|
| 120 |
|
---|
[23902] | 121 | case 'd': // device
|
---|
[23802] | 122 | {
|
---|
[23902] | 123 | device = ValueUnion.u32;
|
---|
| 124 | break;
|
---|
| 125 | }
|
---|
| 126 |
|
---|
[34634] | 127 | case 'm': // medium <none|emptydrive|uuid|filename|host:<drive>|iSCSI>
|
---|
[23902] | 128 | {
|
---|
[23802] | 129 | if (ValueUnion.psz)
|
---|
[23902] | 130 | pszMedium = ValueUnion.psz;
|
---|
[23802] | 131 | else
|
---|
| 132 | rc = E_FAIL;
|
---|
| 133 | break;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
[23902] | 136 | case 't': // type <dvddrive|hdd|fdd>
|
---|
[23802] | 137 | {
|
---|
[23902] | 138 | if (ValueUnion.psz)
|
---|
[34634] | 139 | {
|
---|
| 140 | if (!RTStrICmp(ValueUnion.psz, "hdd"))
|
---|
| 141 | devTypeRequested = DeviceType_HardDisk;
|
---|
| 142 | else if (!RTStrICmp(ValueUnion.psz, "fdd"))
|
---|
| 143 | devTypeRequested = DeviceType_Floppy;
|
---|
| 144 | else if (!RTStrICmp(ValueUnion.psz, "dvddrive"))
|
---|
| 145 | devTypeRequested = DeviceType_DVD;
|
---|
| 146 | else
|
---|
| 147 | return errorArgument("Invalid --type argument '%s'", ValueUnion.psz);
|
---|
| 148 | }
|
---|
[23902] | 149 | else
|
---|
| 150 | rc = E_FAIL;
|
---|
[23802] | 151 | break;
|
---|
| 152 | }
|
---|
| 153 |
|
---|
[23902] | 154 | case 'h': // passthrough <on|off>
|
---|
[23802] | 155 | {
|
---|
[23902] | 156 | if (ValueUnion.psz)
|
---|
| 157 | pszPassThrough = ValueUnion.psz;
|
---|
| 158 | else
|
---|
| 159 | rc = E_FAIL;
|
---|
[23802] | 160 | break;
|
---|
| 161 | }
|
---|
| 162 |
|
---|
[34587] | 163 | case 'b': // bandwidthgroup <name>
|
---|
| 164 | {
|
---|
| 165 | if (ValueUnion.psz)
|
---|
| 166 | pszBandwidthGroup = ValueUnion.psz;
|
---|
| 167 | else
|
---|
| 168 | rc = E_FAIL;
|
---|
| 169 | break;
|
---|
| 170 | }
|
---|
| 171 |
|
---|
[24505] | 172 | case 'f': // force unmount medium during runtime
|
---|
[24504] | 173 | {
|
---|
[24505] | 174 | fForceUnmount = true;
|
---|
[24504] | 175 | break;
|
---|
| 176 | }
|
---|
| 177 |
|
---|
[34634] | 178 | case 'C':
|
---|
| 179 | if (ValueUnion.psz)
|
---|
| 180 | bstrComment = ValueUnion.psz;
|
---|
| 181 | else
|
---|
| 182 | rc = E_FAIL;
|
---|
| 183 | break;
|
---|
| 184 |
|
---|
| 185 | case 'S': // --server
|
---|
| 186 | bstrServer = ValueUnion.psz;
|
---|
| 187 | break;
|
---|
| 188 |
|
---|
| 189 | case 'T': // --target
|
---|
| 190 | bstrTarget = ValueUnion.psz;
|
---|
| 191 | break;
|
---|
| 192 |
|
---|
| 193 | case 'P': // --port
|
---|
| 194 | bstrPort = ValueUnion.psz;
|
---|
| 195 | break;
|
---|
| 196 |
|
---|
| 197 | case 'L': // --lun
|
---|
| 198 | bstrLun = ValueUnion.psz;
|
---|
| 199 | break;
|
---|
| 200 |
|
---|
| 201 | case 'E': // --encodedlun
|
---|
| 202 | bstrLun = BstrFmt("enc%s", ValueUnion.psz);
|
---|
| 203 | break;
|
---|
| 204 |
|
---|
| 205 | case 'U': // --username
|
---|
| 206 | bstrUsername = ValueUnion.psz;
|
---|
| 207 | break;
|
---|
| 208 |
|
---|
| 209 | case 'W': // --password
|
---|
| 210 | bstrPassword = ValueUnion.psz;
|
---|
| 211 | break;
|
---|
| 212 |
|
---|
| 213 | case 'M': // --type
|
---|
| 214 | {
|
---|
| 215 | int vrc = parseDiskType(ValueUnion.psz, &mediumType);
|
---|
| 216 | if (RT_FAILURE(vrc))
|
---|
| 217 | return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
|
---|
[35136] | 218 | fSetMediumType = true;
|
---|
[34634] | 219 | break;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | case 'I': // --intnet
|
---|
| 223 | fIntNet = true;
|
---|
| 224 | break;
|
---|
| 225 |
|
---|
[23802] | 226 | default:
|
---|
| 227 | {
|
---|
[23902] | 228 | errorGetOpt(USAGE_STORAGEATTACH, c, &ValueUnion);
|
---|
[23802] | 229 | rc = E_FAIL;
|
---|
| 230 | break;
|
---|
| 231 | }
|
---|
| 232 | }
|
---|
| 233 | }
|
---|
[31008] | 234 |
|
---|
[30125] | 235 | if (FAILED(rc))
|
---|
[23802] | 236 | return 1;
|
---|
| 237 |
|
---|
[30125] | 238 | if (!pszCtl)
|
---|
| 239 | return errorSyntax(USAGE_STORAGEATTACH, "Storage controller name not specified");
|
---|
| 240 | if (port == ~0U)
|
---|
| 241 | return errorSyntax(USAGE_STORAGEATTACH, "Port not specified");
|
---|
| 242 | if (device == ~0U)
|
---|
| 243 | return errorSyntax(USAGE_STORAGEATTACH, "Device not specified");
|
---|
| 244 |
|
---|
[24346] | 245 | /* get the virtualbox system properties */
|
---|
| 246 | CHECK_ERROR_RET(a->virtualBox, COMGETTER(SystemProperties)(systemProperties.asOutParam()), 1);
|
---|
| 247 |
|
---|
[34634] | 248 | // find the machine, lock it, get the mutable session machine
|
---|
[33294] | 249 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
|
---|
| 250 | machine.asOutParam()), 1);
|
---|
[31019] | 251 | CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
|
---|
| 252 | SessionType_T st;
|
---|
| 253 | CHECK_ERROR_RET(a->session, COMGETTER(Type)(&st), 1);
|
---|
[23802] | 254 | a->session->COMGETTER(Machine)(machine.asOutParam());
|
---|
| 255 |
|
---|
[34634] | 256 | try
|
---|
[23902] | 257 | {
|
---|
[34634] | 258 | bool fRunTime = (st == SessionType_Shared);
|
---|
[23902] | 259 | if (fRunTime)
|
---|
[23802] | 260 | {
|
---|
[34634] | 261 | if (devTypeRequested == DeviceType_HardDisk)
|
---|
| 262 | throw Utf8Str("Hard disk drives cannot be changed while the VM is running\n");
|
---|
| 263 | else if (!RTStrICmp(pszMedium, "none"))
|
---|
| 264 | throw Utf8Str("Drives cannot be removed while the VM is running\n");
|
---|
| 265 | else if (pszPassThrough)
|
---|
| 266 | throw Utf8Str("Drive passthrough state cannot be changed while the VM is running\n");
|
---|
| 267 | else if (pszBandwidthGroup)
|
---|
| 268 | throw Utf8Str("Bandwidth group cannot be changed while the VM is running\n");
|
---|
| 269 | }
|
---|
[23902] | 270 |
|
---|
[34634] | 271 | /* check if the storage controller is present */
|
---|
| 272 | rc = machine->GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 273 | storageCtl.asOutParam());
|
---|
| 274 | if (FAILED(rc))
|
---|
| 275 | throw Utf8StrFmt("Could not find a controller named '%s'\n", pszCtl);
|
---|
[24504] | 276 |
|
---|
[34634] | 277 | /* for sata controller check if the port count is big enough
|
---|
| 278 | * to accommodate the current port which is being assigned
|
---|
| 279 | * else just increase the port count
|
---|
| 280 | */
|
---|
[23802] | 281 | {
|
---|
[34634] | 282 | ULONG ulPortCount = 0;
|
---|
| 283 | ULONG ulMaxPortCount = 0;
|
---|
[23902] | 284 |
|
---|
[34634] | 285 | CHECK_ERROR(storageCtl, COMGETTER(MaxPortCount)(&ulMaxPortCount));
|
---|
| 286 | CHECK_ERROR(storageCtl, COMGETTER(PortCount)(&ulPortCount));
|
---|
[23902] | 287 |
|
---|
[34634] | 288 | if ( (ulPortCount != ulMaxPortCount)
|
---|
| 289 | && (port >= ulPortCount)
|
---|
| 290 | && (port < ulMaxPortCount))
|
---|
| 291 | CHECK_ERROR(storageCtl, COMSETTER(PortCount)(port + 1));
|
---|
| 292 | }
|
---|
[24346] | 293 |
|
---|
[34634] | 294 | StorageControllerType_T ctlType = StorageControllerType_Null;
|
---|
| 295 | CHECK_ERROR(storageCtl, COMGETTER(ControllerType)(&ctlType));
|
---|
[23902] | 296 |
|
---|
[34634] | 297 | if (!RTStrICmp(pszMedium, "none"))
|
---|
| 298 | {
|
---|
| 299 | CHECK_ERROR(machine, DetachDevice(Bstr(pszCtl).raw(), port, device));
|
---|
[23902] | 300 | }
|
---|
[34634] | 301 | else if (!RTStrICmp(pszMedium, "emptydrive"))
|
---|
[23963] | 302 | {
|
---|
[34634] | 303 | if (fRunTime)
|
---|
[23963] | 304 | {
|
---|
[34634] | 305 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 306 | DeviceType_T deviceType = DeviceType_Null;
|
---|
| 307 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device,
|
---|
| 308 | mediumAttachment.asOutParam());
|
---|
[23963] | 309 | if (SUCCEEDED(rc))
|
---|
| 310 | {
|
---|
[34634] | 311 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
[23963] | 312 |
|
---|
[34634] | 313 | if ( (deviceType == DeviceType_DVD)
|
---|
| 314 | || (deviceType == DeviceType_Floppy))
|
---|
[23963] | 315 | {
|
---|
[34634] | 316 | /* just unmount the floppy/dvd */
|
---|
| 317 | CHECK_ERROR(machine, MountMedium(Bstr(pszCtl).raw(),
|
---|
| 318 | port,
|
---|
| 319 | device,
|
---|
| 320 | NULL,
|
---|
| 321 | fForceUnmount));
|
---|
[23963] | 322 | }
|
---|
| 323 | }
|
---|
| 324 |
|
---|
[34634] | 325 | if ( FAILED(rc)
|
---|
| 326 | || !( deviceType == DeviceType_DVD
|
---|
| 327 | || deviceType == DeviceType_Floppy)
|
---|
| 328 | )
|
---|
| 329 | throw Utf8StrFmt("No DVD/Floppy Drive attached to the controller '%s'"
|
---|
| 330 | "at the port: %u, device: %u", pszCtl, port, device);
|
---|
[23902] | 331 |
|
---|
[34634] | 332 | }
|
---|
| 333 | else
|
---|
[24346] | 334 | {
|
---|
[34634] | 335 | StorageBus_T storageBus = StorageBus_Null;
|
---|
| 336 | DeviceType_T deviceType = DeviceType_Null;
|
---|
| 337 | com::SafeArray <DeviceType_T> saDeviceTypes;
|
---|
[24346] | 338 | ULONG driveCheck = 0;
|
---|
[34634] | 339 |
|
---|
| 340 | /* check if the device type is supported by the controller */
|
---|
| 341 | CHECK_ERROR(storageCtl, COMGETTER(Bus)(&storageBus));
|
---|
| 342 | CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
|
---|
[24346] | 343 | for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
|
---|
| 344 | {
|
---|
[34634] | 345 | if ( (saDeviceTypes[i] == DeviceType_DVD)
|
---|
| 346 | || (saDeviceTypes[i] == DeviceType_Floppy))
|
---|
[24346] | 347 | driveCheck++;
|
---|
[34634] | 348 | }
|
---|
[24346] | 349 |
|
---|
[34634] | 350 | if (!driveCheck)
|
---|
| 351 | throw Utf8StrFmt("The attachment is not supported by the storage controller '%s'", pszCtl);
|
---|
[24346] | 352 |
|
---|
[34634] | 353 | if (storageBus == StorageBus_Floppy)
|
---|
| 354 | deviceType = DeviceType_Floppy;
|
---|
| 355 | else
|
---|
| 356 | deviceType = DeviceType_DVD;
|
---|
| 357 |
|
---|
| 358 | /* attach a empty floppy/dvd drive after removing previous attachment */
|
---|
| 359 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
| 360 | CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl).raw(), port, device,
|
---|
| 361 | deviceType, NULL));
|
---|
| 362 | }
|
---|
| 363 | } // end if (!RTStrICmp(pszMedium, "emptydrive"))
|
---|
| 364 | else
|
---|
| 365 | {
|
---|
| 366 | ComPtr<IMedium> pMedium2Mount;
|
---|
| 367 |
|
---|
| 368 | // not "none", not "emptydrive": then it must be a UUID or filename or hostdrive or iSCSI;
|
---|
| 369 | // for all these we first need to know the type of drive we're attaching to
|
---|
| 370 | {
|
---|
| 371 | /*
|
---|
| 372 | * try to determine the type of the drive from the
|
---|
| 373 | * storage controller chipset, the attachment and
|
---|
| 374 | * the medium being attached
|
---|
| 375 | */
|
---|
| 376 | if (ctlType == StorageControllerType_I82078) // floppy controller
|
---|
| 377 | devTypeRequested = DeviceType_Floppy;
|
---|
| 378 | else
|
---|
[24346] | 379 | {
|
---|
[34634] | 380 | /*
|
---|
| 381 | * for SATA/SCSI/IDE it is hard to tell if it is a harddisk or
|
---|
| 382 | * a dvd being attached so lets check if the medium attachment
|
---|
| 383 | * and the medium, both are of same type. if yes then we are
|
---|
| 384 | * sure of its type and don't need the user to enter it manually
|
---|
| 385 | * else ask the user for the type.
|
---|
| 386 | */
|
---|
| 387 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 388 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 389 | device,
|
---|
| 390 | mediumAttachment.asOutParam());
|
---|
| 391 | if (SUCCEEDED(rc))
|
---|
| 392 | {
|
---|
| 393 | DeviceType_T deviceType;
|
---|
| 394 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
| 395 |
|
---|
| 396 | ComPtr<IMedium> pExistingMedium;
|
---|
[35239] | 397 | rc = findMedium(a, pszMedium, deviceType, true /* fSilent */,
|
---|
| 398 | pExistingMedium);
|
---|
[35241] | 399 | if (SUCCEEDED(rc) && pExistingMedium)
|
---|
[34634] | 400 | {
|
---|
| 401 | if ( (deviceType == DeviceType_DVD)
|
---|
| 402 | || (deviceType == DeviceType_HardDisk)
|
---|
| 403 | )
|
---|
[34874] | 404 | devTypeRequested = deviceType;
|
---|
[34634] | 405 | }
|
---|
| 406 | }
|
---|
[24346] | 407 | }
|
---|
[34634] | 408 | /* for all other cases lets ask the user what type of drive it is */
|
---|
[24346] | 409 | }
|
---|
| 410 |
|
---|
[34634] | 411 | if (devTypeRequested == DeviceType_Null) // still the initializer value?
|
---|
| 412 | throw Utf8Str("Argument --type must be specified\n");
|
---|
[23802] | 413 |
|
---|
[34634] | 414 | /* check if the device type is supported by the controller */
|
---|
[23802] | 415 | {
|
---|
[34634] | 416 | StorageBus_T storageBus = StorageBus_Null;
|
---|
| 417 | com::SafeArray <DeviceType_T> saDeviceTypes;
|
---|
[23802] | 418 |
|
---|
[34634] | 419 | CHECK_ERROR(storageCtl, COMGETTER(Bus)(&storageBus));
|
---|
| 420 | CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
|
---|
[23802] | 421 | if (SUCCEEDED(rc))
|
---|
| 422 | {
|
---|
[34634] | 423 | ULONG driveCheck = 0;
|
---|
| 424 | for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
|
---|
| 425 | if (saDeviceTypes[i] == devTypeRequested)
|
---|
| 426 | driveCheck++;
|
---|
| 427 | if (!driveCheck)
|
---|
| 428 | throw Utf8StrFmt("The given attachment is not supported by the storage controller '%s'", pszCtl);
|
---|
[23802] | 429 | }
|
---|
| 430 | else
|
---|
[34634] | 431 | goto leave;
|
---|
[23802] | 432 | }
|
---|
| 433 |
|
---|
[34634] | 434 | // find the medium given
|
---|
| 435 | /* host drive? */
|
---|
| 436 | if (!RTStrNICmp(pszMedium, "host:", 5))
|
---|
[23802] | 437 | {
|
---|
[34634] | 438 | ComPtr<IHost> host;
|
---|
| 439 | CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
|
---|
| 440 |
|
---|
| 441 | if (devTypeRequested == DeviceType_DVD)
|
---|
[23802] | 442 | {
|
---|
[32718] | 443 | rc = host->FindHostDVDDrive(Bstr(pszMedium + 5).raw(),
|
---|
[34634] | 444 | pMedium2Mount.asOutParam());
|
---|
| 445 | if (!pMedium2Mount)
|
---|
[23802] | 446 | {
|
---|
| 447 | /* 2nd try: try with the real name, important on Linux+libhal */
|
---|
| 448 | char szPathReal[RTPATH_MAX];
|
---|
[23902] | 449 | if (RT_FAILURE(RTPathReal(pszMedium + 5, szPathReal, sizeof(szPathReal))))
|
---|
[34634] | 450 | throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5);
|
---|
[32718] | 451 | rc = host->FindHostDVDDrive(Bstr(szPathReal).raw(),
|
---|
[34634] | 452 | pMedium2Mount.asOutParam());
|
---|
| 453 | if (!pMedium2Mount)
|
---|
| 454 | throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5);
|
---|
[23802] | 455 | }
|
---|
| 456 | }
|
---|
| 457 | else
|
---|
| 458 | {
|
---|
[34634] | 459 | // floppy
|
---|
| 460 | rc = host->FindHostFloppyDrive(Bstr(pszMedium + 5).raw(),
|
---|
| 461 | pMedium2Mount.asOutParam());
|
---|
| 462 | if (!pMedium2Mount)
|
---|
| 463 | throw Utf8StrFmt("Invalid host floppy drive name \"%s\"", pszMedium + 5);
|
---|
[23802] | 464 | }
|
---|
[34634] | 465 | }
|
---|
| 466 | else if (!RTStrICmp(pszMedium, "iSCSI"))
|
---|
[23902] | 467 | {
|
---|
[34634] | 468 | /* check for required options */
|
---|
| 469 | if (bstrServer.isEmpty() || bstrTarget.isEmpty())
|
---|
| 470 | throw Utf8StrFmt("Parameters --server and --target are required for iSCSI media");
|
---|
[23802] | 471 |
|
---|
[34634] | 472 | /** @todo move the location stuff to Main, which can use pfnComposeName
|
---|
| 473 | * from the disk backends to construct the location properly. Also do
|
---|
| 474 | * not use slashes to separate the parts, as otherwise only the last
|
---|
| 475 | * element containing information will be shown. */
|
---|
| 476 | Bstr bstrISCSIMedium;
|
---|
| 477 | if ( bstrLun.isEmpty()
|
---|
| 478 | || (bstrLun == "0")
|
---|
| 479 | || (bstrLun == "enc0")
|
---|
| 480 | )
|
---|
| 481 | bstrISCSIMedium = BstrFmt("%ls|%ls", bstrServer.raw(), bstrTarget.raw());
|
---|
| 482 | else
|
---|
| 483 | bstrISCSIMedium = BstrFmt("%ls|%ls|%ls", bstrServer.raw(), bstrTarget.raw(), bstrLun.raw());
|
---|
[23802] | 484 |
|
---|
[34634] | 485 | CHECK_ERROR(a->virtualBox, CreateHardDisk(Bstr("iSCSI").raw(),
|
---|
| 486 | bstrISCSIMedium.raw(),
|
---|
| 487 | pMedium2Mount.asOutParam()));
|
---|
| 488 | if (FAILED(rc)) goto leave;
|
---|
| 489 | if (!bstrPort.isEmpty())
|
---|
| 490 | bstrServer = BstrFmt("%ls:%ls", bstrServer.raw(), bstrPort.raw());
|
---|
[23802] | 491 |
|
---|
[34634] | 492 | // set the other iSCSI parameters as properties
|
---|
| 493 | com::SafeArray <BSTR> names;
|
---|
| 494 | com::SafeArray <BSTR> values;
|
---|
| 495 | Bstr("TargetAddress").detachTo(names.appendedRaw());
|
---|
| 496 | bstrServer.detachTo(values.appendedRaw());
|
---|
| 497 | Bstr("TargetName").detachTo(names.appendedRaw());
|
---|
| 498 | bstrTarget.detachTo(values.appendedRaw());
|
---|
[23802] | 499 |
|
---|
[34634] | 500 | if (!bstrLun.isEmpty())
|
---|
| 501 | {
|
---|
| 502 | Bstr("LUN").detachTo(names.appendedRaw());
|
---|
| 503 | bstrLun.detachTo(values.appendedRaw());
|
---|
| 504 | }
|
---|
| 505 | if (!bstrUsername.isEmpty())
|
---|
| 506 | {
|
---|
| 507 | Bstr("InitiatorUsername").detachTo(names.appendedRaw());
|
---|
| 508 | bstrUsername.detachTo(values.appendedRaw());
|
---|
| 509 | }
|
---|
| 510 | if (!bstrPassword.isEmpty())
|
---|
| 511 | {
|
---|
| 512 | Bstr("InitiatorSecret").detachTo(names.appendedRaw());
|
---|
| 513 | bstrPassword.detachTo(values.appendedRaw());
|
---|
| 514 | }
|
---|
[23802] | 515 |
|
---|
[34634] | 516 | /// @todo add --initiator option - until that happens rely on the
|
---|
| 517 | // defaults of the iSCSI initiator code. Setting it to a constant
|
---|
| 518 | // value does more harm than good, as the initiator name is supposed
|
---|
| 519 | // to identify a particular initiator uniquely.
|
---|
| 520 | // Bstr("InitiatorName").detachTo(names.appendedRaw());
|
---|
| 521 | // Bstr("iqn.2008-04.com.sun.virtualbox.initiator").detachTo(values.appendedRaw());
|
---|
[23802] | 522 |
|
---|
[34634] | 523 | /// @todo add --targetName and --targetPassword options
|
---|
[23802] | 524 |
|
---|
[34634] | 525 | if (fIntNet)
|
---|
[23802] | 526 | {
|
---|
[34634] | 527 | Bstr("HostIPStack").detachTo(names.appendedRaw());
|
---|
| 528 | Bstr("0").detachTo(values.appendedRaw());
|
---|
[23802] | 529 | }
|
---|
[34634] | 530 |
|
---|
| 531 | CHECK_ERROR(pMedium2Mount, SetProperties(ComSafeArrayAsInParam(names),
|
---|
| 532 | ComSafeArrayAsInParam(values)));
|
---|
| 533 | if (FAILED(rc)) goto leave;
|
---|
| 534 | Bstr guid;
|
---|
| 535 | CHECK_ERROR(pMedium2Mount, COMGETTER(Id)(guid.asOutParam()));
|
---|
| 536 | if (FAILED(rc)) goto leave;
|
---|
| 537 | RTPrintf("iSCSI disk created. UUID: %s\n", Utf8Str(guid).c_str());
|
---|
[23802] | 538 | }
|
---|
| 539 | else
|
---|
| 540 | {
|
---|
[34634] | 541 | Bstr bstrMedium(pszMedium);
|
---|
| 542 | if (bstrMedium.isEmpty())
|
---|
| 543 | throw Utf8Str("Missing --medium argument");
|
---|
| 544 |
|
---|
[35239] | 545 | rc = findOrOpenMedium(a, pszMedium, devTypeRequested,
|
---|
| 546 | pMedium2Mount, NULL);
|
---|
[35241] | 547 | if (FAILED(rc) || !pMedium2Mount)
|
---|
[34634] | 548 | throw Utf8StrFmt("Invalid UUID or filename \"%s\"", pszMedium);
|
---|
| 549 | }
|
---|
[23802] | 550 |
|
---|
[35115] | 551 | // set medium type, if so desired
|
---|
[35136] | 552 | if (pMedium2Mount && fSetMediumType)
|
---|
[35115] | 553 | {
|
---|
| 554 | CHECK_ERROR(pMedium2Mount, COMSETTER(Type)(mediumType));
|
---|
[35137] | 555 | if (FAILED(rc))
|
---|
| 556 | throw Utf8Str("Failed to set the medium type");
|
---|
[35115] | 557 | }
|
---|
| 558 |
|
---|
| 559 | if (pMedium2Mount && !bstrComment.isEmpty())
|
---|
| 560 | {
|
---|
| 561 | CHECK_ERROR(pMedium2Mount, COMSETTER(Description)(bstrComment.raw()));
|
---|
| 562 | }
|
---|
| 563 |
|
---|
[34634] | 564 | switch (devTypeRequested)
|
---|
| 565 | {
|
---|
| 566 | case DeviceType_DVD:
|
---|
| 567 | case DeviceType_Floppy:
|
---|
[23902] | 568 | {
|
---|
[34634] | 569 | if (!fRunTime)
|
---|
| 570 | {
|
---|
| 571 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 572 | // check if there is a dvd/floppy drive at the given location, if not attach one first
|
---|
| 573 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(),
|
---|
| 574 | port,
|
---|
| 575 | device,
|
---|
| 576 | mediumAttachment.asOutParam());
|
---|
| 577 | if (SUCCEEDED(rc))
|
---|
| 578 | {
|
---|
| 579 | DeviceType_T deviceType;
|
---|
| 580 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
| 581 | if (deviceType != devTypeRequested)
|
---|
| 582 | {
|
---|
| 583 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
| 584 | rc = machine->AttachDevice(Bstr(pszCtl).raw(),
|
---|
| 585 | port,
|
---|
| 586 | device,
|
---|
| 587 | devTypeRequested, // DeviceType_DVD or DeviceType_Floppy
|
---|
| 588 | NULL);
|
---|
| 589 | }
|
---|
| 590 | }
|
---|
| 591 | else
|
---|
| 592 | {
|
---|
| 593 | rc = machine->AttachDevice(Bstr(pszCtl).raw(),
|
---|
| 594 | port,
|
---|
| 595 | device,
|
---|
| 596 | devTypeRequested, // DeviceType_DVD or DeviceType_Floppy
|
---|
| 597 | NULL);
|
---|
| 598 | }
|
---|
| 599 | }
|
---|
| 600 |
|
---|
| 601 | if (pMedium2Mount)
|
---|
| 602 | {
|
---|
| 603 | CHECK_ERROR(machine, MountMedium(Bstr(pszCtl).raw(),
|
---|
| 604 | port,
|
---|
| 605 | device,
|
---|
| 606 | pMedium2Mount,
|
---|
| 607 | fForceUnmount));
|
---|
| 608 | }
|
---|
| 609 | } // end DeviceType_DVD or DeviceType_Floppy:
|
---|
| 610 | break;
|
---|
| 611 |
|
---|
| 612 | case DeviceType_HardDisk:
|
---|
| 613 | {
|
---|
| 614 | if (fRunTime)
|
---|
| 615 | throw Utf8Str("Hard disk attachments cannot be changed while the VM is running");
|
---|
| 616 |
|
---|
| 617 | // if there is anything attached at the given location, remove it
|
---|
| 618 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
| 619 | CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl).raw(),
|
---|
| 620 | port,
|
---|
| 621 | device,
|
---|
| 622 | DeviceType_HardDisk,
|
---|
| 623 | pMedium2Mount));
|
---|
[23902] | 624 | }
|
---|
[34634] | 625 | break;
|
---|
[23802] | 626 | }
|
---|
| 627 | }
|
---|
[34634] | 628 |
|
---|
| 629 | if ( pszPassThrough
|
---|
| 630 | && (SUCCEEDED(rc)))
|
---|
[23902] | 631 | {
|
---|
[34634] | 632 | ComPtr<IMediumAttachment> mattach;
|
---|
| 633 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 634 | device, mattach.asOutParam()));
|
---|
| 635 |
|
---|
| 636 | if (SUCCEEDED(rc))
|
---|
| 637 | {
|
---|
| 638 | if (!RTStrICmp(pszPassThrough, "on"))
|
---|
| 639 | {
|
---|
| 640 | CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(),
|
---|
| 641 | port, device, TRUE));
|
---|
| 642 | }
|
---|
| 643 | else if (!RTStrICmp(pszPassThrough, "off"))
|
---|
| 644 | {
|
---|
| 645 | CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(),
|
---|
| 646 | port, device, FALSE));
|
---|
| 647 | }
|
---|
| 648 | else
|
---|
| 649 | throw Utf8StrFmt("Invalid --passthrough argument '%s'", pszPassThrough);
|
---|
| 650 | }
|
---|
| 651 | else
|
---|
| 652 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
[23902] | 653 | }
|
---|
[23802] | 654 |
|
---|
[34634] | 655 | if ( pszBandwidthGroup
|
---|
| 656 | && !fRunTime
|
---|
| 657 | && SUCCEEDED(rc))
|
---|
| 658 | {
|
---|
[23902] | 659 |
|
---|
[34634] | 660 | if (!RTStrICmp(pszBandwidthGroup, "none"))
|
---|
[23902] | 661 | {
|
---|
[34634] | 662 | /* Just remove the bandwidth gorup. */
|
---|
| 663 | CHECK_ERROR(machine, SetBandwidthGroupForDevice(Bstr(pszCtl).raw(),
|
---|
| 664 | port, device, NULL));
|
---|
[23902] | 665 | }
|
---|
| 666 | else
|
---|
| 667 | {
|
---|
[34634] | 668 | ComPtr<IBandwidthControl> bwCtrl;
|
---|
| 669 | ComPtr<IBandwidthGroup> bwGroup;
|
---|
[23902] | 670 |
|
---|
[34634] | 671 | CHECK_ERROR(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()));
|
---|
[34587] | 672 |
|
---|
| 673 | if (SUCCEEDED(rc))
|
---|
| 674 | {
|
---|
[34634] | 675 | CHECK_ERROR(bwCtrl, GetBandwidthGroup(Bstr(pszBandwidthGroup).raw(), bwGroup.asOutParam()));
|
---|
| 676 | if (SUCCEEDED(rc))
|
---|
| 677 | {
|
---|
| 678 | CHECK_ERROR(machine, SetBandwidthGroupForDevice(Bstr(pszCtl).raw(),
|
---|
| 679 | port, device, bwGroup));
|
---|
| 680 | }
|
---|
[34587] | 681 | }
|
---|
| 682 | }
|
---|
| 683 | }
|
---|
[34634] | 684 |
|
---|
| 685 | /* commit changes */
|
---|
| 686 | if (SUCCEEDED(rc))
|
---|
| 687 | CHECK_ERROR(machine, SaveSettings());
|
---|
[34587] | 688 | }
|
---|
[34634] | 689 | catch (const Utf8Str &strError)
|
---|
| 690 | {
|
---|
| 691 | errorArgument("%s", strError.c_str());
|
---|
| 692 | rc = E_FAIL;
|
---|
| 693 | }
|
---|
[34587] | 694 |
|
---|
[34634] | 695 | // machine must always be unlocked, even on errors
|
---|
[23902] | 696 | leave:
|
---|
[31070] | 697 | a->session->UnlockMachine();
|
---|
[23802] | 698 |
|
---|
| 699 | return SUCCEEDED(rc) ? 0 : 1;
|
---|
| 700 | }
|
---|
| 701 |
|
---|
| 702 |
|
---|
| 703 | static const RTGETOPTDEF g_aStorageControllerOptions[] =
|
---|
| 704 | {
|
---|
[23809] | 705 | { "--name", 'n', RTGETOPT_REQ_STRING },
|
---|
[23802] | 706 | { "--add", 'a', RTGETOPT_REQ_STRING },
|
---|
[23902] | 707 | { "--controller", 'c', RTGETOPT_REQ_STRING },
|
---|
[23802] | 708 | { "--sataideemulation", 'e', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_INDEX },
|
---|
[23902] | 709 | { "--sataportcount", 'p', RTGETOPT_REQ_UINT32 },
|
---|
[23802] | 710 | { "--remove", 'r', RTGETOPT_REQ_NOTHING },
|
---|
[29480] | 711 | { "--hostiocache", 'i', RTGETOPT_REQ_STRING },
|
---|
[34010] | 712 | { "--bootable", 'b', RTGETOPT_REQ_STRING },
|
---|
[23802] | 713 | };
|
---|
| 714 |
|
---|
| 715 | int handleStorageController(HandlerArg *a)
|
---|
| 716 | {
|
---|
| 717 | int c;
|
---|
| 718 | HRESULT rc = S_OK;
|
---|
| 719 | const char *pszCtl = NULL;
|
---|
| 720 | const char *pszBusType = NULL;
|
---|
| 721 | const char *pszCtlType = NULL;
|
---|
[29480] | 722 | const char *pszHostIOCache = NULL;
|
---|
[34010] | 723 | const char *pszBootable = NULL;
|
---|
[23802] | 724 | ULONG satabootdev = ~0U;
|
---|
| 725 | ULONG sataidedev = ~0U;
|
---|
| 726 | ULONG sataportcount = ~0U;
|
---|
| 727 | bool fRemoveCtl = false;
|
---|
| 728 | ComPtr<IMachine> machine;
|
---|
| 729 | RTGETOPTUNION ValueUnion;
|
---|
| 730 | RTGETOPTSTATE GetState;
|
---|
| 731 |
|
---|
| 732 | if (a->argc < 4)
|
---|
| 733 | return errorSyntax(USAGE_STORAGECONTROLLER, "Too few parameters");
|
---|
| 734 |
|
---|
| 735 | RTGetOptInit (&GetState, a->argc, a->argv, g_aStorageControllerOptions,
|
---|
[26517] | 736 | RT_ELEMENTS(g_aStorageControllerOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
|
---|
[23802] | 737 |
|
---|
| 738 | while ( SUCCEEDED(rc)
|
---|
| 739 | && (c = RTGetOpt(&GetState, &ValueUnion)))
|
---|
| 740 | {
|
---|
| 741 | switch (c)
|
---|
| 742 | {
|
---|
[23809] | 743 | case 'n': // controller name
|
---|
[23802] | 744 | {
|
---|
| 745 | if (ValueUnion.psz)
|
---|
| 746 | pszCtl = ValueUnion.psz;
|
---|
| 747 | else
|
---|
| 748 | rc = E_FAIL;
|
---|
| 749 | break;
|
---|
| 750 | }
|
---|
| 751 |
|
---|
| 752 | case 'a': // controller bus type <ide/sata/scsi/floppy>
|
---|
| 753 | {
|
---|
| 754 | if (ValueUnion.psz)
|
---|
| 755 | pszBusType = ValueUnion.psz;
|
---|
| 756 | else
|
---|
| 757 | rc = E_FAIL;
|
---|
| 758 | break;
|
---|
| 759 | }
|
---|
| 760 |
|
---|
[23902] | 761 | case 'c': // controller <lsilogic/buslogic/intelahci/piix3/piix4/ich6/i82078>
|
---|
[23802] | 762 | {
|
---|
| 763 | if (ValueUnion.psz)
|
---|
| 764 | pszCtlType = ValueUnion.psz;
|
---|
| 765 | else
|
---|
| 766 | rc = E_FAIL;
|
---|
| 767 | break;
|
---|
| 768 | }
|
---|
| 769 |
|
---|
| 770 | case 'e': // sataideemulation
|
---|
| 771 | {
|
---|
| 772 | satabootdev = GetState.uIndex;
|
---|
| 773 | sataidedev = ValueUnion.u32;
|
---|
| 774 | break;
|
---|
| 775 | }
|
---|
| 776 |
|
---|
[23902] | 777 | case 'p': // sataportcount
|
---|
[23802] | 778 | {
|
---|
| 779 | sataportcount = ValueUnion.u32;
|
---|
| 780 | break;
|
---|
| 781 | }
|
---|
| 782 |
|
---|
| 783 | case 'r': // remove controller
|
---|
| 784 | {
|
---|
| 785 | fRemoveCtl = true;
|
---|
| 786 | break;
|
---|
| 787 | }
|
---|
| 788 |
|
---|
[28764] | 789 | case 'i':
|
---|
| 790 | {
|
---|
[29480] | 791 | pszHostIOCache = ValueUnion.psz;
|
---|
[28764] | 792 | break;
|
---|
| 793 | }
|
---|
| 794 |
|
---|
[34010] | 795 | case 'b':
|
---|
| 796 | {
|
---|
| 797 | pszBootable = ValueUnion.psz;
|
---|
| 798 | break;
|
---|
| 799 | }
|
---|
| 800 |
|
---|
[23802] | 801 | default:
|
---|
| 802 | {
|
---|
| 803 | errorGetOpt(USAGE_STORAGECONTROLLER, c, &ValueUnion);
|
---|
| 804 | rc = E_FAIL;
|
---|
| 805 | break;
|
---|
| 806 | }
|
---|
| 807 | }
|
---|
| 808 | }
|
---|
| 809 |
|
---|
| 810 | if (FAILED(rc))
|
---|
| 811 | return 1;
|
---|
| 812 |
|
---|
| 813 | /* try to find the given machine */
|
---|
[33294] | 814 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
|
---|
| 815 | machine.asOutParam()), 1);
|
---|
[23802] | 816 |
|
---|
| 817 | /* open a session for the VM */
|
---|
[31019] | 818 | CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
|
---|
[23802] | 819 |
|
---|
| 820 | /* get the mutable session machine */
|
---|
| 821 | a->session->COMGETTER(Machine)(machine.asOutParam());
|
---|
| 822 |
|
---|
| 823 | if (!pszCtl)
|
---|
| 824 | {
|
---|
[23902] | 825 | /* it's important to always close sessions */
|
---|
[31070] | 826 | a->session->UnlockMachine();
|
---|
[30125] | 827 | errorSyntax(USAGE_STORAGECONTROLLER, "Storage controller name not specified\n");
|
---|
[23802] | 828 | return 1;
|
---|
| 829 | }
|
---|
| 830 |
|
---|
| 831 | if (fRemoveCtl)
|
---|
| 832 | {
|
---|
| 833 | com::SafeIfaceArray<IMediumAttachment> mediumAttachments;
|
---|
| 834 |
|
---|
[23934] | 835 | CHECK_ERROR(machine,
|
---|
[32718] | 836 | GetMediumAttachmentsOfController(Bstr(pszCtl).raw(),
|
---|
[23802] | 837 | ComSafeArrayAsOutParam(mediumAttachments)));
|
---|
| 838 | for (size_t i = 0; i < mediumAttachments.size(); ++ i)
|
---|
| 839 | {
|
---|
| 840 | ComPtr<IMediumAttachment> mediumAttach = mediumAttachments[i];
|
---|
[23902] | 841 | LONG port = 0;
|
---|
| 842 | LONG device = 0;
|
---|
[23802] | 843 |
|
---|
[23934] | 844 | CHECK_ERROR(mediumAttach, COMGETTER(Port)(&port));
|
---|
| 845 | CHECK_ERROR(mediumAttach, COMGETTER(Device)(&device));
|
---|
[32718] | 846 | CHECK_ERROR(machine, DetachDevice(Bstr(pszCtl).raw(), port, device));
|
---|
[23802] | 847 | }
|
---|
| 848 |
|
---|
| 849 | if (SUCCEEDED(rc))
|
---|
[32718] | 850 | CHECK_ERROR(machine, RemoveStorageController(Bstr(pszCtl).raw()));
|
---|
[23802] | 851 | else
|
---|
| 852 | errorArgument("Can't detach the devices connected to '%s' Controller\n"
|
---|
| 853 | "and thus its removal failed.", pszCtl);
|
---|
| 854 | }
|
---|
| 855 | else
|
---|
| 856 | {
|
---|
| 857 | if (pszBusType)
|
---|
| 858 | {
|
---|
| 859 | ComPtr<IStorageController> ctl;
|
---|
| 860 |
|
---|
| 861 | if (!RTStrICmp(pszBusType, "ide"))
|
---|
| 862 | {
|
---|
[32718] | 863 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 864 | StorageBus_IDE,
|
---|
| 865 | ctl.asOutParam()));
|
---|
[23802] | 866 | }
|
---|
| 867 | else if (!RTStrICmp(pszBusType, "sata"))
|
---|
| 868 | {
|
---|
[32718] | 869 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 870 | StorageBus_SATA,
|
---|
| 871 | ctl.asOutParam()));
|
---|
[23802] | 872 | }
|
---|
| 873 | else if (!RTStrICmp(pszBusType, "scsi"))
|
---|
| 874 | {
|
---|
[32718] | 875 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 876 | StorageBus_SCSI,
|
---|
| 877 | ctl.asOutParam()));
|
---|
[23802] | 878 | }
|
---|
| 879 | else if (!RTStrICmp(pszBusType, "floppy"))
|
---|
| 880 | {
|
---|
[32718] | 881 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 882 | StorageBus_Floppy,
|
---|
| 883 | ctl.asOutParam()));
|
---|
[23802] | 884 | }
|
---|
[25589] | 885 | else if (!RTStrICmp(pszBusType, "sas"))
|
---|
| 886 | {
|
---|
[32718] | 887 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 888 | StorageBus_SAS,
|
---|
| 889 | ctl.asOutParam()));
|
---|
[25589] | 890 | }
|
---|
[23802] | 891 | else
|
---|
| 892 | {
|
---|
| 893 | errorArgument("Invalid --add argument '%s'", pszBusType);
|
---|
| 894 | rc = E_FAIL;
|
---|
| 895 | }
|
---|
| 896 | }
|
---|
| 897 |
|
---|
| 898 | if ( pszCtlType
|
---|
| 899 | && SUCCEEDED(rc))
|
---|
| 900 | {
|
---|
| 901 | ComPtr<IStorageController> ctl;
|
---|
| 902 |
|
---|
[32718] | 903 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 904 | ctl.asOutParam()));
|
---|
[23802] | 905 |
|
---|
| 906 | if (SUCCEEDED(rc))
|
---|
| 907 | {
|
---|
| 908 | if (!RTStrICmp(pszCtlType, "lsilogic"))
|
---|
| 909 | {
|
---|
[23934] | 910 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogic));
|
---|
[23802] | 911 | }
|
---|
| 912 | else if (!RTStrICmp(pszCtlType, "buslogic"))
|
---|
| 913 | {
|
---|
[23934] | 914 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_BusLogic));
|
---|
[23802] | 915 | }
|
---|
| 916 | else if (!RTStrICmp(pszCtlType, "intelahci"))
|
---|
| 917 | {
|
---|
[23934] | 918 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_IntelAhci));
|
---|
[23802] | 919 | }
|
---|
| 920 | else if (!RTStrICmp(pszCtlType, "piix3"))
|
---|
| 921 | {
|
---|
[23934] | 922 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX3));
|
---|
[23802] | 923 | }
|
---|
| 924 | else if (!RTStrICmp(pszCtlType, "piix4"))
|
---|
| 925 | {
|
---|
[23934] | 926 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX4));
|
---|
[23802] | 927 | }
|
---|
| 928 | else if (!RTStrICmp(pszCtlType, "ich6"))
|
---|
| 929 | {
|
---|
[23934] | 930 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_ICH6));
|
---|
[23802] | 931 | }
|
---|
| 932 | else if (!RTStrICmp(pszCtlType, "i82078"))
|
---|
| 933 | {
|
---|
[23934] | 934 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_I82078));
|
---|
[23802] | 935 | }
|
---|
[25676] | 936 | else if (!RTStrICmp(pszCtlType, "lsilogicsas"))
|
---|
[25589] | 937 | {
|
---|
| 938 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas));
|
---|
| 939 | }
|
---|
[23802] | 940 | else
|
---|
| 941 | {
|
---|
| 942 | errorArgument("Invalid --type argument '%s'", pszCtlType);
|
---|
| 943 | rc = E_FAIL;
|
---|
| 944 | }
|
---|
| 945 | }
|
---|
| 946 | else
|
---|
| 947 | {
|
---|
| 948 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 949 | rc = E_FAIL;
|
---|
| 950 | }
|
---|
| 951 | }
|
---|
| 952 |
|
---|
| 953 | if ( (sataportcount != ~0U)
|
---|
| 954 | && SUCCEEDED(rc))
|
---|
| 955 | {
|
---|
| 956 | ComPtr<IStorageController> ctl;
|
---|
| 957 |
|
---|
[32718] | 958 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 959 | ctl.asOutParam()));
|
---|
[23802] | 960 |
|
---|
| 961 | if (SUCCEEDED(rc))
|
---|
| 962 | {
|
---|
[23934] | 963 | CHECK_ERROR(ctl, COMSETTER(PortCount)(sataportcount));
|
---|
[23802] | 964 | }
|
---|
| 965 | else
|
---|
| 966 | {
|
---|
| 967 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 968 | rc = E_FAIL;
|
---|
| 969 | }
|
---|
| 970 | }
|
---|
| 971 |
|
---|
| 972 | if ( (sataidedev != ~0U)
|
---|
| 973 | && (satabootdev != ~0U)
|
---|
| 974 | && SUCCEEDED(rc))
|
---|
| 975 | {
|
---|
| 976 | ComPtr<IStorageController> ctl;
|
---|
| 977 |
|
---|
[32718] | 978 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 979 | ctl.asOutParam()));
|
---|
[23802] | 980 |
|
---|
| 981 | if (SUCCEEDED(rc))
|
---|
| 982 | {
|
---|
[23934] | 983 | CHECK_ERROR(ctl, SetIDEEmulationPort(satabootdev, sataidedev));
|
---|
[23802] | 984 | }
|
---|
| 985 | else
|
---|
| 986 | {
|
---|
| 987 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 988 | rc = E_FAIL;
|
---|
| 989 | }
|
---|
| 990 | }
|
---|
[28764] | 991 |
|
---|
[29480] | 992 | if ( pszHostIOCache
|
---|
[28764] | 993 | && SUCCEEDED(rc))
|
---|
| 994 | {
|
---|
[29480] | 995 | ComPtr<IStorageController> ctl;
|
---|
[28764] | 996 |
|
---|
[32718] | 997 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 998 | ctl.asOutParam()));
|
---|
[28764] | 999 |
|
---|
[30403] | 1000 | if (SUCCEEDED(rc))
|
---|
[29480] | 1001 | {
|
---|
[30403] | 1002 | if (!RTStrICmp(pszHostIOCache, "on"))
|
---|
| 1003 | {
|
---|
| 1004 | CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(TRUE));
|
---|
| 1005 | }
|
---|
| 1006 | else if (!RTStrICmp(pszHostIOCache, "off"))
|
---|
| 1007 | {
|
---|
| 1008 | CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(FALSE));
|
---|
| 1009 | }
|
---|
| 1010 | else
|
---|
| 1011 | {
|
---|
| 1012 | errorArgument("Invalid --hostiocache argument '%s'", pszHostIOCache);
|
---|
| 1013 | rc = E_FAIL;
|
---|
| 1014 | }
|
---|
[29480] | 1015 | }
|
---|
| 1016 | else
|
---|
| 1017 | {
|
---|
[30403] | 1018 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
[29480] | 1019 | rc = E_FAIL;
|
---|
| 1020 | }
|
---|
[28764] | 1021 | }
|
---|
[34010] | 1022 |
|
---|
| 1023 | if ( pszBootable
|
---|
| 1024 | && SUCCEEDED(rc))
|
---|
| 1025 | {
|
---|
| 1026 | if (SUCCEEDED(rc))
|
---|
| 1027 | {
|
---|
| 1028 | if (!RTStrICmp(pszBootable, "on"))
|
---|
| 1029 | {
|
---|
| 1030 | CHECK_ERROR(machine, SetStorageControllerBootable(Bstr(pszCtl).raw(), TRUE));
|
---|
| 1031 | }
|
---|
| 1032 | else if (!RTStrICmp(pszBootable, "off"))
|
---|
| 1033 | {
|
---|
| 1034 | CHECK_ERROR(machine, SetStorageControllerBootable(Bstr(pszCtl).raw(), FALSE));
|
---|
| 1035 | }
|
---|
| 1036 | else
|
---|
| 1037 | {
|
---|
| 1038 | errorArgument("Invalid --bootable argument '%s'", pszHostIOCache);
|
---|
| 1039 | rc = E_FAIL;
|
---|
| 1040 | }
|
---|
| 1041 | }
|
---|
| 1042 | else
|
---|
| 1043 | {
|
---|
| 1044 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 1045 | rc = E_FAIL;
|
---|
| 1046 | }
|
---|
| 1047 | }
|
---|
[23802] | 1048 | }
|
---|
| 1049 |
|
---|
| 1050 | /* commit changes */
|
---|
| 1051 | if (SUCCEEDED(rc))
|
---|
[23934] | 1052 | CHECK_ERROR(machine, SaveSettings());
|
---|
[23802] | 1053 |
|
---|
| 1054 | /* it's important to always close sessions */
|
---|
[31070] | 1055 | a->session->UnlockMachine();
|
---|
[23802] | 1056 |
|
---|
| 1057 | return SUCCEEDED(rc) ? 0 : 1;
|
---|
| 1058 | }
|
---|
| 1059 |
|
---|
| 1060 | #endif /* !VBOX_ONLY_DOCS */
|
---|
[24026] | 1061 |
|
---|