STDMETHODIMP Guest::COMGETTER(AdditionsVersion)(BSTR *a_pbstrAdditionsVersion) { CheckComArgOutPointerValid(a_pbstrAdditionsVersion); AutoCaller autoCaller(this); HRESULT hrc = autoCaller.rc(); if (SUCCEEDED(hrc)) { AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); /* * Return the ReportGuestInfo2 version info if available. */ if ( !mData.mAdditionsVersionNew.isEmpty() || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None) mData.mAdditionsVersionNew.cloneTo(a_pbstrAdditionsVersion); else { /* * If we're running older guest additions (< 3.2.0) try get it from * the guest properties. Detected switched around Version and * Revision in early 3.1.x releases (see r57115). */ ComPtr<IMachine> ptrMachine = mParent->machine(); alock.release(); /* No need to hold this during the IPC fun. */ Bstr bstr; hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam()); if ( SUCCEEDED(hrc) && !bstr.isEmpty()) { Utf8Str str(bstr); if (str.count('.') == 0) hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam()); str = bstr; if (str.count('.') != 2) hrc = E_FAIL; } if (SUCCEEDED(hrc)) bstr.detachTo(a_pbstrAdditionsVersion); else { /* Returning 1.4 is better than nothing. */ alock.acquire(); mData.mInterfaceVersion.cloneTo(a_pbstrAdditionsVersion); hrc = S_OK; } } } return hrc; }
RTEXITCODE handleStorageAttach(HandlerArg *a) { int c = VERR_INTERNAL_ERROR; /* initialized to shut up gcc */ HRESULT rc = S_OK; ULONG port = ~0U; ULONG device = ~0U; bool fForceUnmount = false; bool fSetMediumType = false; bool fSetNewUuid = false; bool fSetNewParentUuid = false; MediumType_T enmMediumType = MediumType_Normal; Bstr bstrComment; const char *pszCtl = NULL; DeviceType_T devTypeRequested = DeviceType_Null; const char *pszMedium = NULL; const char *pszPassThrough = NULL; const char *pszTempEject = NULL; const char *pszNonRotational = NULL; const char *pszDiscard = NULL; const char *pszHotPluggable = NULL; const char *pszBandwidthGroup = NULL; Bstr bstrNewUuid; Bstr bstrNewParentUuid; // iSCSI options Bstr bstrServer; Bstr bstrTarget; Bstr bstrPort; Bstr bstrLun; Bstr bstrUsername; Bstr bstrPassword; Bstr bstrInitiator; Bstr bstrIso; Utf8Str strIso; bool fIntNet = false; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; ComPtr<IMachine> machine; ComPtr<IStorageController> storageCtl; ComPtr<ISystemProperties> systemProperties; RTGetOptInit(&GetState, a->argc, a->argv, g_aStorageAttachOptions, RT_ELEMENTS(g_aStorageAttachOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); while ( SUCCEEDED(rc) && (c = RTGetOpt(&GetState, &ValueUnion))) { switch (c) { case 's': // storage controller name { if (ValueUnion.psz) pszCtl = ValueUnion.psz; else rc = E_FAIL; break; } case 'p': // port { port = ValueUnion.u32; break; } case 'd': // device { device = ValueUnion.u32; break; } case 'm': // medium <none|emptydrive|additions|uuid|filename|host:<drive>|iSCSI> { if (ValueUnion.psz) pszMedium = ValueUnion.psz; else rc = E_FAIL; break; } case 't': // type <dvddrive|hdd|fdd> { if (ValueUnion.psz) { if (!RTStrICmp(ValueUnion.psz, "hdd")) devTypeRequested = DeviceType_HardDisk; else if (!RTStrICmp(ValueUnion.psz, "fdd")) devTypeRequested = DeviceType_Floppy; else if (!RTStrICmp(ValueUnion.psz, "dvddrive")) devTypeRequested = DeviceType_DVD; else return errorArgument("Invalid --type argument '%s'", ValueUnion.psz); } else rc = E_FAIL; break; } case 'h': // passthrough <on|off> { if (ValueUnion.psz) pszPassThrough = ValueUnion.psz; else rc = E_FAIL; break; } case 'e': // tempeject <on|off> { if (ValueUnion.psz) pszTempEject = ValueUnion.psz; else rc = E_FAIL; break; } case 'n': // nonrotational <on|off> { if (ValueUnion.psz) pszNonRotational = ValueUnion.psz; else rc = E_FAIL; break; } case 'u': // discard <on|off> { if (ValueUnion.psz) pszDiscard = ValueUnion.psz; else rc = E_FAIL; break; } case 'o': // hotpluggable <on|off> { if (ValueUnion.psz) pszHotPluggable = ValueUnion.psz; else rc = E_FAIL; break; } case 'b': // bandwidthgroup <name> { if (ValueUnion.psz) pszBandwidthGroup = ValueUnion.psz; else rc = E_FAIL; break; } case 'f': // force unmount medium during runtime { fForceUnmount = true; break; } case 'C': if (ValueUnion.psz) bstrComment = ValueUnion.psz; else rc = E_FAIL; break; case 'q': if (ValueUnion.psz) { bstrNewUuid = ValueUnion.psz; fSetNewUuid = true; } else rc = E_FAIL; break; case 'Q': if (ValueUnion.psz) { bstrNewParentUuid = ValueUnion.psz; fSetNewParentUuid = true; } else rc = E_FAIL; break; case 'S': // --server bstrServer = ValueUnion.psz; break; case 'T': // --target bstrTarget = ValueUnion.psz; break; case 'P': // --tport bstrPort = ValueUnion.psz; break; case 'L': // --lun bstrLun = ValueUnion.psz; break; case 'E': // --encodedlun bstrLun = BstrFmt("enc%s", ValueUnion.psz); break; case 'U': // --username bstrUsername = ValueUnion.psz; break; case 'W': // --password bstrPassword = ValueUnion.psz; break; case 'N': // --initiator bstrInitiator = ValueUnion.psz; break; case 'M': // --type { int vrc = parseMediumType(ValueUnion.psz, &enmMediumType); if (RT_FAILURE(vrc)) return errorArgument("Invalid medium type '%s'", ValueUnion.psz); fSetMediumType = true; break; } case 'I': // --intnet fIntNet = true; break; default: { errorGetOpt(USAGE_STORAGEATTACH, c, &ValueUnion); rc = E_FAIL; break; } } } if (FAILED(rc)) return RTEXITCODE_FAILURE; if (!pszCtl) return errorSyntax(USAGE_STORAGEATTACH, "Storage controller name not specified"); /* get the virtualbox system properties */ CHECK_ERROR_RET(a->virtualBox, COMGETTER(SystemProperties)(systemProperties.asOutParam()), RTEXITCODE_FAILURE); // find the machine, lock it, get the mutable session machine CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(), machine.asOutParam()), RTEXITCODE_FAILURE); CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE); SessionType_T st; CHECK_ERROR_RET(a->session, COMGETTER(Type)(&st), RTEXITCODE_FAILURE); a->session->COMGETTER(Machine)(machine.asOutParam()); try { bool fRunTime = (st == SessionType_Shared); if (fRunTime) { if (pszPassThrough) throw Utf8Str("Drive passthrough state cannot be changed while the VM is running\n"); else if (pszBandwidthGroup) throw Utf8Str("Bandwidth group cannot be changed while the VM is running\n"); } /* check if the storage controller is present */ rc = machine->GetStorageControllerByName(Bstr(pszCtl).raw(), storageCtl.asOutParam()); if (FAILED(rc)) throw Utf8StrFmt("Could not find a controller named '%s'\n", pszCtl); StorageBus_T storageBus = StorageBus_Null; CHECK_ERROR_RET(storageCtl, COMGETTER(Bus)(&storageBus), RTEXITCODE_FAILURE); ULONG maxPorts = 0; CHECK_ERROR_RET(systemProperties, GetMaxPortCountForStorageBus(storageBus, &maxPorts), RTEXITCODE_FAILURE); ULONG maxDevices = 0; CHECK_ERROR_RET(systemProperties, GetMaxDevicesPerPortForStorageBus(storageBus, &maxDevices), RTEXITCODE_FAILURE); if (port == ~0U) { if (maxPorts == 1) port = 0; else return errorSyntax(USAGE_STORAGEATTACH, "Port not specified"); } if (device == ~0U) { if (maxDevices == 1) device = 0; else return errorSyntax(USAGE_STORAGEATTACH, "Device not specified"); } /* for sata controller check if the port count is big enough * to accommodate the current port which is being assigned * else just increase the port count */ { ULONG ulPortCount = 0; ULONG ulMaxPortCount = 0; CHECK_ERROR(storageCtl, COMGETTER(MaxPortCount)(&ulMaxPortCount)); CHECK_ERROR(storageCtl, COMGETTER(PortCount)(&ulPortCount)); if ( (ulPortCount != ulMaxPortCount) && (port >= ulPortCount) && (port < ulMaxPortCount)) CHECK_ERROR(storageCtl, COMSETTER(PortCount)(port + 1)); } StorageControllerType_T ctlType = StorageControllerType_Null; CHECK_ERROR(storageCtl, COMGETTER(ControllerType)(&ctlType)); if (!RTStrICmp(pszMedium, "none")) { CHECK_ERROR(machine, DetachDevice(Bstr(pszCtl).raw(), port, device)); } else if (!RTStrICmp(pszMedium, "emptydrive")) { if (fRunTime) { ComPtr<IMediumAttachment> mediumAttachment; DeviceType_T deviceType = DeviceType_Null; rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mediumAttachment.asOutParam()); if (SUCCEEDED(rc)) { mediumAttachment->COMGETTER(Type)(&deviceType); if ( (deviceType == DeviceType_DVD) || (deviceType == DeviceType_Floppy)) { /* just unmount the floppy/dvd */ CHECK_ERROR(machine, UnmountMedium(Bstr(pszCtl).raw(), port, device, fForceUnmount)); } } else if (devTypeRequested == DeviceType_DVD) { /* * Try to attach an empty DVD drive as a hotplug operation. * Main will complain if the controller doesn't support hotplugging. */ CHECK_ERROR(machine, AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device, devTypeRequested)); deviceType = DeviceType_DVD; /* To avoid the error message below. */ } if ( FAILED(rc) || !( deviceType == DeviceType_DVD || deviceType == DeviceType_Floppy) ) throw Utf8StrFmt("No DVD/Floppy Drive attached to the controller '%s'" "at the port: %u, device: %u", pszCtl, port, device); } else { DeviceType_T deviceType = DeviceType_Null; com::SafeArray <DeviceType_T> saDeviceTypes; ULONG driveCheck = 0; /* check if the device type is supported by the controller */ CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes))); for (size_t i = 0; i < saDeviceTypes.size(); ++ i) { if ( (saDeviceTypes[i] == DeviceType_DVD) || (saDeviceTypes[i] == DeviceType_Floppy)) driveCheck++; } if (!driveCheck) throw Utf8StrFmt("The attachment is not supported by the storage controller '%s'", pszCtl); if (storageBus == StorageBus_Floppy) deviceType = DeviceType_Floppy; else deviceType = DeviceType_DVD; /* attach a empty floppy/dvd drive after removing previous attachment */ machine->DetachDevice(Bstr(pszCtl).raw(), port, device); CHECK_ERROR(machine, AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device, deviceType)); } } // end if (!RTStrICmp(pszMedium, "emptydrive")) else { ComPtr<IMedium> pMedium2Mount; // not "none", not "emptydrive": then it must be a UUID or filename or hostdrive or iSCSI; // for all these we first need to know the type of drive we're attaching to { /* * try to determine the type of the drive from the * storage controller chipset, the attachment and * the medium being attached */ if (ctlType == StorageControllerType_I82078) // floppy controller devTypeRequested = DeviceType_Floppy; else { /* * for SATA/SCSI/IDE it is hard to tell if it is a harddisk or * a dvd being attached so lets check if the medium attachment * and the medium, both are of same type. if yes then we are * sure of its type and don't need the user to enter it manually * else ask the user for the type. */ ComPtr<IMediumAttachment> mediumAttachment; rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mediumAttachment.asOutParam()); if (SUCCEEDED(rc)) { DeviceType_T deviceType; mediumAttachment->COMGETTER(Type)(&deviceType); if (pszMedium) { if (!RTStrICmp(pszMedium, "additions")) { ComPtr<ISystemProperties> pProperties; CHECK_ERROR(a->virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam())); CHECK_ERROR(pProperties, COMGETTER(DefaultAdditionsISO)(bstrIso.asOutParam())); strIso = Utf8Str(bstrIso); if (strIso.isEmpty()) throw Utf8Str("Cannot find the Guest Additions ISO image\n"); pszMedium = strIso.c_str(); if (devTypeRequested == DeviceType_Null) devTypeRequested = DeviceType_DVD; } ComPtr<IMedium> pExistingMedium; rc = openMedium(a, pszMedium, deviceType, AccessMode_ReadWrite, pExistingMedium, false /* fForceNewUuidOnOpen */, true /* fSilent */); if (SUCCEEDED(rc) && pExistingMedium) { if ( (deviceType == DeviceType_DVD) || (deviceType == DeviceType_HardDisk) ) devTypeRequested = deviceType; } } else devTypeRequested = deviceType; } } } if (devTypeRequested == DeviceType_Null) // still the initializer value? throw Utf8Str("Argument --type must be specified\n"); /* check if the device type is supported by the controller */ { com::SafeArray <DeviceType_T> saDeviceTypes; CHECK_ERROR(systemProperties, GetDeviceTypesForStorageBus(storageBus, ComSafeArrayAsOutParam(saDeviceTypes))); if (SUCCEEDED(rc)) { ULONG driveCheck = 0; for (size_t i = 0; i < saDeviceTypes.size(); ++ i) if (saDeviceTypes[i] == devTypeRequested) driveCheck++; if (!driveCheck) throw Utf8StrFmt("The given attachment is not supported by the storage controller '%s'", pszCtl); } else goto leave; } // find the medium given /* host drive? */ if (!RTStrNICmp(pszMedium, RT_STR_TUPLE("host:"))) { ComPtr<IHost> host; CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam())); if (devTypeRequested == DeviceType_DVD) { rc = host->FindHostDVDDrive(Bstr(pszMedium + 5).raw(), pMedium2Mount.asOutParam()); if (!pMedium2Mount) { /* 2nd try: try with the real name, important on Linux+libhal */ char szPathReal[RTPATH_MAX]; if (RT_FAILURE(RTPathReal(pszMedium + 5, szPathReal, sizeof(szPathReal)))) throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5); rc = host->FindHostDVDDrive(Bstr(szPathReal).raw(), pMedium2Mount.asOutParam()); if (!pMedium2Mount) throw Utf8StrFmt("Invalid host DVD drive name \"%s\"", pszMedium + 5); } } else { // floppy rc = host->FindHostFloppyDrive(Bstr(pszMedium + 5).raw(), pMedium2Mount.asOutParam()); if (!pMedium2Mount) throw Utf8StrFmt("Invalid host floppy drive name \"%s\"", pszMedium + 5); } } else if (!RTStrICmp(pszMedium, "iSCSI")) { /* check for required options */ if (bstrServer.isEmpty() || bstrTarget.isEmpty()) throw Utf8StrFmt("Parameters --server and --target are required for iSCSI media"); /** @todo move the location stuff to Main, which can use pfnComposeName * from the disk backends to construct the location properly. Also do * not use slashes to separate the parts, as otherwise only the last * element containing information will be shown. */ Bstr bstrISCSIMedium; if ( bstrLun.isEmpty() || (bstrLun == "0") || (bstrLun == "enc0") ) bstrISCSIMedium = BstrFmt("%ls|%ls", bstrServer.raw(), bstrTarget.raw()); else bstrISCSIMedium = BstrFmt("%ls|%ls|%ls", bstrServer.raw(), bstrTarget.raw(), bstrLun.raw()); CHECK_ERROR(a->virtualBox, CreateMedium(Bstr("iSCSI").raw(), bstrISCSIMedium.raw(), AccessMode_ReadWrite, DeviceType_HardDisk, pMedium2Mount.asOutParam())); if (FAILED(rc)) goto leave; if (!bstrPort.isEmpty()) bstrServer = BstrFmt("%ls:%ls", bstrServer.raw(), bstrPort.raw()); // set the other iSCSI parameters as properties com::SafeArray <BSTR> names; com::SafeArray <BSTR> values; Bstr("TargetAddress").detachTo(names.appendedRaw()); bstrServer.detachTo(values.appendedRaw()); Bstr("TargetName").detachTo(names.appendedRaw()); bstrTarget.detachTo(values.appendedRaw()); if (!bstrLun.isEmpty()) { Bstr("LUN").detachTo(names.appendedRaw()); bstrLun.detachTo(values.appendedRaw()); } if (!bstrUsername.isEmpty()) { Bstr("InitiatorUsername").detachTo(names.appendedRaw()); bstrUsername.detachTo(values.appendedRaw()); } if (!bstrPassword.isEmpty()) { Bstr("InitiatorSecret").detachTo(names.appendedRaw()); bstrPassword.detachTo(values.appendedRaw()); } if (!bstrInitiator.isEmpty()) { Bstr("InitiatorName").detachTo(names.appendedRaw()); bstrInitiator.detachTo(values.appendedRaw()); } /// @todo add --targetName and --targetPassword options if (fIntNet) { Bstr("HostIPStack").detachTo(names.appendedRaw()); Bstr("0").detachTo(values.appendedRaw()); } CHECK_ERROR(pMedium2Mount, SetProperties(ComSafeArrayAsInParam(names), ComSafeArrayAsInParam(values))); if (FAILED(rc)) goto leave; Bstr guid; CHECK_ERROR(pMedium2Mount, COMGETTER(Id)(guid.asOutParam())); if (FAILED(rc)) goto leave; RTPrintf("iSCSI disk created. UUID: %s\n", Utf8Str(guid).c_str()); } else { if (!pszMedium) { ComPtr<IMediumAttachment> mediumAttachment; rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mediumAttachment.asOutParam()); if (FAILED(rc)) throw Utf8Str("Missing --medium argument"); } else { Bstr bstrMedium(pszMedium); rc = openMedium(a, pszMedium, devTypeRequested, AccessMode_ReadWrite, pMedium2Mount, fSetNewUuid, false /* fSilent */); if (FAILED(rc) || !pMedium2Mount) throw Utf8StrFmt("Invalid UUID or filename \"%s\"", pszMedium); } } // set medium/parent medium UUID, if so desired if (pMedium2Mount && (fSetNewUuid || fSetNewParentUuid)) { CHECK_ERROR(pMedium2Mount, SetIds(fSetNewUuid, bstrNewUuid.raw(), fSetNewParentUuid, bstrNewParentUuid.raw())); if (FAILED(rc)) throw Utf8Str("Failed to set the medium/parent medium UUID"); } // set medium type, if so desired if (pMedium2Mount && fSetMediumType) { CHECK_ERROR(pMedium2Mount, COMSETTER(Type)(enmMediumType)); if (FAILED(rc)) throw Utf8Str("Failed to set the medium type"); } if (pMedium2Mount && !bstrComment.isEmpty()) { CHECK_ERROR(pMedium2Mount, COMSETTER(Description)(bstrComment.raw())); } if (pszMedium) { switch (devTypeRequested) { case DeviceType_DVD: case DeviceType_Floppy: { if (!fRunTime) { ComPtr<IMediumAttachment> mediumAttachment; // check if there is a dvd/floppy drive at the given location, if not attach one first rc = machine->GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mediumAttachment.asOutParam()); if (SUCCEEDED(rc)) { DeviceType_T deviceType; mediumAttachment->COMGETTER(Type)(&deviceType); if (deviceType != devTypeRequested) { machine->DetachDevice(Bstr(pszCtl).raw(), port, device); rc = machine->AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device, devTypeRequested); // DeviceType_DVD or DeviceType_Floppy } } else { rc = machine->AttachDeviceWithoutMedium(Bstr(pszCtl).raw(), port, device, devTypeRequested); // DeviceType_DVD or DeviceType_Floppy } } if (pMedium2Mount) { CHECK_ERROR(machine, MountMedium(Bstr(pszCtl).raw(), port, device, pMedium2Mount, fForceUnmount)); } } // end DeviceType_DVD or DeviceType_Floppy: break; case DeviceType_HardDisk: { // if there is anything attached at the given location, remove it machine->DetachDevice(Bstr(pszCtl).raw(), port, device); CHECK_ERROR(machine, AttachDevice(Bstr(pszCtl).raw(), port, device, DeviceType_HardDisk, pMedium2Mount)); } break; } } } if ( pszPassThrough && (SUCCEEDED(rc))) { ComPtr<IMediumAttachment> mattach; CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mattach.asOutParam())); if (SUCCEEDED(rc)) { if (!RTStrICmp(pszPassThrough, "on")) { CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(), port, device, TRUE)); } else if (!RTStrICmp(pszPassThrough, "off")) { CHECK_ERROR(machine, PassthroughDevice(Bstr(pszCtl).raw(), port, device, FALSE)); } else throw Utf8StrFmt("Invalid --passthrough argument '%s'", pszPassThrough); } else throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl); } if ( pszTempEject && (SUCCEEDED(rc))) { ComPtr<IMediumAttachment> mattach; CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mattach.asOutParam())); if (SUCCEEDED(rc)) { if (!RTStrICmp(pszTempEject, "on")) { CHECK_ERROR(machine, TemporaryEjectDevice(Bstr(pszCtl).raw(), port, device, TRUE)); } else if (!RTStrICmp(pszTempEject, "off")) { CHECK_ERROR(machine, TemporaryEjectDevice(Bstr(pszCtl).raw(), port, device, FALSE)); } else throw Utf8StrFmt("Invalid --tempeject argument '%s'", pszTempEject); } else throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl); } if ( pszNonRotational && (SUCCEEDED(rc))) { ComPtr<IMediumAttachment> mattach; CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mattach.asOutParam())); if (SUCCEEDED(rc)) { if (!RTStrICmp(pszNonRotational, "on")) { CHECK_ERROR(machine, NonRotationalDevice(Bstr(pszCtl).raw(), port, device, TRUE)); } else if (!RTStrICmp(pszNonRotational, "off")) { CHECK_ERROR(machine, NonRotationalDevice(Bstr(pszCtl).raw(), port, device, FALSE)); } else throw Utf8StrFmt("Invalid --nonrotational argument '%s'", pszNonRotational); } else throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl); } if ( pszDiscard && (SUCCEEDED(rc))) { ComPtr<IMediumAttachment> mattach; CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mattach.asOutParam())); if (SUCCEEDED(rc)) { if (!RTStrICmp(pszDiscard, "on")) { CHECK_ERROR(machine, SetAutoDiscardForDevice(Bstr(pszCtl).raw(), port, device, TRUE)); } else if (!RTStrICmp(pszDiscard, "off")) { CHECK_ERROR(machine, SetAutoDiscardForDevice(Bstr(pszCtl).raw(), port, device, FALSE)); } else throw Utf8StrFmt("Invalid --discard argument '%s'", pszDiscard); } else throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl); } if ( pszHotPluggable && (SUCCEEDED(rc))) { ComPtr<IMediumAttachment> mattach; CHECK_ERROR(machine, GetMediumAttachment(Bstr(pszCtl).raw(), port, device, mattach.asOutParam())); if (SUCCEEDED(rc)) { if (!RTStrICmp(pszHotPluggable, "on")) { CHECK_ERROR(machine, SetHotPluggableForDevice(Bstr(pszCtl).raw(), port, device, TRUE)); } else if (!RTStrICmp(pszHotPluggable, "off")) { CHECK_ERROR(machine, SetHotPluggableForDevice(Bstr(pszCtl).raw(), port, device, FALSE)); } else throw Utf8StrFmt("Invalid --hotpluggable argument '%s'", pszHotPluggable); } else throw Utf8StrFmt("Couldn't find the controller attachment for the controller '%s'\n", pszCtl); } if ( pszBandwidthGroup && !fRunTime && SUCCEEDED(rc)) { if (!RTStrICmp(pszBandwidthGroup, "none")) { /* Just remove the bandwidth gorup. */ CHECK_ERROR(machine, SetNoBandwidthGroupForDevice(Bstr(pszCtl).raw(), port, device)); } else { ComPtr<IBandwidthControl> bwCtrl; ComPtr<IBandwidthGroup> bwGroup; CHECK_ERROR(machine, COMGETTER(BandwidthControl)(bwCtrl.asOutParam())); if (SUCCEEDED(rc)) { CHECK_ERROR(bwCtrl, GetBandwidthGroup(Bstr(pszBandwidthGroup).raw(), bwGroup.asOutParam())); if (SUCCEEDED(rc)) { CHECK_ERROR(machine, SetBandwidthGroupForDevice(Bstr(pszCtl).raw(), port, device, bwGroup)); } } } } /* commit changes */ if (SUCCEEDED(rc)) CHECK_ERROR(machine, SaveSettings()); } catch (const Utf8Str &strError) { errorArgument("%s", strError.c_str()); rc = E_FAIL; } // machine must always be unlocked, even on errors leave: a->session->UnlockMachine(); return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; }