VirtualBox

Changeset 96623 in vbox


Ignore:
Timestamp:
Sep 7, 2022 1:25:44 AM (2 years ago)
Author:
vboxsync
Message:

VBoxManage: Changed the output of guestproperty enumerate a little. Just wanted to format the timestamps a little more readable...

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/manual/en_US/man_VBoxManage-guestproperty.xml

    r96618 r96623  
    6464        <arg choice="plain"><replaceable>vmname</replaceable></arg>
    6565      </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>
    6771    </cmdsynopsis>
    6872
     
    131135        The <command>VBoxManage guestproperty enumerate</command> command
    132136        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 not
     137        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
    135139        running or because the Guest Additions are not installed.
    136140      </para>
    137141      <variablelist>
    138142        <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>
    140160          <listitem><para>
    141161              Filters the list of properties based on the specified
     
    172192            </variablelist></listitem>
    173193        </varlistentry>
    174       </variablelist>
     194
     195        </variablelist>
    175196    </refsect2>
    176197    <refsect2 id="vboxmanage-guestproperty-get">
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp

    r96407 r96623  
    215215
    216216    /*
    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.
    219224     */
    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"));
    233320
    234321    /*
     
    236323     */
    237324    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)
    259368        {
    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];
    263429                RTPrintf(GuestProp::tr("Name: %ls, value: %ls, timestamp: %lld, flags: %ls\n"),
    264430                         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;
    268436}
    269437
     
    405573RTEXITCODE handleGuestProperty(HandlerArg *a)
    406574{
    407     HandlerArg arg = *a;
    408     arg.argc = a->argc - 1;
    409     arg.argv = a->argv + 1;
     575    if (a->argc == 0)
     576        return errorNoSubcommand();
    410577
    411578    /** @todo This command does not follow the syntax where the <uuid|vmname>
     
    414581     */
    415582
    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;
    418586
    419587    /* 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);
    430598
    431599    /* default: */
    432     return errorSyntax(GuestProp::tr("Incorrect parameters"));
     600    return errorUnknownSubcommand(pszSubCmd);
    433601}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette