[23802] | 1 | /* $Id: VBoxManageStorageController.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * VBoxManage - The storage controller related commands.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[76553] | 7 | * Copyright (C) 2006-2019 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 |
|
---|
[57358] | 20 |
|
---|
| 21 | /*********************************************************************************************************************************
|
---|
| 22 | * Header Files *
|
---|
| 23 | *********************************************************************************************************************************/
|
---|
[23802] | 24 | #include <VBox/com/com.h>
|
---|
| 25 | #include <VBox/com/array.h>
|
---|
| 26 | #include <VBox/com/ErrorInfo.h>
|
---|
| 27 | #include <VBox/com/errorprint.h>
|
---|
| 28 | #include <VBox/com/VirtualBox.h>
|
---|
| 29 |
|
---|
| 30 | #include <iprt/path.h>
|
---|
| 31 | #include <iprt/param.h>
|
---|
| 32 | #include <iprt/string.h>
|
---|
| 33 | #include <iprt/ctype.h>
|
---|
| 34 | #include <iprt/stream.h>
|
---|
| 35 | #include <iprt/getopt.h>
|
---|
| 36 | #include <VBox/log.h>
|
---|
| 37 |
|
---|
| 38 | #include "VBoxManage.h"
|
---|
| 39 | using namespace com;
|
---|
| 40 |
|
---|
| 41 |
|
---|
| 42 | // funcs
|
---|
| 43 | ///////////////////////////////////////////////////////////////////////////////
|
---|
| 44 |
|
---|
| 45 |
|
---|
[23902] | 46 | static const RTGETOPTDEF g_aStorageAttachOptions[] =
|
---|
[23802] | 47 | {
|
---|
[34634] | 48 | { "--storagectl", 's', RTGETOPT_REQ_STRING },
|
---|
| 49 | { "--port", 'p', RTGETOPT_REQ_UINT32 },
|
---|
| 50 | { "--device", 'd', RTGETOPT_REQ_UINT32 },
|
---|
| 51 | { "--type", 't', RTGETOPT_REQ_STRING },
|
---|
| 52 | { "--medium", 'm', RTGETOPT_REQ_STRING },
|
---|
| 53 | { "--mtype", 'M', RTGETOPT_REQ_STRING },
|
---|
| 54 | { "--passthrough", 'h', RTGETOPT_REQ_STRING },
|
---|
[37709] | 55 | { "--tempeject", 'e', RTGETOPT_REQ_STRING },
|
---|
[37824] | 56 | { "--nonrotational", 'n', RTGETOPT_REQ_STRING },
|
---|
[38874] | 57 | { "--discard", 'u', RTGETOPT_REQ_STRING },
|
---|
[49190] | 58 | { "--hotpluggable", 'o', RTGETOPT_REQ_STRING },
|
---|
[34634] | 59 | { "--bandwidthgroup", 'b', RTGETOPT_REQ_STRING },
|
---|
| 60 | { "--forceunmount", 'f', RTGETOPT_REQ_NOTHING },
|
---|
| 61 | { "--comment", 'C', RTGETOPT_REQ_STRING },
|
---|
[37525] | 62 | { "--setuuid", 'q', RTGETOPT_REQ_STRING },
|
---|
| 63 | { "--setparentuuid", 'Q', RTGETOPT_REQ_STRING },
|
---|
[34634] | 64 | // iSCSI options
|
---|
| 65 | { "--server", 'S', RTGETOPT_REQ_STRING },
|
---|
| 66 | { "--target", 'T', RTGETOPT_REQ_STRING },
|
---|
[37929] | 67 | { "--tport", 'P', RTGETOPT_REQ_STRING },
|
---|
[34634] | 68 | { "--lun", 'L', RTGETOPT_REQ_STRING },
|
---|
| 69 | { "--encodedlun", 'E', RTGETOPT_REQ_STRING },
|
---|
| 70 | { "--username", 'U', RTGETOPT_REQ_STRING },
|
---|
| 71 | { "--password", 'W', RTGETOPT_REQ_STRING },
|
---|
[69681] | 72 | { "--passwordfile", 'w', RTGETOPT_REQ_STRING },
|
---|
[42395] | 73 | { "--initiator", 'N', RTGETOPT_REQ_STRING },
|
---|
[34634] | 74 | { "--intnet", 'I', RTGETOPT_REQ_NOTHING },
|
---|
[23802] | 75 | };
|
---|
| 76 |
|
---|
[56118] | 77 | RTEXITCODE handleStorageAttach(HandlerArg *a)
|
---|
[23802] | 78 | {
|
---|
[24678] | 79 | int c = VERR_INTERNAL_ERROR; /* initialized to shut up gcc */
|
---|
[23802] | 80 | HRESULT rc = S_OK;
|
---|
[23902] | 81 | ULONG port = ~0U;
|
---|
[37929] | 82 | ULONG device = ~0U;
|
---|
[24504] | 83 | bool fForceUnmount = false;
|
---|
[35136] | 84 | bool fSetMediumType = false;
|
---|
[37525] | 85 | bool fSetNewUuid = false;
|
---|
| 86 | bool fSetNewParentUuid = false;
|
---|
[54438] | 87 | MediumType_T enmMediumType = MediumType_Normal;
|
---|
[34634] | 88 | Bstr bstrComment;
|
---|
[23802] | 89 | const char *pszCtl = NULL;
|
---|
[34634] | 90 | DeviceType_T devTypeRequested = DeviceType_Null;
|
---|
[23902] | 91 | const char *pszMedium = NULL;
|
---|
| 92 | const char *pszPassThrough = NULL;
|
---|
[37709] | 93 | const char *pszTempEject = NULL;
|
---|
[37824] | 94 | const char *pszNonRotational = NULL;
|
---|
[38874] | 95 | const char *pszDiscard = NULL;
|
---|
[49190] | 96 | const char *pszHotPluggable = NULL;
|
---|
[34587] | 97 | const char *pszBandwidthGroup = NULL;
|
---|
[37525] | 98 | Bstr bstrNewUuid;
|
---|
| 99 | Bstr bstrNewParentUuid;
|
---|
[34634] | 100 | // iSCSI options
|
---|
| 101 | Bstr bstrServer;
|
---|
| 102 | Bstr bstrTarget;
|
---|
| 103 | Bstr bstrPort;
|
---|
| 104 | Bstr bstrLun;
|
---|
| 105 | Bstr bstrUsername;
|
---|
| 106 | Bstr bstrPassword;
|
---|
[42395] | 107 | Bstr bstrInitiator;
|
---|
[44131] | 108 | Bstr bstrIso;
|
---|
| 109 | Utf8Str strIso;
|
---|
[34634] | 110 | bool fIntNet = false;
|
---|
| 111 |
|
---|
[23802] | 112 | RTGETOPTUNION ValueUnion;
|
---|
| 113 | RTGETOPTSTATE GetState;
|
---|
| 114 | ComPtr<IMachine> machine;
|
---|
| 115 | ComPtr<IStorageController> storageCtl;
|
---|
[24346] | 116 | ComPtr<ISystemProperties> systemProperties;
|
---|
[23802] | 117 |
|
---|
[23934] | 118 | RTGetOptInit(&GetState, a->argc, a->argv, g_aStorageAttachOptions,
|
---|
[26517] | 119 | RT_ELEMENTS(g_aStorageAttachOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
|
---|
[23802] | 120 |
|
---|
| 121 | while ( SUCCEEDED(rc)
|
---|
| 122 | && (c = RTGetOpt(&GetState, &ValueUnion)))
|
---|
| 123 | {
|
---|
| 124 | switch (c)
|
---|
| 125 | {
|
---|
[23902] | 126 | case 's': // storage controller name
|
---|
[23802] | 127 | {
|
---|
| 128 | if (ValueUnion.psz)
|
---|
[23902] | 129 | pszCtl = ValueUnion.psz;
|
---|
[23802] | 130 | else
|
---|
| 131 | rc = E_FAIL;
|
---|
| 132 | break;
|
---|
| 133 | }
|
---|
| 134 |
|
---|
[23902] | 135 | case 'p': // port
|
---|
[23802] | 136 | {
|
---|
[23902] | 137 | port = ValueUnion.u32;
|
---|
[23802] | 138 | break;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
[23902] | 141 | case 'd': // device
|
---|
[23802] | 142 | {
|
---|
[23902] | 143 | device = ValueUnion.u32;
|
---|
| 144 | break;
|
---|
| 145 | }
|
---|
| 146 |
|
---|
[44131] | 147 | case 'm': // medium <none|emptydrive|additions|uuid|filename|host:<drive>|iSCSI>
|
---|
[23902] | 148 | {
|
---|
[23802] | 149 | if (ValueUnion.psz)
|
---|
[23902] | 150 | pszMedium = ValueUnion.psz;
|
---|
[23802] | 151 | else
|
---|
| 152 | rc = E_FAIL;
|
---|
| 153 | break;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
[23902] | 156 | case 't': // type <dvddrive|hdd|fdd>
|
---|
[23802] | 157 | {
|
---|
[23902] | 158 | if (ValueUnion.psz)
|
---|
[34634] | 159 | {
|
---|
| 160 | if (!RTStrICmp(ValueUnion.psz, "hdd"))
|
---|
| 161 | devTypeRequested = DeviceType_HardDisk;
|
---|
| 162 | else if (!RTStrICmp(ValueUnion.psz, "fdd"))
|
---|
| 163 | devTypeRequested = DeviceType_Floppy;
|
---|
| 164 | else if (!RTStrICmp(ValueUnion.psz, "dvddrive"))
|
---|
| 165 | devTypeRequested = DeviceType_DVD;
|
---|
| 166 | else
|
---|
| 167 | return errorArgument("Invalid --type argument '%s'", ValueUnion.psz);
|
---|
| 168 | }
|
---|
[23902] | 169 | else
|
---|
| 170 | rc = E_FAIL;
|
---|
[23802] | 171 | break;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
[23902] | 174 | case 'h': // passthrough <on|off>
|
---|
[23802] | 175 | {
|
---|
[23902] | 176 | if (ValueUnion.psz)
|
---|
| 177 | pszPassThrough = ValueUnion.psz;
|
---|
| 178 | else
|
---|
| 179 | rc = E_FAIL;
|
---|
[23802] | 180 | break;
|
---|
| 181 | }
|
---|
| 182 |
|
---|
[37709] | 183 | case 'e': // tempeject <on|off>
|
---|
| 184 | {
|
---|
| 185 | if (ValueUnion.psz)
|
---|
| 186 | pszTempEject = ValueUnion.psz;
|
---|
| 187 | else
|
---|
| 188 | rc = E_FAIL;
|
---|
| 189 | break;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
[37824] | 192 | case 'n': // nonrotational <on|off>
|
---|
| 193 | {
|
---|
| 194 | if (ValueUnion.psz)
|
---|
| 195 | pszNonRotational = ValueUnion.psz;
|
---|
| 196 | else
|
---|
| 197 | rc = E_FAIL;
|
---|
| 198 | break;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
[48734] | 201 | case 'u': // discard <on|off>
|
---|
[38874] | 202 | {
|
---|
| 203 | if (ValueUnion.psz)
|
---|
| 204 | pszDiscard = ValueUnion.psz;
|
---|
| 205 | else
|
---|
| 206 | rc = E_FAIL;
|
---|
| 207 | break;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
[49190] | 210 | case 'o': // hotpluggable <on|off>
|
---|
| 211 | {
|
---|
| 212 | if (ValueUnion.psz)
|
---|
| 213 | pszHotPluggable = ValueUnion.psz;
|
---|
| 214 | else
|
---|
| 215 | rc = E_FAIL;
|
---|
| 216 | break;
|
---|
| 217 | }
|
---|
| 218 |
|
---|
[34587] | 219 | case 'b': // bandwidthgroup <name>
|
---|
| 220 | {
|
---|
| 221 | if (ValueUnion.psz)
|
---|
| 222 | pszBandwidthGroup = ValueUnion.psz;
|
---|
| 223 | else
|
---|
| 224 | rc = E_FAIL;
|
---|
| 225 | break;
|
---|
| 226 | }
|
---|
| 227 |
|
---|
[24505] | 228 | case 'f': // force unmount medium during runtime
|
---|
[24504] | 229 | {
|
---|
[24505] | 230 | fForceUnmount = true;
|
---|
[24504] | 231 | break;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
[34634] | 234 | case 'C':
|
---|
| 235 | if (ValueUnion.psz)
|
---|
| 236 | bstrComment = ValueUnion.psz;
|
---|
| 237 | else
|
---|
| 238 | rc = E_FAIL;
|
---|
[37525] | 239 | break;
|
---|
[34634] | 240 |
|
---|
[37525] | 241 | case 'q':
|
---|
| 242 | if (ValueUnion.psz)
|
---|
| 243 | {
|
---|
| 244 | bstrNewUuid = ValueUnion.psz;
|
---|
| 245 | fSetNewUuid = true;
|
---|
| 246 | }
|
---|
| 247 | else
|
---|
| 248 | rc = E_FAIL;
|
---|
| 249 | break;
|
---|
| 250 |
|
---|
| 251 | case 'Q':
|
---|
| 252 | if (ValueUnion.psz)
|
---|
| 253 | {
|
---|
| 254 | bstrNewParentUuid = ValueUnion.psz;
|
---|
| 255 | fSetNewParentUuid = true;
|
---|
| 256 | }
|
---|
| 257 | else
|
---|
| 258 | rc = E_FAIL;
|
---|
| 259 | break;
|
---|
| 260 |
|
---|
[34634] | 261 | case 'S': // --server
|
---|
| 262 | bstrServer = ValueUnion.psz;
|
---|
| 263 | break;
|
---|
| 264 |
|
---|
| 265 | case 'T': // --target
|
---|
| 266 | bstrTarget = ValueUnion.psz;
|
---|
| 267 | break;
|
---|
| 268 |
|
---|
[37929] | 269 | case 'P': // --tport
|
---|
[34634] | 270 | bstrPort = ValueUnion.psz;
|
---|
| 271 | break;
|
---|
| 272 |
|
---|
| 273 | case 'L': // --lun
|
---|
| 274 | bstrLun = ValueUnion.psz;
|
---|
| 275 | break;
|
---|
| 276 |
|
---|
| 277 | case 'E': // --encodedlun
|
---|
| 278 | bstrLun = BstrFmt("enc%s", ValueUnion.psz);
|
---|
| 279 | break;
|
---|
| 280 |
|
---|
| 281 | case 'U': // --username
|
---|
| 282 | bstrUsername = ValueUnion.psz;
|
---|
| 283 | break;
|
---|
| 284 |
|
---|
| 285 | case 'W': // --password
|
---|
| 286 | bstrPassword = ValueUnion.psz;
|
---|
| 287 | break;
|
---|
| 288 |
|
---|
[69693] | 289 | case 'w': // --passwordFile
|
---|
| 290 | {
|
---|
| 291 | Utf8Str utf8Password;
|
---|
| 292 | RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &utf8Password);
|
---|
| 293 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
| 294 | rc = E_FAIL;
|
---|
| 295 | bstrPassword = utf8Password;
|
---|
| 296 | break;
|
---|
| 297 | }
|
---|
[42395] | 298 | case 'N': // --initiator
|
---|
| 299 | bstrInitiator = ValueUnion.psz;
|
---|
| 300 | break;
|
---|
| 301 |
|
---|
[34634] | 302 | case 'M': // --type
|
---|
| 303 | {
|
---|
[54438] | 304 | int vrc = parseMediumType(ValueUnion.psz, &enmMediumType);
|
---|
[34634] | 305 | if (RT_FAILURE(vrc))
|
---|
[54438] | 306 | return errorArgument("Invalid medium type '%s'", ValueUnion.psz);
|
---|
[35136] | 307 | fSetMediumType = true;
|
---|
[34634] | 308 | break;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | case 'I': // --intnet
|
---|
| 312 | fIntNet = true;
|
---|
| 313 | break;
|
---|
| 314 |
|
---|
[23802] | 315 | default:
|
---|
| 316 | {
|
---|
[23902] | 317 | errorGetOpt(USAGE_STORAGEATTACH, c, &ValueUnion);
|
---|
[23802] | 318 | rc = E_FAIL;
|
---|
| 319 | break;
|
---|
| 320 | }
|
---|
| 321 | }
|
---|
| 322 | }
|
---|
[31008] | 323 |
|
---|
[30125] | 324 | if (FAILED(rc))
|
---|
[56118] | 325 | return RTEXITCODE_FAILURE;
|
---|
[23802] | 326 |
|
---|
[30125] | 327 | if (!pszCtl)
|
---|
| 328 | return errorSyntax(USAGE_STORAGEATTACH, "Storage controller name not specified");
|
---|
| 329 |
|
---|
[24346] | 330 | /* get the virtualbox system properties */
|
---|
[56118] | 331 | CHECK_ERROR_RET(a->virtualBox, COMGETTER(SystemProperties)(systemProperties.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[24346] | 332 |
|
---|
[34634] | 333 | // find the machine, lock it, get the mutable session machine
|
---|
[33294] | 334 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
|
---|
[56118] | 335 | machine.asOutParam()), RTEXITCODE_FAILURE);
|
---|
| 336 | CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
|
---|
[31019] | 337 | SessionType_T st;
|
---|
[56118] | 338 | CHECK_ERROR_RET(a->session, COMGETTER(Type)(&st), RTEXITCODE_FAILURE);
|
---|
[23802] | 339 | a->session->COMGETTER(Machine)(machine.asOutParam());
|
---|
| 340 |
|
---|
[34634] | 341 | try
|
---|
[23902] | 342 | {
|
---|
[34634] | 343 | bool fRunTime = (st == SessionType_Shared);
|
---|
[37674] | 344 |
|
---|
[23902] | 345 | if (fRunTime)
|
---|
[23802] | 346 | {
|
---|
[37674] | 347 | if (pszPassThrough)
|
---|
[34634] | 348 | throw Utf8Str("Drive passthrough state cannot be changed while the VM is running\n");
|
---|
| 349 | else if (pszBandwidthGroup)
|
---|
| 350 | throw Utf8Str("Bandwidth group cannot be changed while the VM is running\n");
|
---|
| 351 | }
|
---|
[23902] | 352 |
|
---|
[34634] | 353 | /* check if the storage controller is present */
|
---|
| 354 | rc = machine->GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 355 | storageCtl.asOutParam());
|
---|
| 356 | if (FAILED(rc))
|
---|
| 357 | throw Utf8StrFmt("Could not find a controller named '%s'\n", pszCtl);
|
---|
[24504] | 358 |
|
---|
[37929] | 359 | StorageBus_T storageBus = StorageBus_Null;
|
---|
[56118] | 360 | CHECK_ERROR_RET(storageCtl, COMGETTER(Bus)(&storageBus), RTEXITCODE_FAILURE);
|
---|
[37929] | 361 | ULONG maxPorts = 0;
|
---|
[56118] | 362 | CHECK_ERROR_RET(systemProperties, GetMaxPortCountForStorageBus(storageBus, &maxPorts), RTEXITCODE_FAILURE);
|
---|
[37929] | 363 | ULONG maxDevices = 0;
|
---|
[56118] | 364 | CHECK_ERROR_RET(systemProperties, GetMaxDevicesPerPortForStorageBus(storageBus, &maxDevices), RTEXITCODE_FAILURE);
|
---|
[37929] | 365 |
|
---|
| 366 | if (port == ~0U)
|
---|
| 367 | {
|
---|
| 368 | if (maxPorts == 1)
|
---|
| 369 | port = 0;
|
---|
| 370 | else
|
---|
| 371 | return errorSyntax(USAGE_STORAGEATTACH, "Port not specified");
|
---|
| 372 | }
|
---|
| 373 | if (device == ~0U)
|
---|
| 374 | {
|
---|
| 375 | if (maxDevices == 1)
|
---|
| 376 | device = 0;
|
---|
| 377 | else
|
---|
| 378 | return errorSyntax(USAGE_STORAGEATTACH, "Device not specified");
|
---|
| 379 | }
|
---|
| 380 |
|
---|
[34634] | 381 | /* for sata controller check if the port count is big enough
|
---|
| 382 | * to accommodate the current port which is being assigned
|
---|
| 383 | * else just increase the port count
|
---|
| 384 | */
|
---|
[23802] | 385 | {
|
---|
[34634] | 386 | ULONG ulPortCount = 0;
|
---|
| 387 | ULONG ulMaxPortCount = 0;
|
---|
[23902] | 388 |
|
---|
[34634] | 389 | CHECK_ERROR(storageCtl, COMGETTER(MaxPortCount)(&ulMaxPortCount));
|
---|
| 390 | CHECK_ERROR(storageCtl, COMGETTER(PortCount)(&ulPortCount));
|
---|
[23902] | 391 |
|
---|
[34634] | 392 | if ( (ulPortCount != ulMaxPortCount)
|
---|
| 393 | && (port >= ulPortCount)
|
---|
| 394 | && (port < ulMaxPortCount))
|
---|
| 395 | CHECK_ERROR(storageCtl, COMSETTER(PortCount)(port + 1));
|
---|
| 396 | }
|
---|
[24346] | 397 |
|
---|
[34634] | 398 | StorageControllerType_T ctlType = StorageControllerType_Null;
|
---|
| 399 | CHECK_ERROR(storageCtl, COMGETTER(ControllerType)(&ctlType));
|
---|
[23902] | 400 |
|
---|
[34634] | 401 | if (!RTStrICmp(pszMedium, "none"))
|
---|
| 402 | {
|
---|
| 403 | CHECK_ERROR(machine, DetachDevice(Bstr(pszCtl).raw(), port, device));
|
---|
[23902] | 404 | }
|
---|
[34634] | 405 | else if (!RTStrICmp(pszMedium, "emptydrive"))
|
---|
[23963] | 406 | {
|
---|
[34634] | 407 | if (fRunTime)
|
---|
[23963] | 408 | {
|
---|
[34634] | 409 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 410 | DeviceType_T deviceType = DeviceType_Null;
|
---|
| 411 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device,
|
---|
| 412 | mediumAttachment.asOutParam());
|
---|
[23963] | 413 | if (SUCCEEDED(rc))
|
---|
| 414 | {
|
---|
[34634] | 415 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
[23963] | 416 |
|
---|
[34634] | 417 | if ( (deviceType == DeviceType_DVD)
|
---|
| 418 | || (deviceType == DeviceType_Floppy))
|
---|
[23963] | 419 | {
|
---|
[34634] | 420 | /* just unmount the floppy/dvd */
|
---|
[42442] | 421 | CHECK_ERROR(machine, UnmountMedium(Bstr(pszCtl).raw(),
|
---|
| 422 | port,
|
---|
| 423 | device,
|
---|
| 424 | fForceUnmount));
|
---|
[23963] | 425 | }
|
---|
| 426 | }
|
---|
[38330] | 427 | else if (devTypeRequested == DeviceType_DVD)
|
---|
| 428 | {
|
---|
| 429 | /*
|
---|
| 430 | * Try to attach an empty DVD drive as a hotplug operation.
|
---|
| 431 | * Main will complain if the controller doesn't support hotplugging.
|
---|
| 432 | */
|
---|
[42538] | 433 | CHECK_ERROR(machine, AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device,
|
---|
| 434 | devTypeRequested));
|
---|
[38330] | 435 | deviceType = DeviceType_DVD; /* To avoid the error message below. */
|
---|
| 436 | }
|
---|
[23963] | 437 |
|
---|
[34634] | 438 | if ( FAILED(rc)
|
---|
| 439 | || !( deviceType == DeviceType_DVD
|
---|
| 440 | || deviceType == DeviceType_Floppy)
|
---|
| 441 | )
|
---|
| 442 | throw Utf8StrFmt("No DVD/Floppy Drive attached to the controller '%s'"
|
---|
| 443 | "at the port: %u, device: %u", pszCtl, port, device);
|
---|
[23902] | 444 |
|
---|
[34634] | 445 | }
|
---|
| 446 | else
|
---|
[24346] | 447 | {
|
---|
[34634] | 448 | DeviceType_T deviceType = DeviceType_Null;
|
---|
| 449 | com::SafeArray <DeviceType_T> saDeviceTypes;
|
---|
[24346] | 450 | ULONG driveCheck = 0;
|
---|
[34634] | 451 |
|
---|
| 452 | /* check if the device type is supported by the controller */
|
---|
| 453 | CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
|
---|
[24346] | 454 | for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
|
---|
| 455 | {
|
---|
[34634] | 456 | if ( (saDeviceTypes[i] == DeviceType_DVD)
|
---|
| 457 | || (saDeviceTypes[i] == DeviceType_Floppy))
|
---|
[24346] | 458 | driveCheck++;
|
---|
[34634] | 459 | }
|
---|
[24346] | 460 |
|
---|
[34634] | 461 | if (!driveCheck)
|
---|
| 462 | throw Utf8StrFmt("The attachment is not supported by the storage controller '%s'", pszCtl);
|
---|
[24346] | 463 |
|
---|
[34634] | 464 | if (storageBus == StorageBus_Floppy)
|
---|
| 465 | deviceType = DeviceType_Floppy;
|
---|
| 466 | else
|
---|
| 467 | deviceType = DeviceType_DVD;
|
---|
| 468 |
|
---|
| 469 | /* attach a empty floppy/dvd drive after removing previous attachment */
|
---|
| 470 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
[42538] | 471 | CHECK_ERROR(machine, AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device,
|
---|
| 472 | deviceType));
|
---|
[34634] | 473 | }
|
---|
| 474 | } // end if (!RTStrICmp(pszMedium, "emptydrive"))
|
---|
| 475 | else
|
---|
| 476 | {
|
---|
| 477 | ComPtr<IMedium> pMedium2Mount;
|
---|
| 478 |
|
---|
| 479 | // not "none", not "emptydrive": then it must be a UUID or filename or hostdrive or iSCSI;
|
---|
| 480 | // for all these we first need to know the type of drive we're attaching to
|
---|
| 481 | {
|
---|
| 482 | /*
|
---|
| 483 | * try to determine the type of the drive from the
|
---|
| 484 | * storage controller chipset, the attachment and
|
---|
| 485 | * the medium being attached
|
---|
| 486 | */
|
---|
| 487 | if (ctlType == StorageControllerType_I82078) // floppy controller
|
---|
| 488 | devTypeRequested = DeviceType_Floppy;
|
---|
[37824] | 489 | else
|
---|
[24346] | 490 | {
|
---|
[34634] | 491 | /*
|
---|
| 492 | * for SATA/SCSI/IDE it is hard to tell if it is a harddisk or
|
---|
| 493 | * a dvd being attached so lets check if the medium attachment
|
---|
| 494 | * and the medium, both are of same type. if yes then we are
|
---|
| 495 | * sure of its type and don't need the user to enter it manually
|
---|
| 496 | * else ask the user for the type.
|
---|
| 497 | */
|
---|
| 498 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 499 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 500 | device,
|
---|
| 501 | mediumAttachment.asOutParam());
|
---|
| 502 | if (SUCCEEDED(rc))
|
---|
| 503 | {
|
---|
| 504 | DeviceType_T deviceType;
|
---|
| 505 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
| 506 |
|
---|
[37824] | 507 | if (pszMedium)
|
---|
[34634] | 508 | {
|
---|
[44131] | 509 | if (!RTStrICmp(pszMedium, "additions"))
|
---|
| 510 | {
|
---|
| 511 | ComPtr<ISystemProperties> pProperties;
|
---|
| 512 | CHECK_ERROR(a->virtualBox,
|
---|
| 513 | COMGETTER(SystemProperties)(pProperties.asOutParam()));
|
---|
| 514 | CHECK_ERROR(pProperties, COMGETTER(DefaultAdditionsISO)(bstrIso.asOutParam()));
|
---|
| 515 | strIso = Utf8Str(bstrIso);
|
---|
[44132] | 516 | if (strIso.isEmpty())
|
---|
| 517 | throw Utf8Str("Cannot find the Guest Additions ISO image\n");
|
---|
[44131] | 518 | pszMedium = strIso.c_str();
|
---|
| 519 | if (devTypeRequested == DeviceType_Null)
|
---|
| 520 | devTypeRequested = DeviceType_DVD;
|
---|
| 521 | }
|
---|
[37824] | 522 | ComPtr<IMedium> pExistingMedium;
|
---|
[44028] | 523 | rc = openMedium(a, pszMedium, deviceType,
|
---|
| 524 | AccessMode_ReadWrite,
|
---|
| 525 | pExistingMedium,
|
---|
| 526 | false /* fForceNewUuidOnOpen */,
|
---|
| 527 | true /* fSilent */);
|
---|
[37824] | 528 | if (SUCCEEDED(rc) && pExistingMedium)
|
---|
| 529 | {
|
---|
| 530 | if ( (deviceType == DeviceType_DVD)
|
---|
| 531 | || (deviceType == DeviceType_HardDisk)
|
---|
| 532 | )
|
---|
| 533 | devTypeRequested = deviceType;
|
---|
| 534 | }
|
---|
[34634] | 535 | }
|
---|
[37824] | 536 | else
|
---|
| 537 | devTypeRequested = deviceType;
|
---|
[34634] | 538 | }
|
---|
[24346] | 539 | }
|
---|
| 540 | }
|
---|
| 541 |
|
---|
[34634] | 542 | if (devTypeRequested == DeviceType_Null) // still the initializer value?
|
---|
| 543 | throw Utf8Str("Argument --type must be specified\n");
|
---|
[23802] | 544 |
|
---|
[34634] | 545 | /* check if the device type is supported by the controller */
|
---|
[23802] | 546 | {
|
---|
[34634] | 547 | com::SafeArray <DeviceType_T> saDeviceTypes;
|
---|
[23802] | 548 |
|
---|
[34634] | 549 | CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
|
---|
[23802] | 550 | if (SUCCEEDED(rc))
|
---|
| 551 | {
|
---|
[34634] | 552 | ULONG driveCheck = 0;
|
---|
| 553 | for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
|
---|
| 554 | if (saDeviceTypes[i] == devTypeRequested)
|
---|
| 555 | driveCheck++;
|
---|
| 556 | if (!driveCheck)
|
---|
| 557 | throw Utf8StrFmt("The given attachment is not supported by the storage controller '%s'", pszCtl);
|
---|
[23802] | 558 | }
|
---|
| 559 | else
|
---|
[34634] | 560 | goto leave;
|
---|
[23802] | 561 | }
|
---|
| 562 |
|
---|
[34634] | 563 | // find the medium given
|
---|
| 564 | /* host drive? */
|
---|
[51259] | 565 | if (!RTStrNICmp(pszMedium, RT_STR_TUPLE("host:")))
|
---|
[23802] | 566 | {
|
---|
[34634] | 567 | ComPtr<IHost> host;
|
---|
| 568 | CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
|
---|
| 569 |
|
---|
| 570 | if (devTypeRequested == DeviceType_DVD)
|
---|
[23802] | 571 | {
|
---|
[32718] | 572 | rc = host->FindHostDVDDrive(Bstr(pszMedium + 5).raw(),
|
---|
[34634] | 573 | pMedium2Mount.asOutParam());
|
---|
| 574 | if (!pMedium2Mount)
|
---|
[23802] | 575 | {
|
---|
| 576 | /* 2nd try: try with the real name, important on Linux+libhal */
|
---|
| 577 | char szPathReal[RTPATH_MAX];
|
---|
[23902] | 578 | if (RT_FAILURE(RTPathReal(pszMedium + 5, szPathReal, sizeof(szPathReal))))
|
---|
[34634] | 579 | throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5);
|
---|
[32718] | 580 | rc = host->FindHostDVDDrive(Bstr(szPathReal).raw(),
|
---|
[34634] | 581 | pMedium2Mount.asOutParam());
|
---|
| 582 | if (!pMedium2Mount)
|
---|
| 583 | throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5);
|
---|
[23802] | 584 | }
|
---|
| 585 | }
|
---|
| 586 | else
|
---|
| 587 | {
|
---|
[34634] | 588 | // floppy
|
---|
| 589 | rc = host->FindHostFloppyDrive(Bstr(pszMedium + 5).raw(),
|
---|
| 590 | pMedium2Mount.asOutParam());
|
---|
| 591 | if (!pMedium2Mount)
|
---|
| 592 | throw Utf8StrFmt("Invalid host floppy drive name \"%s\"", pszMedium + 5);
|
---|
[23802] | 593 | }
|
---|
[34634] | 594 | }
|
---|
| 595 | else if (!RTStrICmp(pszMedium, "iSCSI"))
|
---|
[23902] | 596 | {
|
---|
[34634] | 597 | /* check for required options */
|
---|
| 598 | if (bstrServer.isEmpty() || bstrTarget.isEmpty())
|
---|
| 599 | throw Utf8StrFmt("Parameters --server and --target are required for iSCSI media");
|
---|
[23802] | 600 |
|
---|
[34634] | 601 | /** @todo move the location stuff to Main, which can use pfnComposeName
|
---|
| 602 | * from the disk backends to construct the location properly. Also do
|
---|
| 603 | * not use slashes to separate the parts, as otherwise only the last
|
---|
| 604 | * element containing information will be shown. */
|
---|
| 605 | Bstr bstrISCSIMedium;
|
---|
| 606 | if ( bstrLun.isEmpty()
|
---|
| 607 | || (bstrLun == "0")
|
---|
| 608 | || (bstrLun == "enc0")
|
---|
| 609 | )
|
---|
| 610 | bstrISCSIMedium = BstrFmt("%ls|%ls", bstrServer.raw(), bstrTarget.raw());
|
---|
| 611 | else
|
---|
| 612 | bstrISCSIMedium = BstrFmt("%ls|%ls|%ls", bstrServer.raw(), bstrTarget.raw(), bstrLun.raw());
|
---|
[23802] | 613 |
|
---|
[54438] | 614 | CHECK_ERROR(a->virtualBox, CreateMedium(Bstr("iSCSI").raw(),
|
---|
| 615 | bstrISCSIMedium.raw(),
|
---|
| 616 | AccessMode_ReadWrite,
|
---|
| 617 | DeviceType_HardDisk,
|
---|
| 618 | pMedium2Mount.asOutParam()));
|
---|
[34634] | 619 | if (FAILED(rc)) goto leave;
|
---|
| 620 | if (!bstrPort.isEmpty())
|
---|
| 621 | bstrServer = BstrFmt("%ls:%ls", bstrServer.raw(), bstrPort.raw());
|
---|
[23802] | 622 |
|
---|
[34634] | 623 | // set the other iSCSI parameters as properties
|
---|
| 624 | com::SafeArray <BSTR> names;
|
---|
| 625 | com::SafeArray <BSTR> values;
|
---|
| 626 | Bstr("TargetAddress").detachTo(names.appendedRaw());
|
---|
| 627 | bstrServer.detachTo(values.appendedRaw());
|
---|
| 628 | Bstr("TargetName").detachTo(names.appendedRaw());
|
---|
| 629 | bstrTarget.detachTo(values.appendedRaw());
|
---|
[23802] | 630 |
|
---|
[34634] | 631 | if (!bstrLun.isEmpty())
|
---|
| 632 | {
|
---|
| 633 | Bstr("LUN").detachTo(names.appendedRaw());
|
---|
| 634 | bstrLun.detachTo(values.appendedRaw());
|
---|
| 635 | }
|
---|
| 636 | if (!bstrUsername.isEmpty())
|
---|
| 637 | {
|
---|
| 638 | Bstr("InitiatorUsername").detachTo(names.appendedRaw());
|
---|
| 639 | bstrUsername.detachTo(values.appendedRaw());
|
---|
| 640 | }
|
---|
| 641 | if (!bstrPassword.isEmpty())
|
---|
| 642 | {
|
---|
| 643 | Bstr("InitiatorSecret").detachTo(names.appendedRaw());
|
---|
| 644 | bstrPassword.detachTo(values.appendedRaw());
|
---|
| 645 | }
|
---|
[43914] | 646 | if (!bstrInitiator.isEmpty())
|
---|
[42395] | 647 | {
|
---|
| 648 | Bstr("InitiatorName").detachTo(names.appendedRaw());
|
---|
| 649 | bstrInitiator.detachTo(values.appendedRaw());
|
---|
| 650 | }
|
---|
[23802] | 651 |
|
---|
[34634] | 652 | /// @todo add --targetName and --targetPassword options
|
---|
[23802] | 653 |
|
---|
[34634] | 654 | if (fIntNet)
|
---|
[23802] | 655 | {
|
---|
[34634] | 656 | Bstr("HostIPStack").detachTo(names.appendedRaw());
|
---|
| 657 | Bstr("0").detachTo(values.appendedRaw());
|
---|
[23802] | 658 | }
|
---|
[34634] | 659 |
|
---|
| 660 | CHECK_ERROR(pMedium2Mount, SetProperties(ComSafeArrayAsInParam(names),
|
---|
| 661 | ComSafeArrayAsInParam(values)));
|
---|
| 662 | if (FAILED(rc)) goto leave;
|
---|
| 663 | Bstr guid;
|
---|
| 664 | CHECK_ERROR(pMedium2Mount, COMGETTER(Id)(guid.asOutParam()));
|
---|
| 665 | if (FAILED(rc)) goto leave;
|
---|
| 666 | RTPrintf("iSCSI disk created. UUID: %s\n", Utf8Str(guid).c_str());
|
---|
[23802] | 667 | }
|
---|
| 668 | else
|
---|
| 669 | {
|
---|
[37824] | 670 | if (!pszMedium)
|
---|
| 671 | {
|
---|
| 672 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 673 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 674 | device,
|
---|
| 675 | mediumAttachment.asOutParam());
|
---|
| 676 | if (FAILED(rc))
|
---|
| 677 | throw Utf8Str("Missing --medium argument");
|
---|
| 678 | }
|
---|
| 679 | else
|
---|
| 680 | {
|
---|
| 681 | Bstr bstrMedium(pszMedium);
|
---|
[44028] | 682 | rc = openMedium(a, pszMedium, devTypeRequested,
|
---|
| 683 | AccessMode_ReadWrite, pMedium2Mount,
|
---|
| 684 | fSetNewUuid, false /* fSilent */);
|
---|
[37824] | 685 | if (FAILED(rc) || !pMedium2Mount)
|
---|
| 686 | throw Utf8StrFmt("Invalid UUID or filename \"%s\"", pszMedium);
|
---|
| 687 | }
|
---|
[34634] | 688 | }
|
---|
[23802] | 689 |
|
---|
[37525] | 690 | // set medium/parent medium UUID, if so desired
|
---|
[37824] | 691 | if (pMedium2Mount && (fSetNewUuid || fSetNewParentUuid))
|
---|
[37525] | 692 | {
|
---|
[42551] | 693 | CHECK_ERROR(pMedium2Mount, SetIds(fSetNewUuid, bstrNewUuid.raw(),
|
---|
[37525] | 694 | fSetNewParentUuid, bstrNewParentUuid.raw()));
|
---|
| 695 | if (FAILED(rc))
|
---|
| 696 | throw Utf8Str("Failed to set the medium/parent medium UUID");
|
---|
| 697 | }
|
---|
| 698 |
|
---|
[35115] | 699 | // set medium type, if so desired
|
---|
[35136] | 700 | if (pMedium2Mount && fSetMediumType)
|
---|
[35115] | 701 | {
|
---|
[63257] | 702 | MediumType_T enmMediumTypeOld;
|
---|
| 703 | CHECK_ERROR(pMedium2Mount, COMGETTER(Type)(&enmMediumTypeOld));
|
---|
| 704 | if (SUCCEEDED(rc))
|
---|
| 705 | {
|
---|
| 706 | if (enmMediumTypeOld != enmMediumType)
|
---|
| 707 | {
|
---|
| 708 | CHECK_ERROR(pMedium2Mount, COMSETTER(Type)(enmMediumType));
|
---|
| 709 | if (FAILED(rc))
|
---|
| 710 | throw Utf8Str("Failed to set the medium type");
|
---|
| 711 | }
|
---|
| 712 | }
|
---|
[35115] | 713 | }
|
---|
| 714 |
|
---|
| 715 | if (pMedium2Mount && !bstrComment.isEmpty())
|
---|
| 716 | {
|
---|
| 717 | CHECK_ERROR(pMedium2Mount, COMSETTER(Description)(bstrComment.raw()));
|
---|
| 718 | }
|
---|
| 719 |
|
---|
[37824] | 720 | if (pszMedium)
|
---|
[34634] | 721 | {
|
---|
[37824] | 722 | switch (devTypeRequested)
|
---|
[23902] | 723 | {
|
---|
[37824] | 724 | case DeviceType_DVD:
|
---|
| 725 | case DeviceType_Floppy:
|
---|
[34634] | 726 | {
|
---|
[37824] | 727 | if (!fRunTime)
|
---|
[34634] | 728 | {
|
---|
[37824] | 729 | ComPtr<IMediumAttachment> mediumAttachment;
|
---|
| 730 | // check if there is a dvd/floppy drive at the given location, if not attach one first
|
---|
| 731 | rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(),
|
---|
| 732 | port,
|
---|
| 733 | device,
|
---|
| 734 | mediumAttachment.asOutParam());
|
---|
| 735 | if (SUCCEEDED(rc))
|
---|
[34634] | 736 | {
|
---|
[37824] | 737 | DeviceType_T deviceType;
|
---|
| 738 | mediumAttachment->COMGETTER(Type)(&deviceType);
|
---|
| 739 | if (deviceType != devTypeRequested)
|
---|
| 740 | {
|
---|
| 741 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
[42538] | 742 | rc = machine->AttachDeviceWithoutMedium(Bstr(pszCtl).raw(),
|
---|
| 743 | port,
|
---|
| 744 | device,
|
---|
| 745 | devTypeRequested); // DeviceType_DVD or DeviceType_Floppy
|
---|
[37824] | 746 | }
|
---|
| 747 | }
|
---|
| 748 | else
|
---|
| 749 | {
|
---|
[42538] | 750 | rc = machine->AttachDeviceWithoutMedium(Bstr(pszCtl).raw(),
|
---|
| 751 | port,
|
---|
| 752 | device,
|
---|
| 753 | devTypeRequested); // DeviceType_DVD or DeviceType_Floppy
|
---|
[34634] | 754 | }
|
---|
| 755 | }
|
---|
[37824] | 756 |
|
---|
| 757 | if (pMedium2Mount)
|
---|
[34634] | 758 | {
|
---|
[37824] | 759 | CHECK_ERROR(machine, MountMedium(Bstr(pszCtl).raw(),
|
---|
| 760 | port,
|
---|
| 761 | device,
|
---|
| 762 | pMedium2Mount,
|
---|
| 763 | fForceUnmount));
|
---|
[34634] | 764 | }
|
---|
[63300] | 765 | break;
|
---|
[37824] | 766 | } // end DeviceType_DVD or DeviceType_Floppy:
|
---|
[34634] | 767 |
|
---|
[37824] | 768 | case DeviceType_HardDisk:
|
---|
[34634] | 769 | {
|
---|
[37824] | 770 | // if there is anything attached at the given location, remove it
|
---|
| 771 | machine->DetachDevice(Bstr(pszCtl).raw(), port, device);
|
---|
| 772 | CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl).raw(),
|
---|
| 773 | port,
|
---|
| 774 | device,
|
---|
| 775 | DeviceType_HardDisk,
|
---|
| 776 | pMedium2Mount));
|
---|
[63300] | 777 | break;
|
---|
[34634] | 778 | }
|
---|
[63300] | 779 |
|
---|
| 780 | default: break; /* Shut up MSC */
|
---|
[23902] | 781 | }
|
---|
[23802] | 782 | }
|
---|
| 783 | }
|
---|
[34634] | 784 |
|
---|
| 785 | if ( pszPassThrough
|
---|
| 786 | && (SUCCEEDED(rc)))
|
---|
[23902] | 787 | {
|
---|
[34634] | 788 | ComPtr<IMediumAttachment> mattach;
|
---|
| 789 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 790 | device, mattach.asOutParam()));
|
---|
| 791 |
|
---|
| 792 | if (SUCCEEDED(rc))
|
---|
| 793 | {
|
---|
| 794 | if (!RTStrICmp(pszPassThrough, "on"))
|
---|
| 795 | {
|
---|
| 796 | CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(),
|
---|
| 797 | port, device, TRUE));
|
---|
| 798 | }
|
---|
| 799 | else if (!RTStrICmp(pszPassThrough, "off"))
|
---|
| 800 | {
|
---|
| 801 | CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(),
|
---|
| 802 | port, device, FALSE));
|
---|
| 803 | }
|
---|
| 804 | else
|
---|
| 805 | throw Utf8StrFmt("Invalid --passthrough argument '%s'", pszPassThrough);
|
---|
| 806 | }
|
---|
| 807 | else
|
---|
| 808 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
[23902] | 809 | }
|
---|
[23802] | 810 |
|
---|
[37709] | 811 | if ( pszTempEject
|
---|
| 812 | && (SUCCEEDED(rc)))
|
---|
| 813 | {
|
---|
| 814 | ComPtr<IMediumAttachment> mattach;
|
---|
| 815 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 816 | device, mattach.asOutParam()));
|
---|
| 817 |
|
---|
| 818 | if (SUCCEEDED(rc))
|
---|
| 819 | {
|
---|
| 820 | if (!RTStrICmp(pszTempEject, "on"))
|
---|
| 821 | {
|
---|
| 822 | CHECK_ERROR(machine, TemporaryEjectDevice(Bstr(pszCtl).raw(),
|
---|
| 823 | port, device, TRUE));
|
---|
| 824 | }
|
---|
| 825 | else if (!RTStrICmp(pszTempEject, "off"))
|
---|
| 826 | {
|
---|
| 827 | CHECK_ERROR(machine, TemporaryEjectDevice(Bstr(pszCtl).raw(),
|
---|
| 828 | port, device, FALSE));
|
---|
| 829 | }
|
---|
| 830 | else
|
---|
| 831 | throw Utf8StrFmt("Invalid --tempeject argument '%s'", pszTempEject);
|
---|
| 832 | }
|
---|
| 833 | else
|
---|
| 834 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
| 835 | }
|
---|
| 836 |
|
---|
[37824] | 837 | if ( pszNonRotational
|
---|
| 838 | && (SUCCEEDED(rc)))
|
---|
| 839 | {
|
---|
| 840 | ComPtr<IMediumAttachment> mattach;
|
---|
| 841 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 842 | device, mattach.asOutParam()));
|
---|
| 843 |
|
---|
| 844 | if (SUCCEEDED(rc))
|
---|
| 845 | {
|
---|
| 846 | if (!RTStrICmp(pszNonRotational, "on"))
|
---|
| 847 | {
|
---|
| 848 | CHECK_ERROR(machine, NonRotationalDevice(Bstr(pszCtl).raw(),
|
---|
| 849 | port, device, TRUE));
|
---|
| 850 | }
|
---|
| 851 | else if (!RTStrICmp(pszNonRotational, "off"))
|
---|
| 852 | {
|
---|
| 853 | CHECK_ERROR(machine, NonRotationalDevice(Bstr(pszCtl).raw(),
|
---|
| 854 | port, device, FALSE));
|
---|
| 855 | }
|
---|
| 856 | else
|
---|
| 857 | throw Utf8StrFmt("Invalid --nonrotational argument '%s'", pszNonRotational);
|
---|
| 858 | }
|
---|
| 859 | else
|
---|
| 860 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
| 861 | }
|
---|
| 862 |
|
---|
[43531] | 863 | if ( pszDiscard
|
---|
[38874] | 864 | && (SUCCEEDED(rc)))
|
---|
| 865 | {
|
---|
| 866 | ComPtr<IMediumAttachment> mattach;
|
---|
| 867 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 868 | device, mattach.asOutParam()));
|
---|
| 869 |
|
---|
| 870 | if (SUCCEEDED(rc))
|
---|
| 871 | {
|
---|
| 872 | if (!RTStrICmp(pszDiscard, "on"))
|
---|
| 873 | {
|
---|
[38887] | 874 | CHECK_ERROR(machine, SetAutoDiscardForDevice(Bstr(pszCtl).raw(),
|
---|
| 875 | port, device, TRUE));
|
---|
[38874] | 876 | }
|
---|
| 877 | else if (!RTStrICmp(pszDiscard, "off"))
|
---|
| 878 | {
|
---|
[38887] | 879 | CHECK_ERROR(machine, SetAutoDiscardForDevice(Bstr(pszCtl).raw(),
|
---|
| 880 | port, device, FALSE));
|
---|
[38874] | 881 | }
|
---|
| 882 | else
|
---|
[43532] | 883 | throw Utf8StrFmt("Invalid --discard argument '%s'", pszDiscard);
|
---|
[38874] | 884 | }
|
---|
| 885 | else
|
---|
| 886 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
| 887 | }
|
---|
| 888 |
|
---|
[49190] | 889 | if ( pszHotPluggable
|
---|
| 890 | && (SUCCEEDED(rc)))
|
---|
| 891 | {
|
---|
| 892 | ComPtr<IMediumAttachment> mattach;
|
---|
| 893 | CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port,
|
---|
| 894 | device, mattach.asOutParam()));
|
---|
[38874] | 895 |
|
---|
[49190] | 896 | if (SUCCEEDED(rc))
|
---|
| 897 | {
|
---|
| 898 | if (!RTStrICmp(pszHotPluggable, "on"))
|
---|
| 899 | {
|
---|
| 900 | CHECK_ERROR(machine, SetHotPluggableForDevice(Bstr(pszCtl).raw(),
|
---|
| 901 | port, device, TRUE));
|
---|
| 902 | }
|
---|
| 903 | else if (!RTStrICmp(pszHotPluggable, "off"))
|
---|
| 904 | {
|
---|
| 905 | CHECK_ERROR(machine, SetHotPluggableForDevice(Bstr(pszCtl).raw(),
|
---|
| 906 | port, device, FALSE));
|
---|
| 907 | }
|
---|
| 908 | else
|
---|
| 909 | throw Utf8StrFmt("Invalid --hotpluggable argument '%s'", pszHotPluggable);
|
---|
| 910 | }
|
---|
| 911 | else
|
---|
| 912 | throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
|
---|
| 913 | }
|
---|
| 914 |
|
---|
[34634] | 915 | if ( pszBandwidthGroup
|
---|
| 916 | && !fRunTime
|
---|
| 917 | && SUCCEEDED(rc))
|
---|
| 918 | {
|
---|
[23902] | 919 |
|
---|
[34634] | 920 | if (!RTStrICmp(pszBandwidthGroup, "none"))
|
---|
[23902] | 921 | {
|
---|
[34634] | 922 | /* Just remove the bandwidth gorup. */
|
---|
[42538] | 923 | CHECK_ERROR(machine, SetNoBandwidthGroupForDevice(Bstr(pszCtl).raw(),
|
---|
| 924 | port, device));
|
---|
[23902] | 925 | }
|
---|
| 926 | else
|
---|
| 927 | {
|
---|
[34634] | 928 | ComPtr<IBandwidthControl> bwCtrl;
|
---|
| 929 | ComPtr<IBandwidthGroup> bwGroup;
|
---|
[23902] | 930 |
|
---|
[34634] | 931 | CHECK_ERROR(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam()));
|
---|
[34587] | 932 |
|
---|
| 933 | if (SUCCEEDED(rc))
|
---|
| 934 | {
|
---|
[34634] | 935 | CHECK_ERROR(bwCtrl, GetBandwidthGroup(Bstr(pszBandwidthGroup).raw(), bwGroup.asOutParam()));
|
---|
| 936 | if (SUCCEEDED(rc))
|
---|
| 937 | {
|
---|
| 938 | CHECK_ERROR(machine, SetBandwidthGroupForDevice(Bstr(pszCtl).raw(),
|
---|
| 939 | port, device, bwGroup));
|
---|
| 940 | }
|
---|
[34587] | 941 | }
|
---|
| 942 | }
|
---|
| 943 | }
|
---|
[34634] | 944 |
|
---|
| 945 | /* commit changes */
|
---|
| 946 | if (SUCCEEDED(rc))
|
---|
| 947 | CHECK_ERROR(machine, SaveSettings());
|
---|
[34587] | 948 | }
|
---|
[34634] | 949 | catch (const Utf8Str &strError)
|
---|
| 950 | {
|
---|
| 951 | errorArgument("%s", strError.c_str());
|
---|
| 952 | rc = E_FAIL;
|
---|
| 953 | }
|
---|
[34587] | 954 |
|
---|
[34634] | 955 | // machine must always be unlocked, even on errors
|
---|
[23902] | 956 | leave:
|
---|
[31070] | 957 | a->session->UnlockMachine();
|
---|
[23802] | 958 |
|
---|
[56118] | 959 | return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
[23802] | 960 | }
|
---|
| 961 |
|
---|
| 962 |
|
---|
| 963 | static const RTGETOPTDEF g_aStorageControllerOptions[] =
|
---|
| 964 | {
|
---|
[23809] | 965 | { "--name", 'n', RTGETOPT_REQ_STRING },
|
---|
[23802] | 966 | { "--add", 'a', RTGETOPT_REQ_STRING },
|
---|
[23902] | 967 | { "--controller", 'c', RTGETOPT_REQ_STRING },
|
---|
[48985] | 968 | { "--portcount", 'p', RTGETOPT_REQ_UINT32 },
|
---|
[23802] | 969 | { "--remove", 'r', RTGETOPT_REQ_NOTHING },
|
---|
[56821] | 970 | { "--rename", 'R', RTGETOPT_REQ_STRING },
|
---|
[29480] | 971 | { "--hostiocache", 'i', RTGETOPT_REQ_STRING },
|
---|
[34010] | 972 | { "--bootable", 'b', RTGETOPT_REQ_STRING },
|
---|
[23802] | 973 | };
|
---|
| 974 |
|
---|
[56118] | 975 | RTEXITCODE handleStorageController(HandlerArg *a)
|
---|
[23802] | 976 | {
|
---|
| 977 | int c;
|
---|
| 978 | const char *pszCtl = NULL;
|
---|
| 979 | const char *pszBusType = NULL;
|
---|
| 980 | const char *pszCtlType = NULL;
|
---|
[29480] | 981 | const char *pszHostIOCache = NULL;
|
---|
[34010] | 982 | const char *pszBootable = NULL;
|
---|
[56821] | 983 | const char *pszCtlNewName = NULL;
|
---|
[48985] | 984 | ULONG portcount = ~0U;
|
---|
[23802] | 985 | bool fRemoveCtl = false;
|
---|
| 986 | ComPtr<IMachine> machine;
|
---|
| 987 | RTGETOPTUNION ValueUnion;
|
---|
| 988 | RTGETOPTSTATE GetState;
|
---|
| 989 |
|
---|
| 990 | if (a->argc < 4)
|
---|
| 991 | return errorSyntax(USAGE_STORAGECONTROLLER, "Too few parameters");
|
---|
| 992 |
|
---|
| 993 | RTGetOptInit (&GetState, a->argc, a->argv, g_aStorageControllerOptions,
|
---|
[26517] | 994 | RT_ELEMENTS(g_aStorageControllerOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
|
---|
[23802] | 995 |
|
---|
[56118] | 996 | while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
|
---|
[23802] | 997 | {
|
---|
| 998 | switch (c)
|
---|
| 999 | {
|
---|
[23809] | 1000 | case 'n': // controller name
|
---|
[56118] | 1001 | Assert(ValueUnion.psz);
|
---|
| 1002 | pszCtl = ValueUnion.psz;
|
---|
[23802] | 1003 | break;
|
---|
| 1004 |
|
---|
| 1005 | case 'a': // controller bus type <ide/sata/scsi/floppy>
|
---|
[56118] | 1006 | Assert(ValueUnion.psz);
|
---|
| 1007 | pszBusType = ValueUnion.psz;
|
---|
[23802] | 1008 | break;
|
---|
| 1009 |
|
---|
[23902] | 1010 | case 'c': // controller <lsilogic/buslogic/intelahci/piix3/piix4/ich6/i82078>
|
---|
[56118] | 1011 | Assert(ValueUnion.psz);
|
---|
| 1012 | pszCtlType = ValueUnion.psz;
|
---|
[23802] | 1013 | break;
|
---|
| 1014 |
|
---|
[48985] | 1015 | case 'p': // portcount
|
---|
| 1016 | portcount = ValueUnion.u32;
|
---|
[23802] | 1017 | break;
|
---|
| 1018 |
|
---|
| 1019 | case 'r': // remove controller
|
---|
| 1020 | fRemoveCtl = true;
|
---|
| 1021 | break;
|
---|
| 1022 |
|
---|
[56821] | 1023 | case 'R': // rename controller
|
---|
| 1024 | Assert(ValueUnion.psz);
|
---|
| 1025 | pszCtlNewName = ValueUnion.psz;
|
---|
| 1026 | break;
|
---|
| 1027 |
|
---|
[28764] | 1028 | case 'i':
|
---|
[29480] | 1029 | pszHostIOCache = ValueUnion.psz;
|
---|
[28764] | 1030 | break;
|
---|
| 1031 |
|
---|
[34010] | 1032 | case 'b':
|
---|
| 1033 | pszBootable = ValueUnion.psz;
|
---|
| 1034 | break;
|
---|
| 1035 |
|
---|
[23802] | 1036 | default:
|
---|
[56118] | 1037 | return errorGetOpt(USAGE_STORAGECONTROLLER, c, &ValueUnion);
|
---|
[23802] | 1038 | }
|
---|
| 1039 | }
|
---|
| 1040 |
|
---|
[56118] | 1041 | HRESULT rc;
|
---|
[23802] | 1042 |
|
---|
| 1043 | /* try to find the given machine */
|
---|
[33294] | 1044 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
|
---|
[56118] | 1045 | machine.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[23802] | 1046 |
|
---|
| 1047 | /* open a session for the VM */
|
---|
[56118] | 1048 | CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), RTEXITCODE_FAILURE);
|
---|
[23802] | 1049 |
|
---|
| 1050 | /* get the mutable session machine */
|
---|
| 1051 | a->session->COMGETTER(Machine)(machine.asOutParam());
|
---|
| 1052 |
|
---|
| 1053 | if (!pszCtl)
|
---|
| 1054 | {
|
---|
[23902] | 1055 | /* it's important to always close sessions */
|
---|
[31070] | 1056 | a->session->UnlockMachine();
|
---|
[56118] | 1057 | return errorSyntax(USAGE_STORAGECONTROLLER, "Storage controller name not specified\n");
|
---|
[23802] | 1058 | }
|
---|
| 1059 |
|
---|
| 1060 | if (fRemoveCtl)
|
---|
| 1061 | {
|
---|
[42017] | 1062 | CHECK_ERROR(machine, RemoveStorageController(Bstr(pszCtl).raw()));
|
---|
[23802] | 1063 | }
|
---|
| 1064 | else
|
---|
| 1065 | {
|
---|
| 1066 | if (pszBusType)
|
---|
| 1067 | {
|
---|
| 1068 | ComPtr<IStorageController> ctl;
|
---|
| 1069 |
|
---|
| 1070 | if (!RTStrICmp(pszBusType, "ide"))
|
---|
| 1071 | {
|
---|
[32718] | 1072 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1073 | StorageBus_IDE,
|
---|
| 1074 | ctl.asOutParam()));
|
---|
[23802] | 1075 | }
|
---|
| 1076 | else if (!RTStrICmp(pszBusType, "sata"))
|
---|
| 1077 | {
|
---|
[32718] | 1078 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1079 | StorageBus_SATA,
|
---|
| 1080 | ctl.asOutParam()));
|
---|
[23802] | 1081 | }
|
---|
| 1082 | else if (!RTStrICmp(pszBusType, "scsi"))
|
---|
| 1083 | {
|
---|
[32718] | 1084 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1085 | StorageBus_SCSI,
|
---|
| 1086 | ctl.asOutParam()));
|
---|
[23802] | 1087 | }
|
---|
| 1088 | else if (!RTStrICmp(pszBusType, "floppy"))
|
---|
| 1089 | {
|
---|
[32718] | 1090 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1091 | StorageBus_Floppy,
|
---|
| 1092 | ctl.asOutParam()));
|
---|
[23802] | 1093 | }
|
---|
[25589] | 1094 | else if (!RTStrICmp(pszBusType, "sas"))
|
---|
| 1095 | {
|
---|
[32718] | 1096 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1097 | StorageBus_SAS,
|
---|
| 1098 | ctl.asOutParam()));
|
---|
[25589] | 1099 | }
|
---|
[48983] | 1100 | else if (!RTStrICmp(pszBusType, "usb"))
|
---|
| 1101 | {
|
---|
| 1102 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1103 | StorageBus_USB,
|
---|
| 1104 | ctl.asOutParam()));
|
---|
| 1105 | }
|
---|
[57525] | 1106 | else if (!RTStrICmp(pszBusType, "pcie"))
|
---|
| 1107 | {
|
---|
| 1108 | CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl).raw(),
|
---|
| 1109 | StorageBus_PCIe,
|
---|
| 1110 | ctl.asOutParam()));
|
---|
| 1111 | }
|
---|
[23802] | 1112 | else
|
---|
| 1113 | {
|
---|
| 1114 | errorArgument("Invalid --add argument '%s'", pszBusType);
|
---|
| 1115 | rc = E_FAIL;
|
---|
| 1116 | }
|
---|
| 1117 | }
|
---|
| 1118 |
|
---|
| 1119 | if ( pszCtlType
|
---|
| 1120 | && SUCCEEDED(rc))
|
---|
| 1121 | {
|
---|
| 1122 | ComPtr<IStorageController> ctl;
|
---|
| 1123 |
|
---|
[32718] | 1124 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 1125 | ctl.asOutParam()));
|
---|
[23802] | 1126 |
|
---|
| 1127 | if (SUCCEEDED(rc))
|
---|
| 1128 | {
|
---|
| 1129 | if (!RTStrICmp(pszCtlType, "lsilogic"))
|
---|
| 1130 | {
|
---|
[23934] | 1131 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogic));
|
---|
[23802] | 1132 | }
|
---|
| 1133 | else if (!RTStrICmp(pszCtlType, "buslogic"))
|
---|
| 1134 | {
|
---|
[23934] | 1135 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_BusLogic));
|
---|
[23802] | 1136 | }
|
---|
| 1137 | else if (!RTStrICmp(pszCtlType, "intelahci"))
|
---|
| 1138 | {
|
---|
[23934] | 1139 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_IntelAhci));
|
---|
[23802] | 1140 | }
|
---|
| 1141 | else if (!RTStrICmp(pszCtlType, "piix3"))
|
---|
| 1142 | {
|
---|
[23934] | 1143 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX3));
|
---|
[23802] | 1144 | }
|
---|
| 1145 | else if (!RTStrICmp(pszCtlType, "piix4"))
|
---|
| 1146 | {
|
---|
[23934] | 1147 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX4));
|
---|
[23802] | 1148 | }
|
---|
| 1149 | else if (!RTStrICmp(pszCtlType, "ich6"))
|
---|
| 1150 | {
|
---|
[23934] | 1151 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_ICH6));
|
---|
[23802] | 1152 | }
|
---|
| 1153 | else if (!RTStrICmp(pszCtlType, "i82078"))
|
---|
| 1154 | {
|
---|
[23934] | 1155 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_I82078));
|
---|
[23802] | 1156 | }
|
---|
[25676] | 1157 | else if (!RTStrICmp(pszCtlType, "lsilogicsas"))
|
---|
[25589] | 1158 | {
|
---|
| 1159 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas));
|
---|
| 1160 | }
|
---|
[48983] | 1161 | else if (!RTStrICmp(pszCtlType, "usb"))
|
---|
| 1162 | {
|
---|
| 1163 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_USB));
|
---|
| 1164 | }
|
---|
[57525] | 1165 | else if (!RTStrICmp(pszCtlType, "nvme"))
|
---|
| 1166 | {
|
---|
| 1167 | CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_NVMe));
|
---|
| 1168 | }
|
---|
[23802] | 1169 | else
|
---|
| 1170 | {
|
---|
| 1171 | errorArgument("Invalid --type argument '%s'", pszCtlType);
|
---|
| 1172 | rc = E_FAIL;
|
---|
| 1173 | }
|
---|
| 1174 | }
|
---|
| 1175 | else
|
---|
| 1176 | {
|
---|
| 1177 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 1178 | rc = E_FAIL;
|
---|
| 1179 | }
|
---|
| 1180 | }
|
---|
| 1181 |
|
---|
[48985] | 1182 | if ( (portcount != ~0U)
|
---|
[23802] | 1183 | && SUCCEEDED(rc))
|
---|
| 1184 | {
|
---|
| 1185 | ComPtr<IStorageController> ctl;
|
---|
| 1186 |
|
---|
[32718] | 1187 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 1188 | ctl.asOutParam()));
|
---|
[23802] | 1189 |
|
---|
| 1190 | if (SUCCEEDED(rc))
|
---|
| 1191 | {
|
---|
[48985] | 1192 | CHECK_ERROR(ctl, COMSETTER(PortCount)(portcount));
|
---|
[23802] | 1193 | }
|
---|
| 1194 | else
|
---|
| 1195 | {
|
---|
| 1196 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 1197 | rc = E_FAIL;
|
---|
| 1198 | }
|
---|
| 1199 | }
|
---|
| 1200 |
|
---|
[29480] | 1201 | if ( pszHostIOCache
|
---|
[28764] | 1202 | && SUCCEEDED(rc))
|
---|
| 1203 | {
|
---|
[29480] | 1204 | ComPtr<IStorageController> ctl;
|
---|
[28764] | 1205 |
|
---|
[32718] | 1206 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 1207 | ctl.asOutParam()));
|
---|
[28764] | 1208 |
|
---|
[30403] | 1209 | if (SUCCEEDED(rc))
|
---|
[29480] | 1210 | {
|
---|
[30403] | 1211 | if (!RTStrICmp(pszHostIOCache, "on"))
|
---|
| 1212 | {
|
---|
| 1213 | CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(TRUE));
|
---|
| 1214 | }
|
---|
| 1215 | else if (!RTStrICmp(pszHostIOCache, "off"))
|
---|
| 1216 | {
|
---|
| 1217 | CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(FALSE));
|
---|
| 1218 | }
|
---|
| 1219 | else
|
---|
| 1220 | {
|
---|
| 1221 | errorArgument("Invalid --hostiocache argument '%s'", pszHostIOCache);
|
---|
| 1222 | rc = E_FAIL;
|
---|
| 1223 | }
|
---|
[29480] | 1224 | }
|
---|
| 1225 | else
|
---|
| 1226 | {
|
---|
[30403] | 1227 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
[29480] | 1228 | rc = E_FAIL;
|
---|
| 1229 | }
|
---|
[28764] | 1230 | }
|
---|
[34010] | 1231 |
|
---|
| 1232 | if ( pszBootable
|
---|
| 1233 | && SUCCEEDED(rc))
|
---|
| 1234 | {
|
---|
| 1235 | if (SUCCEEDED(rc))
|
---|
| 1236 | {
|
---|
| 1237 | if (!RTStrICmp(pszBootable, "on"))
|
---|
| 1238 | {
|
---|
| 1239 | CHECK_ERROR(machine, SetStorageControllerBootable(Bstr(pszCtl).raw(), TRUE));
|
---|
| 1240 | }
|
---|
| 1241 | else if (!RTStrICmp(pszBootable, "off"))
|
---|
| 1242 | {
|
---|
| 1243 | CHECK_ERROR(machine, SetStorageControllerBootable(Bstr(pszCtl).raw(), FALSE));
|
---|
| 1244 | }
|
---|
| 1245 | else
|
---|
| 1246 | {
|
---|
[36652] | 1247 | errorArgument("Invalid --bootable argument '%s'", pszBootable);
|
---|
[34010] | 1248 | rc = E_FAIL;
|
---|
| 1249 | }
|
---|
| 1250 | }
|
---|
| 1251 | else
|
---|
| 1252 | {
|
---|
| 1253 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 1254 | rc = E_FAIL;
|
---|
| 1255 | }
|
---|
| 1256 | }
|
---|
[56821] | 1257 |
|
---|
| 1258 | if ( pszCtlNewName
|
---|
| 1259 | && SUCCEEDED(rc))
|
---|
| 1260 | {
|
---|
| 1261 | ComPtr<IStorageController> ctl;
|
---|
| 1262 |
|
---|
| 1263 | CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl).raw(),
|
---|
| 1264 | ctl.asOutParam()));
|
---|
| 1265 |
|
---|
| 1266 | if (SUCCEEDED(rc))
|
---|
| 1267 | {
|
---|
| 1268 | CHECK_ERROR(ctl, COMSETTER(Name)(Bstr(pszCtlNewName).raw()));
|
---|
| 1269 | }
|
---|
| 1270 | else
|
---|
| 1271 | {
|
---|
| 1272 | errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
|
---|
| 1273 | rc = E_FAIL;
|
---|
| 1274 | }
|
---|
| 1275 | }
|
---|
| 1276 |
|
---|
[23802] | 1277 | }
|
---|
| 1278 |
|
---|
| 1279 | /* commit changes */
|
---|
| 1280 | if (SUCCEEDED(rc))
|
---|
[23934] | 1281 | CHECK_ERROR(machine, SaveSettings());
|
---|
[23802] | 1282 |
|
---|
| 1283 | /* it's important to always close sessions */
|
---|
[31070] | 1284 | a->session->UnlockMachine();
|
---|
[23802] | 1285 |
|
---|
[56118] | 1286 | return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
[23802] | 1287 | }
|
---|
| 1288 |
|
---|
| 1289 | #endif /* !VBOX_ONLY_DOCS */
|
---|
[24026] | 1290 |
|
---|