VirtualBox

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

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

Main and VBoxManage/GuestProperties: fix deleting GuestProperties in VBoxManage, part 2

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 15.6 KB
Line 
1/* $Id: VBoxManageGuestProp.cpp 24024 2009-10-23 11:53:22Z 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 RTPrintf("Value: %lS\n", value.raw());
251 if (value && verbose)
252 {
253 RTPrintf("Timestamp: %lld\n", u64Timestamp);
254 RTPrintf("Flags: %lS\n", flags.raw());
255 }
256 }
257 return SUCCEEDED(rc) ? 0 : 1;
258}
259
260static int handleSetGuestProperty(HandlerArg *a)
261{
262 HRESULT rc = S_OK;
263
264 /*
265 * Check the syntax. We can deduce the correct syntax from the number of
266 * arguments.
267 */
268 bool usageOK = true;
269 const char *pszName = NULL;
270 const char *pszValue = NULL;
271 const char *pszFlags = NULL;
272 if (a->argc == 3)
273 pszValue = a->argv[2];
274 else if (a->argc == 4)
275 usageOK = false;
276 else if (a->argc == 5)
277 {
278 pszValue = a->argv[2];
279 if ( strcmp(a->argv[3], "--flags")
280 && strcmp(a->argv[3], "-flags"))
281 usageOK = false;
282 pszFlags = a->argv[4];
283 }
284 else if (a->argc != 2)
285 usageOK = false;
286 if (!usageOK)
287 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
288 /* This is always needed. */
289 pszName = a->argv[1];
290
291 ComPtr<IMachine> machine;
292 /* assume it's a UUID */
293 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
294 if (FAILED(rc) || !machine)
295 {
296 /* must be a name */
297 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
298 }
299 if (machine)
300 {
301 Bstr uuid;
302 machine->COMGETTER(Id)(uuid.asOutParam());
303
304 /* open a session for the VM - new or existing */
305 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
306 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
307
308 /* get the mutable session machine */
309 a->session->COMGETTER(Machine)(machine.asOutParam());
310
311 if (!pszValue && !pszFlags)
312 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr("")));
313 else if (!pszFlags)
314 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr(pszValue)));
315 else
316 CHECK_ERROR(machine, SetGuestProperty(Bstr(pszName), Bstr(pszValue), Bstr(pszFlags)));
317
318 if (SUCCEEDED(rc))
319 CHECK_ERROR(machine, SaveSettings());
320
321 a->session->Close();
322 }
323 return SUCCEEDED(rc) ? 0 : 1;
324}
325
326/**
327 * Enumerates the properties in the guest property store.
328 *
329 * @returns 0 on success, 1 on failure
330 * @note see the command line API description for parameters
331 */
332static int handleEnumGuestProperty(HandlerArg *a)
333{
334 /*
335 * Check the syntax. We can deduce the correct syntax from the number of
336 * arguments.
337 */
338 if ( a->argc < 1
339 || a->argc == 2
340 || ( a->argc > 3
341 && strcmp(a->argv[1], "--patterns")
342 && strcmp(a->argv[1], "-patterns")))
343 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
344
345 /*
346 * Pack the patterns
347 */
348 Utf8Str Utf8Patterns(a->argc > 2 ? a->argv[2] : "*");
349 for (int i = 3; i < a->argc; ++i)
350 Utf8Patterns = Utf8StrFmt ("%s,%s", Utf8Patterns.raw(), a->argv[i]);
351
352 /*
353 * Make the actual call to Main.
354 */
355 ComPtr<IMachine> machine;
356 /* assume it's a UUID */
357 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
358 if (FAILED(rc) || !machine)
359 {
360 /* must be a name */
361 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
362 }
363 if (machine)
364 {
365 Bstr uuid;
366 machine->COMGETTER(Id)(uuid.asOutParam());
367
368 /* open a session for the VM - new or existing */
369 if (FAILED(a->virtualBox->OpenSession(a->session, uuid)))
370 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
371
372 /* get the mutable session machine */
373 a->session->COMGETTER(Machine)(machine.asOutParam());
374
375 com::SafeArray <BSTR> names;
376 com::SafeArray <BSTR> values;
377 com::SafeArray <ULONG64> timestamps;
378 com::SafeArray <BSTR> flags;
379 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(Utf8Patterns),
380 ComSafeArrayAsOutParam(names),
381 ComSafeArrayAsOutParam(values),
382 ComSafeArrayAsOutParam(timestamps),
383 ComSafeArrayAsOutParam(flags)));
384 if (SUCCEEDED(rc))
385 {
386 if (names.size() == 0)
387 RTPrintf("No properties found.\n");
388 for (unsigned i = 0; i < names.size(); ++i)
389 RTPrintf("Name: %lS, value: %lS, timestamp: %lld, flags: %lS\n",
390 names[i], values[i], timestamps[i], flags[i]);
391 }
392 }
393 return SUCCEEDED(rc) ? 0 : 1;
394}
395
396/**
397 * Enumerates the properties in the guest property store.
398 *
399 * @returns 0 on success, 1 on failure
400 * @note see the command line API description for parameters
401 */
402static int handleWaitGuestProperty(HandlerArg *a)
403{
404 /*
405 * Handle arguments
406 */
407 bool fFailOnTimeout = false;
408 const char *pszPatterns = NULL;
409 uint32_t cMsTimeout = RT_INDEFINITE_WAIT;
410 bool usageOK = true;
411 if (a->argc < 2)
412 usageOK = false;
413 else
414 pszPatterns = a->argv[1];
415 ComPtr<IMachine> machine;
416 /* assume it's a UUID */
417 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
418 if (FAILED(rc) || !machine)
419 {
420 /* must be a name */
421 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
422 }
423 if (!machine)
424 usageOK = false;
425 for (int i = 2; usageOK && i < a->argc; ++i)
426 {
427 if ( !strcmp(a->argv[i], "--timeout")
428 || !strcmp(a->argv[i], "-timeout"))
429 {
430 if ( i + 1 >= a->argc
431 || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
432 usageOK = false;
433 else
434 ++i;
435 }
436 else if (!strcmp(a->argv[i], "--fail-on-timeout"))
437 fFailOnTimeout = true;
438 else
439 usageOK = false;
440 }
441 if (!usageOK)
442 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
443
444 /*
445 * Set up the callback and loop until signal or timeout.
446 *
447 * We do this in 1000 ms chunks to be on the safe side (there used to be
448 * better reasons for it).
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 uint64_t u64Started = RTTimeMilliTS();
462 do
463 {
464 unsigned cMsWait;
465 if (cMsTimeout == RT_INDEFINITE_WAIT)
466 cMsWait = 1000;
467 else
468 {
469 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
470 if (cMsElapsed >= cMsTimeout)
471 break; /* timed out */
472 cMsWait = RT_MIN(1000, cMsTimeout - (uint32_t)cMsElapsed);
473 }
474 int vrc = com::EventQueue::getMainEventQueue()->processEventQueue(cMsWait);
475 if ( RT_FAILURE(vrc)
476 && vrc != VERR_TIMEOUT)
477 {
478 RTPrintf("Error waiting for event: %Rrc\n", vrc);
479 return 1;
480 }
481 } while (!cbImpl->Signalled());
482
483 a->virtualBox->UnregisterCallback(callback);
484
485 int rcRet = 0;
486 if (!cbImpl->Signalled())
487 {
488 RTPrintf("Time out or interruption while waiting for a notification.\n");
489 if (fFailOnTimeout)
490 rcRet = 2;
491 }
492 return rcRet;
493}
494
495/**
496 * Access the guest property store.
497 *
498 * @returns 0 on success, 1 on failure
499 * @note see the command line API description for parameters
500 */
501int handleGuestProperty(HandlerArg *a)
502{
503 HandlerArg arg = *a;
504 arg.argc = a->argc - 1;
505 arg.argv = a->argv + 1;
506
507 if (a->argc == 0)
508 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
509
510 /* switch (cmd) */
511 if (strcmp(a->argv[0], "get") == 0)
512 return handleGetGuestProperty(&arg);
513 if (strcmp(a->argv[0], "set") == 0)
514 return handleSetGuestProperty(&arg);
515 if (strcmp(a->argv[0], "enumerate") == 0)
516 return handleEnumGuestProperty(&arg);
517 if (strcmp(a->argv[0], "wait") == 0)
518 return handleWaitGuestProperty(&arg);
519
520 /* default: */
521 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
522}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use