Changeset 96623 in vbox
- Timestamp:
- Sep 7, 2022 1:25:44 AM (2 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
-
doc/manual/en_US/man_VBoxManage-guestproperty.xml (modified) (3 diffs)
-
src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/manual/en_US/man_VBoxManage-guestproperty.xml
r96618 r96623 64 64 <arg choice="plain"><replaceable>vmname</replaceable></arg> 65 65 </group> 66 <arg>--patterns=<replaceable>patterns</replaceable></arg> 66 <arg>--no-timestamp</arg> 67 <arg>--no-flags</arg> 68 <arg>--relative</arg> 69 <arg>--old-format</arg> 70 <arg ret="repeat"><replaceable>patterns</replaceable></arg> 67 71 </cmdsynopsis> 68 72 … … 131 135 The <command>VBoxManage guestproperty enumerate</command> command 132 136 lists each guest property and value for the specified 133 VM. Note that the output is limited if the guest's service 134 process cannot be contacted, for example because the VM is not137 VM. Note that the output is limited if the guest's service is 138 not updating the properties, for example because the VM is not 135 139 running or because the Guest Additions are not installed. 136 140 </para> 137 141 <variablelist> 138 142 <varlistentry> 139 <term><option>--patterns=<replaceable>pattern</replaceable></option></term> 143 <term><option>--relative</option></term> 144 <listitem><para>Display the timestamp relative to current time.</para></listitem> 145 </varlistentry> 146 <varlistentry> 147 <term><option>--no-timestamp</option></term> 148 <listitem><para>Do not display the timestamp of the last update.</para></listitem> 149 </varlistentry> 150 <varlistentry> 151 <term><option>--no-flags</option></term> 152 <listitem><para>Do not display the flags.</para></listitem> 153 </varlistentry> 154 <varlistentry> 155 <term><option>--old-format</option></term> 156 <listitem><para>Use the output format from VirtualBox 6.1 and earlier.</para></listitem> 157 </varlistentry> 158 <varlistentry> 159 <term><option><replaceable>pattern</replaceable></option></term> 140 160 <listitem><para> 141 161 Filters the list of properties based on the specified … … 172 192 </variablelist></listitem> 173 193 </varlistentry> 174 </variablelist> 194 195 </variablelist> 175 196 </refsect2> 176 197 <refsect2 id="vboxmanage-guestproperty-get"> -
trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
r96407 r96623 215 215 216 216 /* 217 * Check the syntax. We can deduce the correct syntax from the number of 218 * arguments. 217 * Parse arguments. 218 * 219 * The old syntax was a little boinkers. The --patterns argument just 220 * indicates that the rest of the arguments are options. Sort of like '--'. 221 * This has been normalized a little now, by accepting patterns w/o a 222 * preceding --pattern argument via the VINF_GETOPT_NOT_OPTION. 223 * Though, the first non-option is always the VM name. 219 224 */ 220 if ( a->argc < 1 221 || a->argc == 2 222 || ( a->argc > 3 223 && strcmp(a->argv[1], "--patterns") 224 && strcmp(a->argv[1], "-patterns"))) 225 return errorSyntax(GuestProp::tr("Incorrect parameters")); 226 227 /* 228 * Pack the patterns 229 */ 230 Utf8Str strPatterns(a->argc > 2 ? a->argv[2] : ""); 231 for (int i = 3; i < a->argc; ++i) 232 strPatterns = Utf8StrFmt ("%s,%s", strPatterns.c_str(), a->argv[i]); 225 static const RTGETOPTDEF s_aOptions[] = 226 { 227 { "--old-format", 'o', RTGETOPT_REQ_NOTHING }, 228 { "--sort", 's', RTGETOPT_REQ_NOTHING }, 229 { "--unsort", 'u', RTGETOPT_REQ_NOTHING }, 230 { "--timestamp", 't', RTGETOPT_REQ_NOTHING }, 231 { "--ts", 't', RTGETOPT_REQ_NOTHING }, 232 { "--no-timestamp", 'T', RTGETOPT_REQ_NOTHING }, 233 { "--abs", 'a', RTGETOPT_REQ_NOTHING }, 234 { "--absolute", 'a', RTGETOPT_REQ_NOTHING }, 235 { "--rel", 'r', RTGETOPT_REQ_NOTHING }, 236 { "--relative", 'r', RTGETOPT_REQ_NOTHING }, 237 { "--no-ts", 'T', RTGETOPT_REQ_NOTHING }, 238 { "--flags", 'f', RTGETOPT_REQ_NOTHING }, 239 { "--no-flags", 'F', RTGETOPT_REQ_NOTHING }, 240 /* unnecessary legacy: */ 241 { "--patterns", 'p', RTGETOPT_REQ_STRING }, 242 { "-patterns", 'p', RTGETOPT_REQ_STRING }, 243 }; 244 245 int ch; 246 RTGETOPTUNION ValueUnion; 247 RTGETOPTSTATE GetState; 248 RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0); 249 250 const char *pszVmNameOrUuid = NULL; 251 Utf8Str strPatterns; 252 bool fSort = true; 253 bool fNewStyle = true; 254 bool fTimestamp = true; 255 bool fAbsTime = true; 256 bool fFlags = true; 257 258 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0) 259 { 260 /* For options that require an argument, ValueUnion has received the value. */ 261 switch (ch) 262 { 263 case VINF_GETOPT_NOT_OPTION: 264 /* The first one is the VM name. */ 265 if (!pszVmNameOrUuid) 266 { 267 pszVmNameOrUuid = ValueUnion.psz; 268 break; 269 } 270 /* Everything else would be patterns by the new syntax. */ 271 RT_FALL_THROUGH(); 272 case 'p': 273 if (strPatterns.isNotEmpty()) 274 if (RT_FAILURE(strPatterns.appendNoThrow(','))) 275 return RTMsgErrorExitFailure("out of memory!"); 276 if (RT_FAILURE(strPatterns.appendNoThrow(ValueUnion.psz))) 277 return RTMsgErrorExitFailure("out of memory!"); 278 break; 279 280 case 'o': 281 fNewStyle = false; 282 break; 283 284 case 's': 285 fSort = true; 286 break; 287 case 'u': 288 fSort = false; 289 break; 290 291 case 't': 292 fTimestamp = true; 293 break; 294 case 'T': 295 fTimestamp = false; 296 break; 297 298 case 'a': 299 fAbsTime = true; 300 break; 301 case 'r': 302 fAbsTime = false; 303 break; 304 305 case 'f': 306 fFlags = true; 307 break; 308 case 'F': 309 fFlags = false; 310 break; 311 312 default: 313 return errorGetOpt(ch, &ValueUnion); 314 } 315 } 316 317 /* Only the VM name is required. */ 318 if (!pszVmNameOrUuid) 319 return errorSyntax(GuestProp::tr("No VM name or UUID was specified")); 233 320 234 321 /* … … 236 323 */ 237 324 ComPtr<IMachine> machine; 238 HRESULT hrc; 239 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(), 240 machine.asOutParam())); 241 if (machine) 242 { 243 /* open a session for the VM - new or existing */ 244 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE); 245 246 /* get the mutable session machine */ 247 a->session->COMGETTER(Machine)(machine.asOutParam()); 248 249 com::SafeArray<BSTR> names; 250 com::SafeArray<BSTR> values; 251 com::SafeArray<LONG64> timestamps; 252 com::SafeArray<BSTR> flags; 253 CHECK_ERROR(machine, EnumerateGuestProperties(Bstr(strPatterns).raw(), 254 ComSafeArrayAsOutParam(names), 255 ComSafeArrayAsOutParam(values), 256 ComSafeArrayAsOutParam(timestamps), 257 ComSafeArrayAsOutParam(flags))); 258 if (SUCCEEDED(hrc)) 325 CHECK_ERROR2I_RET(a->virtualBox, FindMachine(Bstr(pszVmNameOrUuid).raw(), machine.asOutParam()), RTEXITCODE_FAILURE); 326 327 /* open a session for the VM - new or existing */ 328 CHECK_ERROR2I_RET(machine, LockMachine(a->session, LockType_Shared), RTEXITCODE_FAILURE); 329 330 /* get the mutable session machine */ 331 a->session->COMGETTER(Machine)(machine.asOutParam()); 332 333 com::SafeArray<BSTR> names; 334 com::SafeArray<BSTR> values; 335 com::SafeArray<LONG64> timestamps; 336 com::SafeArray<BSTR> flags; 337 CHECK_ERROR2I_RET(machine, EnumerateGuestProperties(Bstr(strPatterns).raw(), 338 ComSafeArrayAsOutParam(names), 339 ComSafeArrayAsOutParam(values), 340 ComSafeArrayAsOutParam(timestamps), 341 ComSafeArrayAsOutParam(flags)), 342 RTEXITCODE_FAILURE); 343 344 size_t const cEntries = names.size(); 345 if (cEntries == 0) 346 RTPrintf(GuestProp::tr("No properties found.\n")); 347 else 348 { 349 /* Whether we sort it or not, we work it via a indirect index: */ 350 size_t *paidxSorted = (size_t *)RTMemAlloc(sizeof(paidxSorted[0]) * cEntries); 351 if (!paidxSorted) 352 return RTMsgErrorExitFailure("out of memory!"); 353 for (size_t i = 0; i < cEntries; i++) 354 paidxSorted[i] = i; 355 356 /* Do the sorting: */ 357 if (fSort && cEntries > 1) 358 for (size_t i = 0; i < cEntries - 1; i++) 359 for (size_t j = 0; j < cEntries - i - 1; j++) 360 if (RTUtf16Cmp(names[paidxSorted[j]], names[paidxSorted[j + 1]]) > 0) 361 { 362 size_t iTmp = paidxSorted[j]; 363 paidxSorted[j] = paidxSorted[j + 1]; 364 paidxSorted[j + 1] = iTmp; 365 } 366 367 if (fNewStyle) 259 368 { 260 if (names.size() == 0) 261 RTPrintf(GuestProp::tr("No properties found.\n")); 262 for (unsigned i = 0; i < names.size(); ++i) 369 /* figure the width of the main columns: */ 370 size_t cwcMaxName = 1; 371 size_t cwcMaxValue = 1; 372 for (size_t i = 0; i < cEntries; ++i) 373 { 374 size_t cwcName = RTUtf16Len(names[i]); 375 cwcMaxName = RT_MAX(cwcMaxName, cwcName); 376 size_t cwcValue = RTUtf16Len(values[i]); 377 cwcMaxValue = RT_MAX(cwcMaxValue, cwcValue); 378 } 379 cwcMaxName = RT_MIN(cwcMaxName, 48); 380 cwcMaxValue = RT_MIN(cwcMaxValue, 28); 381 382 /* Get the current time for relative time formatting: */ 383 RTTIMESPEC Now; 384 RTTimeNow(&Now); 385 386 /* Print the table: */ 387 for (size_t iSorted = 0; iSorted < cEntries; ++iSorted) 388 { 389 size_t const i = paidxSorted[iSorted]; 390 char szTime[80]; 391 if (fTimestamp) 392 { 393 RTTIMESPEC TimestampTS; 394 RTTimeSpecSetNano(&TimestampTS, timestamps[i]); 395 if (fAbsTime) 396 { 397 RTTIME Timestamp; 398 RTTimeToStringEx(RTTimeExplode(&Timestamp, &TimestampTS), &szTime[2], sizeof(szTime) - 2, 3); 399 } 400 else 401 { 402 RTTIMESPEC DurationTS = Now; 403 RTTimeFormatDurationEx(&szTime[2], sizeof(szTime) - 2, RTTimeSpecSub(&DurationTS, &TimestampTS), 3); 404 } 405 szTime[0] = '@'; 406 szTime[1] = ' '; 407 } 408 else 409 szTime[0] = '\0'; 410 411 static RTUTF16 s_wszEmpty[] = { 0 }; 412 PCRTUTF16 const pwszFlags = fFlags ? flags[i] : s_wszEmpty; 413 414 int cchOut = RTPrintf("%-*ls = '%ls'", cwcMaxName, names[i], values[i]); 415 if (fTimestamp || *pwszFlags) 416 { 417 size_t const cwcWidth = cwcMaxName + cwcMaxValue + 6; 418 size_t const cwcValPadding = (unsigned)cchOut < cwcWidth ? cwcWidth - (unsigned)cchOut : 1; 419 RTPrintf("%*s%s%s%ls\n", cwcValPadding, "", szTime, *pwszFlags ? " " : "", pwszFlags); 420 } 421 else 422 RTPrintf("\n"); 423 } 424 } 425 else 426 for (size_t iSorted = 0; iSorted < cEntries; ++iSorted) 427 { 428 size_t const i = paidxSorted[iSorted]; 263 429 RTPrintf(GuestProp::tr("Name: %ls, value: %ls, timestamp: %lld, flags: %ls\n"), 264 430 names[i], values[i], timestamps[i], flags[i]); 265 } 266 } 267 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 431 } 432 RTMemFree(paidxSorted); 433 } 434 435 return RTEXITCODE_SUCCESS; 268 436 } 269 437 … … 405 573 RTEXITCODE handleGuestProperty(HandlerArg *a) 406 574 { 407 HandlerArg arg = *a; 408 arg.argc = a->argc - 1; 409 arg.argv = a->argv + 1; 575 if (a->argc == 0) 576 return errorNoSubcommand(); 410 577 411 578 /** @todo This command does not follow the syntax where the <uuid|vmname> … … 414 581 */ 415 582 416 if (a->argc == 0) 417 return errorSyntax(GuestProp::tr("Incorrect parameters")); 583 const char * const pszSubCmd = a->argv[0]; 584 a->argc -= 1; 585 a->argv += 1; 418 586 419 587 /* switch (cmd) */ 420 if (strcmp( a->argv[0], "get") == 0)421 return handleGetGuestProperty( &arg);422 if (strcmp( a->argv[0], "set") == 0)423 return handleSetGuestProperty( &arg);424 if (strcmp( a->argv[0], "delete") == 0 || strcmp(a->argv[0], "unset") == 0)425 return handleDeleteGuestProperty( &arg);426 if (strcmp( a->argv[0], "enumerate") == 0)427 return handleEnumGuestProperty( &arg);428 if (strcmp( a->argv[0], "wait") == 0)429 return handleWaitGuestProperty( &arg);588 if (strcmp(pszSubCmd, "get") == 0) 589 return handleGetGuestProperty(a); 590 if (strcmp(pszSubCmd, "set") == 0) 591 return handleSetGuestProperty(a); 592 if (strcmp(pszSubCmd, "delete") == 0 || strcmp(pszSubCmd, "unset") == 0) 593 return handleDeleteGuestProperty(a); 594 if (strcmp(pszSubCmd, "enumerate") == 0 || strcmp(pszSubCmd, "enum") == 0) 595 return handleEnumGuestProperty(a); 596 if (strcmp(pszSubCmd, "wait") == 0) 597 return handleWaitGuestProperty(a); 430 598 431 599 /* default: */ 432 return error Syntax(GuestProp::tr("Incorrect parameters"));600 return errorUnknownSubcommand(pszSubCmd); 433 601 }
Note:
See TracChangeset
for help on using the changeset viewer.

