VirtualBox

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

Last change on this file since 24912 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
RevLine 
[14732]1/* $Id: VBoxManageGuestProp.cpp 24024 2009-10-23 11:53:22Z vboxsync $ */
[11031]2/** @file
[14732]3 * VBoxManage - The 'guestproperty' command.
[11031]4 */
5
6/*
[20928]7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
[11031]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*******************************************************************************/
[14258]26#include "VBoxManage.h"
27
[11031]28#include <VBox/com/com.h>
29#include <VBox/com/string.h>
[11042]30#include <VBox/com/array.h>
[11031]31#include <VBox/com/ErrorInfo.h>
[20928]32#include <VBox/com/errorprint.h>
[16530]33
[11031]34#include <VBox/com/VirtualBox.h>
[22911]35#include <VBox/com/EventQueue.h>
[11031]36
[14258]37#include <VBox/log.h>
[22686]38#include <iprt/asm.h>
[11031]39#include <iprt/stream.h>
[22686]40#include <iprt/string.h>
41#include <iprt/time.h>
[14258]42#include <iprt/thread.h>
[11031]43
[14258]44#ifdef USE_XPCOM_QUEUE
45# include <sys/select.h>
[22686]46# include <errno.h>
[14258]47#endif
[11031]48
[22690]49#ifdef RT_OS_DARWIN
50# include <CoreFoundation/CFRunLoop.h>
51#endif
52
[11031]53using namespace com;
54
[16724]55/**
56 * IVirtualBoxCallback implementation for handling the GuestPropertyCallback in
57 * relation to the "guestproperty wait" command.
58 */
[20928]59class GuestPropertyCallback :
[19134]60 VBOX_SCRIPTABLE_IMPL(IVirtualBoxCallback)
[14258]61{
62public:
63 GuestPropertyCallback(const char *pszPatterns, Guid aUuid)
64 : mSignalled(false), mPatterns(pszPatterns), mUuid(aUuid)
65 {
[16724]66#ifndef VBOX_WITH_XPCOM
[14258]67 refcnt = 0;
68#endif
69 }
70
[22686]71 virtual ~GuestPropertyCallback()
72 {
73 }
[14258]74
[16724]75#ifndef VBOX_WITH_XPCOM
[14258]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 }
[16724]87#endif /* !VBOX_WITH_XPCOM */
[21520]88 VBOX_SCRIPTABLE_DISPATCH_IMPL(IVirtualBoxCallback)
[14258]89
90 NS_DECL_ISUPPORTS
91
[19239]92 STDMETHOD(OnMachineStateChange)(IN_BSTR machineId,
[14258]93 MachineState_T state)
94 {
95 return S_OK;
96 }
97
[19239]98 STDMETHOD(OnMachineDataChange)(IN_BSTR machineId)
[14258]99 {
100 return S_OK;
101 }
102
[19239]103 STDMETHOD(OnExtraDataCanChange)(IN_BSTR machineId, IN_BSTR key,
[15051]104 IN_BSTR value, BSTR *error,
[14258]105 BOOL *changeAllowed)
106 {
107 /* we never disagree */
108 if (!changeAllowed)
109 return E_INVALIDARG;
110 *changeAllowed = TRUE;
111 return S_OK;
112 }
113
[19239]114 STDMETHOD(OnExtraDataChange)(IN_BSTR machineId, IN_BSTR key,
[15051]115 IN_BSTR value)
[14258]116 {
117 return S_OK;
118 }
119
[23223]120 STDMETHOD(OnMediumRegistered)(IN_BSTR mediaId,
121 DeviceType_T mediaType, BOOL registered)
[14258]122 {
[16724]123 NOREF(mediaId);
124 NOREF(mediaType);
125 NOREF(registered);
[14258]126 return S_OK;
127 }
128
[19239]129 STDMETHOD(OnMachineRegistered)(IN_BSTR machineId, BOOL registered)
[14258]130 {
131 return S_OK;
132 }
133
[19239]134 STDMETHOD(OnSessionStateChange)(IN_BSTR machineId,
[14258]135 SessionState_T state)
136 {
137 return S_OK;
138 }
139
[19239]140 STDMETHOD(OnSnapshotTaken)(IN_BSTR aMachineId,
141 IN_BSTR aSnapshotId)
[14258]142 {
143 return S_OK;
144 }
145
[19239]146 STDMETHOD(OnSnapshotDiscarded)(IN_BSTR aMachineId,
147 IN_BSTR aSnapshotId)
[14258]148 {
149 return S_OK;
150 }
151
[19239]152 STDMETHOD(OnSnapshotChange)(IN_BSTR aMachineId,
153 IN_BSTR aSnapshotId)
[14258]154 {
155 return S_OK;
156 }
157
[19239]158 STDMETHOD(OnGuestPropertyChange)(IN_BSTR machineId,
[15051]159 IN_BSTR name, IN_BSTR value,
160 IN_BSTR flags)
[14258]161 {
[21404]162 Utf8Str utf8Name(name);
[14258]163 Guid uuid(machineId);
[22686]164 if ( uuid == mUuid
[16724]165 && RTStrSimplePatternMultiMatch(mPatterns, RTSTR_MAX,
166 utf8Name.raw(), RTSTR_MAX, NULL))
[14258]167 {
[22686]168 RTPrintf("Name: %lS, value: %lS, flags: %lS\n", name, value, flags);
169 ASMAtomicWriteBool(&mSignalled, true);
[23083]170 com::EventQueue::getMainEventQueue()->interruptEventQueueProcessing();
[14258]171 }
[22686]172 return S_OK;
[14258]173 }
174
[22686]175 bool Signalled(void) const
176 {
177 return mSignalled;
178 }
[14258]179
180private:
[22686]181 bool volatile mSignalled;
[14258]182 const char *mPatterns;
183 Guid mUuid;
[16724]184#ifndef VBOX_WITH_XPCOM
[14258]185 long refcnt;
186#endif
187};
188
189#ifdef VBOX_WITH_XPCOM
190NS_DECL_CLASSINFO(GuestPropertyCallback)
[22686]191NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestPropertyCallback, IVirtualBoxCallback)
[14258]192#endif /* VBOX_WITH_XPCOM */
193
[11031]194void usageGuestProperty(void)
195{
196 RTPrintf("VBoxManage guestproperty get <vmname>|<uuid>\n"
[18772]197 " <property> [--verbose]\n"
[11031]198 "\n");
199 RTPrintf("VBoxManage guestproperty set <vmname>|<uuid>\n"
[18772]200 " <property> [<value> [--flags <flags>]]\n"
[11031]201 "\n");
[11042]202 RTPrintf("VBoxManage guestproperty enumerate <vmname>|<uuid>\n"
[18772]203 " [--patterns <patterns>]\n"
[11042]204 "\n");
[14258]205 RTPrintf("VBoxManage guestproperty wait <vmname>|<uuid> <patterns>\n"
[22686]206 " [--timeout <milliseconds>] [--fail-on-timeout]\n"
[14258]207 "\n");
[11031]208}
209
[16052]210static int handleGetGuestProperty(HandlerArg *a)
[11031]211{
212 HRESULT rc = S_OK;
213
214 bool verbose = false;
[16724]215 if ( a->argc == 3
[18772]216 && ( !strcmp(a->argv[2], "--verbose")
217 || !strcmp(a->argv[2], "-verbose")))
[11031]218 verbose = true;
[16052]219 else if (a->argc != 2)
[11031]220 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
221
222 ComPtr<IMachine> machine;
223 /* assume it's a UUID */
[19239]224 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
[11031]225 if (FAILED(rc) || !machine)
226 {
227 /* must be a name */
[16052]228 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
[11031]229 }
230 if (machine)
231 {
[19239]232 Bstr uuid;
[11088]233 machine->COMGETTER(Id)(uuid.asOutParam());
234
[11113]235 /* open a session for the VM - new or existing */
[16052]236 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
[16724]237 CHECK_ERROR_RET(a->virtualBox, OpenExistingSession(a->session, uuid), 1);
[11088]238
239 /* get the mutable session machine */
[16052]240 a->session->COMGETTER(Machine)(machine.asOutParam());
[11088]241
[11031]242 Bstr value;
[16724]243 ULONG64 u64Timestamp;
[11031]244 Bstr flags;
[16052]245 CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]), value.asOutParam(),
[16724]246 &u64Timestamp, flags.asOutParam()));
[11031]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
[16052]260static int handleSetGuestProperty(HandlerArg *a)
[11031]261{
262 HRESULT rc = S_OK;
263
[16724]264 /*
265 * Check the syntax. We can deduce the correct syntax from the number of
266 * arguments.
267 */
[11031]268 bool usageOK = true;
269 const char *pszName = NULL;
270 const char *pszValue = NULL;
271 const char *pszFlags = NULL;
[16724]272 if (a->argc == 3)
[16052]273 pszValue = a->argv[2];
[16724]274 else if (a->argc == 4)
[13294]275 usageOK = false;
[16724]276 else if (a->argc == 5)
[11031]277 {
[16052]278 pszValue = a->argv[2];
[22734]279 if ( strcmp(a->argv[3], "--flags")
280 && strcmp(a->argv[3], "-flags"))
[11031]281 usageOK = false;
[16052]282 pszFlags = a->argv[4];
[11031]283 }
[16052]284 else if (a->argc != 2)
[11031]285 usageOK = false;
286 if (!usageOK)
287 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[11097]288 /* This is always needed. */
[16052]289 pszName = a->argv[1];
[11031]290
291 ComPtr<IMachine> machine;
292 /* assume it's a UUID */
[19239]293 rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
[11031]294 if (FAILED(rc) || !machine)
295 {
296 /* must be a name */
[16052]297 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
[11031]298 }
299 if (machine)
300 {
[19239]301 Bstr uuid;
[11079]302 machine->COMGETTER(Id)(uuid.asOutParam());
303
[11113]304 /* open a session for the VM - new or existing */
[16052]305 if (FAILED (a->virtualBox->OpenSession(a->session, uuid)))
306 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
[11079]307
308 /* get the mutable session machine */
[16052]309 a->session->COMGETTER(Machine)(machine.asOutParam());
[11079]310
[16724]311 if (!pszValue && !pszFlags)
[24024]312 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr("")));
[16724]313 else if (!pszFlags)
[11031]314 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName), Bstr(pszValue)));
315 else
316 CHECK_ERROR(machine, SetGuestProperty(Bstr(pszName), Bstr(pszValue), Bstr(pszFlags)));
[11079]317
318 if (SUCCEEDED(rc))
319 CHECK_ERROR(machine, SaveSettings());
320
[16052]321 a->session->Close();
[11031]322 }
323 return SUCCEEDED(rc) ? 0 : 1;
324}
325
[11042]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 */
[16052]332static int handleEnumGuestProperty(HandlerArg *a)
[11042]333{
[16724]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
[18772]341 && strcmp(a->argv[1], "--patterns")
342 && strcmp(a->argv[1], "-patterns")))
[11042]343 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[11031]344
[16724]345 /*
346 * Pack the patterns
347 */
[16052]348 Utf8Str Utf8Patterns(a->argc > 2 ? a->argv[2] : "*");
[16724]349 for (int i = 3; i < a->argc; ++i)
[16052]350 Utf8Patterns = Utf8StrFmt ("%s,%s", Utf8Patterns.raw(), a->argv[i]);
[11042]351
[16724]352 /*
353 * Make the actual call to Main.
354 */
[11042]355 ComPtr<IMachine> machine;
356 /* assume it's a UUID */
[19239]357 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
[11042]358 if (FAILED(rc) || !machine)
359 {
360 /* must be a name */
[16052]361 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
[11042]362 }
363 if (machine)
364 {
[19239]365 Bstr uuid;
[11088]366 machine->COMGETTER(Id)(uuid.asOutParam());
367
[11113]368 /* open a session for the VM - new or existing */
[16724]369 if (FAILED(a->virtualBox->OpenSession(a->session, uuid)))
[16052]370 CHECK_ERROR_RET (a->virtualBox, OpenExistingSession(a->session, uuid), 1);
[11088]371
372 /* get the mutable session machine */
[16052]373 a->session->COMGETTER(Machine)(machine.asOutParam());
[11088]374
[11042]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
[11031]396/**
[14258]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 */
[16052]402static int handleWaitGuestProperty(HandlerArg *a)
[14258]403{
[16724]404 /*
405 * Handle arguments
406 */
[22686]407 bool fFailOnTimeout = false;
408 const char *pszPatterns = NULL;
409 uint32_t cMsTimeout = RT_INDEFINITE_WAIT;
410 bool usageOK = true;
[16052]411 if (a->argc < 2)
[14258]412 usageOK = false;
413 else
[16052]414 pszPatterns = a->argv[1];
[14258]415 ComPtr<IMachine> machine;
416 /* assume it's a UUID */
[19239]417 HRESULT rc = a->virtualBox->GetMachine(Bstr(a->argv[0]), machine.asOutParam());
[14258]418 if (FAILED(rc) || !machine)
419 {
420 /* must be a name */
[16052]421 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]), machine.asOutParam()));
[14258]422 }
423 if (!machine)
424 usageOK = false;
[16052]425 for (int i = 2; usageOK && i < a->argc; ++i)
[14258]426 {
[18772]427 if ( !strcmp(a->argv[i], "--timeout")
428 || !strcmp(a->argv[i], "-timeout"))
[14258]429 {
[16052]430 if ( i + 1 >= a->argc
[22686]431 || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
[14258]432 usageOK = false;
433 else
434 ++i;
435 }
[22686]436 else if (!strcmp(a->argv[i], "--fail-on-timeout"))
437 fFailOnTimeout = true;
[14258]438 else
439 usageOK = false;
440 }
441 if (!usageOK)
442 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
443
[16724]444 /*
[23083]445 * Set up the callback and loop until signal or timeout.
[22686]446 *
[23083]447 * We do this in 1000 ms chunks to be on the safe side (there used to be
448 * better reasons for it).
[16724]449 */
[19239]450 Bstr uuid;
[14258]451 machine->COMGETTER(Id)(uuid.asOutParam());
[22686]452 GuestPropertyCallback *cbImpl = new GuestPropertyCallback(pszPatterns, uuid);
[22305]453 ComPtr<IVirtualBoxCallback> callback;
[22686]454 rc = createCallbackWrapper((IVirtualBoxCallback *)cbImpl, callback.asOutParam());
[22305]455 if (FAILED(rc))
[22686]456 {
457 RTPrintf("Error creating callback wrapper: %Rhrc\n", rc);
[22305]458 return 1;
[22686]459 }
460 a->virtualBox->RegisterCallback(callback);
[22914]461 uint64_t u64Started = RTTimeMilliTS();
[23083]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 */
[23091]472 cMsWait = RT_MIN(1000, cMsTimeout - (uint32_t)cMsElapsed);
[23083]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());
[22686]482
[16724]483 a->virtualBox->UnregisterCallback(callback);
[22686]484
485 int rcRet = 0;
[22305]486 if (!cbImpl->Signalled())
[22686]487 {
[14258]488 RTPrintf("Time out or interruption while waiting for a notification.\n");
[22686]489 if (fFailOnTimeout)
490 rcRet = 2;
491 }
492 return rcRet;
[14258]493}
494
495/**
[11031]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 */
[16052]501int handleGuestProperty(HandlerArg *a)
[11031]502{
[16052]503 HandlerArg arg = *a;
504 arg.argc = a->argc - 1;
505 arg.argv = a->argv + 1;
506
[16724]507 if (a->argc == 0)
[11031]508 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[16724]509
510 /* switch (cmd) */
511 if (strcmp(a->argv[0], "get") == 0)
[16052]512 return handleGetGuestProperty(&arg);
[16724]513 if (strcmp(a->argv[0], "set") == 0)
[16052]514 return handleSetGuestProperty(&arg);
[16724]515 if (strcmp(a->argv[0], "enumerate") == 0)
[16052]516 return handleEnumGuestProperty(&arg);
[16724]517 if (strcmp(a->argv[0], "wait") == 0)
[16052]518 return handleWaitGuestProperty(&arg);
[16724]519
520 /* default: */
[11031]521 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
522}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use