VirtualBox

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

Last change on this file since 30734 was 30403, checked in by vboxsync, 15 years ago

VBoxManage: Fix crash when changing the I/O cache option for a non existant controller

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