VirtualBox

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

Last change on this file since 31713 was 31070, checked in by vboxsync, 14 years ago

Main: rename ISession::close() to ISession::unlockMachine(); API documentation

  • 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 31070 2010-07-23 16:00:09Z 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 /* open a session for the VM */
419 CHECK_ERROR_RET(cmd.mMachine, LockMachine(a->session, LockType_Write), 1);
420 /* get the mutable session machine */
421 a->session->COMGETTER(Machine)(cmd.mMachine.asOutParam());
422 /* and get the USB controller */
423 CHECK_ERROR_RET(cmd.mMachine, COMGETTER(USBController)(ctl.asOutParam()), 1);
424 }
425
426 switch (cmd.mAction)
427 {
428 case USBFilterCmd::Add:
429 {
430 if (cmd.mGlobal)
431 {
432 ComPtr <IHostUSBDeviceFilter> flt;
433 CHECK_ERROR_BREAK (host, CreateUSBDeviceFilter (f.mName, flt.asOutParam()));
434
435 if (!f.mActive.isNull())
436 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
437 if (!f.mVendorId.isEmpty())
438 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId));
439 if (!f.mProductId.isEmpty())
440 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId));
441 if (!f.mRevision.isEmpty())
442 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision));
443 if (!f.mManufacturer.isEmpty())
444 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer));
445 if (!f.mSerialNumber.isEmpty())
446 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber));
447 if (!f.mMaskedInterfaces.isNull())
448 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
449
450 if (f.mAction != USBDeviceFilterAction_Null)
451 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
452
453 CHECK_ERROR_BREAK (host, InsertUSBDeviceFilter (cmd.mIndex, flt));
454 }
455 else
456 {
457 ComPtr <IUSBDeviceFilter> flt;
458 CHECK_ERROR_BREAK (ctl, CreateDeviceFilter (f.mName, flt.asOutParam()));
459
460 if (!f.mActive.isNull())
461 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
462 if (!f.mVendorId.isEmpty())
463 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId));
464 if (!f.mProductId.isEmpty())
465 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId));
466 if (!f.mRevision.isEmpty())
467 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision));
468 if (!f.mManufacturer.isEmpty())
469 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer));
470 if (!f.mRemote.isEmpty())
471 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote));
472 if (!f.mSerialNumber.isEmpty())
473 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber));
474 if (!f.mMaskedInterfaces.isNull())
475 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
476
477 CHECK_ERROR_BREAK (ctl, InsertDeviceFilter (cmd.mIndex, flt));
478 }
479 break;
480 }
481 case USBFilterCmd::Modify:
482 {
483 if (cmd.mGlobal)
484 {
485 SafeIfaceArray <IHostUSBDeviceFilter> coll;
486 CHECK_ERROR_BREAK (host, COMGETTER(USBDeviceFilters) (ComSafeArrayAsOutParam(coll)));
487
488 ComPtr <IHostUSBDeviceFilter> flt = coll[cmd.mIndex];
489
490 if (!f.mName.isEmpty())
491 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName));
492 if (!f.mActive.isNull())
493 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
494 if (!f.mVendorId.isEmpty())
495 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId));
496 if (!f.mProductId.isEmpty())
497 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId));
498 if (!f.mRevision.isEmpty())
499 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision));
500 if (!f.mManufacturer.isEmpty())
501 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer));
502 if (!f.mSerialNumber.isEmpty())
503 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber));
504 if (!f.mMaskedInterfaces.isNull())
505 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
506
507 if (f.mAction != USBDeviceFilterAction_Null)
508 CHECK_ERROR_BREAK (flt, COMSETTER(Action) (f.mAction));
509 }
510 else
511 {
512 SafeIfaceArray <IUSBDeviceFilter> coll;
513 CHECK_ERROR_BREAK (ctl, COMGETTER(DeviceFilters) (ComSafeArrayAsOutParam(coll)));
514
515 ComPtr <IUSBDeviceFilter> flt = coll[cmd.mIndex];
516
517 if (!f.mName.isEmpty())
518 CHECK_ERROR_BREAK (flt, COMSETTER(Name) (f.mName));
519 if (!f.mActive.isNull())
520 CHECK_ERROR_BREAK (flt, COMSETTER(Active) (f.mActive));
521 if (!f.mVendorId.isEmpty())
522 CHECK_ERROR_BREAK (flt, COMSETTER(VendorId) (f.mVendorId));
523 if (!f.mProductId.isEmpty())
524 CHECK_ERROR_BREAK (flt, COMSETTER(ProductId) (f.mProductId));
525 if (!f.mRevision.isEmpty())
526 CHECK_ERROR_BREAK (flt, COMSETTER(Revision) (f.mRevision));
527 if (!f.mManufacturer.isEmpty())
528 CHECK_ERROR_BREAK (flt, COMSETTER(Manufacturer) (f.mManufacturer));
529 if (!f.mRemote.isEmpty())
530 CHECK_ERROR_BREAK (flt, COMSETTER(Remote) (f.mRemote));
531 if (!f.mSerialNumber.isEmpty())
532 CHECK_ERROR_BREAK (flt, COMSETTER(SerialNumber) (f.mSerialNumber));
533 if (!f.mMaskedInterfaces.isNull())
534 CHECK_ERROR_BREAK (flt, COMSETTER(MaskedInterfaces) (f.mMaskedInterfaces));
535 }
536 break;
537 }
538 case USBFilterCmd::Remove:
539 {
540 if (cmd.mGlobal)
541 {
542 ComPtr <IHostUSBDeviceFilter> flt;
543 CHECK_ERROR_BREAK (host, RemoveUSBDeviceFilter (cmd.mIndex));
544 }
545 else
546 {
547 ComPtr <IUSBDeviceFilter> flt;
548 CHECK_ERROR_BREAK (ctl, RemoveDeviceFilter (cmd.mIndex, flt.asOutParam()));
549 }
550 break;
551 }
552 default:
553 break;
554 }
555
556 if (cmd.mMachine)
557 {
558 if (SUCCEEDED (rc))
559 {
560 /* commit the session */
561 CHECK_ERROR(cmd.mMachine, SaveSettings());
562 }
563 /* close the session */
564 a->session->UnlockMachine();
565 }
566
567 return SUCCEEDED (rc) ? 0 : 1;
568}
569/* 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