VirtualBox

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

Last change on this file since 29607 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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