VirtualBox

Ignore:
Timestamp:
Sep 7, 2022 1:25:44 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
153503
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.

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