[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] | 53 | using namespace com;
|
---|
| 54 |
|
---|
[16724] | 55 | /**
|
---|
| 56 | * IVirtualBoxCallback implementation for handling the GuestPropertyCallback in
|
---|
| 57 | * relation to the "guestproperty wait" command.
|
---|
| 58 | */
|
---|
[20928] | 59 | class GuestPropertyCallback :
|
---|
[19134] | 60 | VBOX_SCRIPTABLE_IMPL(IVirtualBoxCallback)
|
---|
[14258] | 61 | {
|
---|
| 62 | public:
|
---|
| 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 |
|
---|
| 180 | private:
|
---|
[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
|
---|
| 190 | NS_DECL_CLASSINFO(GuestPropertyCallback)
|
---|
[22686] | 191 | NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestPropertyCallback, IVirtualBoxCallback)
|
---|
[14258] | 192 | #endif /* VBOX_WITH_XPCOM */
|
---|
| 193 |
|
---|
[11031] | 194 | void 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] | 210 | static 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] | 260 | static 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] | 332 | static 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] | 402 | static 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] | 501 | int 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 | }
|
---|