VirtualBox

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

Last change on this file since 34587 was 34587, checked in by vboxsync, 14 years ago

Main: Bandwidth groups for disks (and later network)

This introduces two new interfaces. The first one named IBandwidthGroup
represents one I/O limit and can be assigned to several mediums which
share this limit (which works only for harddisk images with the disabled
host cache).
The second one IBandwdithControl manages the groups and can create new ones
and destroy them if not required anymore.

VBoxManage: commands to access the bandwidth groups

Syntax:
VBoxManage storageattach <uuid|vmname>

...
--bandwidthgroup <name>

--bandwidthgroup assigns the specified device to the given group.

VBoxManage bandwidthctl <uuid|vmname>

--name <name>
--add disk|network
--limit <megabytes per second>
--delete

The --name parameter gives the name of the bandwidth group.
--add creates a new group of the given type (only disk is implemented so far)

with the given name.

--limit sets the limit to the given amount of MB/s

Note that limit can be changed while the VM is running. The VM
will immediately pick up the new limit for the given group name.

--delete deletes the group with the given name if it isn't used anymore.

Trying to delete a still used group will result in an error.

Example:

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 20
Creates a group named Test having a 20 MB/s limit.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup Limit
Adds a new disk to the SATA controller and assigns the bandwidth group Limit to it.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup none
Removes the bandwidth limit from the disk.

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 10
Changes the limit of bandwidth group Limit to 10 MB/s. If the VM is running the limit will be picked up
immediately.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette