VirtualBox

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

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

COM: missed pieces of scriptability support

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