VirtualBox

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

Last change on this file since 77887 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.8 KB
RevLine 
[14732]1/* $Id: VBoxManageGuestProp.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
[11031]2/** @file
[32701]3 * VBoxManage - Implementation of guestproperty command.
[11031]4 */
5
6/*
[76553]7 * Copyright (C) 2006-2019 Oracle Corporation
[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
18
[57358]19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
[14258]22#include "VBoxManage.h"
23
[32712]24#ifndef VBOX_ONLY_DOCS
25
[11031]26#include <VBox/com/com.h>
27#include <VBox/com/string.h>
[11042]28#include <VBox/com/array.h>
[11031]29#include <VBox/com/ErrorInfo.h>
[20928]30#include <VBox/com/errorprint.h>
[11031]31#include <VBox/com/VirtualBox.h>
32
[14258]33#include <VBox/log.h>
[22686]34#include <iprt/asm.h>
[11031]35#include <iprt/stream.h>
[22686]36#include <iprt/string.h>
37#include <iprt/time.h>
[14258]38#include <iprt/thread.h>
[11031]39
[14258]40#ifdef USE_XPCOM_QUEUE
41# include <sys/select.h>
[22686]42# include <errno.h>
[14258]43#endif
[11031]44
[22690]45#ifdef RT_OS_DARWIN
46# include <CoreFoundation/CFRunLoop.h>
47#endif
48
[11031]49using namespace com;
50
[32712]51#endif /* !VBOX_ONLY_DOCS */
52
[42460]53void usageGuestProperty(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2)
[11031]54{
[32712]55 RTStrmPrintf(pStrm,
[47000]56 "%s guestproperty %s get <uuid|vmname>\n"
[32701]57 " <property> [--verbose]\n"
[42460]58 "\n", pcszSep1, pcszSep2);
[32712]59 RTStrmPrintf(pStrm,
[47000]60 "%s guestproperty %s set <uuid|vmname>\n"
[32701]61 " <property> [<value> [--flags <flags>]]\n"
[42460]62 "\n", pcszSep1, pcszSep2);
[32712]63 RTStrmPrintf(pStrm,
[47000]64 "%s guestproperty %s delete|unset <uuid|vmname>\n"
[44322]65 " <property>\n"
66 "\n", pcszSep1, pcszSep2);
67 RTStrmPrintf(pStrm,
[47000]68 "%s guestproperty %s enumerate <uuid|vmname>\n"
[32701]69 " [--patterns <patterns>]\n"
[42460]70 "\n", pcszSep1, pcszSep2);
[32712]71 RTStrmPrintf(pStrm,
[47000]72 "%s guestproperty %s wait <uuid|vmname> <patterns>\n"
[32701]73 " [--timeout <msec>] [--fail-on-timeout]\n"
[42460]74 "\n", pcszSep1, pcszSep2);
[11031]75}
76
[32712]77#ifndef VBOX_ONLY_DOCS
78
[56118]79static RTEXITCODE handleGetGuestProperty(HandlerArg *a)
[11031]80{
81 HRESULT rc = S_OK;
82
83 bool verbose = false;
[16724]84 if ( a->argc == 3
[18772]85 && ( !strcmp(a->argv[2], "--verbose")
86 || !strcmp(a->argv[2], "-verbose")))
[11031]87 verbose = true;
[16052]88 else if (a->argc != 2)
[11031]89 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
90
91 ComPtr<IMachine> machine;
[33294]92 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
93 machine.asOutParam()));
[11031]94 if (machine)
95 {
[11113]96 /* open a session for the VM - new or existing */
[56118]97 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[11088]98
99 /* get the mutable session machine */
[16052]100 a->session->COMGETTER(Machine)(machine.asOutParam());
[11088]101
[11031]102 Bstr value;
[31698]103 LONG64 i64Timestamp;
[11031]104 Bstr flags;
[32718]105 CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]).raw(),
106 value.asOutParam(),
[31698]107 &i64Timestamp, flags.asOutParam()));
[32718]108 if (value.isEmpty())
[11031]109 RTPrintf("No value set!\n");
[32718]110 else
[38735]111 RTPrintf("Value: %ls\n", value.raw());
[32718]112 if (!value.isEmpty() && verbose)
[26587]113 {
[31698]114 RTPrintf("Timestamp: %lld\n", i64Timestamp);
[38735]115 RTPrintf("Flags: %ls\n", flags.raw());
[11031]116 }
117 }
[56118]118 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[11031]119}
120
[56118]121static RTEXITCODE handleSetGuestProperty(HandlerArg *a)
[11031]122{
123 HRESULT rc = S_OK;
124
[16724]125 /*
126 * Check the syntax. We can deduce the correct syntax from the number of
127 * arguments.
128 */
[11031]129 bool usageOK = true;
130 const char *pszName = NULL;
131 const char *pszValue = NULL;
132 const char *pszFlags = NULL;
[16724]133 if (a->argc == 3)
[16052]134 pszValue = a->argv[2];
[16724]135 else if (a->argc == 4)
[13294]136 usageOK = false;
[16724]137 else if (a->argc == 5)
[11031]138 {
[16052]139 pszValue = a->argv[2];
[22734]140 if ( strcmp(a->argv[3], "--flags")
141 && strcmp(a->argv[3], "-flags"))
[11031]142 usageOK = false;
[16052]143 pszFlags = a->argv[4];
[11031]144 }
[16052]145 else if (a->argc != 2)
[11031]146 usageOK = false;
147 if (!usageOK)
148 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[11097]149 /* This is always needed. */
[16052]150 pszName = a->argv[1];
[11031]151
152 ComPtr<IMachine> machine;
[33294]153 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
154 machine.asOutParam()));
[11031]155 if (machine)
156 {
[11113]157 /* open a session for the VM - new or existing */
[56118]158 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[11079]159
160 /* get the mutable session machine */
[16052]161 a->session->COMGETTER(Machine)(machine.asOutParam());
[11079]162
[44322]163 if (!pszFlags)
[32718]164 CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName).raw(),
165 Bstr(pszValue).raw()));
[11031]166 else
[32718]167 CHECK_ERROR(machine, SetGuestProperty(Bstr(pszName).raw(),
168 Bstr(pszValue).raw(),
169 Bstr(pszFlags).raw()));
[11079]170
171 if (SUCCEEDED(rc))
172 CHECK_ERROR(machine, SaveSettings());
173
[31070]174 a->session->UnlockMachine();
[11031]175 }
[56118]176 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[11031]177}
178
[56118]179static RTEXITCODE handleDeleteGuestProperty(HandlerArg *a)
[44322]180{
181 HRESULT rc = S_OK;
182
183 /*
184 * Check the syntax. We can deduce the correct syntax from the number of
185 * arguments.
186 */
187 bool usageOK = true;
188 const char *pszName = NULL;
189 if (a->argc != 2)
190 usageOK = false;
191 if (!usageOK)
192 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
193 /* This is always needed. */
194 pszName = a->argv[1];
195
196 ComPtr<IMachine> machine;
197 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
198 machine.asOutParam()));
199 if (machine)
200 {
201 /* open a session for the VM - new or existing */
[56118]202 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[44322]203
204 /* get the mutable session machine */
205 a->session->COMGETTER(Machine)(machine.asOutParam());
206
207 CHECK_ERROR(machine, DeleteGuestProperty(Bstr(pszName).raw()));
208
209 if (SUCCEEDED(rc))
210 CHECK_ERROR(machine, SaveSettings());
211
212 a->session->UnlockMachine();
213 }
[56118]214 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[44322]215}
216
[11042]217/**
218 * Enumerates the properties in the guest property store.
219 *
220 * @returns 0 on success, 1 on failure
221 * @note see the command line API description for parameters
222 */
[56118]223static RTEXITCODE handleEnumGuestProperty(HandlerArg *a)
[11042]224{
[16724]225 /*
226 * Check the syntax. We can deduce the correct syntax from the number of
227 * arguments.
228 */
229 if ( a->argc < 1
230 || a->argc == 2
231 || ( a->argc > 3
[18772]232 && strcmp(a->argv[1], "--patterns")
233 && strcmp(a->argv[1], "-patterns")))
[11042]234 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[11031]235
[16724]236 /*
237 * Pack the patterns
238 */
[30806]239 Utf8Str Utf8Patterns(a->argc > 2 ? a->argv[2] : "");
[16724]240 for (int i = 3; i < a->argc; ++i)
[31539]241 Utf8Patterns = Utf8StrFmt ("%s,%s", Utf8Patterns.c_str(), a->argv[i]);
[11042]242
[16724]243 /*
244 * Make the actual call to Main.
245 */
[11042]246 ComPtr<IMachine> machine;
[33294]247 HRESULT rc;
248 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
249 machine.asOutParam()));
[11042]250 if (machine)
251 {
[11113]252 /* open a session for the VM - new or existing */
[56118]253 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE);
[11088]254
255 /* get the mutable session machine */
[16052]256 a->session->COMGETTER(Machine)(machine.asOutParam());
[11088]257
[31008]258 com::SafeArray<BSTR> names;
259 com::SafeArray<BSTR> values;
[31698]260 com::SafeArray<LONG64> timestamps;
[31008]261 com::SafeArray<BSTR> flags;
[32718]262 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(Utf8Patterns).raw(),
[11042]263 ComSafeArrayAsOutParam(names),
264 ComSafeArrayAsOutParam(values),
265 ComSafeArrayAsOutParam(timestamps),
266 ComSafeArrayAsOutParam(flags)));
267 if (SUCCEEDED(rc))
268 {
269 if (names.size() == 0)
270 RTPrintf("No properties found.\n");
271 for (unsigned i = 0; i < names.size(); ++i)
[38735]272 RTPrintf("Name: %ls, value: %ls, timestamp: %lld, flags: %ls\n",
[11042]273 names[i], values[i], timestamps[i], flags[i]);
274 }
275 }
[56118]276 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[11042]277}
278
[11031]279/**
[14258]280 * Enumerates the properties in the guest property store.
281 *
282 * @returns 0 on success, 1 on failure
283 * @note see the command line API description for parameters
284 */
[56118]285static RTEXITCODE handleWaitGuestProperty(HandlerArg *a)
[14258]286{
[16724]287 /*
288 * Handle arguments
289 */
[22686]290 bool fFailOnTimeout = false;
291 const char *pszPatterns = NULL;
292 uint32_t cMsTimeout = RT_INDEFINITE_WAIT;
293 bool usageOK = true;
[16052]294 if (a->argc < 2)
[14258]295 usageOK = false;
296 else
[16052]297 pszPatterns = a->argv[1];
[14258]298 ComPtr<IMachine> machine;
[33294]299 HRESULT rc;
300 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
301 machine.asOutParam()));
[14258]302 if (!machine)
303 usageOK = false;
[16052]304 for (int i = 2; usageOK && i < a->argc; ++i)
[14258]305 {
[18772]306 if ( !strcmp(a->argv[i], "--timeout")
307 || !strcmp(a->argv[i], "-timeout"))
[14258]308 {
[16052]309 if ( i + 1 >= a->argc
[22686]310 || RTStrToUInt32Full(a->argv[i + 1], 10, &cMsTimeout) != VINF_SUCCESS)
[14258]311 usageOK = false;
312 else
313 ++i;
314 }
[22686]315 else if (!strcmp(a->argv[i], "--fail-on-timeout"))
316 fFailOnTimeout = true;
[14258]317 else
318 usageOK = false;
319 }
320 if (!usageOK)
321 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
322
[16724]323 /*
[30599]324 * Set up the event listener and wait until found match or timeout.
[16724]325 */
[30599]326 Bstr aMachStrGuid;
327 machine->COMGETTER(Id)(aMachStrGuid.asOutParam());
328 Guid aMachGuid(aMachStrGuid);
329 ComPtr<IEventSource> es;
330 CHECK_ERROR(a->virtualBox, COMGETTER(EventSource)(es.asOutParam()));
331 ComPtr<IEventListener> listener;
332 CHECK_ERROR(es, CreateListener(listener.asOutParam()));
333 com::SafeArray <VBoxEventType_T> eventTypes(1);
[30871]334 eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged);
[30599]335 CHECK_ERROR(es, RegisterListener(listener, ComSafeArrayAsInParam(eventTypes), false));
336
[22914]337 uint64_t u64Started = RTTimeMilliTS();
[30599]338 bool fSignalled = false;
[23083]339 do
340 {
341 unsigned cMsWait;
342 if (cMsTimeout == RT_INDEFINITE_WAIT)
343 cMsWait = 1000;
344 else
345 {
346 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
347 if (cMsElapsed >= cMsTimeout)
348 break; /* timed out */
[23091]349 cMsWait = RT_MIN(1000, cMsTimeout - (uint32_t)cMsElapsed);
[23083]350 }
[30599]351
352 ComPtr<IEvent> ev;
[30608]353 rc = es->GetEvent(listener, cMsWait, ev.asOutParam());
[30599]354 if (ev)
[23083]355 {
[30608]356 VBoxEventType_T aType;
357 rc = ev->COMGETTER(Type)(&aType);
[30599]358 switch (aType)
359 {
[30871]360 case VBoxEventType_OnGuestPropertyChanged:
[30599]361 {
[30825]362 ComPtr<IGuestPropertyChangedEvent> gpcev = ev;
[30606]363 Assert(gpcev);
[30599]364 Bstr aNextStrGuid;
365 gpcev->COMGETTER(MachineId)(aNextStrGuid.asOutParam());
[30608]366 if (aMachGuid != Guid(aNextStrGuid))
[30599]367 continue;
368 Bstr aNextName;
369 gpcev->COMGETTER(Name)(aNextName.asOutParam());
370 if (RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
[31539]371 Utf8Str(aNextName).c_str(), RTSTR_MAX, NULL))
[30599]372 {
373 Bstr aNextValue, aNextFlags;
374 gpcev->COMGETTER(Value)(aNextValue.asOutParam());
375 gpcev->COMGETTER(Flags)(aNextFlags.asOutParam());
[38735]376 RTPrintf("Name: %ls, value: %ls, flags: %ls\n",
[30599]377 aNextName.raw(), aNextValue.raw(), aNextFlags.raw());
378 fSignalled = true;
379 }
[30600]380 break;
[30599]381 }
382 default:
383 AssertFailed();
384 }
[23083]385 }
[30599]386 } while (!fSignalled);
[22686]387
[30599]388 es->UnregisterListener(listener);
[22686]389
[56118]390 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
[30599]391 if (!fSignalled)
[22686]392 {
[32701]393 RTMsgError("Time out or interruption while waiting for a notification.");
[22686]394 if (fFailOnTimeout)
[56118]395 /* Hysterical rasins: We always returned 2 here, which now translates to syntax error... Which is bad. */
396 rcExit = RTEXITCODE_SYNTAX;
[22686]397 }
[56118]398 return rcExit;
[14258]399}
400
401/**
[11031]402 * Access the guest property store.
403 *
404 * @returns 0 on success, 1 on failure
405 * @note see the command line API description for parameters
406 */
[56118]407RTEXITCODE handleGuestProperty(HandlerArg *a)
[11031]408{
[16052]409 HandlerArg arg = *a;
410 arg.argc = a->argc - 1;
411 arg.argv = a->argv + 1;
412
[35951]413 /** @todo This command does not follow the syntax where the <uuid|vmname>
414 * comes between the command and subcommand. The commands controlvm,
415 * snapshot and debugvm puts it between.
416 */
417
[16724]418 if (a->argc == 0)
[11031]419 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
[16724]420
421 /* switch (cmd) */
422 if (strcmp(a->argv[0], "get") == 0)
[16052]423 return handleGetGuestProperty(&arg);
[16724]424 if (strcmp(a->argv[0], "set") == 0)
[16052]425 return handleSetGuestProperty(&arg);
[44329]426 if (strcmp(a->argv[0], "delete") == 0 || strcmp(a->argv[0], "unset") == 0)
[44322]427 return handleDeleteGuestProperty(&arg);
[16724]428 if (strcmp(a->argv[0], "enumerate") == 0)
[16052]429 return handleEnumGuestProperty(&arg);
[16724]430 if (strcmp(a->argv[0], "wait") == 0)
[16052]431 return handleWaitGuestProperty(&arg);
[16724]432
433 /* default: */
[11031]434 return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
435}
[32712]436
437#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use