VirtualBox

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

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

Main: rename ISession::close() to ISession::unlockMachine(); API documentation

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