VirtualBox

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

最後變更 在這個檔案從35136是 35136,由 vboxsync 提交於 14 年 前

Frontends/VBoxManage: small functionality/error handling fix with setting the medium type with storageattach

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette