VirtualBox

Changeset 47625 in vbox


Ignore:
Timestamp:
Aug 9, 2013 8:15:22 AM (11 years ago)
Author:
vboxsync
Message:

VBoxManage/VBoxManageGuestCtrl.cpp: Handle OOM situations, include own PID in guest session name.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r47560 r47625  
    4242#include <iprt/list.h>
    4343#include <iprt/path.h>
     44#include <iprt/process.h> /* For RTProcSelf(). */
    4445#include <iprt/thread.h>
    4546
     
    657658
    658659/* <Missing documentation> */
    659 static RTEXITCODE handleCtrlExecProgram(ComPtr<IGuest> pGuest, HandlerArg *pArg)
     660static RTEXITCODE handleCtrlProcessExec(ComPtr<IGuest> pGuest, HandlerArg *pArg)
    660661{
    661662    AssertPtrReturn(pArg, RTEXITCODE_SYNTAX);
     
    689690    RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
    690691
    691     Utf8Str                 strCmd;
     692    Utf8Str                              strCmd;
    692693    com::SafeArray<ProcessCreateFlag_T>  aCreateFlags;
    693694    com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
     
    699700    RTMSINTERVAL                         cMsTimeout      = 0;
    700701    OUTPUTTYPE                           eOutputType     = OUTPUTTYPE_UNDEFINED;
    701     bool                                 fWaitForExit    = false;
     702    bool                                 fDetached       = true;
    702703    bool                                 fVerbose        = false;
    703704    int                                  vrc             = VINF_SUCCESS;
    704705
    705     /* Wait for process start in any case. This is useful for scripting VBoxManage
    706      * when relying on its overall exit code. */
    707     aWaitFlags.push_back(ProcessWaitForFlag_Start);
    708 
    709     while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    710            && RT_SUCCESS(vrc))
    711     {
    712         /* For options that require an argument, ValueUnion has received the value. */
    713         switch (ch)
     706    try
     707    {
     708        /* Wait for process start in any case. This is useful for scripting VBoxManage
     709         * when relying on its overall exit code. */
     710        aWaitFlags.push_back(ProcessWaitForFlag_Start);
     711
     712        while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     713               && RT_SUCCESS(vrc))
    714714        {
    715             case GETOPTDEF_EXEC_DOS2UNIX:
    716                 if (eOutputType != OUTPUTTYPE_UNDEFINED)
    717                     return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
    718                 eOutputType = OUTPUTTYPE_DOS2UNIX;
    719                 break;
    720 
    721             case 'e': /* Environment */
    722             {
    723                 char **papszArg;
    724                 int cArgs;
    725 
    726                 vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
    727                 if (RT_FAILURE(vrc))
    728                     return errorSyntax(USAGE_GUESTCONTROL, "Failed to parse environment value, rc=%Rrc", vrc);
    729                 for (int j = 0; j < cArgs; j++)
    730                     aEnv.push_back(Bstr(papszArg[j]).raw());
    731 
    732                 RTGetOptArgvFree(papszArg);
    733                 break;
    734             }
    735 
    736             case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES:
    737                 aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
    738                 break;
    739 
    740             case GETOPTDEF_EXEC_NO_PROFILE:
    741                 aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
    742                 break;
    743 
    744             case 'i':
    745                 strCmd = ValueUnion.psz;
    746                 break;
    747 
    748             /** @todo Add a hidden flag. */
    749 
    750             case 'u': /* User name */
    751                 strUsername = ValueUnion.psz;
    752                 break;
    753 
    754             case GETOPTDEF_EXEC_PASSWORD: /* Password */
    755                 strPassword = ValueUnion.psz;
    756                 break;
    757 
    758             case 'p': /* Password file */
    759             {
    760                 RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
    761                 if (rcExit != RTEXITCODE_SUCCESS)
    762                     return rcExit;
    763                 break;
    764             }
    765 
    766             case 'd': /* domain */
    767                 strDomain = ValueUnion.psz;
    768                 break;
    769 
    770             case 't': /* Timeout */
    771                 cMsTimeout = ValueUnion.u32;
    772                 break;
    773 
    774             case GETOPTDEF_EXEC_UNIX2DOS:
    775                 if (eOutputType != OUTPUTTYPE_UNDEFINED)
    776                     return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
    777                 eOutputType = OUTPUTTYPE_UNIX2DOS;
    778                 break;
    779 
    780             case 'v': /* Verbose */
    781                 fVerbose = true;
    782                 break;
    783 
    784             case GETOPTDEF_EXEC_WAITFOREXIT:
    785                 aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
    786                 fWaitForExit = true;
    787                 break;
    788 
    789             case GETOPTDEF_EXEC_WAITFORSTDOUT:
    790                 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
    791                 aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
    792                 fWaitForExit = true;
    793                 break;
    794 
    795             case GETOPTDEF_EXEC_WAITFORSTDERR:
    796                 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
    797                 aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
    798                 fWaitForExit = true;
    799                 break;
    800 
    801             case VINF_GETOPT_NOT_OPTION:
    802             {
    803                 if (aArgs.size() == 0 && strCmd.isEmpty())
     715            /* For options that require an argument, ValueUnion has received the value. */
     716            switch (ch)
     717            {
     718                case GETOPTDEF_EXEC_DOS2UNIX:
     719                    if (eOutputType != OUTPUTTYPE_UNDEFINED)
     720                        return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
     721                    eOutputType = OUTPUTTYPE_DOS2UNIX;
     722                    break;
     723
     724                case 'e': /* Environment */
     725                {
     726                    char **papszArg;
     727                    int cArgs;
     728
     729                    vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
     730                    if (RT_FAILURE(vrc))
     731                        return errorSyntax(USAGE_GUESTCONTROL, "Failed to parse environment value, rc=%Rrc", vrc);
     732                    for (int j = 0; j < cArgs; j++)
     733                        aEnv.push_back(Bstr(papszArg[j]).raw());
     734
     735                    RTGetOptArgvFree(papszArg);
     736                    break;
     737                }
     738
     739                case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES:
     740                    aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
     741                    break;
     742
     743                case GETOPTDEF_EXEC_NO_PROFILE:
     744                    aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
     745                    break;
     746
     747                case 'i':
    804748                    strCmd = ValueUnion.psz;
    805                 else
    806                     aArgs.push_back(Bstr(ValueUnion.psz).raw());
    807                 break;
    808             }
    809 
    810             default:
    811                 return RTGetOptPrintError(ch, &ValueUnion);
    812         }
    813     }
     749                    break;
     750
     751                /** @todo Add a hidden flag. */
     752
     753                case 'u': /* User name */
     754                    strUsername = ValueUnion.psz;
     755                    break;
     756
     757                case GETOPTDEF_EXEC_PASSWORD: /* Password */
     758                    strPassword = ValueUnion.psz;
     759                    break;
     760
     761                case 'p': /* Password file */
     762                {
     763                    RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
     764                    if (rcExit != RTEXITCODE_SUCCESS)
     765                        return rcExit;
     766                    break;
     767                }
     768
     769                case 'd': /* domain */
     770                    strDomain = ValueUnion.psz;
     771                    break;
     772
     773                case 't': /* Timeout */
     774                    cMsTimeout = ValueUnion.u32;
     775                    break;
     776
     777                case GETOPTDEF_EXEC_UNIX2DOS:
     778                    if (eOutputType != OUTPUTTYPE_UNDEFINED)
     779                        return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
     780                    eOutputType = OUTPUTTYPE_UNIX2DOS;
     781                    break;
     782
     783                case 'v': /* Verbose */
     784                    fVerbose = true;
     785                    break;
     786
     787                case GETOPTDEF_EXEC_WAITFOREXIT:
     788                    aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
     789                    fDetached = false;
     790                    break;
     791
     792                case GETOPTDEF_EXEC_WAITFORSTDOUT:
     793                    aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
     794                    aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
     795                    fDetached = false;
     796                    break;
     797
     798                case GETOPTDEF_EXEC_WAITFORSTDERR:
     799                    aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
     800                    aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
     801                    fDetached = false;
     802                    break;
     803
     804                case VINF_GETOPT_NOT_OPTION:
     805                {
     806                    if (aArgs.size() == 0 && strCmd.isEmpty())
     807                        strCmd = ValueUnion.psz;
     808                    else
     809                        aArgs.push_back(Bstr(ValueUnion.psz).raw());
     810                    break;
     811                }
     812
     813                default:
     814                    return RTGetOptPrintError(ch, &ValueUnion);
     815
     816            } /* switch */
     817        } /* while RTGetOpt */
     818    }
     819    catch (std::bad_alloc &)
     820    {
     821        vrc = VERR_NO_MEMORY;
     822    }
     823
     824    if (RT_FAILURE(vrc))
     825        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc);
    814826
    815827    if (strCmd.isEmpty())
     
    819831        return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
    820832
    821     /* Any output conversion not supported yet! */
     833    /** @todo Any output conversion not supported yet! */
    822834    if (eOutputType != OUTPUTTYPE_UNDEFINED)
    823835        return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!");
     
    830842        RTPrintf("Opening guest session as user '%s' ...\n", strUsername.c_str());
    831843
     844    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     845
    832846    /** @todo This eventually needs a bit of revamping so that a valid session gets passed
    833847     *        into this function already so that we don't need to mess around with closing
     
    835849
    836850    ComPtr<IGuestSession> pGuestSession;
    837     rc = pGuest->CreateSession(Bstr(strUsername).raw(),
    838                                Bstr(strPassword).raw(),
    839                                Bstr(strDomain).raw(),
    840                                Bstr("VBoxManage Guest Control").raw(),
    841                                pGuestSession.asOutParam());
    842     if (FAILED(rc))
    843     {
    844         ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    845         return RTEXITCODE_FAILURE;
    846     }
    847 
    848     /* Adjust process creation flags if we don't want to wait for process termination. */
    849     if (!fWaitForExit)
    850         aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly);
    851 
    852     /* Get current time stamp to later calculate rest of timeout left. */
    853     uint64_t u64StartMS = RTTimeMilliTS();
    854 
    855     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    856     do
    857     {
    858         /*
    859          * Wait for guest session to start.
    860          */
    861         if (fVerbose)
     851    try
     852    {
     853        do
    862854        {
    863             if (cMsTimeout == 0)
    864                 RTPrintf("Waiting for guest session to start ...\n");
     855            Utf8Str strVBoxManage;
     856            strVBoxManage.printf("VBoxManage Guest Control (PID %RU32)", RTProcSelf());
     857
     858            CHECK_ERROR_BREAK(pGuest, CreateSession(Bstr(strUsername).raw(),
     859                                      Bstr(strPassword).raw(),
     860                                      Bstr(strDomain).raw(),
     861                                      Bstr(strVBoxManage).raw(),
     862                                      pGuestSession.asOutParam()));
     863
     864            /* Adjust process creation flags if we don't want to wait for process termination. */
     865            if (fDetached)
     866                aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly);
     867
     868            /* Get current time stamp to later calculate rest of timeout left. */
     869            uint64_t u64StartMS = RTTimeMilliTS();
     870
     871            /*
     872             * Wait for guest session to start.
     873             */
     874            if (fVerbose)
     875            {
     876                if (cMsTimeout == 0)
     877                    RTPrintf("Waiting for guest session to start ...\n");
     878                else
     879                    RTPrintf("Waiting for guest session to start (within %ums)\n", cMsTimeout);
     880            }
     881
     882            com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
     883            aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
     884            GuestSessionWaitResult_T sessionWaitResult;
     885            CHECK_ERROR_BREAK(pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), cMsTimeout, &sessionWaitResult));
     886            ULONG uSessionID;
     887            CHECK_ERROR_BREAK(pGuestSession, COMGETTER(Id)(&uSessionID));
     888
     889            if (   sessionWaitResult == GuestSessionWaitResult_Start
     890                /* Note: This might happen when Guest Additions < 4.3 are installed which don't
     891                 *       support dedicated guest sessions. */
     892                || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
     893            {
     894                if (fVerbose)
     895                    RTPrintf("Guest session (ID %RU32) has been started\n", uSessionID);
     896            }
    865897            else
    866                 RTPrintf("Waiting for guest session to start (within %ums)\n", cMsTimeout);
    867         }
    868 
    869         com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
    870         aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
    871         GuestSessionWaitResult_T sessionWaitResult;
    872         rc = pGuestSession->WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags), cMsTimeout, &sessionWaitResult);
    873         if (FAILED(rc))
    874         {
    875             ctrlPrintError(pGuestSession, COM_IIDOF(IGuestSession));
    876 
    877             rcExit = RTEXITCODE_FAILURE;
    878             break;
    879         }
    880 
    881         Assert(   sessionWaitResult == GuestSessionWaitResult_Start
    882                /* Note: This might happen when Guest Additions < 4.3 are installed which don't
    883                 *       support dedicated guest sessions. */
    884                || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported);
    885         if (fVerbose)
    886             RTPrintf("Guest session has been started\n");
    887 
    888         if (fVerbose)
    889         {
    890             if (cMsTimeout == 0)
    891                 RTPrintf("Waiting for guest process to start ...\n");
    892             else
    893                 RTPrintf("Waiting for guest process to start (within %ums)\n", cMsTimeout);
    894         }
    895 
    896         /*
    897          * Execute the process.
    898          */
    899         ComPtr<IGuestProcess> pProcess;
    900         rc = pGuestSession->ProcessCreate(Bstr(strCmd).raw(),
    901                                           ComSafeArrayAsInParam(aArgs),
    902                                           ComSafeArrayAsInParam(aEnv),
    903                                           ComSafeArrayAsInParam(aCreateFlags),
    904                                           cMsTimeout,
    905                                           pProcess.asOutParam());
    906         if (FAILED(rc))
    907         {
    908             ctrlPrintError(pGuestSession, COM_IIDOF(IGuestSession));
    909 
    910             rcExit = RTEXITCODE_FAILURE;
    911             break;
    912         }
    913 
    914         /** @todo does this need signal handling? there's no progress object etc etc */
    915 
    916         vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */);
    917         if (RT_FAILURE(vrc))
    918             RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc);
    919         vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */);
    920         if (RT_FAILURE(vrc))
    921             RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc);
    922 
    923         /* Wait for process to exit ... */
    924         RTMSINTERVAL cMsTimeLeft = 1;
    925         bool fReadStdOut, fReadStdErr;
    926         fReadStdOut = fReadStdErr = false;
    927         bool fCompleted = false;
    928         while (!fCompleted && cMsTimeLeft != 0)
    929         {
    930             cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
    931             ProcessWaitResult_T waitResult;
    932             rc = pProcess->WaitForArray(ComSafeArrayAsInParam(aWaitFlags), cMsTimeLeft, &waitResult);
    933             if (FAILED(rc))
    934             {
    935                 ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    936 
    937                 rcExit = RTEXITCODE_FAILURE;
    938                 break;
    939             }
    940 
    941             switch (waitResult)
    942             {
    943                 case ProcessWaitResult_Start:
     898            {
     899                RTPrintf("Error starting guest session\n");
     900                break;
     901            }
     902
     903            if (fVerbose)
     904            {
     905                if (cMsTimeout == 0)
     906                    RTPrintf("Waiting for guest process to start ...\n");
     907                else
     908                    RTPrintf("Waiting for guest process to start (within %ums)\n", cMsTimeout);
     909            }
     910
     911            /*
     912             * Execute the process.
     913             */
     914            ComPtr<IGuestProcess> pProcess;
     915            CHECK_ERROR_BREAK(pGuestSession, ProcessCreate(Bstr(strCmd).raw(),
     916                                                           ComSafeArrayAsInParam(aArgs),
     917                                                           ComSafeArrayAsInParam(aEnv),
     918                                                           ComSafeArrayAsInParam(aCreateFlags),
     919                                                           cMsTimeout,
     920                                                           pProcess.asOutParam()));
     921
     922            /** @todo does this need signal handling? there's no progress object etc etc */
     923
     924            vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */);
     925            if (RT_FAILURE(vrc))
     926                RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc);
     927            vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */);
     928            if (RT_FAILURE(vrc))
     929                RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc);
     930
     931            /* Wait for process to exit ... */
     932            RTMSINTERVAL cMsTimeLeft = 1;
     933            bool fReadStdOut, fReadStdErr;
     934            fReadStdOut = fReadStdErr = false;
     935
     936            bool fCompleted = false;
     937            while (!fCompleted && cMsTimeLeft != 0)
     938            {
     939                cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
     940                ProcessWaitResult_T waitResult;
     941                CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
     942                                                         cMsTimeLeft, &waitResult));
     943                switch (waitResult)
    944944                {
    945                     ULONG uPID = 0;
    946                     rc = pProcess->COMGETTER(PID)(&uPID);
    947                     if (FAILED(rc))
     945                    case ProcessWaitResult_Start:
    948946                    {
    949                         ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    950 
    951                         rcExit = RTEXITCODE_FAILURE;
     947                        ULONG uPID = 0;
     948                        CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
     949                        if (fVerbose)
     950                        {
     951                            RTPrintf("Process '%s' (PID %RU32) started\n",
     952                                     strCmd.c_str(), uPID);
     953                        }
     954                        else /** @todo Introduce a --quiet option for not printing this. */
     955                        {
     956                            /* Just print plain PID to make it easier for scripts
     957                             * invoking VBoxManage. */
     958                            RTPrintf("%RU32, session ID %RU32\n", uPID, uSessionID);
     959                        }
     960
     961                        /* We're done here if we don't want to wait for termination. */
     962                        if (fDetached)
     963                            fCompleted = true;
     964
    952965                        break;
    953966                    }
    954 
     967                    case ProcessWaitResult_StdOut:
     968                        fReadStdOut = true;
     969                        break;
     970                    case ProcessWaitResult_StdErr:
     971                        fReadStdErr = true;
     972                        break;
     973                    case ProcessWaitResult_Terminate:
     974                        /* Process terminated, we're done */
     975                        fCompleted = true;
     976                        break;
     977                    case ProcessWaitResult_WaitFlagNotSupported:
     978                    {
     979                        /* The guest does not support waiting for stdout/err, so
     980                         * yield to reduce the CPU load due to busy waiting. */
     981                        RTThreadYield(); /* Optional, don't check rc. */
     982
     983                        /* Try both, stdout + stderr. */
     984                        fReadStdOut = fReadStdErr = true;
     985                        break;
     986                    }
     987                    default:
     988                        /* Ignore all other results, let the timeout expire */
     989                        break;
     990                }
     991
     992                if (FAILED(rc))
     993                    break;
     994
     995                if (fReadStdOut) /* Do we need to fetch stdout data? */
     996                {
     997                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
     998                    vrc = ctrlExecPrintOutput(pProcess, g_pStdOut,
     999                                              1 /* StdOut */, cMsTimeLeft);
     1000                    fReadStdOut = false;
     1001                }
     1002
     1003                if (fReadStdErr) /* Do we need to fetch stdout data? */
     1004                {
     1005                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
     1006                    vrc = ctrlExecPrintOutput(pProcess, g_pStdErr,
     1007                                              2 /* StdErr */, cMsTimeLeft);
     1008                    fReadStdErr = false;
     1009                }
     1010
     1011                if (RT_FAILURE(vrc))
     1012                    break;
     1013
     1014                /* Did we run out of time? */
     1015                if (   cMsTimeout
     1016                    && RTTimeMilliTS() - u64StartMS > cMsTimeout)
     1017                    break;
     1018
     1019                NativeEventQueue::getMainEventQueue()->processEventQueue(0);
     1020
     1021            } /* while */
     1022
     1023            /* Report status back to the user. */
     1024            if (fCompleted)
     1025            {
     1026                ProcessStatus_T procStatus;
     1027                CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus));
     1028                if (   procStatus == ProcessStatus_TerminatedNormally
     1029                    || procStatus == ProcessStatus_TerminatedAbnormally
     1030                    || procStatus == ProcessStatus_TerminatedSignal)
     1031                {
     1032                    LONG exitCode;
     1033                    CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode));
    9551034                    if (fVerbose)
    956                     {
    957                         RTPrintf("Process '%s' (PID: %ld) %s\n",
    958                                  strCmd.c_str(), uPID,
    959                                  fWaitForExit ? "started" : "started (detached)");
    960                     }
    961                     else /** @todo Introduce a --quiet option for not printing this. */
    962                     {
    963                         /* Just print plain PID to make it easier for scripts
    964                          * invoking VBoxManage. */
    965                         RTPrintf("%ld\n", uPID);
    966                     }
    967 
    968                     /* We're done here if we don't want to wait for termination. */
    969                     if (!fWaitForExit)
    970                         fCompleted = true;
    971 
    972                     break;
     1035                        RTPrintf("Exit code=%u (Status=%u [%s])\n",
     1036                                 exitCode, procStatus, ctrlExecProcessStatusToText(procStatus));
     1037
     1038                    rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode);
    9731039                }
    974                 case ProcessWaitResult_StdOut:
    975                     fReadStdOut = true;
    976                     break;
    977                 case ProcessWaitResult_StdErr:
    978                     fReadStdErr = true;
    979                     break;
    980                 case ProcessWaitResult_Terminate:
    981                     /* Process terminated, we're done */
    982                     fCompleted = true;
    983                     break;
    984                 case ProcessWaitResult_WaitFlagNotSupported:
    985                 {
    986                     /* The guest does not support waiting for stdout/err, so
    987                      * yield to reduce the CPU load due to busy waiting. */
    988                     RTThreadYield(); /* Optional, don't check rc. */
    989 
    990                     /* Try both, stdout + stderr. */
    991                     fReadStdOut = fReadStdErr = true;
    992                     break;
    993                 }
    994                 default:
    995                     /* Ignore all other results, let the timeout expire */
    996                     break;
    997             }
    998 
    999             if (FAILED(rc))
    1000                 break;
    1001 
    1002             if (fReadStdOut) /* Do we need to fetch stdout data? */
    1003             {
    1004                 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
    1005                 vrc = ctrlExecPrintOutput(pProcess, g_pStdOut,
    1006                                           1 /* StdOut */, cMsTimeLeft);
    1007                 fReadStdOut = false;
    1008             }
    1009 
    1010             if (fReadStdErr) /* Do we need to fetch stdout data? */
    1011             {
    1012                 cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
    1013                 vrc = ctrlExecPrintOutput(pProcess, g_pStdErr,
    1014                                           2 /* StdErr */, cMsTimeLeft);
    1015                 fReadStdErr = false;
    1016             }
    1017 
    1018             if (RT_FAILURE(vrc))
    1019                 break;
    1020 
    1021             /* Did we run out of time? */
    1022             if (   cMsTimeout
    1023                 && RTTimeMilliTS() - u64StartMS > cMsTimeout)
    1024                 break;
    1025 
    1026             NativeEventQueue::getMainEventQueue()->processEventQueue(0);
    1027 
    1028         } /* while */
    1029 
    1030         /* Report status back to the user. */
    1031         if (fCompleted)
    1032         {
    1033             ProcessStatus_T status;
    1034             rc = pProcess->COMGETTER(Status)(&status);
    1035             if (FAILED(rc))
    1036             {
    1037                 ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    1038 
    1039                 rcExit = RTEXITCODE_FAILURE;
     1040                else if (fVerbose)
     1041                    RTPrintf("Process now is in status [%s]\n", ctrlExecProcessStatusToText(procStatus));
    10401042            }
    10411043            else
    10421044            {
    1043                 LONG exitCode;
    1044                 rc = pProcess->COMGETTER(ExitCode)(&exitCode);
    1045                 if (FAILED(rc))
    1046                 {
    1047                     ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    1048 
    1049                     rcExit = RTEXITCODE_FAILURE;
    1050                 }
    1051                 else
    1052                 {
    1053                     if (fVerbose)
    1054                         RTPrintf("Exit code=%u (Status=%u [%s])\n", exitCode, status, ctrlExecProcessStatusToText(status));
    1055 
    1056                     rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(status, exitCode);
    1057                 }
    1058             }
    1059         }
    1060         else
    1061         {
    1062             if (fVerbose)
    1063                 RTPrintf("Process execution aborted!\n");
    1064 
    1065             rcExit = (RTEXITCODE)EXITCODEEXEC_TERM_ABEND;
    1066         }
    1067     } while (0);
    1068 
    1069     /*
    1070      * Only close the guest session if we waited for the guest
    1071      * process to exit. Otherwise we wouldn't have any chance to
    1072      * access and/or kill detached guest process lateron.
    1073      */
    1074     if (   fWaitForExit
    1075         || rcExit != RTEXITCODE_SUCCESS)
     1045                if (fVerbose)
     1046                    RTPrintf("Process execution aborted!\n");
     1047
     1048                rcExit = (RTEXITCODE)EXITCODEEXEC_TERM_ABEND;
     1049            }
     1050
     1051        } while (0);
     1052    }
     1053    catch (std::bad_alloc)
     1054    {
     1055        rc = E_OUTOFMEMORY;
     1056    }
     1057
     1058    bool fCloseSession = false;
     1059    if (SUCCEEDED(rc))
     1060    {
     1061        /*
     1062         * Only close the guest session if we waited for the guest
     1063         * process to exit. Otherwise we wouldn't have any chance to
     1064         * access and/or kill detached guest process lateron.
     1065         */
     1066        fCloseSession = !fDetached;
     1067    }
     1068    else /* Close session on error. */
     1069        fCloseSession = true;
     1070
     1071    if (   fCloseSession
     1072        && !pGuestSession.isNull())
    10761073    {
    10771074        if (fVerbose)
    10781075            RTPrintf("Closing guest session ...\n");
    10791076        rc = pGuestSession->Close();
    1080         if (FAILED(rc))
    1081         {
    1082             ctrlPrintError(pGuestSession, COM_IIDOF(ISession));
    1083 
    1084             if (rcExit == RTEXITCODE_SUCCESS)
    1085                 rcExit = RTEXITCODE_FAILURE;
    1086         }
    1087     }
    1088     else if (fVerbose)
     1077    }
     1078    else if (!fCloseSession && fVerbose)
    10891079        RTPrintf("Guest session detached\n");
     1080
     1081    if (   rcExit == RTEXITCODE_SUCCESS
     1082        && FAILED(rc))
     1083    {
     1084        /* Make sure an appropriate exit code is set on error. */
     1085        rcExit = RTEXITCODE_FAILURE;
     1086    }
    10901087
    10911088    return rcExit;
     
    31063103                    {
    31073104                        if (fVerbose)
    3108                             RTPrintf("Terminating process PID=%RU32 (session ID=%RU32) ...\n",
     3105                            RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n",
    31093106                                     uPID, uID);
    31103107                        CHECK_ERROR_BREAK(pProcess, Terminate());
     
    31143111                    {
    31153112                        if (ulSessionID != UINT32_MAX)
    3116                             RTPrintf("No matching process(es) for session %RU32 found\n",
     3113                            RTPrintf("No matching process(es) for session ID %RU32 found\n",
    31173114                                     ulSessionID);
    31183115                    }
     
    33433340        else if (   !RTStrICmp(pArg->argv[1], "exec")
    33443341                 || !RTStrICmp(pArg->argv[1], "execute"))
    3345             rcExit = handleCtrlExecProgram(guest, &arg);
     3342            rcExit = handleCtrlProcessExec(guest, &arg);
    33463343        else if (!RTStrICmp(pArg->argv[1], "copyfrom"))
    33473344            rcExit = handleCtrlCopy(guest, &arg, false /* Guest to host */);
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