VirtualBox

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

Last change on this file since 29607 was 29480, checked in by vboxsync, 15 years ago

Main: Remove IoBackendType in StorageController and have a boolean setting fUseAsyncHostIOMgr instead; change XML settings and frontends accordingly; change VBoxManage storagectl syntax to --hostiocache on|off as well

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/* $Id: VBoxManageStorageController.cpp 29480 2010-05-14 15:24:19Z vboxsync $ */
2/** @file
3 * VBoxManage - The storage controller related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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 fRunTime = false;
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 Bstr machineuuid (a->argv[0]);
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 'f': // force unmount medium during runtime
137 {
138 fForceUnmount = true;
139 break;
140 }
141
142 default:
143 {
144 errorGetOpt(USAGE_STORAGEATTACH, c, &ValueUnion);
145 rc = E_FAIL;
146 break;
147 }
148 }
149 }
150
151 if ( FAILED(rc)
152 || !pszCtl
153 || port == ~0U
154 || device == ~0U)
155 {
156 errorGetOpt(USAGE_STORAGEATTACH, c, &ValueUnion);
157 return 1;
158 }
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, machine.asOutParam()), 1);
167 }
168 else
169 {
170 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()), 1);
171 machine->COMGETTER(Id)(machineuuid.asOutParam());
172 }
173
174 /* open a session for the VM */
175 rc = a->virtualBox->OpenSession(a->session, machineuuid);
176 if (FAILED(rc))
177 {
178 /* try to open an existing session for the VM */
179 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, machineuuid), 1);
180 fRunTime = true;
181 }
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 /* get the mutable session machine */
202 a->session->COMGETTER(Machine)(machine.asOutParam());
203
204 /* check if the storage controller is present */
205 rc = machine->GetStorageControllerByName(Bstr(pszCtl), 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), 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), port, device, mediumAttachment.asOutParam());
240 if (SUCCEEDED(rc))
241 {
242 mediumAttachment->COMGETTER(Type)(&deviceType);
243
244 if ( (deviceType == DeviceType_DVD)
245 || (deviceType == DeviceType_Floppy))
246 {
247 /* just unmount the floppy/dvd */
248 CHECK_ERROR(machine, MountMedium(Bstr(pszCtl), port, device, Bstr(""), fForceUnmount));
249 }
250 }
251
252 if ( FAILED(rc)
253 || !( deviceType == DeviceType_DVD
254 || deviceType == DeviceType_Floppy))
255 {
256 errorArgument("No DVD/Floppy Drive attached to the controller '%s'"
257 "at the port: %u, device: %u", pszCtl, port, device);
258 goto leave;
259 }
260
261 }
262 else
263 {
264 StorageBus_T storageBus = StorageBus_Null;
265 DeviceType_T deviceType = DeviceType_Null;
266 com::SafeArray <DeviceType_T> saDeviceTypes;
267 ULONG driveCheck = 0;
268
269 /* check if the device type is supported by the controller */
270 CHECK_ERROR(storageCtl, COMGETTER(Bus)(&storageBus));
271 CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
272 for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
273 {
274 if ( (saDeviceTypes[i] == DeviceType_DVD)
275 || (saDeviceTypes[i] == DeviceType_Floppy))
276 driveCheck++;
277 }
278
279 if (!driveCheck)
280 {
281 errorArgument("The Attachment is not supported by the Storage Controller: '%s'", pszCtl);
282 goto leave;
283 }
284
285 if (storageBus == StorageBus_Floppy)
286 deviceType = DeviceType_Floppy;
287 else
288 deviceType = DeviceType_DVD;
289
290 /* attach a empty floppy/dvd drive after removing previous attachment */
291 machine->DetachDevice(Bstr(pszCtl), port, device);
292 CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl), port, device, deviceType, Bstr("")));
293 }
294 }
295 else
296 {
297 {
298 /*
299 * try to determine the type of the drive from the
300 * storage controller chipset, the attachment and
301 * the medium being attached
302 */
303 StorageControllerType_T ctlType = StorageControllerType_Null;
304 CHECK_ERROR(storageCtl, COMGETTER(ControllerType)(&ctlType));
305 if (ctlType == StorageControllerType_I82078)
306 {
307 /*
308 * floppy controller found so lets assume the medium
309 * given by the user is also a floppy image or floppy
310 * host drive
311 */
312 pszType = "fdd";
313 }
314 else
315 {
316 /*
317 * for SATA/SCSI/IDE it is hard to tell if it is a harddisk or
318 * a dvd being attached so lets check if the medium attachment
319 * and the medium, both are of same type. if yes then we are
320 * sure of its type and don't need the user to enter it manually
321 * else ask the user for the type.
322 */
323 ComPtr<IMediumAttachment> mediumAttachement;
324 rc = machine->GetMediumAttachment(Bstr(pszCtl), port, device, mediumAttachement.asOutParam());
325 if (SUCCEEDED(rc))
326 {
327 DeviceType_T deviceType;
328 mediumAttachement->COMGETTER(Type)(&deviceType);
329
330 if (deviceType == DeviceType_DVD)
331 {
332 Bstr uuid(pszMedium);
333 ComPtr<IMedium> dvdMedium;
334 /* first assume it's a UUID */
335 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
336 if (FAILED(rc) || !dvdMedium)
337 {
338 /* must be a filename, check if it's in the collection */
339 a->virtualBox->FindDVDImage(Bstr(pszMedium), dvdMedium.asOutParam());
340 }
341 if (dvdMedium)
342 {
343 /*
344 * ok so the medium and attachment both are DVD's so it is
345 * safe to assume that we are dealing with a DVD here
346 */
347 pszType = "dvddrive";
348 }
349 }
350 else if (deviceType == DeviceType_HardDisk)
351 {
352 Bstr uuid(pszMedium);
353 ComPtr<IMedium> hardDisk;
354 /* first assume it's a UUID */
355 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
356 if (FAILED(rc) || !hardDisk)
357 {
358 /* must be a filename, check if it's in the collection */
359 a->virtualBox->FindHardDisk(Bstr(pszMedium), hardDisk.asOutParam());
360 }
361 if (hardDisk)
362 {
363 /*
364 * ok so the medium and attachment both are hdd's so it is
365 * safe to assume that we are dealing with a hdd here
366 */
367 pszType = "hdd";
368 }
369 }
370 }
371 }
372 /* for all other cases lets ask the user what type of drive it is */
373 }
374
375 if (!pszType)
376 {
377 errorSyntax(USAGE_STORAGEATTACH, "Argument --type not specified\n");
378 goto leave;
379 }
380
381 /* check if the device type is supported by the controller */
382 {
383 StorageBus_T storageBus = StorageBus_Null;
384 com::SafeArray <DeviceType_T> saDeviceTypes;
385
386 CHECK_ERROR(storageCtl, COMGETTER(Bus)(&storageBus));
387 CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes)));
388 if (SUCCEEDED(rc))
389 {
390 ULONG driveCheck = 0;
391 for (size_t i = 0; i < saDeviceTypes.size(); ++ i)
392 {
393 if ( !RTStrICmp(pszType, "dvddrive")
394 && (saDeviceTypes[i] == DeviceType_DVD))
395 driveCheck++;
396
397 if ( !RTStrICmp(pszType, "hdd")
398 && (saDeviceTypes[i] == DeviceType_HardDisk))
399 driveCheck++;
400
401 if ( !RTStrICmp(pszType, "fdd")
402 && (saDeviceTypes[i] == DeviceType_Floppy))
403 driveCheck++;
404 }
405 if (!driveCheck)
406 {
407 errorArgument("The Attachment is not supported by the Storage Controller: '%s'", pszCtl);
408 goto leave;
409 }
410 }
411 else
412 goto leave;
413 }
414
415 if (!RTStrICmp(pszType, "dvddrive"))
416 {
417 Bstr uuid;
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), port, device, mediumAttachement.asOutParam());
426 if (SUCCEEDED(rc))
427 {
428 DeviceType_T deviceType;
429 mediumAttachement->COMGETTER(Type)(&deviceType);
430
431 if (deviceType != DeviceType_DVD)
432 {
433 machine->DetachDevice(Bstr(pszCtl), port, device);
434 rc = machine->AttachDevice(Bstr(pszCtl), port, device, DeviceType_DVD, Bstr(""));
435 }
436 }
437 else
438 {
439 rc = machine->AttachDevice(Bstr(pszCtl), port, device, DeviceType_DVD, Bstr(""));
440 }
441 }
442
443 /* Attach/Detach the dvd medium now */
444 do
445 {
446 /* host drive? */
447 if (!RTStrNICmp(pszMedium, "host:", 5))
448 {
449 ComPtr<IHost> host;
450 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
451 rc = host->FindHostDVDDrive(Bstr(pszMedium + 5), dvdMedium.asOutParam());
452 if (!dvdMedium)
453 {
454 /* 2nd try: try with the real name, important on Linux+libhal */
455 char szPathReal[RTPATH_MAX];
456 if (RT_FAILURE(RTPathReal(pszMedium + 5, szPathReal, sizeof(szPathReal))))
457 {
458 errorArgument("Invalid host DVD drive name \"%s\"", pszMedium + 5);
459 rc = E_FAIL;
460 break;
461 }
462 rc = host->FindHostDVDDrive(Bstr(szPathReal), dvdMedium.asOutParam());
463 if (!dvdMedium)
464 {
465 errorArgument("Invalid host DVD drive name \"%s\"", pszMedium + 5);
466 rc = E_FAIL;
467 break;
468 }
469 }
470 }
471 else
472 {
473 /* first assume it's a UUID */
474 uuid = pszMedium;
475 rc = a->virtualBox->GetDVDImage(uuid, dvdMedium.asOutParam());
476 if (FAILED(rc) || !dvdMedium)
477 {
478 /* must be a filename, check if it's in the collection */
479 rc = a->virtualBox->FindDVDImage(Bstr(pszMedium), dvdMedium.asOutParam());
480 /* not registered, do that on the fly */
481 if (!dvdMedium)
482 {
483 Bstr emptyUUID;
484 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(pszMedium),
485 emptyUUID, dvdMedium.asOutParam()));
486 }
487 }
488 if (!dvdMedium)
489 {
490 errorArgument("Invalid UUID or filename \"%s\"", pszMedium);
491 rc = E_FAIL;
492 break;
493 }
494 }
495 } while (0);
496
497 if (dvdMedium)
498 {
499 dvdMedium->COMGETTER(Id)(uuid.asOutParam());
500 CHECK_ERROR(machine, MountMedium(Bstr(pszCtl), port, device, uuid, fForceUnmount));
501 }
502 }
503 else if ( !RTStrICmp(pszType, "hdd")
504 && !fRunTime)
505 {
506 ComPtr<IMediumAttachment> mediumAttachement;
507
508 /* if there is anything attached at the given location, remove it */
509 machine->DetachDevice(Bstr(pszCtl), port, device);
510
511 /* first guess is that it's a UUID */
512 Bstr uuid(pszMedium);
513 ComPtr<IMedium> hardDisk;
514 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
515
516 /* not successful? Then it must be a filename */
517 if (!hardDisk)
518 {
519 rc = a->virtualBox->FindHardDisk(Bstr(pszMedium), hardDisk.asOutParam());
520 if (FAILED(rc))
521 {
522 /* open the new hard disk object */
523 CHECK_ERROR(a->virtualBox,
524 OpenHardDisk(Bstr(pszMedium),
525 AccessMode_ReadWrite, false, Bstr(""),
526 false, Bstr(""), hardDisk.asOutParam()));
527 }
528 }
529
530 if (hardDisk)
531 {
532 hardDisk->COMGETTER(Id)(uuid.asOutParam());
533 CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl), port, device, DeviceType_HardDisk, uuid));
534 }
535 else
536 {
537 errorArgument("Invalid UUID or filename \"%s\"", pszMedium);
538 rc = E_FAIL;
539 }
540 }
541 else if (!RTStrICmp(pszType, "fdd"))
542 {
543 Bstr uuid;
544 ComPtr<IMedium> floppyMedium;
545 ComPtr<IMediumAttachment> floppyAttachment;
546 machine->GetMediumAttachment(Bstr(pszCtl), port, device, floppyAttachment.asOutParam());
547
548 if ( !fRunTime
549 && !floppyAttachment)
550 CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl), port, device, DeviceType_Floppy, Bstr("")));
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), floppyMedium.asOutParam());
559 if (!floppyMedium)
560 {
561 errorArgument("Invalid host floppy drive name \"%s\"", pszMedium + 5);
562 rc = E_FAIL;
563 }
564 }
565 else
566 {
567 /* first assume it's a UUID */
568 uuid = pszMedium;
569 rc = a->virtualBox->GetFloppyImage(uuid, floppyMedium.asOutParam());
570 if (FAILED(rc) || !floppyMedium)
571 {
572 /* must be a filename, check if it's in the collection */
573 rc = a->virtualBox->FindFloppyImage(Bstr(pszMedium), floppyMedium.asOutParam());
574 /* not registered, do that on the fly */
575 if (!floppyMedium)
576 {
577 Bstr emptyUUID;
578 CHECK_ERROR(a->virtualBox,
579 OpenFloppyImage(Bstr(pszMedium),
580 emptyUUID,
581 floppyMedium.asOutParam()));
582 }
583 }
584
585 if (!floppyMedium)
586 {
587 errorArgument("Invalid UUID or filename \"%s\"", pszMedium);
588 rc = E_FAIL;
589 }
590 }
591
592 if (floppyMedium)
593 {
594 floppyMedium->COMGETTER(Id)(uuid.asOutParam());
595 CHECK_ERROR(machine, MountMedium(Bstr(pszCtl), port, device, uuid, 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), port, device, mattach.asOutParam()));
611
612 if (SUCCEEDED(rc))
613 {
614 if (!RTStrICmp(pszPassThrough, "on"))
615 {
616 CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl), port, device, TRUE));
617 }
618 else if (!RTStrICmp(pszPassThrough, "off"))
619 {
620 CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl), port, device, FALSE));
621 }
622 else
623 {
624 errorArgument("Invalid --passthrough argument '%s'", pszPassThrough);
625 rc = E_FAIL;
626 }
627 }
628 else
629 {
630 errorArgument("Couldn't find the controller attachment for the controller '%s'\n", pszCtl);
631 rc = E_FAIL;
632 }
633 }
634
635 /* commit changes */
636 if (SUCCEEDED(rc))
637 CHECK_ERROR(machine, SaveSettings());
638
639leave:
640 /* it's important to always close sessions */
641 a->session->Close();
642
643 return SUCCEEDED(rc) ? 0 : 1;
644}
645
646
647static const RTGETOPTDEF g_aStorageControllerOptions[] =
648{
649 { "--name", 'n', RTGETOPT_REQ_STRING },
650 { "--add", 'a', RTGETOPT_REQ_STRING },
651 { "--controller", 'c', RTGETOPT_REQ_STRING },
652 { "--sataideemulation", 'e', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_INDEX },
653 { "--sataportcount", 'p', RTGETOPT_REQ_UINT32 },
654 { "--remove", 'r', RTGETOPT_REQ_NOTHING },
655 { "--hostiocache", 'i', RTGETOPT_REQ_STRING },
656};
657
658int handleStorageController(HandlerArg *a)
659{
660 int c;
661 HRESULT rc = S_OK;
662 const char *pszCtl = NULL;
663 const char *pszBusType = NULL;
664 const char *pszCtlType = NULL;
665 const char *pszHostIOCache = NULL;
666 ULONG satabootdev = ~0U;
667 ULONG sataidedev = ~0U;
668 ULONG sataportcount = ~0U;
669 bool fRemoveCtl = false;
670 Bstr machineuuid (a->argv[0]);
671 ComPtr<IMachine> machine;
672 RTGETOPTUNION ValueUnion;
673 RTGETOPTSTATE GetState;
674
675 if (a->argc < 4)
676 return errorSyntax(USAGE_STORAGECONTROLLER, "Too few parameters");
677
678 RTGetOptInit (&GetState, a->argc, a->argv, g_aStorageControllerOptions,
679 RT_ELEMENTS(g_aStorageControllerOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
680
681 while ( SUCCEEDED(rc)
682 && (c = RTGetOpt(&GetState, &ValueUnion)))
683 {
684 switch (c)
685 {
686 case 'n': // controller name
687 {
688 if (ValueUnion.psz)
689 pszCtl = ValueUnion.psz;
690 else
691 rc = E_FAIL;
692 break;
693 }
694
695 case 'a': // controller bus type <ide/sata/scsi/floppy>
696 {
697 if (ValueUnion.psz)
698 pszBusType = ValueUnion.psz;
699 else
700 rc = E_FAIL;
701 break;
702 }
703
704 case 'c': // controller <lsilogic/buslogic/intelahci/piix3/piix4/ich6/i82078>
705 {
706 if (ValueUnion.psz)
707 pszCtlType = ValueUnion.psz;
708 else
709 rc = E_FAIL;
710 break;
711 }
712
713 case 'e': // sataideemulation
714 {
715 satabootdev = GetState.uIndex;
716 sataidedev = ValueUnion.u32;
717 break;
718 }
719
720 case 'p': // sataportcount
721 {
722 sataportcount = ValueUnion.u32;
723 break;
724 }
725
726 case 'r': // remove controller
727 {
728 fRemoveCtl = true;
729 break;
730 }
731
732 case 'i':
733 {
734 pszHostIOCache = ValueUnion.psz;
735 break;
736 }
737
738 default:
739 {
740 errorGetOpt(USAGE_STORAGECONTROLLER, c, &ValueUnion);
741 rc = E_FAIL;
742 break;
743 }
744 }
745 }
746
747 if (FAILED(rc))
748 return 1;
749
750 /* try to find the given machine */
751 if (!Guid(machineuuid).isEmpty())
752 {
753 CHECK_ERROR_RET(a->virtualBox, GetMachine (machineuuid, machine.asOutParam()), 1);
754 }
755 else
756 {
757 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()), 1);
758 machine->COMGETTER(Id)(machineuuid.asOutParam());
759 }
760
761 /* open a session for the VM */
762 CHECK_ERROR_RET(a->virtualBox, OpenSession (a->session, machineuuid), 1);
763
764 /* get the mutable session machine */
765 a->session->COMGETTER(Machine)(machine.asOutParam());
766
767 if (!pszCtl)
768 {
769 /* it's important to always close sessions */
770 a->session->Close();
771 errorSyntax(USAGE_STORAGECONTROLLER, "Storage Controller Name not specified\n");
772 return 1;
773 }
774
775 if (fRemoveCtl)
776 {
777 com::SafeIfaceArray<IMediumAttachment> mediumAttachments;
778
779 CHECK_ERROR(machine,
780 GetMediumAttachmentsOfController(Bstr(pszCtl),
781 ComSafeArrayAsOutParam(mediumAttachments)));
782 for (size_t i = 0; i < mediumAttachments.size(); ++ i)
783 {
784 ComPtr<IMediumAttachment> mediumAttach = mediumAttachments[i];
785 LONG port = 0;
786 LONG device = 0;
787
788 CHECK_ERROR(mediumAttach, COMGETTER(Port)(&port));
789 CHECK_ERROR(mediumAttach, COMGETTER(Device)(&device));
790 CHECK_ERROR(machine, DetachDevice(Bstr(pszCtl), port, device));
791 }
792
793 if (SUCCEEDED(rc))
794 CHECK_ERROR(machine, RemoveStorageController(Bstr(pszCtl)));
795 else
796 errorArgument("Can't detach the devices connected to '%s' Controller\n"
797 "and thus its removal failed.", pszCtl);
798 }
799 else
800 {
801 if (pszBusType)
802 {
803 ComPtr<IStorageController> ctl;
804
805 if (!RTStrICmp(pszBusType, "ide"))
806 {
807 CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl), StorageBus_IDE, ctl.asOutParam()));
808 }
809 else if (!RTStrICmp(pszBusType, "sata"))
810 {
811 CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl), StorageBus_SATA, ctl.asOutParam()));
812 }
813 else if (!RTStrICmp(pszBusType, "scsi"))
814 {
815 CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl), StorageBus_SCSI, ctl.asOutParam()));
816 }
817 else if (!RTStrICmp(pszBusType, "floppy"))
818 {
819 CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl), StorageBus_Floppy, ctl.asOutParam()));
820 }
821 else if (!RTStrICmp(pszBusType, "sas"))
822 {
823 CHECK_ERROR(machine, AddStorageController(Bstr(pszCtl), StorageBus_SAS, ctl.asOutParam()));
824 }
825 else
826 {
827 errorArgument("Invalid --add argument '%s'", pszBusType);
828 rc = E_FAIL;
829 }
830 }
831
832 if ( pszCtlType
833 && SUCCEEDED(rc))
834 {
835 ComPtr<IStorageController> ctl;
836
837 CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl), ctl.asOutParam()));
838
839 if (SUCCEEDED(rc))
840 {
841 if (!RTStrICmp(pszCtlType, "lsilogic"))
842 {
843 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogic));
844 }
845 else if (!RTStrICmp(pszCtlType, "buslogic"))
846 {
847 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_BusLogic));
848 }
849 else if (!RTStrICmp(pszCtlType, "intelahci"))
850 {
851 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_IntelAhci));
852 }
853 else if (!RTStrICmp(pszCtlType, "piix3"))
854 {
855 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX3));
856 }
857 else if (!RTStrICmp(pszCtlType, "piix4"))
858 {
859 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_PIIX4));
860 }
861 else if (!RTStrICmp(pszCtlType, "ich6"))
862 {
863 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_ICH6));
864 }
865 else if (!RTStrICmp(pszCtlType, "i82078"))
866 {
867 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_I82078));
868 }
869 else if (!RTStrICmp(pszCtlType, "lsilogicsas"))
870 {
871 CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_LsiLogicSas));
872 }
873 else
874 {
875 errorArgument("Invalid --type argument '%s'", pszCtlType);
876 rc = E_FAIL;
877 }
878 }
879 else
880 {
881 errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
882 rc = E_FAIL;
883 }
884 }
885
886 if ( (sataportcount != ~0U)
887 && SUCCEEDED(rc))
888 {
889 ComPtr<IStorageController> ctl;
890
891 CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl), ctl.asOutParam()));
892
893 if (SUCCEEDED(rc))
894 {
895 CHECK_ERROR(ctl, COMSETTER(PortCount)(sataportcount));
896 }
897 else
898 {
899 errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
900 rc = E_FAIL;
901 }
902 }
903
904 if ( (sataidedev != ~0U)
905 && (satabootdev != ~0U)
906 && SUCCEEDED(rc))
907 {
908 ComPtr<IStorageController> ctl;
909
910 CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl), ctl.asOutParam()));
911
912 if (SUCCEEDED(rc))
913 {
914 CHECK_ERROR(ctl, SetIDEEmulationPort(satabootdev, sataidedev));
915 }
916 else
917 {
918 errorArgument("Couldn't find the controller with the name: '%s'\n", pszCtl);
919 rc = E_FAIL;
920 }
921 }
922
923 if ( pszHostIOCache
924 && SUCCEEDED(rc))
925 {
926 ComPtr<IStorageController> ctl;
927
928 CHECK_ERROR(machine, GetStorageControllerByName(Bstr(pszCtl), ctl.asOutParam()));
929
930 if (!RTStrICmp(pszHostIOCache, "on"))
931 {
932 CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(TRUE));
933 }
934 else if (!RTStrICmp(pszHostIOCache, "off"))
935 {
936 CHECK_ERROR(ctl, COMSETTER(UseHostIOCache)(FALSE));
937 }
938 else
939 {
940 errorArgument("Invalid --hostiocache argument '%s'", pszHostIOCache);
941 rc = E_FAIL;
942 }
943 }
944 }
945
946 /* commit changes */
947 if (SUCCEEDED(rc))
948 CHECK_ERROR(machine, SaveSettings());
949
950 /* it's important to always close sessions */
951 a->session->Close();
952
953 return SUCCEEDED(rc) ? 0 : 1;
954}
955
956#endif /* !VBOX_ONLY_DOCS */
957
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