VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp@ 94660

Last change on this file since 94660 was 94213, checked in by vboxsync, 3 years ago

doc/manual,FE/VBoxManage: Convert usbdevsource command to refentry documentation, ​bugref:9186

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