VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp@ 22722

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

VBoxCOM,VBoxManage,WebService: Event queue fun.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.3 KB
Line 
1/* $Id: VBoxManageGuestProp.cpp 22722 2009-09-02 15:05:57Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'guestproperty' command.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include "VBoxManage.h"
27
28#include <VBox/com/com.h>
29#include <VBox/com/string.h>
30#include <VBox/com/array.h>
31#include <VBox/com/ErrorInfo.h>
32#include <VBox/com/errorprint.h>
33
34#include <VBox/com/VirtualBox.h>
35
36#include <VBox/log.h>
37#include <iprt/asm.h>
38#include <iprt/semaphore.h>
39#include <iprt/stream.h>
40#include <iprt/string.h>
41#include <iprt/time.h>
42#include <iprt/thread.h>
43
44#ifdef USE_XPCOM_QUEUE
45# include <sys/select.h>
46# include <errno.h>
47#endif
48
49#ifdef RT_OS_DARWIN
50# include <CoreFoundation/CFRunLoop.h>
51#endif
52
53using namespace com;
54
55/**
56 * IVirtualBoxCallback implementation for handling the GuestPropertyCallback in
57 * relation to the "guestproperty wait" command.
58 */
59class GuestPropertyCallback :
60 VBOX_SCRIPTABLE_IMPL(IVirtualBoxCallback)
61{
62public:
63 GuestPropertyCallback(const char *pszPatterns, Guid aUuid)
64 : mSignalled(false), mPatterns(pszPatterns), mUuid(aUuid)
65 {
66#ifndef VBOX_WITH_XPCOM
67 refcnt = 0;
68#endif
69#ifndef USE_XPCOM_QUEUE
70 int rc = RTSemEventMultiCreate(&mhEvent);
71 if (RT_FAILURE(rc))
72 mhEvent = NIL_RTSEMEVENTMULTI;
73#endif
74 }
75
76 virtual ~GuestPropertyCallback()
77 {
78#ifndef USE_XPCOM_QUEUE
79 RTSemEventMultiDestroy(mhEvent);
80 mhEvent = NIL_RTSEMEVENTMULTI;
81#endif
82 }
83
84#ifndef VBOX_WITH_XPCOM
85 STDMETHOD_(ULONG, AddRef)()
86 {
87 return ::InterlockedIncrement(&refcnt);
88 }
89 STDMETHOD_(ULONG, Release)()
90 {
91 long cnt = ::InterlockedDecrement(&refcnt);
92 if (cnt == 0)
93 delete this;
94 return cnt;
95 }
96#endif /* !VBOX_WITH_XPCOM */
97 VBOX_SCRIPTABLE_DISPATCH_IMPL(IVirtualBoxCallback)
98
99 NS_DECL_ISUPPORTS
100
101 STDMETHOD(OnMachineStateChange)(IN_BSTR machineId,
102 MachineState_T state)
103 {
104 return S_OK;
105 }
106
107 STDMETHOD(OnMachineDataChange)(IN_BSTR machineId)
108 {
109 return S_OK;
110 }
111
112 STDMETHOD(OnExtraDataCanChange)(IN_BSTR machineId, IN_BSTR key,
113 IN_BSTR value, BSTR *error,
114 BOOL *changeAllowed)
115 {
116 /* we never disagree */
117 if (!changeAllowed)
118 return E_INVALIDARG;
119 *changeAllowed = TRUE;
120 return S_OK;
121 }
122
123 STDMETHOD(OnExtraDataChange)(IN_BSTR machineId, IN_BSTR key,
124 IN_BSTR value)
125 {
126 return S_OK;
127 }
128
129 STDMETHOD(OnMediaRegistered)(IN_BSTR mediaId,
130 DeviceType_T mediaType, BOOL registered)
131 {
132 NOREF(mediaId);
133 NOREF(mediaType);
134 NOREF(registered);
135 return S_OK;
136 }
137
138 STDMETHOD(OnMachineRegistered)(IN_BSTR machineId, BOOL registered)
139 {
140 return S_OK;
141 }
142
143 STDMETHOD(OnSessionStateChange)(IN_BSTR machineId,
144 SessionState_T state)
145 {
146 return S_OK;
147 }
148
149 STDMETHOD(OnSnapshotTaken)(IN_BSTR aMachineId,
150 IN_BSTR aSnapshotId)
151 {
152 return S_OK;
153 }
154
155 STDMETHOD(OnSnapshotDiscarded)(IN_BSTR aMachineId,
156 IN_BSTR aSnapshotId)
157 {
158 return S_OK;
159 }
160
161 STDMETHOD(OnSnapshotChange)(IN_BSTR aMachineId,
162 IN_BSTR aSnapshotId)
163 {
164 return S_OK;
165 }
166
167 STDMETHOD(OnGuestPropertyChange)(IN_BSTR machineId,
168 IN_BSTR name, IN_BSTR value,
169 IN_BSTR flags)
170 {
171 Utf8Str utf8Name(name);
172 Guid uuid(machineId);
173 if ( uuid == mUuid
174 && RTStrSimplePatternMultiMatch(mPatterns, RTSTR_MAX,
175 utf8Name.raw(), RTSTR_MAX, NULL))
176 {
177 RTPrintf("Name: %lS, value: %lS, flags: %lS\n", name, value, flags);
178 ASMAtomicWriteBool(&mSignalled, true);
179#ifndef USE_XPCOM_QUEUE
180 int rc = RTSemEventMultiSignal(mhEvent);
181 AssertRC(rc);
182#endif
183 }
184 return S_OK;
185 }
186
187 bool Signalled(void) const
188 {
189 return mSignalled;
190 }
191
192#ifndef USE_XPCOM_QUEUE
193 /** Wrapper around RTSemEventMultiWait. */
194 int wait(uint32_t cMillies)
195 {
196 return RTSemEventMultiWait(mhEvent, cMillies);
197 }
198#endif
199
200private:
201 bool volatile mSignalled;
202 const char *mPatterns;
203 Guid mUuid;
204#ifndef VBOX_WITH_XPCOM
205 long refcnt;
206#endif
207#ifndef USE_XPCOM_QUEUE
208 /** Event semaphore to wait on. */
209 RTSEMEVENTMULTI mhEvent;
210#endif
211};
212
213#ifdef VBOX_WITH_XPCOM
214NS_DECL_CLASSINFO(GuestPropertyCallback)
215NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestPropertyCallback, IVirtualBoxCallback)
216#endif /* VBOX_WITH_XPCOM */
217
218void usageGuestProperty(void)
219{
220 RTPrintf("VBoxManage guestproperty get <vmname>|<uuid>\n"
221 " <property> [--verbose]\n"
222 "\n");
223 RTPrintf("VBoxManage guestproperty set <vmname>|<uuid>\n"
224 " <property> [<value> [--flags <flags>]]\n"
225 "\n");
226 RTPrintf("VBoxManage guestproperty enumerate <vmname>|<uuid>\n"
227 " [--patterns <patterns>]\n"
228 "\n");
229 RTPrintf("VBoxManage guestproperty wait <vmname>|<uuid> <patterns>\n"
230 " [--timeout <milliseconds>] [--fail-on-timeout]\n"
231 "\n");
232}
233
234static int handleGetGuestProperty(HandlerArg *a)
235{
236 HRESULT rc = S_OK;
237
238 bool verbose = false;
239 if ( a->argc == 3
240 && ( !strcmp(a->argv[2], "--verbose")
241 || !strcmp(a->argv[2], "-verbose")))
242 verbose = true;
243 else if (a->argc != 2)
244 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
245
246 ComPtr<IMachine> machine;
247 /* assume it's a UUID */
248 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
249 if (FAILED(rc) || !machine)
250 {
251 /* must be a name */
252 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
253 }
254 if (machine)
255 {
256 Bstr uuid;
257 machine->COMGETTER(Id)(uuid.asOutParam());
258
259 /* open a session for the VM - new or existing */
260 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
261 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, uuid), 1);
262
263 /* get the mutable session machine */
264 a->session->COMGETTER(Machine)(machine.asOutParam());
265
266 Bstr value;
267 ULONG64 u64Timestamp;
268 Bstr flags;
269 CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]), value.asOutParam(),
270 &u64Timestamp, flags.asOutParam()));
271 if (!value)
272 RTPrintf("No value set!\n");
273 if (value)
274 RTPrintf("Value: %lS\n", value.raw());
275 if (value && verbose)
276 {
277 RTPrintf("Timestamp: %lld\n", u64Timestamp);
278 RTPrintf("Flags: %lS\n", flags.raw());
279 }
280 }
281 return SUCCEEDED(rc) ? 0 : 1;
282}
283
284static int handleSetGuestProperty(HandlerArg *a)
285{
286 HRESULT rc = S_OK;
287
288 /*
289 * Check the syntax. We can deduce the correct syntax from the number of
290 * arguments.
291 */
292 bool usageOK = true;
293 const char *pszName = NULL;
294 const char *pszValue = NULL;
295 const char *pszFlags = NULL;
296 if (a->argc == 3)
297 pszValue = a->argv[2];
298 else if (a->argc == 4)
299 usageOK = false;
300 else if (a->argc == 5)
301 {
302 pszValue = a->argv[2];
303 if ( !strcmp(a->argv[3], "--flags")
304 || !strcmp(a->argv[3], "-flags"))
305 usageOK = false;
306 pszFlags = a->argv[4];
307 }
308 else if (a->argc != 2)
309 usageOK = false;
310 if (!usageOK)
311 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
312 /* This is always needed. */
313 pszName = a->argv[1];
314
315 ComPtr<IMachine> machine;
316 /* assume it's a UUID */
317 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
318 if (FAILED(rc) || !machine)
319 {
320 /* must be a name */
321 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
322 }
323 if (machine)
324 {
325 Bstr uuid;
326 machine->COMGETTER(Id)(uuid.asOutParam());
327
328 /* open a session for the VM - new or existing */
329 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
330 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
331
332 /* get the mutable session machine */
333 a->session->COMGETTER(Machine)(machine.asOutParam());
334
335 if (!pszValue && !pszFlags)
336 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), NULL));
337 else if (!pszFlags)
338 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr(pszValue)));
339 else
340 CHECK_ERROR(machine, SetGuestProperty(Bstr(pszName), Bstr(pszValue), Bstr(pszFlags)));
341
342 if (SUCCEEDED(rc))
343 CHECK_ERROR(machine, SaveSettings());
344
345 a->session->Close();
346 }
347 return SUCCEEDED(rc) ? 0 : 1;
348}
349
350/**
351 * Enumerates the properties in the guest property store.
352 *
353 * @returns 0 on success, 1 on failure
354 * @note see the command line API description for parameters
355 */
356static int handleEnumGuestProperty(HandlerArg *a)
357{
358 /*
359 * Check the syntax. We can deduce the correct syntax from the number of
360 * arguments.
361 */
362 if ( a->argc < 1
363 || a->argc == 2
364 || ( a->argc > 3
365 && strcmp(a->argv[1], "--patterns")
366 && strcmp(a->argv[1], "-patterns")))
367 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
368
369 /*
370 * Pack the patterns
371 */
372 Utf8Str Utf8Patterns(a->argc > 2 ? a->argv[2] : "*");
373 for (int i = 3; i < a->argc; ++i)
374 Utf8Patterns = Utf8StrFmt ("%s,%s", Utf8Patterns.raw(), a->argv[i]);
375
376 /*
377 * Make the actual call to Main.
378 */
379 ComPtr<IMachine> machine;
380 /* assume it's a UUID */
381 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
382 if (FAILED(rc) || !machine)
383 {
384 /* must be a name */
385 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
386 }
387 if (machine)
388 {
389 Bstr uuid;
390 machine->COMGETTER(Id)(uuid.asOutParam());
391
392 /* open a session for the VM - new or existing */
393 if (FAILED(a->virtualBox->OpenSession(a->session, uuid)))
394 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
395
396 /* get the mutable session machine */
397 a->session->COMGETTER(Machine)(machine.asOutParam());
398
399 com::SafeArray <BSTR> names;
400 com::SafeArray <BSTR> values;
401 com::SafeArray <ULONG64> timestamps;
402 com::SafeArray <BSTR> flags;
403 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(Utf8Patterns),
404 ComSafeArrayAsOutParam(names),
405 ComSafeArrayAsOutParam(values),
406 ComSafeArrayAsOutParam(timestamps),
407 ComSafeArrayAsOutParam(flags)));
408 if (SUCCEEDED(rc))
409 {
410 if (names.size() == 0)
411 RTPrintf("No properties found.\n");
412 for (unsigned i = 0; i < names.size(); ++i)
413 RTPrintf("Name: %lS, value: %lS, timestamp: %lld, flags: %lS\n",
414 names[i], values[i], timestamps[i], flags[i]);
415 }
416 }
417 return SUCCEEDED(rc) ? 0 : 1;
418}
419
420/**
421 * Callback for processThreadEventQueue.
422 *
423 * @param pvUser Pointer to the callback object.
424 *
425 * @returns true if it should return or false if it should continue waiting for
426 * events.
427 */
428static bool eventExitCheck(void *pvUser)
429{
430 GuestPropertyCallback const *pCallbacks = (GuestPropertyCallback const *)pvUser;
431 return pCallbacks->Signalled();
432}
433
434/**
435 * Enumerates the properties in the guest property store.
436 *
437 * @returns 0 on success, 1 on failure
438 * @note see the command line API description for parameters
439 */
440static int handleWaitGuestProperty(HandlerArg *a)
441{
442 /*
443 * Handle arguments
444 */
445 bool fFailOnTimeout = false;
446 const char *pszPatterns = NULL;
447 uint32_t cMsTimeout = RT_INDEFINITE_WAIT;
448 bool usageOK = true;
449 if (a->argc < 2)
450 usageOK = false;
451 else
452 pszPatterns = a->argv[1];
453 ComPtr<IMachine> machine;
454 /* assume it's a UUID */
455 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
456 if (FAILED(rc) || !machine)
457 {
458 /* must be a name */
459 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
460 }
461 if (!machine)
462 usageOK = false;
463 for (int i = 2; usageOK && i < a->argc; ++i)
464 {
465 if ( !strcmp(a->argv[i], "--timeout")
466 || !strcmp(a->argv[i], "-timeout"))
467 {
468 if ( i + 1 >= a->argc
469 || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
470 usageOK = false;
471 else
472 ++i;
473 }
474 else if (!strcmp(a->argv[i], "--fail-on-timeout"))
475 fFailOnTimeout = true;
476 else
477 usageOK = false;
478 }
479 if (!usageOK)
480 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
481
482 /*
483 * Set up the callback and wait.
484 *
485 *
486 * The waiting is done is 1 sec at the time since there there are races
487 * between the callback and us going to sleep. This also guards against
488 * neglecting XPCOM event queues as well as any select timeout restrictions.
489 */
490 Bstr uuid;
491 machine->COMGETTER(Id)(uuid.asOutParam());
492 GuestPropertyCallback *cbImpl = new GuestPropertyCallback(pszPatterns, uuid);
493 ComPtr<IVirtualBoxCallback> callback;
494 rc = createCallbackWrapper((IVirtualBoxCallback *)cbImpl, callback.asOutParam());
495 if (FAILED(rc))
496 {
497 RTPrintf("Error creating callback wrapper: %Rhrc\n", rc);
498 return 1;
499 }
500 a->virtualBox->RegisterCallback(callback);
501
502 int vrc = com::EventQueue::processThreadEventQueue(cMsTimeout, eventExitCheck, (void *)cbImpl,
503 1000 /*cMsPollInterval*/, false /*fReturnOnEvent*/);
504 if ( RT_FAILURE(vrc)
505 && vrc != VERR_CALLBACK_RETURN
506 && vrc != VERR_TIMEOUT)
507 {
508 RTPrintf("Error waiting for event: %Rrc\n", vrc);
509 return 1;
510 }
511
512 a->virtualBox->UnregisterCallback(callback);
513
514 int rcRet = 0;
515 if (!cbImpl->Signalled())
516 {
517 RTPrintf("Time out or interruption while waiting for a notification.\n");
518 if (fFailOnTimeout)
519 rcRet = 2;
520 }
521 return rcRet;
522}
523
524/**
525 * Access the guest property store.
526 *
527 * @returns 0 on success, 1 on failure
528 * @note see the command line API description for parameters
529 */
530int handleGuestProperty(HandlerArg *a)
531{
532 HandlerArg arg = *a;
533 arg.argc = a->argc - 1;
534 arg.argv = a->argv + 1;
535
536 if (a->argc == 0)
537 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
538
539 /* switch (cmd) */
540 if (strcmp(a->argv[0], "get") == 0)
541 return handleGetGuestProperty(&arg);
542 if (strcmp(a->argv[0], "set") == 0)
543 return handleSetGuestProperty(&arg);
544 if (strcmp(a->argv[0], "enumerate") == 0)
545 return handleEnumGuestProperty(&arg);
546 if (strcmp(a->argv[0], "wait") == 0)
547 return handleWaitGuestProperty(&arg);
548
549 /* default: */
550 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
551}
552
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