VirtualBox

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

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

Main: Bstr makeover (second attempt) -- make Bstr(NULL) and Bstr() behave the same; resulting cleanup; make some more internal methods use Utf8Str instead of Bstr; fix a lot of CheckComArgNotNull?() usage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.6 KB
Line 
1/* $Id: VBoxManageGuestProp.cpp 26587 2010-02-16 16:57:09Z 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(OnMediumRegistered)(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 com::EventQueue::getMainEventQueue()->interruptEventQueueProcessing();
171 }
172 return S_OK;
173 }
174
175 bool Signalled(void) const
176 {
177 return mSignalled;
178 }
179
180private:
181 bool volatile mSignalled;
182 const char *mPatterns;
183 Guid mUuid;
184#ifndef VBOX_WITH_XPCOM
185 long refcnt;
186#endif
187};
188
189#ifdef VBOX_WITH_XPCOM
190NS_DECL_CLASSINFO(GuestPropertyCallback)
191NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestPropertyCallback, IVirtualBoxCallback)
192#endif /* VBOX_WITH_XPCOM */
193
194void usageGuestProperty(void)
195{
196 RTPrintf("VBoxManage guestproperty get <vmname>|<uuid>\n"
197 " <property> [--verbose]\n"
198 "\n");
199 RTPrintf("VBoxManage guestproperty set <vmname>|<uuid>\n"
200 " <property> [<value> [--flags <flags>]]\n"
201 "\n");
202 RTPrintf("VBoxManage guestproperty enumerate <vmname>|<uuid>\n"
203 " [--patterns <patterns>]\n"
204 "\n");
205 RTPrintf("VBoxManage guestproperty wait <vmname>|<uuid> <patterns>\n"
206 " [--timeout <milliseconds>] [--fail-on-timeout]\n"
207 "\n");
208}
209
210static int handleGetGuestProperty(HandlerArg *a)
211{
212 HRESULT rc = S_OK;
213
214 bool verbose = false;
215 if ( a->argc == 3
216 && ( !strcmp(a->argv[2], "--verbose")
217 || !strcmp(a->argv[2], "-verbose")))
218 verbose = true;
219 else if (a->argc != 2)
220 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
221
222 ComPtr<IMachine> machine;
223 /* assume it's a UUID */
224 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
225 if (FAILED(rc) || !machine)
226 {
227 /* must be a name */
228 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
229 }
230 if (machine)
231 {
232 Bstr uuid;
233 machine->COMGETTER(Id)(uuid.asOutParam());
234
235 /* open a session for the VM - new or existing */
236 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
237 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, uuid), 1);
238
239 /* get the mutable session machine */
240 a->session->COMGETTER(Machine)(machine.asOutParam());
241
242 Bstr value;
243 ULONG64 u64Timestamp;
244 Bstr flags;
245 CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]), value.asOutParam(),
246 &u64Timestamp, flags.asOutParam()));
247 if (!value)
248 RTPrintf("No value set!\n");
249 if (value)
250 {
251 RTPrintf("Value: %lS\n", value.raw());
252 if (verbose)
253 {
254 RTPrintf("Timestamp: %lld\n", u64Timestamp);
255 RTPrintf("Flags: %lS\n", flags.raw());
256 }
257 }
258 }
259 return SUCCEEDED(rc) ? 0 : 1;
260}
261
262static int handleSetGuestProperty(HandlerArg *a)
263{
264 HRESULT rc = S_OK;
265
266 /*
267 * Check the syntax. We can deduce the correct syntax from the number of
268 * arguments.
269 */
270 bool usageOK = true;
271 const char *pszName = NULL;
272 const char *pszValue = NULL;
273 const char *pszFlags = NULL;
274 if (a->argc == 3)
275 pszValue = a->argv[2];
276 else if (a->argc == 4)
277 usageOK = false;
278 else if (a->argc == 5)
279 {
280 pszValue = a->argv[2];
281 if ( strcmp(a->argv[3], "--flags")
282 && strcmp(a->argv[3], "-flags"))
283 usageOK = false;
284 pszFlags = a->argv[4];
285 }
286 else if (a->argc != 2)
287 usageOK = false;
288 if (!usageOK)
289 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
290 /* This is always needed. */
291 pszName = a->argv[1];
292
293 ComPtr<IMachine> machine;
294 /* assume it's a UUID */
295 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
296 if (FAILED(rc) || !machine)
297 {
298 /* must be a name */
299 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
300 }
301 if (machine)
302 {
303 Bstr uuid;
304 machine->COMGETTER(Id)(uuid.asOutParam());
305
306 /* open a session for the VM - new or existing */
307 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
308 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
309
310 /* get the mutable session machine */
311 a->session->COMGETTER(Machine)(machine.asOutParam());
312
313 if (!pszValue && !pszFlags)
314 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr("")));
315 else if (!pszFlags)
316 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr(pszValue)));
317 else
318 CHECK_ERROR(machine, SetGuestProperty(Bstr(pszName), Bstr(pszValue), Bstr(pszFlags)));
319
320 if (SUCCEEDED(rc))
321 CHECK_ERROR(machine, SaveSettings());
322
323 a->session->Close();
324 }
325 return SUCCEEDED(rc) ? 0 : 1;
326}
327
328/**
329 * Enumerates the properties in the guest property store.
330 *
331 * @returns 0 on success, 1 on failure
332 * @note see the command line API description for parameters
333 */
334static int handleEnumGuestProperty(HandlerArg *a)
335{
336 /*
337 * Check the syntax. We can deduce the correct syntax from the number of
338 * arguments.
339 */
340 if ( a->argc < 1
341 || a->argc == 2
342 || ( a->argc > 3
343 && strcmp(a->argv[1], "--patterns")
344 && strcmp(a->argv[1], "-patterns")))
345 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
346
347 /*
348 * Pack the patterns
349 */
350 Utf8Str Utf8Patterns(a->argc > 2 ? a->argv[2] : "*");
351 for (int i = 3; i < a->argc; ++i)
352 Utf8Patterns = Utf8StrFmt ("%s,%s", Utf8Patterns.raw(), a->argv[i]);
353
354 /*
355 * Make the actual call to Main.
356 */
357 ComPtr<IMachine> machine;
358 /* assume it's a UUID */
359 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
360 if (FAILED(rc) || !machine)
361 {
362 /* must be a name */
363 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
364 }
365 if (machine)
366 {
367 Bstr uuid;
368 machine->COMGETTER(Id)(uuid.asOutParam());
369
370 /* open a session for the VM - new or existing */
371 if (FAILED(a->virtualBox->OpenSession(a->session, uuid)))
372 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
373
374 /* get the mutable session machine */
375 a->session->COMGETTER(Machine)(machine.asOutParam());
376
377 com::SafeArray <BSTR> names;
378 com::SafeArray <BSTR> values;
379 com::SafeArray <ULONG64> timestamps;
380 com::SafeArray <BSTR> flags;
381 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(Utf8Patterns),
382 ComSafeArrayAsOutParam(names),
383 ComSafeArrayAsOutParam(values),
384 ComSafeArrayAsOutParam(timestamps),
385 ComSafeArrayAsOutParam(flags)));
386 if (SUCCEEDED(rc))
387 {
388 if (names.size() == 0)
389 RTPrintf("No properties found.\n");
390 for (unsigned i = 0; i < names.size(); ++i)
391 RTPrintf("Name: %lS, value: %lS, timestamp: %lld, flags: %lS\n",
392 names[i], values[i], timestamps[i], flags[i]);
393 }
394 }
395 return SUCCEEDED(rc) ? 0 : 1;
396}
397
398/**
399 * Enumerates the properties in the guest property store.
400 *
401 * @returns 0 on success, 1 on failure
402 * @note see the command line API description for parameters
403 */
404static int handleWaitGuestProperty(HandlerArg *a)
405{
406 /*
407 * Handle arguments
408 */
409 bool fFailOnTimeout = false;
410 const char *pszPatterns = NULL;
411 uint32_t cMsTimeout = RT_INDEFINITE_WAIT;
412 bool usageOK = true;
413 if (a->argc < 2)
414 usageOK = false;
415 else
416 pszPatterns = a->argv[1];
417 ComPtr<IMachine> machine;
418 /* assume it's a UUID */
419 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
420 if (FAILED(rc) || !machine)
421 {
422 /* must be a name */
423 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
424 }
425 if (!machine)
426 usageOK = false;
427 for (int i = 2; usageOK && i < a->argc; ++i)
428 {
429 if ( !strcmp(a->argv[i], "--timeout")
430 || !strcmp(a->argv[i], "-timeout"))
431 {
432 if ( i + 1 >= a->argc
433 || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
434 usageOK = false;
435 else
436 ++i;
437 }
438 else if (!strcmp(a->argv[i], "--fail-on-timeout"))
439 fFailOnTimeout = true;
440 else
441 usageOK = false;
442 }
443 if (!usageOK)
444 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
445
446 /*
447 * Set up the callback and loop until signal or timeout.
448 *
449 * We do this in 1000 ms chunks to be on the safe side (there used to be
450 * better reasons for it).
451 */
452 Bstr uuid;
453 machine->COMGETTER(Id)(uuid.asOutParam());
454 GuestPropertyCallback *cbImpl = new GuestPropertyCallback(pszPatterns, uuid);
455 ComPtr<IVirtualBoxCallback> callback;
456 rc = createCallbackWrapper((IVirtualBoxCallback *)cbImpl, callback.asOutParam());
457 if (FAILED(rc))
458 {
459 RTPrintf("Error creating callback wrapper: %Rhrc\n", rc);
460 return 1;
461 }
462 a->virtualBox->RegisterCallback(callback);
463 uint64_t u64Started = RTTimeMilliTS();
464 do
465 {
466 unsigned cMsWait;
467 if (cMsTimeout == RT_INDEFINITE_WAIT)
468 cMsWait = 1000;
469 else
470 {
471 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
472 if (cMsElapsed >= cMsTimeout)
473 break; /* timed out */
474 cMsWait = RT_MIN(1000, cMsTimeout - (uint32_t)cMsElapsed);
475 }
476 int vrc = com::EventQueue::getMainEventQueue()->processEventQueue(cMsWait);
477 if ( RT_FAILURE(vrc)
478 && vrc != VERR_TIMEOUT)
479 {
480 RTPrintf("Error waiting for event: %Rrc\n", vrc);
481 return 1;
482 }
483 } while (!cbImpl->Signalled());
484
485 a->virtualBox->UnregisterCallback(callback);
486
487 int rcRet = 0;
488 if (!cbImpl->Signalled())
489 {
490 RTPrintf("Time out or interruption while waiting for a notification.\n");
491 if (fFailOnTimeout)
492 rcRet = 2;
493 }
494 return rcRet;
495}
496
497/**
498 * Access the guest property store.
499 *
500 * @returns 0 on success, 1 on failure
501 * @note see the command line API description for parameters
502 */
503int handleGuestProperty(HandlerArg *a)
504{
505 HandlerArg arg = *a;
506 arg.argc = a->argc - 1;
507 arg.argv = a->argv + 1;
508
509 if (a->argc == 0)
510 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
511
512 /* switch (cmd) */
513 if (strcmp(a->argv[0], "get") == 0)
514 return handleGetGuestProperty(&arg);
515 if (strcmp(a->argv[0], "set") == 0)
516 return handleSetGuestProperty(&arg);
517 if (strcmp(a->argv[0], "enumerate") == 0)
518 return handleEnumGuestProperty(&arg);
519 if (strcmp(a->argv[0], "wait") == 0)
520 return handleWaitGuestProperty(&arg);
521
522 /* default: */
523 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
524}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use