VirtualBox

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

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