VirtualBox

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

Last change on this file since 22911 was 22911, checked in by vboxsync, 16 years ago

event queues cleaned up

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette