[12599] | 1 | /* $Id: VBoxManageUSB.cpp 100772 2023-08-01 17:34:48Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[12599] | 3 | * VBoxManage - VirtualBox's command-line interface.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[1] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[1] | 26 | */
|
---|
| 27 |
|
---|
| 28 | #include <VBox/com/com.h>
|
---|
| 29 | #include <VBox/com/string.h>
|
---|
| 30 | #include <VBox/com/Guid.h>
|
---|
[7379] | 31 | #include <VBox/com/array.h>
|
---|
[1] | 32 | #include <VBox/com/ErrorInfo.h>
|
---|
[20928] | 33 | #include <VBox/com/errorprint.h>
|
---|
[1] | 34 | #include <VBox/com/VirtualBox.h>
|
---|
| 35 |
|
---|
[17104] | 36 | #include "VBoxManage.h"
|
---|
[1] | 37 |
|
---|
[14619] | 38 | #include <iprt/asm.h>
|
---|
[1] | 39 |
|
---|
[17104] | 40 | using namespace com;
|
---|
[1] | 41 |
|
---|
[92372] | 42 | DECLARE_TRANSLATION_CONTEXT(Usb);
|
---|
| 43 |
|
---|
[1] | 44 | /**
|
---|
| 45 | * Quick IUSBDevice implementation for detaching / attaching
|
---|
| 46 | * devices to the USB Controller.
|
---|
| 47 | */
|
---|
| 48 | class MyUSBDevice : public IUSBDevice
|
---|
| 49 | {
|
---|
| 50 | public:
|
---|
| 51 | // public initializer/uninitializer for internal purposes only
|
---|
| 52 | MyUSBDevice(uint16_t a_u16VendorId, uint16_t a_u16ProductId, uint16_t a_bcdRevision, uint64_t a_u64SerialHash, const char *a_pszComment)
|
---|
| 53 | : m_usVendorId(a_u16VendorId), m_usProductId(a_u16ProductId),
|
---|
| 54 | m_bcdRevision(a_bcdRevision), m_u64SerialHash(a_u64SerialHash),
|
---|
| 55 | m_bstrComment(a_pszComment),
|
---|
| 56 | m_cRefs(0)
|
---|
| 57 | {
|
---|
| 58 | }
|
---|
[62183] | 59 | virtual ~MyUSBDevice() {}
|
---|
[1] | 60 |
|
---|
| 61 | STDMETHOD_(ULONG, AddRef)(void)
|
---|
| 62 | {
|
---|
| 63 | return ASMAtomicIncU32(&m_cRefs);
|
---|
| 64 | }
|
---|
| 65 | STDMETHOD_(ULONG, Release)(void)
|
---|
| 66 | {
|
---|
| 67 | ULONG cRefs = ASMAtomicDecU32(&m_cRefs);
|
---|
| 68 | if (!cRefs)
|
---|
| 69 | delete this;
|
---|
| 70 | return cRefs;
|
---|
| 71 | }
|
---|
| 72 | STDMETHOD(QueryInterface)(const IID &iid, void **ppvObject)
|
---|
| 73 | {
|
---|
| 74 | Guid guid(iid);
|
---|
[50117] | 75 | if (guid == Guid(COM_IIDOF(IUnknown)))
|
---|
[1] | 76 | *ppvObject = (IUnknown *)this;
|
---|
[21520] | 77 | #ifdef RT_OS_WINDOWS
|
---|
[50117] | 78 | else if (guid == Guid(COM_IIDOF(IDispatch)))
|
---|
[21520] | 79 | *ppvObject = (IDispatch *)this;
|
---|
| 80 | #endif
|
---|
[50117] | 81 | else if (guid == Guid(COM_IIDOF(IUSBDevice)))
|
---|
[1] | 82 | *ppvObject = (IUSBDevice *)this;
|
---|
| 83 | else
|
---|
| 84 | return E_NOINTERFACE;
|
---|
| 85 | AddRef();
|
---|
| 86 | return S_OK;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
[63300] | 89 | STDMETHOD(COMGETTER(Id))(OUT_GUID a_pId) { NOREF(a_pId); return E_NOTIMPL; }
|
---|
[1] | 90 | STDMETHOD(COMGETTER(VendorId))(USHORT *a_pusVendorId) { *a_pusVendorId = m_usVendorId; return S_OK; }
|
---|
| 91 | STDMETHOD(COMGETTER(ProductId))(USHORT *a_pusProductId) { *a_pusProductId = m_usProductId; return S_OK; }
|
---|
| 92 | STDMETHOD(COMGETTER(Revision))(USHORT *a_pusRevision) { *a_pusRevision = m_bcdRevision; return S_OK; }
|
---|
| 93 | STDMETHOD(COMGETTER(SerialHash))(ULONG64 *a_pullSerialHash) { *a_pullSerialHash = m_u64SerialHash; return S_OK; }
|
---|
[63300] | 94 | STDMETHOD(COMGETTER(Manufacturer))(BSTR *a_pManufacturer) { NOREF(a_pManufacturer); return E_NOTIMPL; }
|
---|
| 95 | STDMETHOD(COMGETTER(Product))(BSTR *a_pProduct) { NOREF(a_pProduct); return E_NOTIMPL; }
|
---|
| 96 | STDMETHOD(COMGETTER(SerialNumber))(BSTR *a_pSerialNumber) { NOREF(a_pSerialNumber); return E_NOTIMPL; }
|
---|
| 97 | STDMETHOD(COMGETTER(Address))(BSTR *a_pAddress) { NOREF(a_pAddress); return E_NOTIMPL; }
|
---|
[1] | 98 |
|
---|
| 99 | private:
|
---|
| 100 | /** The vendor id of this USB device. */
|
---|
| 101 | USHORT m_usVendorId;
|
---|
| 102 | /** The product id of this USB device. */
|
---|
| 103 | USHORT m_usProductId;
|
---|
| 104 | /** The product revision number of this USB device.
|
---|
| 105 | * (high byte = integer; low byte = decimal) */
|
---|
| 106 | USHORT m_bcdRevision;
|
---|
| 107 | /** The USB serial hash of the device. */
|
---|
| 108 | uint64_t m_u64SerialHash;
|
---|
| 109 | /** The user comment string. */
|
---|
| 110 | Bstr m_bstrComment;
|
---|
| 111 | /** Reference counter. */
|
---|
| 112 | uint32_t volatile m_cRefs;
|
---|
| 113 | };
|
---|
| 114 |
|
---|
| 115 |
|
---|
| 116 | // types
|
---|
| 117 | ///////////////////////////////////////////////////////////////////////////////
|
---|
| 118 |
|
---|
| 119 | template <typename T>
|
---|
| 120 | class Nullable
|
---|
| 121 | {
|
---|
| 122 | public:
|
---|
| 123 |
|
---|
[32718] | 124 | Nullable() : mIsNull(true) {}
|
---|
| 125 | Nullable(const T &aValue, bool aIsNull = false)
|
---|
| 126 | : mIsNull(aIsNull), mValue(aValue) {}
|
---|
[1] | 127 |
|
---|
| 128 | bool isNull() const { return mIsNull; };
|
---|
[32718] | 129 | void setNull(bool aIsNull = true) { mIsNull = aIsNull; }
|
---|
[1] | 130 |
|
---|
| 131 | operator const T&() const { return mValue; }
|
---|
| 132 |
|
---|
| 133 | Nullable &operator= (const T &aValue)
|
---|
| 134 | {
|
---|
| 135 | mValue = aValue;
|
---|
| 136 | mIsNull = false;
|
---|
| 137 | return *this;
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | private:
|
---|
| 141 |
|
---|
| 142 | bool mIsNull;
|
---|
| 143 | T mValue;
|
---|
| 144 | };
|
---|
| 145 |
|
---|
| 146 | /** helper structure to encapsulate USB filter manipulation commands */
|
---|
| 147 | struct USBFilterCmd
|
---|
| 148 | {
|
---|
| 149 | struct USBFilter
|
---|
| 150 | {
|
---|
[32718] | 151 | USBFilter()
|
---|
| 152 | : mAction(USBDeviceFilterAction_Null)
|
---|
[1] | 153 | {}
|
---|
| 154 |
|
---|
| 155 | Bstr mName;
|
---|
| 156 | Nullable <bool> mActive;
|
---|
| 157 | Bstr mVendorId;
|
---|
| 158 | Bstr mProductId;
|
---|
| 159 | Bstr mRevision;
|
---|
| 160 | Bstr mManufacturer;
|
---|
| 161 | Bstr mProduct;
|
---|
[97804] | 162 | Bstr mPort;
|
---|
[1] | 163 | Bstr mRemote;
|
---|
| 164 | Bstr mSerialNumber;
|
---|
[5713] | 165 | Nullable <ULONG> mMaskedInterfaces;
|
---|
[1] | 166 | USBDeviceFilterAction_T mAction;
|
---|
| 167 | };
|
---|
| 168 |
|
---|
| 169 | enum Action { Invalid, Add, Modify, Remove };
|
---|
| 170 |
|
---|
[32718] | 171 | USBFilterCmd() : mAction(Invalid), mIndex(0), mGlobal(false) {}
|
---|
[1] | 172 |
|
---|
| 173 | Action mAction;
|
---|
[14620] | 174 | uint32_t mIndex;
|
---|
[1] | 175 | /** flag whether the command target is a global filter */
|
---|
| 176 | bool mGlobal;
|
---|
| 177 | /** machine this command is targeted at (null for global filters) */
|
---|
| 178 | ComPtr<IMachine> mMachine;
|
---|
| 179 | USBFilter mFilter;
|
---|
| 180 | };
|
---|
| 181 |
|
---|
[56118] | 182 | RTEXITCODE handleUSBFilter(HandlerArg *a)
|
---|
[3077] | 183 | {
|
---|
[95140] | 184 | HRESULT hrc = S_OK;
|
---|
[1] | 185 | USBFilterCmd cmd;
|
---|
| 186 |
|
---|
[18779] | 187 | /* at least: 0: command, 1: index, 2: --target, 3: <target value> */
|
---|
[16052] | 188 | if (a->argc < 4)
|
---|
[94207] | 189 | return errorSyntax(Usb::tr("Not enough parameters"));
|
---|
[1] | 190 |
|
---|
| 191 | /* which command? */
|
---|
| 192 | cmd.mAction = USBFilterCmd::Invalid;
|
---|
[94207] | 193 | if (!strcmp(a->argv[0], "add"))
|
---|
| 194 | {
|
---|
| 195 | cmd.mAction = USBFilterCmd::Add;
|
---|
| 196 | setCurrentSubcommand(HELP_SCOPE_USBFILTER_ADD);
|
---|
| 197 | }
|
---|
| 198 | else if (!strcmp(a->argv[0], "modify"))
|
---|
| 199 | {
|
---|
| 200 | cmd.mAction = USBFilterCmd::Modify;
|
---|
| 201 | setCurrentSubcommand(HELP_SCOPE_USBFILTER_MODIFY);
|
---|
| 202 | }
|
---|
| 203 | else if (!strcmp(a->argv[0], "remove"))
|
---|
| 204 | {
|
---|
| 205 | cmd.mAction = USBFilterCmd::Remove;
|
---|
| 206 | setCurrentSubcommand(HELP_SCOPE_USBFILTER_REMOVE);
|
---|
| 207 | }
|
---|
[1] | 208 |
|
---|
| 209 | if (cmd.mAction == USBFilterCmd::Invalid)
|
---|
[94207] | 210 | return errorSyntax(Usb::tr("Invalid parameter '%s'"), a->argv[0]);
|
---|
[1] | 211 |
|
---|
| 212 | /* which index? */
|
---|
[32718] | 213 | if (VINF_SUCCESS != RTStrToUInt32Full(a->argv[1], 10, &cmd.mIndex))
|
---|
[94207] | 214 | return errorSyntax(Usb::tr("Invalid index '%s'"), a->argv[1]);
|
---|
[1] | 215 |
|
---|
| 216 | switch (cmd.mAction)
|
---|
| 217 | {
|
---|
| 218 | case USBFilterCmd::Add:
|
---|
| 219 | case USBFilterCmd::Modify:
|
---|
| 220 | {
|
---|
[18779] | 221 | /* at least: 0: command, 1: index, 2: --target, 3: <target value>, 4: --name, 5: <name value> */
|
---|
[16052] | 222 | if (a->argc < 6)
|
---|
[1] | 223 | {
|
---|
| 224 | if (cmd.mAction == USBFilterCmd::Add)
|
---|
[94207] | 225 | return errorSyntax(Usb::tr("Not enough parameters"));
|
---|
[8373] | 226 |
|
---|
[94207] | 227 | return errorSyntax(Usb::tr("Not enough parameters"));
|
---|
[1] | 228 | }
|
---|
| 229 |
|
---|
| 230 | // set Active to true by default
|
---|
| 231 | // (assuming that the user sets up all necessary attributes
|
---|
| 232 | // at once and wants the filter to be active immediately)
|
---|
| 233 | if (cmd.mAction == USBFilterCmd::Add)
|
---|
| 234 | cmd.mFilter.mActive = true;
|
---|
| 235 |
|
---|
[16052] | 236 | for (int i = 2; i < a->argc; i++)
|
---|
[1] | 237 | {
|
---|
[18779] | 238 | if ( !strcmp(a->argv[i], "--target")
|
---|
| 239 | || !strcmp(a->argv[i], "-target"))
|
---|
[1] | 240 | {
|
---|
[16052] | 241 | if (a->argc <= i + 1 || !*a->argv[i+1])
|
---|
[92372] | 242 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 243 | i++;
|
---|
[18779] | 244 | if (!strcmp(a->argv[i], "global"))
|
---|
[1] | 245 | cmd.mGlobal = true;
|
---|
| 246 | else
|
---|
| 247 | {
|
---|
| 248 | /* assume it's a UUID of a machine */
|
---|
[33294] | 249 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[i]).raw(),
|
---|
[56118] | 250 | cmd.mMachine.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[1] | 251 | }
|
---|
| 252 | }
|
---|
[18779] | 253 | else if ( !strcmp(a->argv[i], "--name")
|
---|
| 254 | || !strcmp(a->argv[i], "-name"))
|
---|
[1] | 255 | {
|
---|
[16052] | 256 | if (a->argc <= i + 1 || !*a->argv[i+1])
|
---|
[92372] | 257 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 258 | i++;
|
---|
[18779] | 259 | cmd.mFilter.mName = a->argv[i];
|
---|
[1] | 260 | }
|
---|
[18779] | 261 | else if ( !strcmp(a->argv[i], "--active")
|
---|
| 262 | || !strcmp(a->argv[i], "-active"))
|
---|
[1] | 263 | {
|
---|
[16052] | 264 | if (a->argc <= i + 1)
|
---|
[92372] | 265 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 266 | i++;
|
---|
[18779] | 267 | if (!strcmp(a->argv[i], "yes"))
|
---|
[1] | 268 | cmd.mFilter.mActive = true;
|
---|
[18779] | 269 | else if (!strcmp(a->argv[i], "no"))
|
---|
[1] | 270 | cmd.mFilter.mActive = false;
|
---|
| 271 | else
|
---|
[92372] | 272 | return errorArgument(Usb::tr("Invalid --active argument '%s'"), a->argv[i]);
|
---|
[1] | 273 | }
|
---|
[18779] | 274 | else if ( !strcmp(a->argv[i], "--vendorid")
|
---|
| 275 | || !strcmp(a->argv[i], "-vendorid"))
|
---|
[1] | 276 | {
|
---|
[16052] | 277 | if (a->argc <= i + 1)
|
---|
[92372] | 278 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 279 | i++;
|
---|
[18779] | 280 | cmd.mFilter.mVendorId = a->argv[i];
|
---|
[1] | 281 | }
|
---|
[18779] | 282 | else if ( !strcmp(a->argv[i], "--productid")
|
---|
| 283 | || !strcmp(a->argv[i], "-productid"))
|
---|
[1] | 284 | {
|
---|
[16052] | 285 | if (a->argc <= i + 1)
|
---|
[92372] | 286 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 287 | i++;
|
---|
[18779] | 288 | cmd.mFilter.mProductId = a->argv[i];
|
---|
[1] | 289 | }
|
---|
[18779] | 290 | else if ( !strcmp(a->argv[i], "--revision")
|
---|
| 291 | || !strcmp(a->argv[i], "-revision"))
|
---|
[1] | 292 | {
|
---|
[16052] | 293 | if (a->argc <= i + 1)
|
---|
[92372] | 294 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 295 | i++;
|
---|
[18779] | 296 | cmd.mFilter.mRevision = a->argv[i];
|
---|
[1] | 297 | }
|
---|
[18779] | 298 | else if ( !strcmp(a->argv[i], "--manufacturer")
|
---|
| 299 | || !strcmp(a->argv[i], "-manufacturer"))
|
---|
[1] | 300 | {
|
---|
[16052] | 301 | if (a->argc <= i + 1)
|
---|
[92372] | 302 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 303 | i++;
|
---|
[18779] | 304 | cmd.mFilter.mManufacturer = a->argv[i];
|
---|
[1] | 305 | }
|
---|
[97804] | 306 | else if (!strcmp(a->argv[i], "--port"))
|
---|
| 307 | {
|
---|
| 308 | if (a->argc <= i + 1)
|
---|
| 309 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
| 310 | i++;
|
---|
| 311 | cmd.mFilter.mPort = a->argv[i];
|
---|
| 312 | }
|
---|
[18779] | 313 | else if ( !strcmp(a->argv[i], "--product")
|
---|
| 314 | || !strcmp(a->argv[i], "-product"))
|
---|
[1] | 315 | {
|
---|
[16052] | 316 | if (a->argc <= i + 1)
|
---|
[92372] | 317 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 318 | i++;
|
---|
[18779] | 319 | cmd.mFilter.mProduct = a->argv[i];
|
---|
[1] | 320 | }
|
---|
[18779] | 321 | else if ( !strcmp(a->argv[i], "--remote")
|
---|
| 322 | || !strcmp(a->argv[i], "-remote"))
|
---|
[1] | 323 | {
|
---|
[16052] | 324 | if (a->argc <= i + 1)
|
---|
[92372] | 325 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 326 | i++;
|
---|
[16052] | 327 | cmd.mFilter.mRemote = a->argv[i];
|
---|
[1] | 328 | }
|
---|
[18779] | 329 | else if ( !strcmp(a->argv[i], "--serialnumber")
|
---|
| 330 | || !strcmp(a->argv[i], "-serialnumber"))
|
---|
[1] | 331 | {
|
---|
[16052] | 332 | if (a->argc <= i + 1)
|
---|
[92372] | 333 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 334 | i++;
|
---|
[18779] | 335 | cmd.mFilter.mSerialNumber = a->argv[i];
|
---|
[1] | 336 | }
|
---|
[18779] | 337 | else if ( !strcmp(a->argv[i], "--maskedinterfaces")
|
---|
| 338 | || !strcmp(a->argv[i], "-maskedinterfaces"))
|
---|
[5713] | 339 | {
|
---|
[16052] | 340 | if (a->argc <= i + 1)
|
---|
[92372] | 341 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[5713] | 342 | i++;
|
---|
| 343 | uint32_t u32;
|
---|
[22489] | 344 | int vrc = RTStrToUInt32Full(a->argv[i], 0, &u32);
|
---|
| 345 | if (RT_FAILURE(vrc))
|
---|
[92372] | 346 | return errorArgument(Usb::tr("Failed to convert the --maskedinterfaces value '%s' to a number, vrc=%Rrc"),
|
---|
| 347 | a->argv[i], vrc);
|
---|
[5713] | 348 | cmd.mFilter.mMaskedInterfaces = u32;
|
---|
| 349 | }
|
---|
[18779] | 350 | else if ( !strcmp(a->argv[i], "--action")
|
---|
| 351 | || !strcmp(a->argv[i], "-action"))
|
---|
[1] | 352 | {
|
---|
[16052] | 353 | if (a->argc <= i + 1)
|
---|
[92372] | 354 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 355 | i++;
|
---|
[18779] | 356 | if (!strcmp(a->argv[i], "ignore"))
|
---|
[7207] | 357 | cmd.mFilter.mAction = USBDeviceFilterAction_Ignore;
|
---|
[18779] | 358 | else if (!strcmp(a->argv[i], "hold"))
|
---|
[7207] | 359 | cmd.mFilter.mAction = USBDeviceFilterAction_Hold;
|
---|
[1] | 360 | else
|
---|
[92372] | 361 | return errorArgument(Usb::tr("Invalid USB filter action '%s'"), a->argv[i]);
|
---|
[1] | 362 | }
|
---|
[5788] | 363 | else
|
---|
[94207] | 364 | return errorSyntax(Usb::tr("Unknown option '%s'"), a->argv[i]);
|
---|
[1] | 365 | }
|
---|
| 366 |
|
---|
| 367 | if (cmd.mAction == USBFilterCmd::Add)
|
---|
| 368 | {
|
---|
| 369 | // mandatory/forbidden options
|
---|
| 370 | if ( cmd.mFilter.mName.isEmpty()
|
---|
| 371 | ||
|
---|
| 372 | ( cmd.mGlobal
|
---|
[7207] | 373 | && cmd.mFilter.mAction == USBDeviceFilterAction_Null
|
---|
[1] | 374 | )
|
---|
| 375 | || ( !cmd.mGlobal
|
---|
| 376 | && !cmd.mMachine)
|
---|
| 377 | || ( cmd.mGlobal
|
---|
[32718] | 378 | && !cmd.mFilter.mRemote.isEmpty())
|
---|
[1] | 379 | )
|
---|
| 380 | {
|
---|
[94207] | 381 | return errorSyntax(Usb::tr("Mandatory options not supplied"));
|
---|
[1] | 382 | }
|
---|
| 383 | }
|
---|
| 384 | break;
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | case USBFilterCmd::Remove:
|
---|
| 388 | {
|
---|
[18779] | 389 | /* at least: 0: command, 1: index, 2: --target, 3: <target value> */
|
---|
[16052] | 390 | if (a->argc < 4)
|
---|
[94207] | 391 | return errorSyntax(Usb::tr("Not enough parameters"));
|
---|
[1] | 392 |
|
---|
[16052] | 393 | for (int i = 2; i < a->argc; i++)
|
---|
[1] | 394 | {
|
---|
[18779] | 395 | if ( !strcmp(a->argv[i], "--target")
|
---|
| 396 | || !strcmp(a->argv[i], "-target"))
|
---|
[1] | 397 | {
|
---|
[16052] | 398 | if (a->argc <= i + 1 || !*a->argv[i+1])
|
---|
[92372] | 399 | return errorArgument(Usb::tr("Missing argument to '%s'"), a->argv[i]);
|
---|
[1] | 400 | i++;
|
---|
[18779] | 401 | if (!strcmp(a->argv[i], "global"))
|
---|
[1] | 402 | cmd.mGlobal = true;
|
---|
| 403 | else
|
---|
| 404 | {
|
---|
[33294] | 405 | CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[i]).raw(),
|
---|
[56118] | 406 | cmd.mMachine.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[1] | 407 | }
|
---|
| 408 | }
|
---|
| 409 | }
|
---|
| 410 |
|
---|
| 411 | // mandatory options
|
---|
| 412 | if (!cmd.mGlobal && !cmd.mMachine)
|
---|
[94207] | 413 | return errorSyntax(Usb::tr("Mandatory options not supplied"));
|
---|
[1] | 414 |
|
---|
| 415 | break;
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 | default: break;
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | USBFilterCmd::USBFilter &f = cmd.mFilter;
|
---|
| 422 |
|
---|
[47908] | 423 | ComPtr<IHost> host;
|
---|
| 424 | ComPtr<IUSBDeviceFilters> flts;
|
---|
[1] | 425 | if (cmd.mGlobal)
|
---|
[56118] | 426 | CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[1] | 427 | else
|
---|
| 428 | {
|
---|
| 429 | /* open a session for the VM */
|
---|
[56118] | 430 | CHECK_ERROR_RET(cmd.mMachine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
|
---|
[1] | 431 | /* get the mutable session machine */
|
---|
[16052] | 432 | a->session->COMGETTER(Machine)(cmd.mMachine.asOutParam());
|
---|
[47376] | 433 | /* and get the USB device filters */
|
---|
[56118] | 434 | CHECK_ERROR_RET(cmd.mMachine, COMGETTER(USBDeviceFilters)(flts.asOutParam()), RTEXITCODE_FAILURE);
|
---|
[1] | 435 | }
|
---|
| 436 |
|
---|
| 437 | switch (cmd.mAction)
|
---|
| 438 | {
|
---|
| 439 | case USBFilterCmd::Add:
|
---|
| 440 | {
|
---|
| 441 | if (cmd.mGlobal)
|
---|
| 442 | {
|
---|
[47908] | 443 | ComPtr<IHostUSBDeviceFilter> flt;
|
---|
[32718] | 444 | CHECK_ERROR_BREAK(host, CreateUSBDeviceFilter(f.mName.raw(),
|
---|
| 445 | flt.asOutParam()));
|
---|
[1] | 446 |
|
---|
| 447 | if (!f.mActive.isNull())
|
---|
[32718] | 448 | CHECK_ERROR_BREAK(flt, COMSETTER(Active)(f.mActive));
|
---|
[26753] | 449 | if (!f.mVendorId.isEmpty())
|
---|
[32718] | 450 | CHECK_ERROR_BREAK(flt, COMSETTER(VendorId)(f.mVendorId.raw()));
|
---|
[26753] | 451 | if (!f.mProductId.isEmpty())
|
---|
[32718] | 452 | CHECK_ERROR_BREAK(flt, COMSETTER(ProductId)(f.mProductId.raw()));
|
---|
[26753] | 453 | if (!f.mRevision.isEmpty())
|
---|
[32718] | 454 | CHECK_ERROR_BREAK(flt, COMSETTER(Revision)(f.mRevision.raw()));
|
---|
[26753] | 455 | if (!f.mManufacturer.isEmpty())
|
---|
[32718] | 456 | CHECK_ERROR_BREAK(flt, COMSETTER(Manufacturer)(f.mManufacturer.raw()));
|
---|
[100772] | 457 | if (!f.mProduct.isEmpty())
|
---|
| 458 | CHECK_ERROR_BREAK(flt, COMSETTER(Product)(f.mProduct.raw()));
|
---|
[97804] | 459 | if (!f.mPort.isEmpty())
|
---|
| 460 | CHECK_ERROR_BREAK(flt, COMSETTER(Port)(f.mPort.raw()));
|
---|
[26753] | 461 | if (!f.mSerialNumber.isEmpty())
|
---|
[32718] | 462 | CHECK_ERROR_BREAK(flt, COMSETTER(SerialNumber)(f.mSerialNumber.raw()));
|
---|
[5713] | 463 | if (!f.mMaskedInterfaces.isNull())
|
---|
[32718] | 464 | CHECK_ERROR_BREAK(flt, COMSETTER(MaskedInterfaces)(f.mMaskedInterfaces));
|
---|
[1] | 465 |
|
---|
[7207] | 466 | if (f.mAction != USBDeviceFilterAction_Null)
|
---|
[32718] | 467 | CHECK_ERROR_BREAK(flt, COMSETTER(Action)(f.mAction));
|
---|
[1] | 468 |
|
---|
[32718] | 469 | CHECK_ERROR_BREAK(host, InsertUSBDeviceFilter(cmd.mIndex, flt));
|
---|
[1] | 470 | }
|
---|
| 471 | else
|
---|
| 472 | {
|
---|
[47908] | 473 | ComPtr<IUSBDeviceFilter> flt;
|
---|
[47376] | 474 | CHECK_ERROR_BREAK(flts, CreateDeviceFilter(f.mName.raw(),
|
---|
[32718] | 475 | flt.asOutParam()));
|
---|
[1] | 476 |
|
---|
| 477 | if (!f.mActive.isNull())
|
---|
[32718] | 478 | CHECK_ERROR_BREAK(flt, COMSETTER(Active)(f.mActive));
|
---|
[26753] | 479 | if (!f.mVendorId.isEmpty())
|
---|
[32718] | 480 | CHECK_ERROR_BREAK(flt, COMSETTER(VendorId)(f.mVendorId.raw()));
|
---|
[26753] | 481 | if (!f.mProductId.isEmpty())
|
---|
[32718] | 482 | CHECK_ERROR_BREAK(flt, COMSETTER(ProductId)(f.mProductId.raw()));
|
---|
[26753] | 483 | if (!f.mRevision.isEmpty())
|
---|
[32718] | 484 | CHECK_ERROR_BREAK(flt, COMSETTER(Revision)(f.mRevision.raw()));
|
---|
[26753] | 485 | if (!f.mManufacturer.isEmpty())
|
---|
[32718] | 486 | CHECK_ERROR_BREAK(flt, COMSETTER(Manufacturer)(f.mManufacturer.raw()));
|
---|
[100772] | 487 | if (!f.mProduct.isEmpty())
|
---|
| 488 | CHECK_ERROR_BREAK(flt, COMSETTER(Product)(f.mProduct.raw()));
|
---|
[97804] | 489 | if (!f.mPort.isEmpty())
|
---|
| 490 | CHECK_ERROR_BREAK(flt, COMSETTER(Port)(f.mPort.raw()));
|
---|
[26753] | 491 | if (!f.mRemote.isEmpty())
|
---|
[32718] | 492 | CHECK_ERROR_BREAK(flt, COMSETTER(Remote)(f.mRemote.raw()));
|
---|
[26753] | 493 | if (!f.mSerialNumber.isEmpty())
|
---|
[32718] | 494 | CHECK_ERROR_BREAK(flt, COMSETTER(SerialNumber)(f.mSerialNumber.raw()));
|
---|
[5713] | 495 | if (!f.mMaskedInterfaces.isNull())
|
---|
[32718] | 496 | CHECK_ERROR_BREAK(flt, COMSETTER(MaskedInterfaces)(f.mMaskedInterfaces));
|
---|
[1] | 497 |
|
---|
[47376] | 498 | CHECK_ERROR_BREAK(flts, InsertDeviceFilter(cmd.mIndex, flt));
|
---|
[1] | 499 | }
|
---|
| 500 | break;
|
---|
| 501 | }
|
---|
| 502 | case USBFilterCmd::Modify:
|
---|
| 503 | {
|
---|
| 504 | if (cmd.mGlobal)
|
---|
| 505 | {
|
---|
[17394] | 506 | SafeIfaceArray <IHostUSBDeviceFilter> coll;
|
---|
[32718] | 507 | CHECK_ERROR_BREAK(host, COMGETTER(USBDeviceFilters)(ComSafeArrayAsOutParam(coll)));
|
---|
[1] | 508 |
|
---|
[47908] | 509 | ComPtr<IHostUSBDeviceFilter> flt = coll[cmd.mIndex];
|
---|
[17394] | 510 |
|
---|
[26753] | 511 | if (!f.mName.isEmpty())
|
---|
[32718] | 512 | CHECK_ERROR_BREAK(flt, COMSETTER(Name)(f.mName.raw()));
|
---|
[1] | 513 | if (!f.mActive.isNull())
|
---|
[32718] | 514 | CHECK_ERROR_BREAK(flt, COMSETTER(Active)(f.mActive));
|
---|
[26753] | 515 | if (!f.mVendorId.isEmpty())
|
---|
[32718] | 516 | CHECK_ERROR_BREAK(flt, COMSETTER(VendorId)(f.mVendorId.raw()));
|
---|
[26753] | 517 | if (!f.mProductId.isEmpty())
|
---|
[32718] | 518 | CHECK_ERROR_BREAK(flt, COMSETTER(ProductId)(f.mProductId.raw()));
|
---|
[26753] | 519 | if (!f.mRevision.isEmpty())
|
---|
[32718] | 520 | CHECK_ERROR_BREAK(flt, COMSETTER(Revision)(f.mRevision.raw()));
|
---|
[26753] | 521 | if (!f.mManufacturer.isEmpty())
|
---|
[32718] | 522 | CHECK_ERROR_BREAK(flt, COMSETTER(Manufacturer)(f.mManufacturer.raw()));
|
---|
[100772] | 523 | if (!f.mProduct.isEmpty())
|
---|
| 524 | CHECK_ERROR_BREAK(flt, COMSETTER(Product)(f.mProduct.raw()));
|
---|
[97804] | 525 | if (!f.mPort.isEmpty())
|
---|
| 526 | CHECK_ERROR_BREAK(flt, COMSETTER(Port)(f.mPort.raw()));
|
---|
[26753] | 527 | if (!f.mSerialNumber.isEmpty())
|
---|
[32718] | 528 | CHECK_ERROR_BREAK(flt, COMSETTER(SerialNumber)(f.mSerialNumber.raw()));
|
---|
[5713] | 529 | if (!f.mMaskedInterfaces.isNull())
|
---|
[32718] | 530 | CHECK_ERROR_BREAK(flt, COMSETTER(MaskedInterfaces)(f.mMaskedInterfaces));
|
---|
[1] | 531 |
|
---|
[7207] | 532 | if (f.mAction != USBDeviceFilterAction_Null)
|
---|
[32718] | 533 | CHECK_ERROR_BREAK(flt, COMSETTER(Action)(f.mAction));
|
---|
[1] | 534 | }
|
---|
| 535 | else
|
---|
| 536 | {
|
---|
[17336] | 537 | SafeIfaceArray <IUSBDeviceFilter> coll;
|
---|
[47376] | 538 | CHECK_ERROR_BREAK(flts, COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(coll)));
|
---|
[1] | 539 |
|
---|
[47908] | 540 | ComPtr<IUSBDeviceFilter> flt = coll[cmd.mIndex];
|
---|
[1] | 541 |
|
---|
[26753] | 542 | if (!f.mName.isEmpty())
|
---|
[32718] | 543 | CHECK_ERROR_BREAK(flt, COMSETTER(Name)(f.mName.raw()));
|
---|
[1] | 544 | if (!f.mActive.isNull())
|
---|
[32718] | 545 | CHECK_ERROR_BREAK(flt, COMSETTER(Active)(f.mActive));
|
---|
[26753] | 546 | if (!f.mVendorId.isEmpty())
|
---|
[32718] | 547 | CHECK_ERROR_BREAK(flt, COMSETTER(VendorId)(f.mVendorId.raw()));
|
---|
[26753] | 548 | if (!f.mProductId.isEmpty())
|
---|
[32718] | 549 | CHECK_ERROR_BREAK(flt, COMSETTER(ProductId)(f.mProductId.raw()));
|
---|
[26753] | 550 | if (!f.mRevision.isEmpty())
|
---|
[32718] | 551 | CHECK_ERROR_BREAK(flt, COMSETTER(Revision)(f.mRevision.raw()));
|
---|
[26753] | 552 | if (!f.mManufacturer.isEmpty())
|
---|
[32718] | 553 | CHECK_ERROR_BREAK(flt, COMSETTER(Manufacturer)(f.mManufacturer.raw()));
|
---|
[100772] | 554 | if (!f.mProduct.isEmpty())
|
---|
| 555 | CHECK_ERROR_BREAK(flt, COMSETTER(Product)(f.mProduct.raw()));
|
---|
[97804] | 556 | if (!f.mPort.isEmpty())
|
---|
| 557 | CHECK_ERROR_BREAK(flt, COMSETTER(Port)(f.mPort.raw()));
|
---|
[26753] | 558 | if (!f.mRemote.isEmpty())
|
---|
[32718] | 559 | CHECK_ERROR_BREAK(flt, COMSETTER(Remote)(f.mRemote.raw()));
|
---|
[26753] | 560 | if (!f.mSerialNumber.isEmpty())
|
---|
[32718] | 561 | CHECK_ERROR_BREAK(flt, COMSETTER(SerialNumber)(f.mSerialNumber.raw()));
|
---|
[5713] | 562 | if (!f.mMaskedInterfaces.isNull())
|
---|
[32718] | 563 | CHECK_ERROR_BREAK(flt, COMSETTER(MaskedInterfaces)(f.mMaskedInterfaces));
|
---|
[1] | 564 | }
|
---|
| 565 | break;
|
---|
| 566 | }
|
---|
| 567 | case USBFilterCmd::Remove:
|
---|
| 568 | {
|
---|
| 569 | if (cmd.mGlobal)
|
---|
| 570 | {
|
---|
[47908] | 571 | ComPtr<IHostUSBDeviceFilter> flt;
|
---|
[32718] | 572 | CHECK_ERROR_BREAK(host, RemoveUSBDeviceFilter(cmd.mIndex));
|
---|
[1] | 573 | }
|
---|
| 574 | else
|
---|
| 575 | {
|
---|
[47908] | 576 | ComPtr<IUSBDeviceFilter> flt;
|
---|
[47376] | 577 | CHECK_ERROR_BREAK(flts, RemoveDeviceFilter(cmd.mIndex, flt.asOutParam()));
|
---|
[1] | 578 | }
|
---|
| 579 | break;
|
---|
| 580 | }
|
---|
| 581 | default:
|
---|
| 582 | break;
|
---|
| 583 | }
|
---|
| 584 |
|
---|
| 585 | if (cmd.mMachine)
|
---|
| 586 | {
|
---|
[95140] | 587 | if (SUCCEEDED(hrc))
|
---|
[20834] | 588 | {
|
---|
| 589 | /* commit the session */
|
---|
| 590 | CHECK_ERROR(cmd.mMachine, SaveSettings());
|
---|
| 591 | }
|
---|
| 592 | /* close the session */
|
---|
[31070] | 593 | a->session->UnlockMachine();
|
---|
[1] | 594 | }
|
---|
| 595 |
|
---|
[95140] | 596 | return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
[1] | 597 | }
|
---|
[60089] | 598 |
|
---|
| 599 | RTEXITCODE handleUSBDevSource(HandlerArg *a)
|
---|
| 600 | {
|
---|
[95140] | 601 | HRESULT hrc = S_OK;
|
---|
[60089] | 602 |
|
---|
| 603 | /* at least: 0: command, 1: source id */
|
---|
| 604 | if (a->argc < 2)
|
---|
[94213] | 605 | return errorSyntax(Usb::tr("Not enough parameters"));
|
---|
[60089] | 606 |
|
---|
| 607 | ComPtr<IHost> host;
|
---|
| 608 | if (!strcmp(a->argv[0], "add"))
|
---|
| 609 | {
|
---|
[94213] | 610 | setCurrentSubcommand(HELP_SCOPE_USBDEVSOURCE_ADD);
|
---|
| 611 |
|
---|
[60089] | 612 | Bstr strBackend;
|
---|
| 613 | Bstr strAddress;
|
---|
| 614 | if (a->argc != 6)
|
---|
[94213] | 615 | return errorSyntax(Usb::tr("Invalid number of parameters"));
|
---|
[60089] | 616 |
|
---|
| 617 | for (int i = 2; i < a->argc; i++)
|
---|
| 618 | {
|
---|
| 619 | if (!strcmp(a->argv[i], "--backend"))
|
---|
| 620 | {
|
---|
| 621 | i++;
|
---|
| 622 | strBackend = a->argv[i];
|
---|
| 623 | }
|
---|
| 624 | else if (!strcmp(a->argv[i], "--address"))
|
---|
| 625 | {
|
---|
| 626 | i++;
|
---|
| 627 | strAddress = a->argv[i];
|
---|
| 628 | }
|
---|
| 629 | else
|
---|
[94213] | 630 | return errorSyntax(Usb::tr("Parameter \"%s\" is invalid"), a->argv[i]);
|
---|
[60089] | 631 | }
|
---|
| 632 |
|
---|
| 633 | SafeArray<BSTR> usbSourcePropNames;
|
---|
| 634 | SafeArray<BSTR> usbSourcePropValues;
|
---|
| 635 |
|
---|
| 636 | CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
|
---|
| 637 | CHECK_ERROR_RET(host, AddUSBDeviceSource(strBackend.raw(), Bstr(a->argv[1]).raw(), strAddress.raw(),
|
---|
| 638 | ComSafeArrayAsInParam(usbSourcePropNames), ComSafeArrayAsInParam(usbSourcePropValues)),
|
---|
| 639 | RTEXITCODE_FAILURE);
|
---|
| 640 | }
|
---|
| 641 | else if (!strcmp(a->argv[0], "remove"))
|
---|
| 642 | {
|
---|
[94213] | 643 | setCurrentSubcommand(HELP_SCOPE_USBDEVSOURCE_REMOVE);
|
---|
[60089] | 644 | CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), RTEXITCODE_FAILURE);
|
---|
| 645 | CHECK_ERROR_RET(host, RemoveUSBDeviceSource(Bstr(a->argv[1]).raw()), RTEXITCODE_FAILURE);
|
---|
| 646 | }
|
---|
| 647 |
|
---|
[95140] | 648 | return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
[60089] | 649 | }
|
---|
| 650 |
|
---|
[17394] | 651 | /* vi: set tabstop=4 shiftwidth=4 expandtab: */
|
---|