VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp

Last change on this file was 101035, checked in by vboxsync, 8 months ago

Initial commit (based draft v2 / on patch v5) for implementing platform architecture support for x86 and ARM. bugref:10384

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

© 2023 Oracle
ContactPrivacy policyTerms of Use