VirtualBox

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

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

Main: Introduce a per controller setting to switch to the unbuffered async I/O interface (UseNewIo). Configurable through VBoxManage, default is still buffered

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