VirtualBox

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

Last change on this file since 76678 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use