VirtualBox

Changeset 47557 in vbox


Ignore:
Timestamp:
Aug 6, 2013 11:59:35 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
87756
Message:

FE/VBoxManage: Added support for terminating guest processes of specific guest sessions.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/manual/en_US/user_VBoxManage.xml

    r47544 r47557  
    32983298
    32993299        <listitem>
     3300          <para><emphasis role="bold"><computeroutput>process kill</computeroutput></emphasis>,
     3301          which terminates specific guest processes of a guest session, based on either the
     3302          session's ID or the session's name.</para>
     3303
     3304          <screen>VBoxManage guestcontrol &lt;uuid|vmname&gt; process kill
     3305            --session-id &lt;ID&gt;
     3306          | --session-name &lt;name or pattern&gt;
     3307          [--verbose]
     3308          &lt;PID&gt; ... &lt;PID n&gt;</screen>
     3309
     3310          <para>where the parameters mean: <glosslist>
     3311            <glossentry>
     3312              <glossterm><computeroutput>uuid|vmname</computeroutput></glossterm>
     3313
     3314              <glossdef>
     3315                <para>The VM UUID or VM name. Mandatory.</para>
     3316              </glossdef>
     3317            </glossentry>
     3318
     3319            <glossentry>
     3320              <glossterm><computeroutput>--session-id</computeroutput></glossterm>
     3321
     3322              <glossdef>
     3323                <para>Specifies the guest session to use by its ID.</para>
     3324              </glossdef>
     3325            </glossentry>
     3326
     3327            <glossentry>
     3328              <glossterm><computeroutput>--session-name</computeroutput></glossterm>
     3329
     3330              <glossdef>
     3331                <para>Specifies the guest session to use by its name. Multiple
     3332                  sessions can be closed when specifying * or ? wildcards.</para>
     3333              </glossdef>
     3334            </glossentry>
     3335
     3336            <glossentry>
     3337              <glossterm><computeroutput>--verbose</computeroutput></glossterm>
     3338
     3339              <glossdef>
     3340                <para>Tells VBoxManage to be more verbose.</para>
     3341              </glossdef>
     3342            </glossentry>
     3343
     3344            <glossentry>
     3345              <glossterm><computeroutput>&lt;PID&gt; ... &lt;PID n&gt;</computeroutput></glossterm>
     3346
     3347              <glossdef>
     3348                <para>List of process identifiers (PIDs) to terminate.</para>
     3349              </glossdef>
     3350            </glossentry>
     3351          </glosslist></para>
     3352        </listitem>
     3353
     3354        <listitem>
     3355          <para><emphasis role="bold"><computeroutput>[p[s]]kill</computeroutput></emphasis>,
     3356          which terminates specific guest processes of a guest session, based on either the
     3357          session's ID or the session's name.</para>
     3358
     3359          <screen>VBoxManage guestcontrol &lt;uuid|vmname&gt; process kill
     3360            --session-id &lt;ID&gt;
     3361          | --session-name &lt;name or pattern&gt;
     3362          [--verbose]
     3363          &lt;PID&gt; ... &lt;PID n&gt;</screen>
     3364
     3365          <para>where the parameters mean: <glosslist>
     3366            <glossentry>
     3367              <glossterm><computeroutput>uuid|vmname</computeroutput></glossterm>
     3368
     3369              <glossdef>
     3370                <para>The VM UUID or VM name. Mandatory.</para>
     3371              </glossdef>
     3372            </glossentry>
     3373
     3374            <glossentry>
     3375              <glossterm><computeroutput>--session-id</computeroutput></glossterm>
     3376
     3377              <glossdef>
     3378                <para>Specifies the guest session to use by its ID.</para>
     3379              </glossdef>
     3380            </glossentry>
     3381
     3382            <glossentry>
     3383              <glossterm><computeroutput>--session-name</computeroutput></glossterm>
     3384
     3385              <glossdef>
     3386                <para>Specifies the guest session to use by its name. Multiple
     3387                  sessions can be closed when specifying * or ? wildcards.</para>
     3388              </glossdef>
     3389            </glossentry>
     3390
     3391            <glossentry>
     3392              <glossterm><computeroutput>--verbose</computeroutput></glossterm>
     3393
     3394              <glossdef>
     3395                <para>Tells VBoxManage to be more verbose.</para>
     3396              </glossdef>
     3397            </glossentry>
     3398
     3399            <glossentry>
     3400              <glossterm><computeroutput>&lt;PID&gt; ... &lt;PID n&gt;</computeroutput></glossterm>
     3401
     3402              <glossdef>
     3403                <para>List of process identifiers (PIDs) to terminate.</para>
     3404              </glossdef>
     3405            </glossentry>
     3406          </glosslist></para>
     3407        </listitem>
     3408
     3409        <listitem>
    33003410          <para><emphasis role="bold"><computeroutput>session close</computeroutput></emphasis>,
    33013411          which closes specific guest sessions, based on either the session's ID or the
  • trunk/doc/manual/user_ChangeLogImpl.xml

    r47495 r47557  
    5959      <listitem>
    6060        <para>VBoxManage: added support for closing active guest sessions via
    61           <computeroutput>guestcontrol session close --session-id &lt;ID&gt;|--session-name &lt;name or pattern&gt;|--all</computeroutput>
     61          <computeroutput>guestcontrol session close --session-id &lt;ID&gt;|
     62            --session-name &lt;name or pattern&gt;|--all</computeroutput>
     63        </para>
     64      </listitem>
     65
     66      <listitem>
     67        <para>VBoxManage: added support for terminating active guest processes via
     68          <computeroutput>guestcontrol process kill|close|terminate --session-id &lt;ID&gt;|
     69            --session-name &lt;name or pattern&gt; &lt;PID&gt; ... &lt;PID n&gt;</computeroutput>
     70          or
     71          <computeroutput>guestcontrol [p[s]]kill --session-id &lt;ID&gt;|
     72            --session-name &lt;name or pattern&gt; &lt;PID&gt; ... &lt;PID n&gt;</computeroutput>
    6273        </para>
    6374      </listitem>
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r47538 r47557  
    266266                 "                            list <all|sessions|processes> [--verbose]\n"
    267267                 "\n"
     268                 /** @todo Add an own help group for "session" and "process" sub commands. */
     269                 "                            process kill --session-id <ID>\n"
     270                 "                                         | --session-name <name or pattern>\n"
     271                 "                                         [--verbose]\n"
     272                 "                                         <PID> ... <PID n>\n"
     273                 "\n"
     274                 "                            [p[s]]kill --session-id <ID>\n"
     275                 "                                       | --session-name <name or pattern>\n"
     276                 "                                       [--verbose]\n"
     277                 "                                       <PID> ... <PID n>\n"
     278                 "\n"
    268279                 "                            session close  --session-id <ID>\n"
    269280                 "                                         | --session-name <name or pattern>\n"
     
    29412952}
    29422953
    2943 static RTEXITCODE handleCtrlSessionClose(ComPtr<IGuest> guest, HandlerArg *pArg)
     2954static RTEXITCODE handleCtrlProcessClose(ComPtr<IGuest> guest, HandlerArg *pArg)
    29442955{
    29452956    AssertPtrReturn(pArg, RTEXITCODE_SYNTAX);
    29462957
    29472958    if (pArg->argc < 1)
    2948         return errorSyntax(USAGE_GUESTCONTROL, "Must specify at least session ID to close");
     2959        return errorSyntax(USAGE_GUESTCONTROL, "Must specify at least a PID to close");
    29492960
    29502961    /*
     
    29562967    static const RTGETOPTDEF s_aOptions[] =
    29572968    {
    2958         { "--all",                 GETOPTDEF_SESSIONCLOSE_ALL,      RTGETOPT_REQ_NOTHING  },
    29592969        { "--session-id",          'i',                             RTGETOPT_REQ_UINT32  },
    2960         { "--session-name",        'n',                             RTGETOPT_REQ_UINT32  },
     2970        { "--session-name",        'n',                             RTGETOPT_REQ_STRING  },
    29612971        { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
    29622972    };
     
    29682978                 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    29692979
     2980    std::vector < uint32_t > vecPID;
    29702981    ULONG ulSessionID = UINT32_MAX;
    2971     Utf8Str strNamePattern;
     2982    Utf8Str strSessionName;
    29722983    bool fVerbose = false;
    29732984
    2974     while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     2985    int vrc = VINF_SUCCESS;
     2986
     2987    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     2988           && RT_SUCCESS(vrc))
    29752989    {
    29762990        /* For options that require an argument, ValueUnion has received the value. */
    29772991        switch (ch)
    29782992        {
    2979             case 'n': /* Session name pattern */
    2980                 strNamePattern = ValueUnion.psz;
     2993            case 'n': /* Session name (or pattern) */
     2994                strSessionName = ValueUnion.psz;
    29812995                break;
    29822996
     
    29852999                break;
    29863000
    2987             /** @todo Add an option for finding all session by a name pattern. */
    2988 
    29893001            case 'v': /* Verbose */
    29903002                fVerbose = true;
    29913003                break;
    29923004
    2993             case GETOPTDEF_SESSIONCLOSE_ALL:
    2994                 strNamePattern = "*";
    2995                 break;
    2996 
    29973005            case VINF_GETOPT_NOT_OPTION:
    2998                 /** @todo Supply a CSV list of IDs or patterns to close? */
     3006                if (pArg->argc == GetState.iNext)
     3007                {
     3008                    /* Treat every else specified as a PID to kill. */
     3009                    try
     3010                    {
     3011                        uint32_t uPID = RTStrToUInt32(ValueUnion.psz);
     3012                        if (uPID) /** @todo Is this what we want? If specifying PID 0
     3013                                            this is not going to work on most systems anyway. */
     3014                            vecPID.push_back(uPID);
     3015                        else
     3016                            vrc = VERR_INVALID_PARAMETER;
     3017                    }
     3018                    catch(std::bad_alloc &)
     3019                    {
     3020                        vrc = VERR_NO_MEMORY;
     3021                    }
     3022                }
    29993023                break;
    30003024
     
    30043028    }
    30053029
    3006     if (   strNamePattern.isEmpty()
    3007         && ulSessionID == UINT32_MAX)
     3030    if (vecPID.empty())
     3031        return errorSyntax(USAGE_GUESTCONTROL, "At least one PID must be specified to kill!");
     3032    else if (   strSessionName.isEmpty()
     3033             && ulSessionID == UINT32_MAX)
    30083034    {
    30093035        return errorSyntax(USAGE_GUESTCONTROL, "No session ID specified!");
    30103036    }
    3011     else if (   !strNamePattern.isEmpty()
     3037    else if (   !strSessionName.isEmpty()
    30123038             && ulSessionID != UINT32_MAX)
    30133039    {
     
    30153041    }
    30163042
     3043    if (RT_FAILURE(vrc))
     3044        return errorSyntax(USAGE_GUESTCONTROL, "Invalid parameters specified");
     3045
    30173046    HRESULT rc = S_OK;
    30183047
    30193048    ComPtr<IGuestSession> pSession;
     3049    ComPtr<IGuestProcess> pProcess;
    30203050    do
    30213051    {
     
    30373067            Utf8Str strNameUtf8(strName); /* Session name */
    30383068
    3039             if (strNamePattern.isEmpty()) /* Search by ID. Slow lookup. */
     3069            if (strSessionName.isEmpty()) /* Search by ID. Slow lookup. */
    30403070            {
    30413071                fSessionFound = uID == ulSessionID;
     
    30433073            else /* ... or by naming pattern. */
    30443074            {
    3045                 if (RTStrSimplePatternMatch(strNamePattern.c_str(), strNameUtf8.c_str()))
     3075                if (RTStrSimplePatternMatch(strSessionName.c_str(), strNameUtf8.c_str()))
     3076                    fSessionFound = true;
     3077            }
     3078
     3079            if (fSessionFound)
     3080            {
     3081                Assert(!pSession.isNull());
     3082
     3083                SafeIfaceArray <IGuestProcess> collProcs;
     3084                CHECK_ERROR_BREAK(pSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcs)));
     3085
     3086                size_t cProcs = collProcs.size();
     3087                for (size_t p = 0; p < cProcs; p++)
     3088                {
     3089                    pProcess = collProcs[p];
     3090                    Assert(!pProcess.isNull());
     3091
     3092                    ULONG uPID; /* Process ID */
     3093                    CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
     3094
     3095                    bool fProcFound = false;
     3096                    for (size_t a = 0; a < vecPID.size(); a++) /* Slow, but works. */
     3097                    {
     3098                        fProcFound = vecPID[a] == uPID;
     3099                        if (fProcFound)
     3100                            break;
     3101                    }
     3102
     3103                    if (fProcFound)
     3104                    {
     3105                        if (fVerbose)
     3106                            RTPrintf("Terminating process PID=%RU32 (session ID=%RU32) ...\n",
     3107                                     uPID, uID);
     3108                        CHECK_ERROR_BREAK(pProcess, Terminate());
     3109                    }
     3110
     3111                    pProcess.setNull();
     3112                }
     3113
     3114                pSession.setNull();
     3115            }
     3116        }
     3117
     3118        if (!fSessionFound)
     3119        {
     3120            RTPrintf("No guest session(s) found\n");
     3121            rc = E_ABORT; /* To set exit code accordingly. */
     3122        }
     3123
     3124    } while (0);
     3125
     3126    pProcess.setNull();
     3127    pSession.setNull();
     3128
     3129    return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     3130}
     3131
     3132static RTEXITCODE handleCtrlProcess(ComPtr<IGuest> guest, HandlerArg *pArg)
     3133{
     3134    AssertPtrReturn(pArg, RTEXITCODE_SYNTAX);
     3135
     3136    if (pArg->argc < 1)
     3137        return errorSyntax(USAGE_GUESTCONTROL, "Must specify an action");
     3138
     3139    /** Use RTGetOpt here when handling command line args gets more complex. */
     3140
     3141    HandlerArg argSub = *pArg;
     3142    argSub.argc = pArg->argc - 1; /* Skip session action. */
     3143    argSub.argv = pArg->argv + 1; /* Same here. */
     3144
     3145    if (   !RTStrICmp(pArg->argv[0], "close")
     3146        || !RTStrICmp(pArg->argv[0], "kill")
     3147        || !RTStrICmp(pArg->argv[0], "terminate"))
     3148    {
     3149        return handleCtrlProcessClose(guest, &argSub);
     3150    }
     3151
     3152    return errorSyntax(USAGE_GUESTCONTROL, "Invalid process action '%s'", pArg->argv[0]);
     3153}
     3154
     3155static RTEXITCODE handleCtrlSessionClose(ComPtr<IGuest> guest, HandlerArg *pArg)
     3156{
     3157    AssertPtrReturn(pArg, RTEXITCODE_SYNTAX);
     3158
     3159    if (pArg->argc < 1)
     3160        return errorSyntax(USAGE_GUESTCONTROL, "Must specify at least a session ID to close");
     3161
     3162    /*
     3163     * Parse arguments.
     3164     *
     3165     * Note! No direct returns here, everyone must go thru the cleanup at the
     3166     *       end of this function.
     3167     */
     3168    static const RTGETOPTDEF s_aOptions[] =
     3169    {
     3170        { "--all",                 GETOPTDEF_SESSIONCLOSE_ALL,      RTGETOPT_REQ_NOTHING  },
     3171        { "--session-id",          'i',                             RTGETOPT_REQ_UINT32  },
     3172        { "--session-name",        'n',                             RTGETOPT_REQ_STRING  },
     3173        { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
     3174    };
     3175
     3176    int ch;
     3177    RTGETOPTUNION ValueUnion;
     3178    RTGETOPTSTATE GetState;
     3179    RTGetOptInit(&GetState, pArg->argc, pArg->argv,
     3180                 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     3181
     3182    ULONG ulSessionID = UINT32_MAX;
     3183    Utf8Str strSessionName;
     3184    bool fVerbose = false;
     3185
     3186    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     3187    {
     3188        /* For options that require an argument, ValueUnion has received the value. */
     3189        switch (ch)
     3190        {
     3191            case 'n': /* Session name pattern */
     3192                strSessionName = ValueUnion.psz;
     3193                break;
     3194
     3195            case 'i': /* Session ID */
     3196                ulSessionID = ValueUnion.u32;
     3197                break;
     3198
     3199            case 'v': /* Verbose */
     3200                fVerbose = true;
     3201                break;
     3202
     3203            case GETOPTDEF_SESSIONCLOSE_ALL:
     3204                strSessionName = "*";
     3205                break;
     3206
     3207            case VINF_GETOPT_NOT_OPTION:
     3208                /** @todo Supply a CSV list of IDs or patterns to close? */
     3209                break;
     3210
     3211            default:
     3212                return RTGetOptPrintError(ch, &ValueUnion);
     3213        }
     3214    }
     3215
     3216    if (   strSessionName.isEmpty()
     3217        && ulSessionID == UINT32_MAX)
     3218    {
     3219        return errorSyntax(USAGE_GUESTCONTROL, "No session ID specified!");
     3220    }
     3221    else if (   !strSessionName.isEmpty()
     3222             && ulSessionID != UINT32_MAX)
     3223    {
     3224        return errorSyntax(USAGE_GUESTCONTROL, "Either session ID or name (pattern) must be specified");
     3225    }
     3226
     3227    HRESULT rc = S_OK;
     3228
     3229    ComPtr<IGuestSession> pSession;
     3230    do
     3231    {
     3232        bool fSessionFound = false;
     3233
     3234        SafeIfaceArray <IGuestSession> collSessions;
     3235        CHECK_ERROR_BREAK(guest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
     3236        size_t cSessions = collSessions.size();
     3237
     3238        for (size_t i = 0; i < cSessions; i++)
     3239        {
     3240            pSession = collSessions[i];
     3241            Assert(!pSession.isNull());
     3242
     3243            ULONG uID; /* Session ID */
     3244            CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));
     3245            Bstr strName;
     3246            CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));
     3247            Utf8Str strNameUtf8(strName); /* Session name */
     3248
     3249            if (strSessionName.isEmpty()) /* Search by ID. Slow lookup. */
     3250            {
     3251                fSessionFound = uID == ulSessionID;
     3252            }
     3253            else /* ... or by naming pattern. */
     3254            {
     3255                if (RTStrSimplePatternMatch(strSessionName.c_str(), strNameUtf8.c_str()))
    30463256                    fSessionFound = true;
    30473257            }
     
    31383348                 || !RTStrICmp(pArg->argv[1], "mktemp"))
    31393349            rcExit = handleCtrlCreateTemp(guest, &arg);
     3350        else if (   !RTStrICmp(pArg->argv[1], "kill")    /* Linux. */
     3351                 || !RTStrICmp(pArg->argv[1], "pkill")   /* Solaris / *BSD. */
     3352                 || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */
     3353        {
     3354            /** @todo What about "taskkill" on Windows? */
     3355            rcExit = handleCtrlProcessClose(guest, &arg);
     3356        }
     3357        /** @todo Implement "killall"? */
    31403358        else if (   !RTStrICmp(pArg->argv[1], "stat"))
    31413359            rcExit = handleCtrlStat(guest, &arg);
     
    31473365        else if (   !RTStrICmp(pArg->argv[1], "session"))
    31483366            rcExit = handleCtrlSession(guest, &arg);
     3367        else if (   !RTStrICmp(pArg->argv[1], "process"))
     3368            rcExit = handleCtrlProcess(guest, &arg);
    31493369        else
    31503370            rcExit = errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]);
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