VirtualBox

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

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

Main: have Machine::MountMedium() behave like AttachDevice (use IMedium* pointer instead of UUID); add missing saveSettings calls there

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