VirtualBox

Changeset 55535 in vbox


Ignore:
Timestamp:
Apr 30, 2015 2:13:56 AM (9 years ago)
Author:
vboxsync
Message:

Main,VBoxManage,VBoxShell,ValidationKit: Changed the IGuestSession:createProcess[Ex] interfaces to take argv[0] as input separate from the executable name. This is not yet implemented on the guest side.

Location:
trunk/src/VBox
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp

    r55531 r55535  
    15001500     * Prepare environment variables list.
    15011501     */
     1502/** @todo r=bird: you don't need to prepare this, do you? Why don't you replace
     1503 * the brilliant RTStrAPrintf call with RTEnvPutEx and drop the papszEnv related code? */
    15021504    char **papszEnv = NULL;
    15031505    uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h

    r55182 r55535  
    111111
    112112#ifdef VBOX_WITH_GUEST_CONTROL
    113 # define USAGE_GSTCTRL_EXEC         RT_BIT(0)
    114 # define USAGE_GSTCTRL_COPYFROM     RT_BIT(1)
    115 # define USAGE_GSTCTRL_COPYTO       RT_BIT(2)
    116 # define USAGE_GSTCTRL_CREATEDIR    RT_BIT(3)
    117 # define USAGE_GSTCTRL_REMOVEDIR    RT_BIT(4)
    118 # define USAGE_GSTCTRL_REMOVEFILE   RT_BIT(5)
    119 # define USAGE_GSTCTRL_RENAME       RT_BIT(6)
    120 # define USAGE_GSTCTRL_CREATETEMP   RT_BIT(7)
    121 # define USAGE_GSTCTRL_LIST         RT_BIT(8)
    122 # define USAGE_GSTCTRL_PROCESS      RT_BIT(9)
    123 # define USAGE_GSTCTRL_KILL         RT_BIT(10)
    124 # define USAGE_GSTCTRL_SESSION      RT_BIT(11)
    125 # define USAGE_GSTCTRL_STAT         RT_BIT(12)
    126 # define USAGE_GSTCTRL_UPDATEADDS   RT_BIT(13)
    127 # define USAGE_GSTCTRL_WATCH        RT_BIT(14)
     113# define USAGE_GSTCTRL_RUN          RT_BIT(0)
     114# define USAGE_GSTCTRL_START        RT_BIT(1)
     115# define USAGE_GSTCTRL_COPYFROM     RT_BIT(2)
     116# define USAGE_GSTCTRL_COPYTO       RT_BIT(3)
     117# define USAGE_GSTCTRL_CREATEDIR    RT_BIT(4)
     118# define USAGE_GSTCTRL_REMOVEDIR    RT_BIT(5)
     119# define USAGE_GSTCTRL_REMOVEFILE   RT_BIT(6)
     120# define USAGE_GSTCTRL_RENAME       RT_BIT(7)
     121# define USAGE_GSTCTRL_CREATETEMP   RT_BIT(8)
     122# define USAGE_GSTCTRL_LIST         RT_BIT(9)
     123# define USAGE_GSTCTRL_PROCESS      RT_BIT(10)
     124# define USAGE_GSTCTRL_KILL         RT_BIT(11)
     125# define USAGE_GSTCTRL_SESSION      RT_BIT(12)
     126# define USAGE_GSTCTRL_STAT         RT_BIT(13)
     127# define USAGE_GSTCTRL_UPDATEADDS   RT_BIT(14)
     128# define USAGE_GSTCTRL_WATCH        RT_BIT(15)
     129# define USAGE_GSTCTRL_EXEC         RT_BIT(31) /**< @deprecated Remember to remove. */
    128130#endif
    129131
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r55532 r55535  
    4646#include <iprt/process.h> /* For RTProcSelf(). */
    4747#include <iprt/thread.h>
     48#include <iprt/vfs.h>
    4849
    4950#include <map>
     
    218219typedef std::map< Utf8Str, std::vector<DESTFILEENTRY> >::iterator DESTDIRMAPITER, *PDESTDIRMAPITER;
    219220
    220 /**
    221  * Special exit codes for returning errors/information of a
    222  * started guest process to the command line VBoxManage was started from.
    223  * Useful for e.g. scripting.
    224  *
    225  * @note    These are frozen as of 4.1.0.
    226  */
    227 enum EXITCODEEXEC
    228 {
    229     EXITCODEEXEC_SUCCESS        = RTEXITCODE_SUCCESS,
    230     /* Process exited normally but with an exit code <> 0. */
    231     EXITCODEEXEC_CODE           = 16,
    232     EXITCODEEXEC_FAILED         = 17,
    233     EXITCODEEXEC_TERM_SIGNAL    = 18,
    234     EXITCODEEXEC_TERM_ABEND     = 19,
    235     EXITCODEEXEC_TIMEOUT        = 20,
    236     EXITCODEEXEC_DOWN           = 21,
    237     EXITCODEEXEC_CANCELED       = 22
    238 };
    239221
    240222/*
     
    245227{
    246228    GETOPTDEF_COMMON_PASSWORD = 1000
     229};
     230
     231/**
     232 * Long option IDs for the guestcontrol run command.
     233 */
     234enum kGstCtrlRunOpt
     235{
     236    kGstCtrlRunOpt_IgnoreOrphanedProcesses = 1000,
     237    kGstCtrlRunOpt_NoProfile,
     238    kGstCtrlRunOpt_Dos2Unix,
     239    kGstCtrlRunOpt_Unix2Dos,
     240    kGstCtrlRunOpt_WaitForStdOut,
     241    kGstCtrlRunOpt_NoWaitForStdOut,
     242    kGstCtrlRunOpt_WaitForStdErr,
     243    kGstCtrlRunOpt_NoWaitForStdErr
    247244};
    248245
     
    290287};
    291288
    292 enum OUTPUTTYPE
    293 {
    294     OUTPUTTYPE_UNDEFINED = 0,
    295     OUTPUTTYPE_DOS2UNIX  = 10,
    296     OUTPUTTYPE_UNIX2DOS  = 20
     289enum kStreamTransform
     290{
     291    kStreamTransform_None = 0,
     292    kStreamTransform_Dos2Unix,
     293    kStreamTransform_Unix2Dos
    297294};
    298295
     
    307304                 pcszSep1, pcszSep2,
    308305                 uSubCmd == ~0U ? "\n" : "");
    309     if (uSubCmd & USAGE_GSTCTRL_EXEC)
     306    if (uSubCmd & USAGE_GSTCTRL_RUN)
    310307        RTStrmPrintf(pStrm,
    311                  "                              exec[ute]\n"
    312                  "                              --image <path to program> --username <name>\n"
    313                  "                              [--passwordfile <file> | --password <password>]\n"
    314                  "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
    315                  "                              [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
    316                  "                              [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
    317                  "                              [--dos2unix] [--unquoted-args] [--unix2dos]\n"
    318                  "                              [-- [<argument1>] ... [<argumentN>]]\n"
     308                     "                              run\n"
     309                     "                              [--image <path to executable>] --username <name>\n"
     310                     "                              [--passwordfile <file> | --password <password>]\n"
     311                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
     312                     "                              [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n"
     313                     "                              [--unquoted-args] [--no-wait-stdout|--wait-stdout]\n"
     314                     "                              [--no-wait-stderr|--wait-stderr]\n"
     315                     "                              [--dos2unix] [--unix2dos]\n"
     316                     "                              [--] <program/arg0> [argument1] ... [argumentN]]\n"
     317                     "\n");
     318    if (uSubCmd & USAGE_GSTCTRL_START)
     319        RTStrmPrintf(pStrm,
     320                     "                              start\n"
     321                     "                              [--image <path to executable>] --username <name>\n"
     322                     "                              [--passwordfile <file> | --password <password>]\n"
     323                     "                              [--domain <domain>] [--verbose] [--timeout <msec>]\n"
     324                     "                              [--setenv <NAME>=<VALUE>] [--unset <NAME>]\n"
     325                     "                              [--unquoted-args] [--dos2unix] [--unix2dos]\n"
     326                     "                              [--] <program/arg0> [argument1] ... [argumentN]]\n"
     327                 "\n");
     328    if (uSubCmd == USAGE_GSTCTRL_EXEC)
     329        RTStrmPrintf(pStrm,
     330                 "   {DEPRECATED}               exec[ute]\n"
     331                 "   {DEPRECATED}               --image <path to program> --username <name>\n"
     332                 "   {DEPRECATED}               [--passwordfile <file> | --password <password>]\n"
     333                 "   {DEPRECATED}               [--domain <domain>] [--verbose] [--timeout <msec>]\n"
     334                 "   {DEPRECATED}               [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
     335                 "   {DEPRECATED}               [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
     336                 "   {DEPRECATED}               [--dos2unix] [--unquoted-args] [--unix2dos]\n"
     337                 "   {DEPRECATED}               [-- [<argument1>] ... [<argumentN>]]\n"
    319338                 "\n");
    320339    if (uSubCmd & USAGE_GSTCTRL_COPYFROM)
     
    537556}
    538557
    539 static int ctrlExecProcessStatusToExitCode(ProcessStatus_T enmStatus, ULONG uExitCode)
    540 {
    541     int vrc = EXITCODEEXEC_SUCCESS;
     558const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
     559{
     560    switch (enmWaitResult)
     561    {
     562        case ProcessWaitResult_Start:
     563            return "started";
     564        case ProcessWaitResult_Terminate:
     565            return "terminated";
     566        case ProcessWaitResult_Status:
     567            return "status changed";
     568        case ProcessWaitResult_Error:
     569            return "error";
     570        case ProcessWaitResult_Timeout:
     571            return "timed out";
     572        case ProcessWaitResult_StdIn:
     573            return "stdin ready";
     574        case ProcessWaitResult_StdOut:
     575            return "data on stdout";
     576        case ProcessWaitResult_StdErr:
     577            return "data on stderr";
     578        case ProcessWaitResult_WaitFlagNotSupported:
     579            return "waiting flag not supported";
     580        default:
     581            break;
     582    }
     583    return "unknown";
     584}
     585
     586/**
     587 * Translates a guest session status to a human readable
     588 * string.
     589 */
     590const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
     591{
    542592    switch (enmStatus)
    543593    {
     594        case GuestSessionStatus_Starting:
     595            return "starting";
     596        case GuestSessionStatus_Started:
     597            return "started";
     598        case GuestSessionStatus_Terminating:
     599            return "terminating";
     600        case GuestSessionStatus_Terminated:
     601            return "terminated";
     602        case GuestSessionStatus_TimedOutKilled:
     603            return "timed out";
     604        case GuestSessionStatus_TimedOutAbnormally:
     605            return "timed out, hanging";
     606        case GuestSessionStatus_Down:
     607            return "killed";
     608        case GuestSessionStatus_Error:
     609            return "error";
     610        default:
     611            break;
     612    }
     613    return "unknown";
     614}
     615
     616/**
     617 * Translates a guest file status to a human readable
     618 * string.
     619 */
     620const char *ctrlFileStatusToText(FileStatus_T enmStatus)
     621{
     622    switch (enmStatus)
     623    {
     624        case FileStatus_Opening:
     625            return "opening";
     626        case FileStatus_Open:
     627            return "open";
     628        case FileStatus_Closing:
     629            return "closing";
     630        case FileStatus_Closed:
     631            return "closed";
     632        case FileStatus_Down:
     633            return "killed";
     634        case FileStatus_Error:
     635            return "error";
     636        default:
     637            break;
     638    }
     639    return "unknown";
     640}
     641
     642static int ctrlPrintError(com::ErrorInfo &errorInfo)
     643{
     644    if (   errorInfo.isFullAvailable()
     645        || errorInfo.isBasicAvailable())
     646    {
     647        /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     648         * because it contains more accurate info about what went wrong. */
     649        if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR)
     650            RTMsgError("%ls.", errorInfo.getText().raw());
     651        else
     652        {
     653            RTMsgError("Error details:");
     654            GluePrintErrorInfo(errorInfo);
     655        }
     656        return VERR_GENERAL_FAILURE; /** @todo */
     657    }
     658    AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()),
     659                          VERR_INVALID_PARAMETER);
     660}
     661
     662static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)
     663{
     664    com::ErrorInfo ErrInfo(pObj, aIID);
     665    return ctrlPrintError(ErrInfo);
     666}
     667
     668static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
     669{
     670    int vrc = VINF_SUCCESS;
     671    HRESULT rc;
     672
     673    do
     674    {
     675        BOOL fCanceled;
     676        CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled));
     677        if (!fCanceled)
     678        {
     679            LONG rcProc;
     680            CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc));
     681            if (FAILED(rcProc))
     682            {
     683                com::ProgressErrorInfo ErrInfo(pProgress);
     684                vrc = ctrlPrintError(ErrInfo);
     685            }
     686        }
     687
     688    } while(0);
     689
     690    AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
     691
     692    return vrc;
     693}
     694
     695/**
     696 * Un-initializes the VM after guest control usage.
     697 * @param   pCmdCtx                 Pointer to command context.
     698 * @param   uFlags                  Command context flags.
     699 */
     700static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
     701{
     702    AssertPtrReturnVoid(pCtx);
     703
     704    if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
     705        ctrlSignalHandlerUninstall();
     706
     707    HRESULT rc;
     708
     709    do
     710    {
     711        if (!pCtx->pGuestSession.isNull())
     712        {
     713            if (   !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
     714                && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
     715            {
     716                if (pCtx->fVerbose)
     717                    RTPrintf("Closing guest session ...\n");
     718
     719                CHECK_ERROR(pCtx->pGuestSession, Close());
     720                /* Keep going - don't break here. Try to unlock the
     721                 * machine down below. */
     722            }
     723            else if (   (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
     724                     && pCtx->fVerbose)
     725                RTPrintf("Guest session detached\n");
     726
     727            pCtx->pGuestSession.setNull();
     728        }
     729
     730        if (pCtx->handlerArg.session)
     731            CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
     732
     733    } while (0);
     734
     735    for (int i = 0; i < pCtx->iArgc; i++)
     736        RTStrFree(pCtx->ppaArgv[i]);
     737    RTMemFree(pCtx->ppaArgv);
     738    pCtx->iArgc = 0;
     739}
     740
     741/**
     742 * Initializes the VM for IGuest operations.
     743 *
     744 * That is, checks whether it's up and running, if it can be locked (shared
     745 * only) and returns a valid IGuest pointer on success. Also, it does some
     746 * basic command line processing and opens a guest session, if required.
     747 *
     748 * @return  RTEXITCODE status code.
     749 * @param   pArg                    Pointer to command line argument structure.
     750 * @param   pCmdCtx                 Pointer to command context.
     751 * @param   uFlags                  Command context flags.
     752 */
     753static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
     754                             PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
     755{
     756    AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
     757    AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
     758    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
     759
     760#ifdef DEBUG_andy
     761    RTPrintf("Original argv:\n");
     762    for (int i=0; i<pArg->argc;i++)
     763        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
     764#endif
     765
     766    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     767
     768    const char *pszNameOrId = pArg->argv[0];
     769    const char *pszCmd = pArg->argv[1];
     770
     771    /* Lookup VM. */
     772    ComPtr<IMachine> machine;
     773    /* Assume it's an UUID. */
     774    HRESULT rc;
     775    CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
     776                                              machine.asOutParam()));
     777    if (SUCCEEDED(rc))
     778    {
     779        /* Machine is running? */
     780        MachineState_T machineState;
     781        CHECK_ERROR(machine, COMGETTER(State)(&machineState));
     782        if (   SUCCEEDED(rc)
     783            && (machineState != MachineState_Running))
     784            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
     785                                    pszNameOrId, machineStateToName(machineState, false));
     786    }
     787    else
     788        rcExit = RTEXITCODE_FAILURE;
     789
     790    if (rcExit == RTEXITCODE_SUCCESS)
     791    {
     792        /*
     793         * Process standard options which are served by all commands.
     794         */
     795        static const RTGETOPTDEF s_aOptions[] =
     796        {
     797            { "--username",            'u',                             RTGETOPT_REQ_STRING  },
     798            { "--passwordfile",        'p',                             RTGETOPT_REQ_STRING  },
     799            { "--password",            GETOPTDEF_COMMON_PASSWORD,       RTGETOPT_REQ_STRING  },
     800            { "--domain",              'd',                             RTGETOPT_REQ_STRING  },
     801            { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
     802        };
     803
     804
     805
     806        /** @todo r=bird: This is just SOOOO hackish and fragile, especially wrt to the
     807         * exec/run commands. If you don't have the full option syntax, there is no way
     808         * you can safely tell an option from an option value. sigh.
     809         * The way to do this is by a defines with the above s_aOptions entries, calling
     810         * a common function in the default case of each option parser, and a routine to
     811         * be called at the end of option parsing to open the session. */
     812
     813
     814
     815        /*
     816         * Allocate per-command argv. This then only contains the specific arguments
     817         * the command needs.
     818         */
     819        pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
     820        if (!pCtx->ppaArgv)
     821        {
     822            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
     823        }
     824        else
     825        {
     826            pCtx->iArgc = 0;
     827
     828            int iArgIdx = 2; /* Skip VM name and guest control command */
     829            int ch;
     830            RTGETOPTUNION ValueUnion;
     831            RTGETOPTSTATE GetState;
     832            RTGetOptInit(&GetState, pArg->argc, pArg->argv,
     833                         s_aOptions, RT_ELEMENTS(s_aOptions),
     834                         iArgIdx, 0);
     835
     836            while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     837                   && (rcExit == RTEXITCODE_SUCCESS))
     838            {
     839                /* For options that require an argument, ValueUnion has received the value. */
     840                switch (ch)
     841                {
     842                    case 'u': /* User name */
     843                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     844                            pCtx->strUsername = ValueUnion.psz;
     845                        iArgIdx = GetState.iNext;
     846                        break;
     847
     848                    case GETOPTDEF_COMMON_PASSWORD: /* Password */
     849                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     850                        {
     851                            if (pCtx->strPassword.isEmpty())
     852                                pCtx->strPassword = ValueUnion.psz;
     853                        }
     854                        iArgIdx = GetState.iNext;
     855                        break;
     856
     857                    case 'p': /* Password file */
     858                    {
     859                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     860                            rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
     861                        iArgIdx = GetState.iNext;
     862                        break;
     863                    }
     864
     865                    case 'd': /* domain */
     866                        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     867                            pCtx->strDomain = ValueUnion.psz;
     868                        iArgIdx = GetState.iNext;
     869                        break;
     870
     871                    case 'v': /* Verbose */
     872                        pCtx->fVerbose = true;
     873                        iArgIdx = GetState.iNext;
     874                        break;
     875
     876                    case 'h': /* Help */
     877                        errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
     878                        return RTEXITCODE_SYNTAX;
     879
     880                    default:
     881                        /* Simply skip; might be handled in a specific command
     882                         * handler later. */
     883                        break;
     884
     885                } /* switch */
     886
     887                int iArgDiff = GetState.iNext - iArgIdx;
     888                if (iArgDiff)
     889                {
     890#ifdef DEBUG_andy
     891                    RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
     892#endif
     893                    for (int i = iArgIdx; i < GetState.iNext; i++)
     894                    {
     895                        char *pszArg = RTStrDup(pArg->argv[i]);
     896                        if (!pszArg)
     897                        {
     898                            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
     899                                                    "Not enough memory for command line handling\n");
     900                            break;
     901                        }
     902                        pCtx->ppaArgv[pCtx->iArgc] = pszArg;
     903                        pCtx->iArgc++;
     904#ifdef DEBUG_andy
     905                        RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
     906#endif
     907                    }
     908
     909                    iArgIdx = GetState.iNext;
     910                }
     911
     912            } /* while RTGetOpt */
     913        }
     914    }
     915
     916    /*
     917     * Check for mandatory stuff.
     918     */
     919    if (rcExit == RTEXITCODE_SUCCESS)
     920    {
     921#if 0
     922        RTPrintf("argc=%d\n", pCtx->iArgc);
     923        for (int i = 0; i < pCtx->iArgc; i++)
     924            RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
     925#endif
     926        if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     927        {
     928            if (pCtx->strUsername.isEmpty())
     929                rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
     930        }
     931    }
     932
     933    if (rcExit == RTEXITCODE_SUCCESS)
     934    {
     935        /*
     936         * Build up a reasonable guest session name. Useful for identifying
     937         * a specific session when listing / searching for them.
     938         */
     939        char *pszSessionName;
     940        if (0 >= RTStrAPrintf(&pszSessionName,
     941                              "[%RU32] VBoxManage Guest Control [%s] - %s",
     942                              RTProcSelf(), pszNameOrId, pszCmd))
     943            return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
     944
     945        do
     946        {
     947            /* Open a session for the VM. */
     948            CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
     949            /* Get the associated console. */
     950            ComPtr<IConsole> console;
     951            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
     952            /* ... and session machine. */
     953            ComPtr<IMachine> sessionMachine;
     954            CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
     955            /* Get IGuest interface. */
     956            CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
     957            if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
     958            {
     959                if (pCtx->fVerbose)
     960                    RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
     961
     962                /* Open a guest session. */
     963                Assert(!pCtx->pGuest.isNull());
     964                CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
     965                                                              Bstr(pCtx->strPassword).raw(),
     966                                                              Bstr(pCtx->strDomain).raw(),
     967                                                              Bstr(pszSessionName).raw(),
     968                                                              pCtx->pGuestSession.asOutParam()));
     969
     970                /*
     971                 * Wait for guest session to start.
     972                 */
     973                if (pCtx->fVerbose)
     974                    RTPrintf("Waiting for guest session to start ...\n");
     975
     976                com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
     977                aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
     978                GuestSessionWaitResult_T sessionWaitResult;
     979                CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
     980                                                                    /** @todo Make session handling timeouts configurable. */
     981                                                                    30 * 1000, &sessionWaitResult));
     982
     983                if (   sessionWaitResult == GuestSessionWaitResult_Start
     984                    /* Note: This might happen when Guest Additions < 4.3 are installed which don't
     985                     *       support dedicated guest sessions. */
     986                    || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
     987                {
     988                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
     989                    if (pCtx->fVerbose)
     990                        RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
     991                }
     992                else
     993                {
     994                    GuestSessionStatus_T sessionStatus;
     995                    CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
     996                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
     997                                            ctrlSessionStatusToText(sessionStatus));
     998                    break;
     999                }
     1000            }
     1001
     1002            if (   SUCCEEDED(rc)
     1003                && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
     1004            {
     1005                ctrlSignalHandlerInstall();
     1006            }
     1007
     1008        } while (0);
     1009
     1010        if (FAILED(rc))
     1011            rcExit = RTEXITCODE_FAILURE;
     1012
     1013        RTStrFree(pszSessionName);
     1014    }
     1015
     1016    if (rcExit == RTEXITCODE_SUCCESS)
     1017    {
     1018        pCtx->handlerArg = *pArg;
     1019        pCtx->uFlags = uFlags;
     1020    }
     1021    else /* Clean up on failure. */
     1022        ctrlUninitVM(pCtx, uFlags);
     1023
     1024    return rcExit;
     1025}
     1026
     1027
     1028/** @name EXITCODEEXEC_XXX - Special run exit codes.
     1029 *
     1030 * Special exit codes for returning errors/information of a started guest
     1031 * process to the command line VBoxManage was started from.  Useful for e.g.
     1032 * scripting.
     1033 *
     1034 * ASSUMING that all platforms have at least 7-bits for the exit code we can do
     1035 * the following mapping:
     1036 *  - Guest exit code 0 is mapped to 0 on the host.
     1037 *  - Guest exit codes 1 thru 93 (0x5d) are displaced by 32, so that 1
     1038 *    becomes 33 (0x21) on the host and 93 becomes 125 (0x7d) on the host.
     1039 *  - Guest exit codes 94 (0x5e) and above are mapped to 126 (0x5e).
     1040 *
     1041 * We ASSUME that all VBoxManage status codes are in the range 0 thru 32.
     1042 *
     1043 * @note    These are frozen as of 4.1.0.
     1044 * @note    The guest exit code mappings was introduced with 5.0 and the 'run'
     1045 *          command, they are/was not supported by 'exec'.
     1046 * @sa      ctrlRunCalculateExitCode
     1047 */
     1048/** Process exited normally but with an exit code <> 0. */
     1049#define EXITCODEEXEC_CODE           ((RTEXITCODE)16)
     1050#define EXITCODEEXEC_FAILED         ((RTEXITCODE)17)
     1051#define EXITCODEEXEC_TERM_SIGNAL    ((RTEXITCODE)18)
     1052#define EXITCODEEXEC_TERM_ABEND     ((RTEXITCODE)19)
     1053#define EXITCODEEXEC_TIMEOUT        ((RTEXITCODE)20)
     1054#define EXITCODEEXEC_DOWN           ((RTEXITCODE)21)
     1055/** Execution was interrupt by user (ctrl-c). */
     1056#define EXITCODEEXEC_CANCELED       ((RTEXITCODE)22)
     1057/** The first mapped guest (non-zero) exit code. */
     1058#define EXITCODEEXEC_MAPPED_FIRST           33
     1059/** The last mapped guest (non-zero) exit code value (inclusive). */
     1060#define EXITCODEEXEC_MAPPED_LAST            125
     1061/** The number of exit codes from EXITCODEEXEC_MAPPED_FIRST to
     1062 * EXITCODEEXEC_MAPPED_LAST.  This is also the highest guest exit code number
     1063 * we're able to map. */
     1064#define EXITCODEEXEC_MAPPED_RANGE           (93)
     1065/** The guest exit code displacement value. */
     1066#define EXITCODEEXEC_MAPPED_DISPLACEMENT    32
     1067/** The guest exit code was too big to be mapped. */
     1068#define EXITCODEEXEC_MAPPED_BIG             ((RTEXITCODE)126)
     1069/** @} */
     1070
     1071/**
     1072 * Calculates the exit code of VBoxManage.
     1073 *
     1074 * @returns The exit code to return.
     1075 * @param   enmStatus           The guest process status.
     1076 * @param   uExitCode           The associated guest process exit code (where
     1077 *                              applicable).
     1078 * @param   fReturnExitCodes    Set if we're to use the 32-126 range for guest
     1079 *                              exit codes.
     1080 */
     1081static RTEXITCODE ctrlRunCalculateExitCode(ProcessStatus_T enmStatus, ULONG uExitCode, bool fReturnExitCodes)
     1082{
     1083    int vrc = RTEXITCODE_SUCCESS;
     1084    switch (enmStatus)
     1085    {
     1086        case ProcessStatus_TerminatedNormally:
     1087            if (uExitCode == 0)
     1088                return RTEXITCODE_SUCCESS;
     1089            if (!fReturnExitCodes)
     1090                return EXITCODEEXEC_CODE;
     1091            if (uExitCode <= EXITCODEEXEC_MAPPED_RANGE)
     1092                return (RTEXITCODE) (uExitCode + EXITCODEEXEC_MAPPED_DISPLACEMENT);
     1093            return EXITCODEEXEC_MAPPED_BIG;
     1094
     1095        case ProcessStatus_TerminatedAbnormally:
     1096            return EXITCODEEXEC_TERM_ABEND;
     1097        case ProcessStatus_TerminatedSignal:
     1098            return EXITCODEEXEC_TERM_SIGNAL;
     1099
     1100#if 0  /* see caller! */
     1101        case ProcessStatus_TimedOutKilled:
     1102            return EXITCODEEXEC_TIMEOUT;
     1103        case ProcessStatus_Down:
     1104            return EXITCODEEXEC_DOWN;   /* Service/OS is stopping, process was killed. */
     1105        case ProcessStatus_Error:
     1106            return EXITCODEEXEC_FAILED;
     1107
     1108        /* The following is probably for detached? */
    5441109        case ProcessStatus_Starting:
    545             vrc = EXITCODEEXEC_SUCCESS;
     1110            return RTEXITCODE_SUCCESS;
     1111        case ProcessStatus_Started:
     1112            return RTEXITCODE_SUCCESS;
     1113        case ProcessStatus_Paused:
     1114            return RTEXITCODE_SUCCESS;
     1115        case ProcessStatus_Terminating:
     1116            return RTEXITCODE_SUCCESS; /** @todo ???? */
     1117#endif
     1118
     1119        default:
     1120            AssertMsgFailed(("Unknown exit status (%u/%u) from guest process returned!\n", enmStatus, uExitCode));
     1121            return RTEXITCODE_FAILURE;
     1122    }
     1123}
     1124
     1125
     1126/**
     1127 * Pumps guest output to the host.
     1128 *
     1129 * @return  IPRT status code.
     1130 * @param   pProcess        Pointer to appropriate process object.
     1131 * @param   hVfsIosDst      Where to write the data.
     1132 * @param   uHandle         Handle where to read the data from.
     1133 * @param   cMsTimeout      Timeout (in ms) to wait for the operation to
     1134 *                          complete.
     1135 */
     1136static int ctrlRunPumpOutput(IProcess *pProcess, RTVFSIOSTREAM hVfsIosDst, ULONG uHandle, RTMSINTERVAL cMsTimeout)
     1137{
     1138    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     1139    Assert(hVfsIosDst != NIL_RTVFSIOSTREAM);
     1140
     1141    int vrc;
     1142
     1143    SafeArray<BYTE> aOutputData;
     1144    HRESULT hrc = pProcess->Read(uHandle, _64K, RT_MAX(cMsTimeout, 1), ComSafeArrayAsOutParam(aOutputData));
     1145    if (SUCCEEDED(hrc))
     1146    {
     1147        size_t cbOutputData = aOutputData.size();
     1148        if (cbOutputData == 0)
     1149            vrc = VINF_SUCCESS;
     1150        else
     1151        {
     1152            BYTE const *pbBuf = aOutputData.raw();
     1153            AssertPtr(pbBuf);
     1154
     1155            vrc = RTVfsIoStrmWrite(hVfsIosDst, pbBuf, cbOutputData, true /*fBlocking*/,  NULL);
     1156            if (RT_FAILURE(vrc))
     1157                RTMsgError("Unable to write output, rc=%Rrc\n", vrc);
     1158        }
     1159    }
     1160    else
     1161        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
     1162    return vrc;
     1163}
     1164
     1165
     1166/**
     1167 * Configures a host handle for pumping guest bits.
     1168 *
     1169 * @returns true if enabled and we successfully configured it.
     1170 * @param   fEnabled            Whether pumping this pipe is configured.
     1171 * @param   enmHandle           The IPRT standard handle designation.
     1172 * @param   pszName             The name for user messages.
     1173 * @param   enmTransformation   The transformation to apply.
     1174 * @param   phVfsIos            Where to return the resulting I/O stream handle.
     1175 */
     1176static bool ctrlRunSetupHandle(bool fEnabled, RTHANDLESTD enmHandle, const char *pszName,
     1177                               kStreamTransform enmTransformation, PRTVFSIOSTREAM phVfsIos)
     1178{
     1179    if (fEnabled)
     1180    {
     1181        int vrc = RTVfsIoStrmFromStdHandle(enmHandle, 0, true /*fLeaveOpen*/, phVfsIos);
     1182        if (RT_SUCCESS(vrc))
     1183        {
     1184            if (enmTransformation != kStreamTransform_None)
     1185            {
     1186                RTMsgWarning("Unsupported %s line ending conversion", pszName);
     1187                /** @todo Implement dos2unix and unix2dos stream filters. */
     1188            }
     1189            return true;
     1190        }
     1191        RTMsgWarning("Error getting %s handle: %Rrc", pszName, vrc);
     1192    }
     1193    return false;
     1194}
     1195
     1196
     1197/**
     1198 * Returns the remaining time (in ms) based on the start time and a set
     1199 * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified.
     1200 *
     1201 * @return  RTMSINTERVAL    Time left (in ms).
     1202 * @param   u64StartMs      Start time (in ms).
     1203 * @param   cMsTimeout      Timeout value (in ms).
     1204 */
     1205static RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
     1206{
     1207    if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
     1208        return RT_INDEFINITE_WAIT;
     1209
     1210    uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
     1211    if (u64ElapsedMs >= cMsTimeout)
     1212        return 0;
     1213
     1214    return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs;
     1215}
     1216
     1217/**
     1218 * Common handler for the 'run' and 'start' commands.
     1219 *
     1220 * @returns Command exit code.
     1221 * @param   pCtx        Guest session context.
     1222 * @param   fRunCmd     Set if it's 'run' clear if 'start'.
     1223 * @param   fHelp       The help flag for the command.
     1224 */
     1225static RTEXITCODE handleCtrlProcessRunCommon(PGCTLCMDCTX pCtx, bool fRunCmd, uint32_t fHelp)
     1226{
     1227    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
     1228
     1229    /*
     1230     * Parse arguments.
     1231     */
     1232    static const RTGETOPTDEF s_aOptions[] =
     1233    {
     1234        { "--environment",                  'E',                                      RTGETOPT_REQ_STRING  },
     1235        { "--executable",                   'e',                                      RTGETOPT_REQ_STRING  },
     1236        { "--timeout",                      't',                                      RTGETOPT_REQ_UINT32  },
     1237        { "--unquoted-args",                'u',                                      RTGETOPT_REQ_NOTHING },
     1238        { "--ignore-operhaned-processes",   kGstCtrlRunOpt_IgnoreOrphanedProcesses,   RTGETOPT_REQ_NOTHING },
     1239        { "--no-profile",                   kGstCtrlRunOpt_NoProfile,                 RTGETOPT_REQ_NOTHING },
     1240        { "--dos2unix",                     kGstCtrlRunOpt_Dos2Unix,                  RTGETOPT_REQ_NOTHING },
     1241        { "--unix2dos",                     kGstCtrlRunOpt_Unix2Dos,                  RTGETOPT_REQ_NOTHING },
     1242        { "--no-wait-stdout",               kGstCtrlRunOpt_NoWaitForStdOut,           RTGETOPT_REQ_NOTHING },
     1243        { "--wait-stdout",                  kGstCtrlRunOpt_WaitForStdOut,             RTGETOPT_REQ_NOTHING },
     1244        { "--no-wait-stderr",               kGstCtrlRunOpt_NoWaitForStdErr,           RTGETOPT_REQ_NOTHING },
     1245        { "--wait-stderr",                  kGstCtrlRunOpt_WaitForStdErr,             RTGETOPT_REQ_NOTHING },
     1246    };
     1247
     1248    int                     ch;
     1249    RTGETOPTUNION           ValueUnion;
     1250    RTGETOPTSTATE           GetState;
     1251    RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),
     1252                 pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     1253
     1254    com::SafeArray<ProcessCreateFlag_T>     aCreateFlags;
     1255    com::SafeArray<ProcessWaitForFlag_T>    aWaitFlags;
     1256    com::SafeArray<IN_BSTR>                 aArgs;
     1257    com::SafeArray<IN_BSTR>                 aEnv;
     1258    const char *                            pszImage            = NULL;
     1259    bool                                    fDetached           = false;
     1260    bool                                    fWaitForStdOut      = true;
     1261    bool                                    fWaitForStdErr      = true;
     1262    RTVFSIOSTREAM                           hVfsStdOut          = NIL_RTVFSIOSTREAM;
     1263    RTVFSIOSTREAM                           hVfsStdErr          = NIL_RTVFSIOSTREAM;
     1264    enum kStreamTransform                   enmStdOutTransform  = kStreamTransform_None;
     1265    enum kStreamTransform                   enmStdErrTransform  = kStreamTransform_None;
     1266    RTMSINTERVAL                            cMsTimeout          = 0;
     1267
     1268    try
     1269    {
     1270        /* Wait for process start in any case. This is useful for scripting VBoxManage
     1271         * when relying on its overall exit code. */
     1272        aWaitFlags.push_back(ProcessWaitForFlag_Start);
     1273
     1274        while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
     1275        {
     1276            /* For options that require an argument, ValueUnion has received the value. */
     1277            switch (ch)
     1278            {
     1279                case 'E':
     1280                    if (   ValueUnion.psz[0] == '\0'
     1281                        || ValueUnion.psz[0] == '='
     1282                        || strchr(ValueUnion.psz, '=') == NULL)
     1283                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
     1284                                             "Invalid argument variable=value pair: '%s'", ValueUnion.psz);
     1285                    aEnv.push_back(Bstr(ValueUnion.psz).raw());
     1286                    break;
     1287
     1288                case kGstCtrlRunOpt_IgnoreOrphanedProcesses:
     1289                    aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
     1290                    break;
     1291
     1292                case kGstCtrlRunOpt_NoProfile:
     1293                    aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
     1294                    break;
     1295
     1296                case 'i':
     1297                    pszImage = ValueUnion.psz;
     1298                    break;
     1299
     1300                case 'u':
     1301                    aCreateFlags.push_back(ProcessCreateFlag_UnquotedArguments);
     1302                    break;
     1303
     1304                /** @todo Add a hidden flag. */
     1305
     1306                case 't': /* Timeout */
     1307                    cMsTimeout = ValueUnion.u32;
     1308                    break;
     1309
     1310                case kGstCtrlRunOpt_Dos2Unix:
     1311                    enmStdErrTransform = enmStdOutTransform = kStreamTransform_Dos2Unix;
     1312                    break;
     1313                case kGstCtrlRunOpt_Unix2Dos:
     1314                    enmStdErrTransform = enmStdOutTransform = kStreamTransform_Unix2Dos;
     1315                    break;
     1316
     1317                case kGstCtrlRunOpt_WaitForStdOut:
     1318                    if (!fRunCmd)
     1319                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stdout");
     1320                    fWaitForStdOut = true;
     1321                    break;
     1322                case kGstCtrlRunOpt_NoWaitForStdOut:
     1323                    if (!fRunCmd)
     1324                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --no-wait-for-stdout");
     1325                    fWaitForStdOut = false;
     1326                    break;
     1327
     1328                case kGstCtrlRunOpt_WaitForStdErr:
     1329                    if (!fRunCmd)
     1330                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr");
     1331                    fWaitForStdErr = true;
     1332                    break;
     1333                case kGstCtrlRunOpt_NoWaitForStdErr:
     1334                    if (!fRunCmd)
     1335                        return errorSyntaxEx(USAGE_GUESTCONTROL, fHelp, "Invalid option --wait-for-stderr");
     1336                    fWaitForStdErr = false;
     1337                    break;
     1338
     1339                case VINF_GETOPT_NOT_OPTION:
     1340                    aArgs.push_back(Bstr(ValueUnion.psz).raw());
     1341                    if (!pszImage)
     1342                    {
     1343                        Assert(aArgs.size() == 1);
     1344                        pszImage = ValueUnion.psz;
     1345                    }
     1346                    break;
     1347
     1348                default:
     1349                    return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion);
     1350
     1351            } /* switch */
     1352        } /* while RTGetOpt */
     1353
     1354        /* Must have something to execute. */
     1355        if (!pszImage || *pszImage)
     1356            return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, "No executable specified!");
     1357
     1358        /*
     1359         * Finalize process creation and wait flags and input/output streams.
     1360         */
     1361        if (!fRunCmd)
     1362        {
     1363            aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly);
     1364            Assert(!fWaitForStdOut);
     1365            Assert(!fWaitForStdErr);
     1366        }
     1367        else
     1368        {
     1369            aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
     1370            fWaitForStdOut = ctrlRunSetupHandle(fWaitForStdOut, RTHANDLESTD_OUTPUT, "stdout", enmStdOutTransform, &hVfsStdOut);
     1371            if (fWaitForStdOut)
     1372            {
     1373                aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
     1374                aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
     1375            }
     1376            fWaitForStdErr = ctrlRunSetupHandle(fWaitForStdErr, RTHANDLESTD_ERROR, "stderr", enmStdErrTransform, &hVfsStdErr);
     1377            if (fWaitForStdErr)
     1378            {
     1379                aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
     1380                aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
     1381            }
     1382        }
     1383    }
     1384    catch (std::bad_alloc &)
     1385    {
     1386        return RTMsgErrorExit(RTEXITCODE_FAILURE, "VERR_NO_MEMORY\n");
     1387    }
     1388
     1389    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     1390    HRESULT rc;
     1391
     1392    try
     1393    {
     1394        do
     1395        {
     1396            /* Get current time stamp to later calculate rest of timeout left. */
     1397            uint64_t msStart = RTTimeMilliTS();
     1398
     1399            /*
     1400             * Create the process.
     1401             */
     1402            if (pCtx->fVerbose)
     1403            {
     1404                if (cMsTimeout == 0)
     1405                    RTPrintf("Starting guest process ...\n");
     1406                else
     1407                    RTPrintf("Starting guest process (within %ums)\n", cMsTimeout);
     1408            }
     1409            ComPtr<IGuestProcess> pProcess;
     1410            CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(pszImage).raw(),
     1411                                                                 ComSafeArrayAsInParam(aArgs),
     1412                                                                 ComSafeArrayAsInParam(aEnv),
     1413                                                                 ComSafeArrayAsInParam(aCreateFlags),
     1414                                                                 ctrlExecGetRemainingTime(msStart, cMsTimeout),
     1415                                                                 pProcess.asOutParam()));
     1416
     1417            /*
     1418             * Explicitly wait for the guest process to be in a started state.
     1419             */
     1420            com::SafeArray<ProcessWaitForFlag_T> aWaitStartFlags;
     1421            aWaitStartFlags.push_back(ProcessWaitForFlag_Start);
     1422            ProcessWaitResult_T waitResult;
     1423            CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags),
     1424                                                     ctrlExecGetRemainingTime(msStart, cMsTimeout), &waitResult));
     1425
     1426            ULONG uPID = 0;
     1427            CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
     1428            if (fRunCmd && pCtx->fVerbose)
     1429                RTPrintf("Process '%s' (PID %RU32) started\n", pszImage, uPID);
     1430            else if (!fRunCmd) /** @todo Introduce a --quiet option for not printing this. */
     1431            {
     1432                /* Just print plain PID to make it easier for scripts
     1433                 * invoking VBoxManage. */
     1434                RTPrintf("[%RU32 - Session %RU32]\n", uPID, pCtx->uSessionID);
     1435            }
     1436
     1437            /*
     1438             * Wait for process to exit/start...
     1439             */
     1440            RTMSINTERVAL    cMsTimeLeft = 1; /* Will be calculated. */
     1441            bool            fReadStdOut = false;
     1442            bool            fReadStdErr = false;
     1443            bool            fCompleted  = false;
     1444            bool            fCompletedStartCmd = false;
     1445            int             vrc         = VINF_SUCCESS;
     1446
     1447            while (   !fCompleted
     1448                   && cMsTimeLeft > 0)
     1449            {
     1450                cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
     1451                CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
     1452                                                         RT_MIN(500 /*ms*/, RT_MAX(cMsTimeLeft, 1 /*ms*/)),
     1453                                                         &waitResult));
     1454                switch (waitResult)
     1455                {
     1456                    case ProcessWaitResult_Start:
     1457                        fCompletedStartCmd = fCompleted = !fRunCmd; /* Only wait for startup if the 'start' command. */
     1458                        break;
     1459                    case ProcessWaitResult_StdOut:
     1460                        fReadStdOut = true;
     1461                        break;
     1462                    case ProcessWaitResult_StdErr:
     1463                        fReadStdErr = true;
     1464                        break;
     1465                    case ProcessWaitResult_Terminate:
     1466                        if (pCtx->fVerbose)
     1467                            RTPrintf("Process terminated\n");
     1468                        /* Process terminated, we're done. */
     1469                        fCompleted = true;
     1470                        break;
     1471                    case ProcessWaitResult_WaitFlagNotSupported:
     1472                        /* The guest does not support waiting for stdout/err, so
     1473                         * yield to reduce the CPU load due to busy waiting. */
     1474                        RTThreadYield();
     1475                        fReadStdOut = fReadStdErr = true;
     1476                        break;
     1477                    case ProcessWaitResult_Timeout:
     1478                    {
     1479                        /** @todo It is really unclear whether we will get stuck with the timeout
     1480                         *        result here if the guest side times out the process and fails to
     1481                         *        kill the process...  To be on the save side, double the IPC and
     1482                         *        check the process status every time we time out.  */
     1483                        ProcessStatus_T enmProcStatus;
     1484                        CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&enmProcStatus));
     1485                        if (   enmProcStatus == ProcessStatus_TimedOutKilled
     1486                            || enmProcStatus == ProcessStatus_TimedOutAbnormally)
     1487                            fCompleted = true;
     1488                        fReadStdOut = fReadStdErr = true;
     1489                        break;
     1490                    }
     1491                    case ProcessWaitResult_Status:
     1492                        /* ignore. */
     1493                        break;
     1494                    case ProcessWaitResult_Error:
     1495                        /* waitFor is dead in the water, I think, so better leave the loop. */
     1496                        vrc = VERR_CALLBACK_RETURN;
     1497                        break;
     1498
     1499                    case ProcessWaitResult_StdIn:   AssertFailed(); /* did ask for this! */ break;
     1500                    case ProcessWaitResult_None:    AssertFailed(); /* used. */ break;
     1501                    default:                        AssertFailed(); /* huh? */ break;
     1502                }
     1503
     1504                if (g_fGuestCtrlCanceled)
     1505                    break;
     1506
     1507                /*
     1508                 * Pump output as needed.
     1509                 */
     1510                if (fReadStdOut)
     1511                {
     1512                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
     1513                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdOut, 1 /* StdOut */, cMsTimeLeft);
     1514                    if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
     1515                        vrc = vrc2;
     1516                    fReadStdOut = false;
     1517                }
     1518                if (fReadStdErr)
     1519                {
     1520                    cMsTimeLeft = ctrlExecGetRemainingTime(msStart, cMsTimeout);
     1521                    int vrc2 = ctrlRunPumpOutput(pProcess, hVfsStdErr, 2 /* StdErr */, cMsTimeLeft);
     1522                    if (RT_FAILURE(vrc2) && RT_SUCCESS(vrc))
     1523                        vrc = vrc2;
     1524                    fReadStdErr = false;
     1525                }
     1526                if (   RT_FAILURE(vrc)
     1527                    || g_fGuestCtrlCanceled)
     1528                    break;
     1529
     1530                /*
     1531                 * Process events before looping.
     1532                 */
     1533                NativeEventQueue::getMainEventQueue()->processEventQueue(0);
     1534            } /* while */
     1535
     1536            /*
     1537             * Report status back to the user.
     1538             */
     1539            if (g_fGuestCtrlCanceled)
     1540            {
     1541                if (pCtx->fVerbose)
     1542                    RTPrintf("Process execution aborted!\n");
     1543                rcExit = EXITCODEEXEC_CANCELED;
     1544            }
     1545            else if (fCompletedStartCmd)
     1546            {
     1547                if (pCtx->fVerbose)
     1548                    RTPrintf("Process successfully started!\n");
     1549                rcExit = RTEXITCODE_SUCCESS;
     1550            }
     1551            else if (fCompleted)
     1552            {
     1553                ProcessStatus_T procStatus;
     1554                CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus));
     1555                if (   procStatus == ProcessStatus_TerminatedNormally
     1556                    || procStatus == ProcessStatus_TerminatedAbnormally
     1557                    || procStatus == ProcessStatus_TerminatedSignal)
     1558                {
     1559                    LONG lExitCode;
     1560                    CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&lExitCode));
     1561                    if (pCtx->fVerbose)
     1562                        RTPrintf("Exit code=%u (Status=%u [%s])\n",
     1563                                 lExitCode, procStatus, ctrlProcessStatusToText(procStatus));
     1564
     1565                    rcExit = ctrlRunCalculateExitCode(procStatus, lExitCode, true /*fReturnExitCodes*/);
     1566                }
     1567                else if (   procStatus == ProcessStatus_TimedOutKilled
     1568                         || procStatus == ProcessStatus_TimedOutAbnormally)
     1569                {
     1570                    if (pCtx->fVerbose)
     1571                        RTPrintf("Process timed out (guest side) and\n",
     1572                                 procStatus == ProcessStatus_TimedOutAbnormally
     1573                                 ? " failed to terminate so far" : " was terminated");
     1574                    rcExit = EXITCODEEXEC_TIMEOUT;
     1575                }
     1576                else
     1577                {
     1578                    if (pCtx->fVerbose)
     1579                        RTPrintf("Process now is in status [%s] (unexpected)\n", ctrlProcessStatusToText(procStatus));
     1580                    rcExit = RTEXITCODE_FAILURE;
     1581                }
     1582            }
     1583            else if (RT_FAILURE_NP(vrc))
     1584            {
     1585                if (pCtx->fVerbose)
     1586                    RTPrintf("Process monitor loop quit with vrc=%Rrc\n", vrc);
     1587                rcExit = RTEXITCODE_FAILURE;
     1588            }
     1589            else
     1590            {
     1591                if (pCtx->fVerbose)
     1592                    RTPrintf("Process monitor loop timed out\n");
     1593                rcExit = EXITCODEEXEC_TIMEOUT;
     1594            }
     1595
     1596        } while (0);
     1597    }
     1598    catch (std::bad_alloc)
     1599    {
     1600        rc = E_OUTOFMEMORY;
     1601    }
     1602
     1603    /*
     1604     * Decide what to do with the guest session.
     1605     *
     1606     * If it's the 'start' command where detach the guest process after
     1607     * starting, don't close the guest session it is part of, except on
     1608     * failure or ctrl-c.
     1609     *
     1610     * For the 'run' command the guest process quits with us.
     1611     */
     1612    if (!fRunCmd && SUCCEEDED(rc) && !g_fGuestCtrlCanceled)
     1613        pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;
     1614
     1615    /* Make sure we return failure on failure. */
     1616    if (FAILED(rc) && rcExit == RTEXITCODE_SUCCESS)
     1617        rcExit = RTEXITCODE_FAILURE;
     1618    return rcExit;
     1619}
     1620
     1621
     1622static DECLCALLBACK(RTEXITCODE) handleCtrlProcessRun(PGCTLCMDCTX pCtx)
     1623{
     1624    return handleCtrlProcessRunCommon(pCtx, true /*fRunCmd*/, USAGE_GSTCTRL_RUN);
     1625}
     1626
     1627
     1628static DECLCALLBACK(RTEXITCODE) handleCtrlProcessStart(PGCTLCMDCTX pCtx)
     1629{
     1630    return handleCtrlProcessRunCommon(pCtx, false /*fRunCmd*/, USAGE_GSTCTRL_START);
     1631}
     1632
     1633#if 1 /* Old exec code. */
     1634
     1635static int ctrlExecProcessStatusToExitCodeDeprecated(ProcessStatus_T enmStatus, ULONG uExitCode)
     1636{
     1637    int vrc = RTEXITCODE_SUCCESS;
     1638    switch (enmStatus)
     1639    {
     1640        case ProcessStatus_Starting:
     1641            vrc = RTEXITCODE_SUCCESS;
    5461642            break;
    5471643        case ProcessStatus_Started:
    548             vrc = EXITCODEEXEC_SUCCESS;
     1644            vrc = RTEXITCODE_SUCCESS;
    5491645            break;
    5501646        case ProcessStatus_Paused:
    551             vrc = EXITCODEEXEC_SUCCESS;
     1647            vrc = RTEXITCODE_SUCCESS;
    5521648            break;
    5531649        case ProcessStatus_Terminating:
    554             vrc = EXITCODEEXEC_SUCCESS;
     1650            vrc = RTEXITCODE_SUCCESS;
    5551651            break;
    5561652        case ProcessStatus_TerminatedNormally:
    557             vrc = !uExitCode ? EXITCODEEXEC_SUCCESS : EXITCODEEXEC_CODE;
     1653            vrc = !uExitCode ? RTEXITCODE_SUCCESS : EXITCODEEXEC_CODE;
    5581654            break;
    5591655        case ProcessStatus_TerminatedSignal:
     
    5841680}
    5851681
    586 const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
    587 {
    588     switch (enmWaitResult)
    589     {
    590         case ProcessWaitResult_Start:
    591             return "started";
    592         case ProcessWaitResult_Terminate:
    593             return "terminated";
    594         case ProcessWaitResult_Status:
    595             return "status changed";
    596         case ProcessWaitResult_Error:
    597             return "error";
    598         case ProcessWaitResult_Timeout:
    599             return "timed out";
    600         case ProcessWaitResult_StdIn:
    601             return "stdin ready";
    602         case ProcessWaitResult_StdOut:
    603             return "data on stdout";
    604         case ProcessWaitResult_StdErr:
    605             return "data on stderr";
    606         case ProcessWaitResult_WaitFlagNotSupported:
    607             return "waiting flag not supported";
    608         default:
    609             break;
    610     }
    611     return "unknown";
    612 }
    613 
    614 /**
    615  * Translates a guest session status to a human readable
    616  * string.
    617  */
    618 const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
    619 {
    620     switch (enmStatus)
    621     {
    622         case GuestSessionStatus_Starting:
    623             return "starting";
    624         case GuestSessionStatus_Started:
    625             return "started";
    626         case GuestSessionStatus_Terminating:
    627             return "terminating";
    628         case GuestSessionStatus_Terminated:
    629             return "terminated";
    630         case GuestSessionStatus_TimedOutKilled:
    631             return "timed out";
    632         case GuestSessionStatus_TimedOutAbnormally:
    633             return "timed out, hanging";
    634         case GuestSessionStatus_Down:
    635             return "killed";
    636         case GuestSessionStatus_Error:
    637             return "error";
    638         default:
    639             break;
    640     }
    641     return "unknown";
    642 }
    643 
    644 /**
    645  * Translates a guest file status to a human readable
    646  * string.
    647  */
    648 const char *ctrlFileStatusToText(FileStatus_T enmStatus)
    649 {
    650     switch (enmStatus)
    651     {
    652         case FileStatus_Opening:
    653             return "opening";
    654         case FileStatus_Open:
    655             return "open";
    656         case FileStatus_Closing:
    657             return "closing";
    658         case FileStatus_Closed:
    659             return "closed";
    660         case FileStatus_Down:
    661             return "killed";
    662         case FileStatus_Error:
    663             return "error";
    664         default:
    665             break;
    666     }
    667     return "unknown";
    668 }
    669 
    670 static int ctrlPrintError(com::ErrorInfo &errorInfo)
    671 {
    672     if (   errorInfo.isFullAvailable()
    673         || errorInfo.isBasicAvailable())
    674     {
    675         /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
    676          * because it contains more accurate info about what went wrong. */
    677         if (errorInfo.getResultCode() == VBOX_E_IPRT_ERROR)
    678             RTMsgError("%ls.", errorInfo.getText().raw());
    679         else
    680         {
    681             RTMsgError("Error details:");
    682             GluePrintErrorInfo(errorInfo);
    683         }
    684         return VERR_GENERAL_FAILURE; /** @todo */
    685     }
    686     AssertMsgFailedReturn(("Object has indicated no error (%Rhrc)!?\n", errorInfo.getResultCode()),
    687                           VERR_INVALID_PARAMETER);
    688 }
    689 
    690 static int ctrlPrintError(IUnknown *pObj, const GUID &aIID)
    691 {
    692     com::ErrorInfo ErrInfo(pObj, aIID);
    693     return ctrlPrintError(ErrInfo);
    694 }
    695 
    696 static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
    697 {
    698     int vrc = VINF_SUCCESS;
    699     HRESULT rc;
    700 
    701     do
    702     {
    703         BOOL fCanceled;
    704         CHECK_ERROR_BREAK(pProgress, COMGETTER(Canceled)(&fCanceled));
    705         if (!fCanceled)
    706         {
    707             LONG rcProc;
    708             CHECK_ERROR_BREAK(pProgress, COMGETTER(ResultCode)(&rcProc));
    709             if (FAILED(rcProc))
    710             {
    711                 com::ProgressErrorInfo ErrInfo(pProgress);
    712                 vrc = ctrlPrintError(ErrInfo);
    713             }
    714         }
    715 
    716     } while(0);
    717 
    718     AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
    719 
    720     return vrc;
    721 }
    722 
    723 /**
    724  * Un-initializes the VM after guest control usage.
    725  * @param   pCmdCtx                 Pointer to command context.
    726  * @param   uFlags                  Command context flags.
    727  */
    728 static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
    729 {
    730     AssertPtrReturnVoid(pCtx);
    731 
    732     if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
    733         ctrlSignalHandlerUninstall();
    734 
    735     HRESULT rc;
    736 
    737     do
    738     {
    739         if (!pCtx->pGuestSession.isNull())
    740         {
    741             if (   !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
    742                 && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
    743             {
    744                 if (pCtx->fVerbose)
    745                     RTPrintf("Closing guest session ...\n");
    746 
    747                 CHECK_ERROR(pCtx->pGuestSession, Close());
    748                 /* Keep going - don't break here. Try to unlock the
    749                  * machine down below. */
    750             }
    751             else if (   (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
    752                      && pCtx->fVerbose)
    753                 RTPrintf("Guest session detached\n");
    754 
    755             pCtx->pGuestSession.setNull();
    756         }
    757 
    758         if (pCtx->handlerArg.session)
    759             CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
    760 
    761     } while (0);
    762 
    763     for (int i = 0; i < pCtx->iArgc; i++)
    764         RTStrFree(pCtx->ppaArgv[i]);
    765     RTMemFree(pCtx->ppaArgv);
    766     pCtx->iArgc = 0;
    767 }
    768 
    769 /**
    770  * Initializes the VM for IGuest operations.
    771  *
    772  * That is, checks whether it's up and running, if it can be locked (shared
    773  * only) and returns a valid IGuest pointer on success. Also, it does some
    774  * basic command line processing and opens a guest session, if required.
    775  *
    776  * @return  RTEXITCODE status code.
    777  * @param   pArg                    Pointer to command line argument structure.
    778  * @param   pCmdCtx                 Pointer to command context.
    779  * @param   uFlags                  Command context flags.
    780  */
    781 static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
    782                              PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
    783 {
    784     AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
    785     AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
    786     AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
    787 
    788 #ifdef DEBUG_andy
    789     RTPrintf("Original argv:\n");
    790     for (int i=0; i<pArg->argc;i++)
    791         RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
    792 #endif
    793 
    794     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    795 
    796     const char *pszNameOrId = pArg->argv[0];
    797     const char *pszCmd = pArg->argv[1];
    798 
    799     /* Lookup VM. */
    800     ComPtr<IMachine> machine;
    801     /* Assume it's an UUID. */
    802     HRESULT rc;
    803     CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
    804                                               machine.asOutParam()));
    805     if (SUCCEEDED(rc))
    806     {
    807         /* Machine is running? */
    808         MachineState_T machineState;
    809         CHECK_ERROR(machine, COMGETTER(State)(&machineState));
    810         if (   SUCCEEDED(rc)
    811             && (machineState != MachineState_Running))
    812             rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
    813                                     pszNameOrId, machineStateToName(machineState, false));
    814     }
    815     else
    816         rcExit = RTEXITCODE_FAILURE;
    817 
    818     if (rcExit == RTEXITCODE_SUCCESS)
    819     {
    820         /*
    821          * Process standard options which are served by all commands.
    822          */
    823         static const RTGETOPTDEF s_aOptions[] =
    824         {
    825             { "--username",            'u',                             RTGETOPT_REQ_STRING  },
    826             { "--passwordfile",        'p',                             RTGETOPT_REQ_STRING  },
    827             { "--password",            GETOPTDEF_COMMON_PASSWORD,       RTGETOPT_REQ_STRING  },
    828             { "--domain",              'd',                             RTGETOPT_REQ_STRING  },
    829             { "--verbose",             'v',                             RTGETOPT_REQ_NOTHING }
    830         };
    831 
    832         /*
    833          * Allocate per-command argv. This then only contains the specific arguments
    834          * the command needs.
    835          */
    836         pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
    837         if (!pCtx->ppaArgv)
    838         {
    839             rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
    840         }
    841         else
    842         {
    843             pCtx->iArgc = 0;
    844 
    845             int iArgIdx = 2; /* Skip VM name and guest control command */
    846             int ch;
    847             RTGETOPTUNION ValueUnion;
    848             RTGETOPTSTATE GetState;
    849             RTGetOptInit(&GetState, pArg->argc, pArg->argv,
    850                          s_aOptions, RT_ELEMENTS(s_aOptions),
    851                          iArgIdx, 0);
    852 
    853             while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    854                    && (rcExit == RTEXITCODE_SUCCESS))
    855             {
    856                 /* For options that require an argument, ValueUnion has received the value. */
    857                 switch (ch)
    858                 {
    859                     case 'u': /* User name */
    860                         if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    861                             pCtx->strUsername = ValueUnion.psz;
    862                         iArgIdx = GetState.iNext;
    863                         break;
    864 
    865                     case GETOPTDEF_COMMON_PASSWORD: /* Password */
    866                         if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    867                         {
    868                             if (pCtx->strPassword.isEmpty())
    869                                 pCtx->strPassword = ValueUnion.psz;
    870                         }
    871                         iArgIdx = GetState.iNext;
    872                         break;
    873 
    874                     case 'p': /* Password file */
    875                     {
    876                         if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    877                             rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
    878                         iArgIdx = GetState.iNext;
    879                         break;
    880                     }
    881 
    882                     case 'd': /* domain */
    883                         if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    884                             pCtx->strDomain = ValueUnion.psz;
    885                         iArgIdx = GetState.iNext;
    886                         break;
    887 
    888                     case 'v': /* Verbose */
    889                         pCtx->fVerbose = true;
    890                         iArgIdx = GetState.iNext;
    891                         break;
    892 
    893                     case 'h': /* Help */
    894                         errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
    895                         return RTEXITCODE_SYNTAX;
    896 
    897                     default:
    898                         /* Simply skip; might be handled in a specific command
    899                          * handler later. */
    900                         break;
    901 
    902                 } /* switch */
    903 
    904                 int iArgDiff = GetState.iNext - iArgIdx;
    905                 if (iArgDiff)
    906                 {
    907 #ifdef DEBUG_andy
    908                     RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
    909 #endif
    910                     for (int i = iArgIdx; i < GetState.iNext; i++)
    911                     {
    912                         char *pszArg = RTStrDup(pArg->argv[i]);
    913                         if (!pszArg)
    914                         {
    915                             rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
    916                                                     "Not enough memory for command line handling\n");
    917                             break;
    918                         }
    919                         pCtx->ppaArgv[pCtx->iArgc] = pszArg;
    920                         pCtx->iArgc++;
    921 #ifdef DEBUG_andy
    922                         RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
    923 #endif
    924                     }
    925 
    926                     iArgIdx = GetState.iNext;
    927                 }
    928 
    929             } /* while RTGetOpt */
    930         }
    931     }
    932 
    933     /*
    934      * Check for mandatory stuff.
    935      */
    936     if (rcExit == RTEXITCODE_SUCCESS)
    937     {
    938 #if 0
    939         RTPrintf("argc=%d\n", pCtx->iArgc);
    940         for (int i = 0; i < pCtx->iArgc; i++)
    941             RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
    942 #endif
    943         if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    944         {
    945             if (pCtx->strUsername.isEmpty())
    946                 rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
    947         }
    948     }
    949 
    950     if (rcExit == RTEXITCODE_SUCCESS)
    951     {
    952         /*
    953          * Build up a reasonable guest session name. Useful for identifying
    954          * a specific session when listing / searching for them.
    955          */
    956         char *pszSessionName;
    957         if (0 >= RTStrAPrintf(&pszSessionName,
    958                               "[%RU32] VBoxManage Guest Control [%s] - %s",
    959                               RTProcSelf(), pszNameOrId, pszCmd))
    960             return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
    961 
    962         do
    963         {
    964             /* Open a session for the VM. */
    965             CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
    966             /* Get the associated console. */
    967             ComPtr<IConsole> console;
    968             CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
    969             /* ... and session machine. */
    970             ComPtr<IMachine> sessionMachine;
    971             CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
    972             /* Get IGuest interface. */
    973             CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
    974             if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
    975             {
    976                 if (pCtx->fVerbose)
    977                     RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
    978 
    979                 /* Open a guest session. */
    980                 Assert(!pCtx->pGuest.isNull());
    981                 CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
    982                                                               Bstr(pCtx->strPassword).raw(),
    983                                                               Bstr(pCtx->strDomain).raw(),
    984                                                               Bstr(pszSessionName).raw(),
    985                                                               pCtx->pGuestSession.asOutParam()));
    986 
    987                 /*
    988                  * Wait for guest session to start.
    989                  */
    990                 if (pCtx->fVerbose)
    991                     RTPrintf("Waiting for guest session to start ...\n");
    992 
    993                 com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
    994                 aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
    995                 GuestSessionWaitResult_T sessionWaitResult;
    996                 CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
    997                                                                     /** @todo Make session handling timeouts configurable. */
    998                                                                     30 * 1000, &sessionWaitResult));
    999 
    1000                 if (   sessionWaitResult == GuestSessionWaitResult_Start
    1001                     /* Note: This might happen when Guest Additions < 4.3 are installed which don't
    1002                      *       support dedicated guest sessions. */
    1003                     || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
    1004                 {
    1005                     CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
    1006                     if (pCtx->fVerbose)
    1007                         RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
    1008                 }
    1009                 else
    1010                 {
    1011                     GuestSessionStatus_T sessionStatus;
    1012                     CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
    1013                     rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
    1014                                             ctrlSessionStatusToText(sessionStatus));
    1015                     break;
    1016                 }
    1017             }
    1018 
    1019             if (   SUCCEEDED(rc)
    1020                 && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
    1021             {
    1022                 ctrlSignalHandlerInstall();
    1023             }
    1024 
    1025         } while (0);
    1026 
    1027         if (FAILED(rc))
    1028             rcExit = RTEXITCODE_FAILURE;
    1029 
    1030         RTStrFree(pszSessionName);
    1031     }
    1032 
    1033     if (rcExit == RTEXITCODE_SUCCESS)
    1034     {
    1035         pCtx->handlerArg = *pArg;
    1036         pCtx->uFlags = uFlags;
    1037     }
    1038     else /* Clean up on failure. */
    1039         ctrlUninitVM(pCtx, uFlags);
    1040 
    1041     return rcExit;
    1042 }
    10431682
    10441683/**
     
    10491688 * @param   pStrmOutput     Where to write the data.
    10501689 * @param   uHandle         Handle where to read the data from.
    1051  * @param   uTimeoutMS      Timeout (in ms) to wait for the operation to complete.
     1690 * @param   cMsTimeout      Timeout (in ms) to wait for the operation to
     1691 *                          complete.
     1692 * @remarks Obsolete.
    10521693 */
    1053 static int ctrlExecPrintOutput(IProcess *pProcess, PRTSTREAM pStrmOutput,
    1054                                ULONG uHandle, ULONG uTimeoutMS)
     1694static int ctrlExecPrintOutputDeprecated(IProcess *pProcess, PRTSTREAM pStrmOutput,
     1695                                         ULONG uHandle, RTMSINTERVAL cMsTimeout)
    10551696{
    10561697    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     
    10601701
    10611702    SafeArray<BYTE> aOutputData;
    1062     HRESULT rc = pProcess->Read(uHandle, _64K, uTimeoutMS,
     1703    HRESULT rc = pProcess->Read(uHandle, _64K, cMsTimeout,
    10631704                                ComSafeArrayAsOutParam(aOutputData));
    1064     if (FAILED(rc))
    1065         vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    1066     else
     1705    if (SUCCEEDED(rc))
    10671706    {
    10681707        size_t cbOutputData = aOutputData.size();
     
    10721711            AssertPtr(pBuf);
    10731712            pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */
    1074 
    1075             /** @todo implement the dos2unix/unix2dos conversions */
    10761713
    10771714            /*
     
    10881725                cbOutputData = strlen(pszBufUTF8);
    10891726
    1090                 ULONG cbOutputDataPrint = cbOutputData;
     1727                ULONG cbOutputDataPrint = (ULONG)cbOutputData;
    10911728                for (char *s = pszBufUTF8, *d = s;
    10921729                     s - pszBufUTF8 < (ssize_t)cbOutputData;
     
    11131750        }
    11141751    }
    1115 
     1752    else
     1753        vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
    11161754    return vrc;
    11171755}
    11181756
    1119 /**
    1120  * Returns the remaining time (in ms) based on the start time and a set
    1121  * timeout value. Returns RT_INDEFINITE_WAIT if no timeout was specified.
    1122  *
    1123  * @return  RTMSINTERVAL    Time left (in ms).
    1124  * @param   u64StartMs      Start time (in ms).
    1125  * @param   cMsTimeout      Timeout value (in ms).
    1126  */
    1127 inline RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL cMsTimeout)
    1128 {
    1129     if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
    1130         return RT_INDEFINITE_WAIT;
    1131 
    1132     uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
    1133     if (u64ElapsedMs >= cMsTimeout)
    1134         return 0;
    1135 
    1136     return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs;
    1137 }
    1138 
    1139 static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExec(PGCTLCMDCTX pCtx)
     1757
     1758static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExecDeprecated(PGCTLCMDCTX pCtx)
    11401759{
    11411760    AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
     
    11751794    com::SafeArray<ProcessCreateFlag_T>  aCreateFlags;
    11761795    com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
    1177     com::SafeArray<IN_BSTR>              aArgs;
     1796    com::SafeArray<IN_BSTR>              aArgsWithout0;
     1797    com::SafeArray<IN_BSTR>              aArgsWith0;
    11781798    com::SafeArray<IN_BSTR>              aEnv;
    11791799    RTMSINTERVAL                         cMsTimeout      = 0;
    1180     OUTPUTTYPE                           eOutputType     = OUTPUTTYPE_UNDEFINED;
    11811800    bool                                 fDetached       = true;
    11821801    int                                  vrc             = VINF_SUCCESS;
     
    11941813            switch (ch)
    11951814            {
    1196                 case GETOPTDEF_EXEC_DOS2UNIX:
    1197                     if (eOutputType != OUTPUTTYPE_UNDEFINED)
    1198                         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
    1199                                              "More than one output type (dos2unix/unix2dos) specified!");
    1200                     eOutputType = OUTPUTTYPE_DOS2UNIX;
    1201                     break;
    1202 
    12031815                case 'e': /* Environment */
    12041816                {
     
    12081820                    vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
    12091821                    if (RT_FAILURE(vrc))
    1210                         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
     1822                        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
    12111823                                             "Failed to parse environment value, rc=%Rrc", vrc);
    12121824                    for (int j = 0; j < cArgs; j++)
     
    12401852
    12411853                case GETOPTDEF_EXEC_UNIX2DOS:
    1242                     if (eOutputType != OUTPUTTYPE_UNDEFINED)
    1243                         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
    1244                                              "More than one output type (dos2unix/unix2dos) specified!");
    1245                     eOutputType = OUTPUTTYPE_UNIX2DOS;
    1246                     break;
     1854                case GETOPTDEF_EXEC_DOS2UNIX:
     1855                    return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
     1856                                         "Output conversion not implemented yet!");
    12471857
    12481858                case GETOPTDEF_EXEC_WAITFOREXIT:
     
    12641874
    12651875                case VINF_GETOPT_NOT_OPTION:
    1266                     if (aArgs.size() == 0 && strCmd.isEmpty())
     1876                    if (aArgsWithout0.size() == 0 && strCmd.isEmpty())
    12671877                        strCmd = ValueUnion.psz;
    12681878                    else
    1269                         aArgs.push_back(Bstr(ValueUnion.psz).raw());
     1879                        aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw());
    12701880                    break;
    12711881
     
    12741884                     *       contain a single dash, e.g. "-- foo.exe -s". */
    12751885                    if (GetState.argc == GetState.iNext)
    1276                         aArgs.push_back(Bstr(ValueUnion.psz).raw());
     1886                        aArgsWithout0.push_back(Bstr(ValueUnion.psz).raw());
    12771887                    else
    1278                         return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC, ch, &ValueUnion);
     1888                        return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN, ch, &ValueUnion);
    12791889                    break;
    12801890
    12811891            } /* switch */
    12821892        } /* while RTGetOpt */
     1893
     1894        /* Create aArgsWith0 from strCmd and aArgsWithout0. */
     1895        aArgsWith0.push_back(Bstr(strCmd).raw());
     1896        for (size_t i = 0; i < aArgsWithout0.size(); i++)
     1897            aArgsWith0.push_back(aArgsWithout0[i]);
    12831898    }
    12841899    catch (std::bad_alloc &)
     
    12911906
    12921907    if (strCmd.isEmpty())
    1293         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
     1908        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RUN,
    12941909                             "No command to execute specified!");
    1295 
    1296     /** @todo Any output conversion not supported yet! */
    1297     if (eOutputType != OUTPUTTYPE_UNDEFINED)
    1298         return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
    1299                              "Output conversion not implemented yet!");
    13001910
    13011911    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     
    13261936            ComPtr<IGuestProcess> pProcess;
    13271937            CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(strCmd).raw(),
    1328                                                                  ComSafeArrayAsInParam(aArgs),
     1938                                                                 ComSafeArrayAsInParam(aArgsWith0),
    13291939                                                                 ComSafeArrayAsInParam(aEnv),
    13301940                                                                 ComSafeArrayAsInParam(aCreateFlags),
     
    14212031                {
    14222032                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
    1423                     vrc = ctrlExecPrintOutput(pProcess, g_pStdOut,
    1424                                               1 /* StdOut */, cMsTimeLeft);
     2033                    vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdOut,
     2034                                                        1 /* StdOut */, cMsTimeLeft);
    14252035                    fReadStdOut = false;
    14262036                }
     
    14292039                {
    14302040                    cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
    1431                     vrc = ctrlExecPrintOutput(pProcess, g_pStdErr,
    1432                                               2 /* StdErr */, cMsTimeLeft);
     2041                    vrc = ctrlExecPrintOutputDeprecated(pProcess, g_pStdErr,
     2042                                                        2 /* StdErr */, cMsTimeLeft);
    14332043                    fReadStdErr = false;
    14342044                }
     
    14672077                                         exitCode, procStatus, ctrlProcessStatusToText(procStatus));
    14682078
    1469                             rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode);
     2079                            rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCodeDeprecated(procStatus, exitCode);
    14702080                        }
    14712081                        else if (pCtx->fVerbose)
     
    15262136    return rcExit;
    15272137}
     2138
     2139#endif /* Old exec code. */
    15282140
    15292141/**
     
    27183330    }
    27193331
    2720     uint32_t cDirs = mapDirs.size();
     3332    size_t cDirs = mapDirs.size();
    27213333    if (!cDirs)
    27223334        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR,
     
    27813393    }
    27823394
    2783     uint32_t cDirs = mapDirs.size();
     3395    size_t cDirs = mapDirs.size();
    27843396    if (!cDirs)
    27853397        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR,
     
    28643476    }
    28653477
    2866     uint32_t cFiles = mapDirs.size();
     3478    size_t cFiles = mapDirs.size();
    28673479    if (!cFiles)
    28683480        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE,
     
    29423554        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc);
    29433555
    2944     uint32_t cSources = vecSources.size();
     3556    size_t cSources = vecSources.size();
    29453557    if (!cSources)
    29463558        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
     
    31793791    }
    31803792
    3181     uint32_t cObjs = mapObjs.size();
     3793    size_t cObjs = mapObjs.size();
    31823794    if (!cObjs)
    31833795        return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT,
     
    39484560        || !RTStrICmp(pArg->argv[1], "execute"))
    39494561    {
    3950         gctlCmd.pfnHandler = handleCtrlProcessExec;
     4562        gctlCmd.pfnHandler = handleCtrlProcessExecDeprecated;
    39514563        uUsage = USAGE_GSTCTRL_EXEC;
     4564    }
     4565    else if (!strcmp(pArg->argv[1], "run"))
     4566    {
     4567        gctlCmd.pfnHandler = handleCtrlProcessRun;
     4568        uUsage = USAGE_GSTCTRL_RUN;
     4569    }
     4570    else if (!strcmp(pArg->argv[1], "start"))
     4571    {
     4572        gctlCmd.pfnHandler = handleCtrlProcessStart;
     4573        uUsage = USAGE_GSTCTRL_START;
    39524574    }
    39534575    else if (!RTStrICmp(pArg->argv[1], "copyfrom"))
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r55531 r55535  
    1007910079      To wait for a guest process to terminate after it has been
    1008010080      created by <link to="IGuestSession::processCreate"/> or <link to="IGuestSession::processCreateEx"/>
    10081       one would specify ProcessWaitResult_Terminate.
     10081      one would specify ProcessWaitFor_Terminate.
    1008210082
    1008310083      If a guest process has been started with ProcessCreateFlag_WaitForStdOut
     
    1010710107    <const name="Timeout"               value="5">
    1010810108      <desc>
    10109         The waiting operation timed out. This also will happen
    10110         when no event has been occurred matching the
    10111         current waiting flags in a <link to="IProcess::waitFor"/> call.
     10109        The waiting operation timed out. Also use if the guest process has
     10110        timed out on the guest side (kill attempted).
    1011210111      </desc>
    1011310112    </const>
    1011410113    <const name="StdIn"                 value="6">
    10115       <desc>
    10116         The process signalled that stdin became available for writing
    10117         and that the process awaits input now.</desc>
     10114      <desc>The process signalled that stdin became available for writing.</desc>
    1011810115    </const>
    1011910116    <const name="StdOut"                value="7">
     
    1021310210  <enum
    1021410211    name="ProcessCreateFlag"
    10215     uuid="35192799-bfde-405d-9bea-c735ab9998e4"
     10212    uuid="be8c8dbd-4a76-e9ac-20df-468e86edf383"
    1021610213    >
    1021710214    <desc>
     
    1078610783  <interface
    1078710784    name="IGuestSession" extends="$unknown"
    10788     uuid="5b28703c-07b6-4fcb-afba-ac199b309752"
     10785    uuid="c899776d-41f7-7aee-7056-4bac979d58b7"
    1078910786    wsmap="managed"
    1079010787    >
     
    1143111428          appropriate error message.
    1143211429
    11433           If ProcessCreateFlag_WaitForStdOut and / or respectively ProcessCreateFlag_WaitForStdErr
    11434           is / are set, the guest process will not exit until all data from the specified
    11435           stream(s) is / are read out.
     11430          If ProcessCreateFlag_WaitForStdOut and/or ProcessCreateFlag_WaitForStdErr
     11431          are set, the guest process will not exit until all data from the specified
     11432          streams are read out.
    1143611433        </note>
    1143711434
     
    1144011437        </result>
    1144111438      </desc>
    11442       <param name="command" type="wstring" dir="in">
    11443         <desc>
    11444           Full path name of the command to execute on the guest; the
    11445           commands has to exists in the guest VM in order to be executed.
     11439      <param name="executable" type="wstring" dir="in">
     11440        <desc>
     11441          Full path name of the file to execute on the guest.  The file has to
     11442          exists in the guest VM with executable right to the session user in
     11443          order to be executed. If empty/null, the first entry in the
     11444          @a arguments array will be used in stead (i.e. argv[0]).
    1144611445        </desc>
    1144711446      </param>
    1144811447      <param name="arguments" type="wstring" dir="in" safearray="yes">
    11449         <desc>Array of arguments passed to the execution command.</desc>
     11448        <desc>Array of arguments passed to the new process.
     11449          <note>
     11450            Starting with VirtualBox 5.0 this array starts with argument 0
     11451            instead of argument 1 as in previous versions.  Whether the zeroth
     11452            argument can be passed to the guest depends on the VBoxService
     11453            version running there.
     11454          </note>
     11455        </desc>
    1145011456      </param>
    1145111457      <param name="environment" type="wstring" dir="in" safearray="yes">
    1145211458        <desc>
    11453           Environment variables that can be set while the command is being
    11454           executed, in form of "NAME=VALUE"; one pair per entry. To unset a
    11455           variable just set its name ("NAME") without a value.
    11456 
    11457           This parameter can be used to override environment variables set by
    11458           the guest session, which will be applied to the newly started process
    11459           in any case.
     11459          Environment variables to set or unset for the guest process,
     11460          relative to the environment of the guest session.
     11461
     11462          The variables are in the traditional "NAME=VALUE" form with one pair
     11463          per array entry.  To unset a variable just leave out the equal sign
     11464          and the value ("NAME").
    1146011465        </desc>
    1146111466      </param>
     
    1148611491        See <link to="IGuestSession::processCreate"/> for more information.
    1148711492      </desc>
    11488       <param name="command" type="wstring" dir="in">
    11489         <desc>
    11490           Full path name of the command to execute on the guest; the
    11491           commands has to exists in the guest VM in order to be executed.
     11493      <param name="executable" type="wstring" dir="in">
     11494        <desc>
     11495          Full path name of the file to execute on the guest.  The file has to
     11496          exists in the guest VM with executable right to the session user in
     11497          order to be executed.  If empty/null, the first entry in the
     11498          @a arguments array will be used in stead (i.e. argv[0]).
    1149211499        </desc>
    1149311500      </param>
    1149411501      <param name="arguments" type="wstring" dir="in" safearray="yes">
    11495         <desc>Array of arguments passed to the execution command.</desc>
     11502        <desc>Array of arguments passed to the new process.
     11503          <note>
     11504            Starting with VirtualBox 5.0 this array starts with argument 0
     11505            instead of argument 1 as in previous versions.  Whether the zeroth
     11506            argument can be passed to the guest depends on the VBoxService
     11507            version running there.
     11508          </note>
     11509        </desc>
    1149611510      </param>
    1149711511      <param name="environment" type="wstring" dir="in" safearray="yes">
    1149811512        <desc>
    11499           Environment variables that can be set while the command is being
    11500           executed, in form of "NAME=VALUE"; one pair per entry. To unset a
    11501           variable just set its name ("NAME") without a value.
    11502 
    11503           This parameter can be used to override environment variables set by
    11504           the guest session, which will be applied to the newly started process
    11505           in any case.
     11513          Environment variables to set or unset for the guest process,
     11514          relative to the environment of the guest session.
     11515
     11516          The variables are in the traditional "NAME=VALUE" form with one pair
     11517          per array entry.  To unset a variable just leave out the equal sign
     11518          and the value ("NAME").
    1150611519        </desc>
    1150711520      </param>
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r55401 r55535  
    221221    /** The process' friendly name. */
    222222    Utf8Str                     mName;
    223     /** The actual command to execute. */
    224     Utf8Str                     mCommand;
     223    /** The executable. */
     224    Utf8Str                     mExecutable;
     225    /** Arguments vector (starting with argument \#0). */
    225226    ProcessArguments            mArguments;
    226227    GuestEnvironment            mEnvironment;
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r51321 r55535  
    204204              mProcInfo(startupInfo)
    205205        {
    206             mProcInfo.mCommand = strDest;
     206            mProcInfo.mExecutable = strDest;
    207207            if (mProcInfo.mName.isEmpty())
    208208                mProcInfo.mName = strDest;
     
    432432                                                 int *pGuestRc);
    433433    int                     i_processRemoveFromList(GuestProcess *pProcess);
    434     int                     i_processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
     434    int                     i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProgress);
    435435    inline bool             i_processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess);
    436436    inline int              i_processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess);
  • trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp

    r53127 r55535  
    9191        GuestProcessStartupInfo procInfo;
    9292        procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\""), openInfo.mPath.c_str());
    93         procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
     93        procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS);
    9494        procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
    9595        procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r55491 r55535  
    266266
    267267#ifdef VBOX_WITH_GUEST_CONTROL
    268     LogFlowThisFunc(("mCmd=%s, PID=%RU32\n",
    269                      mData.mProcess.mCommand.c_str(), mData.mPID));
     268    LogFlowThisFunc(("mExe=%s, PID=%RU32\n", mData.mProcess.mExecutable.c_str(), mData.mPID));
    270269
    271270    /* Terminate process if not already done yet. */
     
    334333    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    335334
    336     aExecutablePath = mData.mProcess.mCommand;
     335    aExecutablePath = mData.mProcess.mExecutable;
    337336
    338337    return S_OK;
     
    987986int GuestProcess::i_startProcess(uint32_t uTimeoutMS, int *pGuestRc)
    988987{
    989     LogFlowThisFunc(("uTimeoutMS=%RU32, procCmd=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
    990                      uTimeoutMS, mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
     988    LogFlowThisFunc(("uTimeoutMS=%RU32, procExe=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
     989                     uTimeoutMS, mData.mProcess.mExecutable.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
    991990                     mSession->i_getId()));
    992991
     
    10171016    GuestSession *pSession = mSession;
    10181017    AssertPtr(pSession);
     1018    uint32_t const uProtocol = pSession->i_getProtocolVersion();
    10191019
    10201020    const GuestCredentials &sessionCreds = pSession->i_getCredentials();
     1021
    10211022
    10221023    /* Prepare arguments. */
     
    10291030        && cArgs)
    10301031    {
    1031         char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
     1032        char const **papszArgv = (char const **)RTMemAlloc((cArgs + 1) * sizeof(papszArgv[0]));
    10321033        AssertReturn(papszArgv, VERR_NO_MEMORY);
    10331034
    1034         for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
    1035         {
    1036             const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
    1037             AssertPtr(pszCurArg);
    1038             vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
     1035        for (size_t i = 0; i < cArgs; i++)
     1036        {
     1037            papszArgv[i] = mData.mProcess.mArguments[i].c_str();
     1038            AssertPtr(papszArgv[i]);
    10391039        }
    10401040        papszArgv[cArgs] = NULL;
    10411041
    1042         if (RT_SUCCESS(vrc))
     1042        if (uProtocol < UINT32_C(0xdeadbeef) ) /** @todo implement a way of sending argv[0], best idea is a new command. */
     1043            vrc = RTGetOptArgvToString(&pszArgs, papszArgv + 1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
     1044        else
    10431045            vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
    10441046
    1045         if (papszArgv)
    1046         {
    1047             size_t i = 0;
    1048             while (papszArgv[i])
    1049                 RTStrFree(papszArgv[i++]);
    1050             RTMemFree(papszArgv);
    1051         }
     1047        RTMemFree(papszArgv);
    10521048    }
    10531049
     
    10651061    if (RT_SUCCESS(vrc))
    10661062    {
    1067         AssertPtr(mSession);
    1068         uint32_t uProtocol = mSession->i_getProtocolVersion();
    1069 
    10701063        /* Prepare HGCM call. */
    10711064        VBOXHGCMSVCPARM paParms[16];
    10721065        int i = 0;
    10731066        paParms[i++].setUInt32(pEvent->ContextID());
    1074         paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
    1075                                 (ULONG)mData.mProcess.mCommand.length() + 1);
     1067        paParms[i++].setPointer((void*)mData.mProcess.mExecutable.c_str(),
     1068                                (ULONG)mData.mProcess.mExecutable.length() + 1);
    10761069        paParms[i++].setUInt32(mData.mProcess.mFlags);
    10771070        paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
     
    17641757                hr = setError(VBOX_E_IPRT_ERROR,
    17651758                              tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
    1766                               mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1759                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
    17671760                break;
    17681761        }
     
    17981791                hr = setError(VBOX_E_IPRT_ERROR,
    17991792                              tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
    1800                               mData.mProcess.mCommand.c_str(), mData.mPID);
     1793                              mData.mProcess.mExecutable.c_str(), mData.mPID);
    18011794                break;
    18021795
     
    18041797                hr = setError(VBOX_E_IPRT_ERROR,
    18051798                              tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
    1806                               mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1799                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
    18071800                break;
    18081801        }
     
    18341827    HRESULT hr = S_OK;
    18351828
    1836     int guestRc; ProcessWaitResult_T waitResult;
     1829    int guestRc;
     1830    ProcessWaitResult_T waitResult;
    18371831    int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
    18381832    if (RT_SUCCESS(vrc))
     
    18551849                hr = setError(VBOX_E_IPRT_ERROR,
    18561850                              tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
    1857                               mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1851                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
    18581852                break;
    18591853        }
     
    19071901                hr = setError(VBOX_E_IPRT_ERROR,
    19081902                              tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
    1909                               mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
     1903                              mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
    19101904                break;
    19111905        }
     
    19561950                           bool fAsync, int *pGuestRc)
    19571951{
    1958     LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
    1959                      pGuestSession, startupInfo.mCommand.c_str(), fAsync));
     1952    LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n",
     1953                     pGuestSession, startupInfo.mExecutable.c_str(), fAsync));
    19601954
    19611955    AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
     
    19671961    mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
    19681962
    1969     int vrc = pSession->i_processCreateExInteral(mStartupInfo, pProcess);
     1963    int vrc = pSession->i_processCreateExInternal(mStartupInfo, pProcess);
    19701964    if (RT_SUCCESS(vrc))
    19711965        vrc = fAsync
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r54009 r55535  
    661661
    662662    GuestProcessStartupInfo procInfo;
    663     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
    664     procInfo.mFlags   = ProcessCreateFlag_Hidden;
     663    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
     664    procInfo.mFlags      = ProcessCreateFlag_Hidden;
    665665
    666666    try
     
    816816
    817817    GuestProcessStartupInfo procInfo;
    818     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
    819     procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
     818    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
     819    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
    820820
    821821    try
     
    12171217    GuestProcessStream      streamOut;
    12181218
    1219     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
    1220     procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
     1219    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM);
     1220    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
    12211221
    12221222    try
     
    13741374    /** @todo Merge this with IGuestFile::queryInfo(). */
    13751375    GuestProcessStartupInfo procInfo;
    1376     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
    1377     procInfo.mFlags   = ProcessCreateFlag_WaitForStdOut;
     1376    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT);
     1377    procInfo.mFlags      = ProcessCreateFlag_WaitForStdOut;
    13781378
    13791379    try
     
    18371837
    18381838/**
    1839  * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
    1840  * GuestProcess::startProcessAsync() for that.
     1839 * Creates but does *not* start the process yet.
     1840 *
     1841 * See GuestProcess::startProcess() or GuestProcess::startProcessAsync() for
     1842 * starting the process.
    18411843 *
    18421844 * @return  IPRT status code.
     
    18441846 * @param   pProcess
    18451847 */
    1846 int GuestSession::i_processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
    1847 {
    1848     LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
    1849                  procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
     1848int GuestSession::i_processCreateExInternal(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
     1849{
     1850    LogFlowFunc(("mExe=%s, mFlags=%x, mTimeoutMS=%RU32\n",
     1851                 procInfo.mExecutable.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
    18501852#ifdef DEBUG
    18511853    if (procInfo.mArguments.size())
     
    33083310}
    33093311
    3310 HRESULT GuestSession::processCreate(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments,
     3312HRESULT GuestSession::processCreate(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
    33113313                                    const std::vector<com::Utf8Str> &aEnvironment,
    33123314                                    const std::vector<ProcessCreateFlag_T> &aFlags,
     
    33203322    std::vector<LONG> affinityIgnored;
    33213323
    3322     return processCreateEx(aCommand, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
     3324    return processCreateEx(aExecutable, aArguments, aEnvironment, aFlags, aTimeoutMS, ProcessPriority_Default,
    33233325                           affinityIgnored, aGuestProcess);
    33243326#endif /* VBOX_WITH_GUEST_CONTROL */
    33253327}
    33263328
    3327 HRESULT GuestSession::processCreateEx(const com::Utf8Str &aCommand, const std::vector<com::Utf8Str> &aArguments,
     3329HRESULT GuestSession::processCreateEx(const com::Utf8Str &aExecutable, const std::vector<com::Utf8Str> &aArguments,
    33283330                                      const std::vector<com::Utf8Str> &aEnvironment,
    33293331                                      const std::vector<ProcessCreateFlag_T> &aFlags, ULONG aTimeoutMS,
     
    33363338    LogFlowThisFuncEnter();
    33373339
    3338     if (RT_UNLIKELY((aCommand.c_str()) == NULL || *(aCommand.c_str()) == '\0'))
    3339         return setError(E_INVALIDARG, tr("No command to execute specified"));
    3340 
     3340    /*
     3341     * Must have an executable to execute.  If none is given, we try use the
     3342     * zero'th argument.
     3343     */
     3344    const char *pszExecutable = aExecutable.c_str();
     3345    if (RT_UNLIKELY(pszExecutable == NULL || *pszExecutable == '\0'))
     3346    {
     3347        if (aArguments.size() > 0)
     3348            pszExecutable = aArguments[0].c_str();
     3349        if (pszExecutable == NULL || *pszExecutable == '\0')
     3350            return setError(E_INVALIDARG, tr("No command to execute specified"));
     3351    }
     3352
     3353    /*
     3354     * Check the session.
     3355     */
    33413356    HRESULT hr = i_isReadyExternal();
    33423357    if (FAILED(hr))
    33433358        return hr;
    33443359
     3360    /*
     3361     * Build the process startup info.
     3362     */
    33453363    GuestProcessStartupInfo procInfo;
    3346     procInfo.mCommand = aCommand;
    3347 
     3364
     3365    /* Executable and arguments. */
     3366    procInfo.mExecutable = pszExecutable;
    33483367    if (aArguments.size())
    33493368        for (size_t i = 0; i < aArguments.size(); i++)
    33503369            procInfo.mArguments.push_back(aArguments[i]);
    3351 
    3352     int rc = VINF_SUCCESS;
    33533370
    33543371    /*
     
    33603377    procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
    33613378
     3379    int rc = VINF_SUCCESS;
    33623380    if (aEnvironment.size())
    33633381        for (size_t i = 0; i < aEnvironment.size() && RT_SUCCESS(rc); i++)
     3382        {
     3383            /** @todo r=bird: What ARE you trying to do here??? The documentation is crystal
     3384             *        clear on that each entry contains ONE pair, however,
     3385             *        GuestEnvironment::Set(const Utf8Str &) here will split up the input
     3386             *        into any number of pairs, from what I can tell.  Such that for e.g.
     3387             *        "VBOX_LOG_DEST=file=/tmp/foobared.log" becomes "VBOX_LOG_DEST=file"
     3388             *        and "/tmp/foobared.log" - which I obviously don't want! */
    33643389            rc = procInfo.mEnvironment.Set(aEnvironment[i]);
     3390        }
    33653391
    33663392    if (RT_SUCCESS(rc))
    33673393    {
     3394        /* Convert the flag array into a mask. */
    33683395        if (aFlags.size())
    33693396            for (size_t i = 0; i < aFlags.size(); i++)
     
    33723399        procInfo.mTimeoutMS = aTimeoutMS;
    33733400
     3401        /** @todo use RTCPUSET instead of archaic 64-bit variables! */
    33743402        if (aAffinity.size())
    33753403            for (size_t i = 0; i < aAffinity.size(); i++)
     
    33793407        procInfo.mPriority = aPriority;
    33803408
     3409        /*
     3410         * Create a guest process object.
     3411         */
    33813412        ComObjPtr<GuestProcess> pProcess;
    3382         rc = i_processCreateExInteral(procInfo, pProcess);
     3413        rc = i_processCreateExInternal(procInfo, pProcess);
    33833414        if (RT_SUCCESS(rc))
    33843415        {
    33853416            /* Return guest session to the caller. */
    33863417            HRESULT hr2 = pProcess.queryInterfaceTo(aGuestProcess.asOutParam());
    3387             if (FAILED(hr2))
     3418            if (SUCCEEDED(hr2))
     3419            {
     3420                /*
     3421                 * Start the process.
     3422                 */
     3423                rc = pProcess->i_startProcessAsync();
     3424                if (RT_FAILURE(rc))
     3425                {
     3426                    /** @todo r=bird: What happens to the interface that *aGuestProcess points to
     3427                     *        now?  Looks like a leak or an undocument hack of sorts... */
     3428                }
     3429            }
     3430            else
    33883431                rc = VERR_COM_OBJECT_NOT_FOUND;
    3389 
    3390             if (RT_SUCCESS(rc))
    3391                 rc = pProcess->i_startProcessAsync();
    3392         }
    3393     }
    3394 
     3432        }
     3433    }
     3434
     3435    /** @todo you're better off doing this is 'else if (rc == xxx') statements,
     3436     *        since there is just one place where you'll get
     3437     *        VERR_MAX_PROCS_REACHED in the above code. */
    33953438    if (RT_FAILURE(rc))
    33963439    {
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r53873 r55535  
    309309
    310310    GuestProcessStartupInfo procInfo;
    311     procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT);
    312     procInfo.mFlags   = ProcessCreateFlag_Hidden;
     311    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
     312    procInfo.mFlags      = ProcessCreateFlag_Hidden;
    313313
    314314    /* Set arguments.*/
     
    318318    ComObjPtr<GuestProcess> pProcess; int guestRc;
    319319    if (RT_SUCCESS(rc))
    320         rc = pSession->i_processCreateExInteral(procInfo, pProcess);
     320        rc = pSession->i_processCreateExInternal(procInfo, pProcess);
    321321    if (RT_SUCCESS(rc))
    322322    {
     
    637637            procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
    638638                                        mSource.c_str(), mDest.c_str(), objData.mObjectSize);
    639             procInfo.mCommand  = Utf8Str(VBOXSERVICE_TOOL_CAT);
    640             procInfo.mFlags     = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
     639            procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
     640            procInfo.mFlags      = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
    641641
    642642            /* Set arguments.*/
     
    645645            /* Startup process. */
    646646            ComObjPtr<GuestProcess> pProcess;
    647             rc = pSession->i_processCreateExInteral(procInfo, pProcess);
     647            rc = pSession->i_processCreateExInternal(procInfo, pProcess);
    648648            if (RT_SUCCESS(rc))
    649649                rc = pProcess->i_startProcess(30 * 1000 /* 30s timeout */,
     
    10401040                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    10411041                                    Utf8StrFmt(GuestSession::tr("Running update file \"%s\" on guest terminated with exit code %ld"),
    1042                                                procInfo.mCommand.c_str(), exitCode));
     1042                                               procInfo.mExecutable.c_str(), exitCode));
    10431043                break;
    10441044
     
    10511051                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    10521052                                    Utf8StrFmt(GuestSession::tr("Update file \"%s\" reported invalid running state"),
    1053                                                procInfo.mCommand.c_str()));
     1053                                               procInfo.mExecutable.c_str()));
    10541054                break;
    10551055
     
    10571057                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    10581058                                    Utf8StrFmt(GuestSession::tr("Error while running update file \"%s\" on guest: %Rrc"),
    1059                                                procInfo.mCommand.c_str(), vrc));
     1059                                               procInfo.mExecutable.c_str(), vrc));
    10601060                break;
    10611061        }
     
    14131413                 * calculate the specific percentage step of each copied file. */
    14141414                uint8_t uOffset = 20; /* Start at 20%. */
    1415                 uint8_t uStep = 40 / mFiles.size();
     1415                uint8_t uStep = 40 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10);
    14161416
    14171417                LogRel(("Copying over Guest Additions update files to the guest ...\n"));
     
    14531453                 * calculate the specific percentage step of each copied file. */
    14541454                uint8_t uOffset = 60; /* Start at 60%. */
    1455                 uint8_t uStep = 35 / mFiles.size();
     1455                uint8_t uStep = 35 / (uint8_t)mFiles.size(); Assert(mFiles.size() <= 10);
    14561456
    14571457                LogRel(("Executing Guest Additions update files ...\n"));
  • trunk/src/VBox/ValidationKit/tests/additions/tdAddGuestCtrl.py

    r52776 r55535  
    99__copyright__ = \
    1010"""
    11 Copyright (C) 2010-2014 Oracle Corporation
     11Copyright (C) 2010-2015 Oracle Corporation
    1212
    1313This file is part of VirtualBox Open Source Edition (OSE), as
     
    262262        self.oCreds = tdCtxCreds(sUser, sPassword, sDomain);
    263263        self.sCmd = sCmd;
    264         self.aArgs = aArgs;
     264        self.aArgs = aArgs if aArgs is not None else [sCmd,];
    265265        self.aEnv = aEnv;
    266266        self.aFlags = aFlags or [];
     
    998998                         oTest.aArgs, oTest.aEnv));
    999999        try:
    1000             curProc = oGuestSession.processCreate(oTest.sCmd, \
    1001                                                   oTest.aArgs, oTest.aEnv, \
    1002                                                   oTest.aFlags, oTest.timeoutMS);
     1000            curProc = oGuestSession.processCreate(oTest.sCmd,
     1001                                                  oTest.aArgs if self.oTstDrv.fpApiVer >= 5.0 else oTest.aArgs[1:],
     1002                                                  oTest.aEnv, oTest.aFlags, oTest.timeoutMS);
    10031003            if curProc is not None:
    10041004                reporter.log2('Process start requested, waiting for start (%ldms) ...' % (oTest.timeoutMS,));
     
    15111511            sDomain = "";
    15121512            sCmd = "C:\\windows\\system32\\cmd.exe";
    1513             sArgs = [];
     1513            aArgs = [sCmd,];
    15141514
    15151515        # Number of stale guest processes to create.
     
    15421542            for i in range(0, cStaleProcs):
    15431543                try:
    1544                     oGuestSession.processCreate(sCmd, \
    1545                                                 sArgs, [], \
     1544                    oGuestSession.processCreate(sCmd,
     1545                                                aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:], [],
    15461546                                                [ vboxcon.ProcessCreateFlag_WaitForStdOut ], \
    15471547                                                30 * 1000);
     
    15651565                #
    15661566                if oTestVm.isWindows():
    1567                     sArgs = [ '/C', 'dir', '/S', 'C:\\Windows\\system'];
     1567                    aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows\\system'];
    15681568                reporter.log2('Starting non-stale processes');
    15691569                aaProcs = [];
    15701570                for i in range(0, cStaleProcs):
    15711571                    try:
    1572                         oCurProc = oGuestSession.processCreate(sCmd, \
    1573                                                                sArgs, [], \
    1574                                                                [], \
    1575                                                                0); # Infinite timeout.
     1572                        oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:],
     1573                                                               [], [], 0); # Infinite timeout.
    15761574                        aaProcs.append(oCurProc);
    15771575                    except:
     
    16171615                # Fire off blocking processes which are terminated via terminate().
    16181616                if oTestVm.isWindows():
    1619                     sArgs = [ '/C', 'dir', '/S', 'C:\\Windows'];
     1617                    aArgs = [ sCmd, '/C', 'dir', '/S', 'C:\\Windows'];
    16201618                reporter.log2('Starting blocking processes');
    16211619                aaProcs = [];
    16221620                for i in range(0, cStaleProcs):
    16231621                    try:
    1624                         oCurProc = oGuestSession.processCreate(sCmd, \
    1625                                                                sArgs, [], \
    1626                                                                [], 30 * 1000);
     1622                        oCurProc = oGuestSession.processCreate(sCmd, aArgs if self.oTstDrv.fpApiVer >= 5.0 else aArgs[1:],
     1623                                                               [],  [], 30 * 1000);
    16271624                        # Note: Use a timeout in the call above for not letting the stale processes
    16281625                        #       hanging around forever.  This can happen if the installed Guest Additions
     
    16981695
    16991696        if oTestVm.isWindows():
     1697            sVBoxControl = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe";
    17001698            aaExec = [
    17011699                # Basic executon.
    1702                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
     1700                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
    17031701                             sUser = sUser, sPassword = sPassword),
    17041702                  tdTestResultExec(fRc = True) ],
    1705                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ],
     1703                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\kernel32.dll' ],
    17061704                             sUser = sUser, sPassword = sPassword),
    17071705                  tdTestResultExec(fRc = True) ],
    1708                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ],
     1706                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32\\nonexist.dll' ],
    17091707                             sUser = sUser, sPassword = sPassword),
    17101708                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    1711                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', '/wrongparam' ],
     1709                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', '/wrongparam' ],
    17121710                             sUser = sUser, sPassword = sPassword),
    17131711                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    17141712                # Paths with spaces.
    17151713                ## @todo Get path of installed Guest Additions. Later.
    1716                 [ tdTestExec(sCmd = "C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\VBoxControl.exe",
    1717                              aArgs = [ 'version' ],
     1714                [ tdTestExec(sCmd = sVBoxControl, aArgs = [ sVBoxControl, 'version' ],
    17181715                             sUser = sUser, sPassword = sPassword),
    17191716                  tdTestResultExec(fRc = True) ],
    17201717                # StdOut.
    1721                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
     1718                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
    17221719                             sUser = sUser, sPassword = sPassword),
    17231720                  tdTestResultExec(fRc = True) ],
    1724                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdout-non-existing' ],
     1721                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdout-non-existing' ],
    17251722                             sUser = sUser, sPassword = sPassword),
    17261723                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    17271724                # StdErr.
    1728                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
     1725                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
    17291726                             sUser = sUser, sPassword = sPassword),
    17301727                  tdTestResultExec(fRc = True) ],
    1731                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stderr-non-existing' ],
     1728                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stderr-non-existing' ],
    17321729                             sUser = sUser, sPassword = sPassword),
    17331730                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    17341731                # StdOut + StdErr.
    1735                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'c:\\windows\\system32' ],
     1732                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'c:\\windows\\system32' ],
    17361733                             sUser = sUser, sPassword = sPassword),
    17371734                  tdTestResultExec(fRc = True) ],
    1738                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir', '/S', 'stdouterr-non-existing' ],
     1735                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir', '/S', 'stdouterr-non-existing' ],
    17391736                             sUser = sUser, sPassword = sPassword),
    17401737                  tdTestResultExec(fRc = True, iExitCode = 1) ]
    17411738                # FIXME: Failing tests.
    17421739                # Environment variables.
    1743                 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_NONEXIST' ],
     1740                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_NONEXIST' ],
    17441741                #              sUser = sUser, sPassword = sPassword),
    17451742                #   tdTestResultExec(fRc = True, iExitCode = 1) ]
    1746                 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'windir' ],
     1743                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'windir' ],
    17471744                #              sUser = sUser, sPassword = sPassword,
    17481745                #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    17491746                #   tdTestResultExec(fRc = True, sBuf = 'windir=C:\\WINDOWS\r\n') ],
    1750                 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],
     1747                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
    17511748                #              sUser = sUser, sPassword = sPassword,
    17521749                #              aEnv = [ 'TEST_FOO=BAR' ],
    17531750                #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    17541751                #   tdTestResultExec(fRc = True, sBuf = 'TEST_FOO=BAR\r\n') ],
    1755                 # [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'set', 'TEST_FOO' ],
     1752                # [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'set', 'TEST_FOO' ],
    17561753                #              sUser = sUser, sPassword = sPassword,
    17571754                #              aEnv = [ 'TEST_FOO=BAR', 'TEST_BAZ=BAR' ],
     
    17651762            # Manual test, not executed automatically.
    17661763            aaManual = [
    1767                 [ tdTestExec(sCmd = sImageOut, aArgs = [ '/C', 'dir /S C:\\Windows' ],
     1764                [ tdTestExec(sCmd = sImageOut, aArgs = [ sImageOut, '/C', 'dir /S C:\\Windows' ],
    17681765                             sUser = sUser, sPassword = sPassword,
    17691766                             aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
     
    19221919            aaTests.extend([
    19231920                # Simple.
    1924                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'wrongcommand' ],
     1921                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'wrongcommand' ],
    19251922                             sUser = sUser, sPassword = sPassword),
    19261923                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    1927                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'exit', '22' ],
     1924                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'exit', '22' ],
    19281925                             sUser = sUser, sPassword = sPassword),
    19291926                  tdTestResultExec(fRc = True, iExitCode = 22) ],
    1930                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=234' ],
     1927                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=234' ],
    19311928                             sUser = sUser, sPassword = sPassword),
    19321929                  tdTestResultExec(fRc = True, iExitCode = 0) ],
    1933                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'echo', '%WINDIR%' ],
     1930                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'echo', '%WINDIR%' ],
    19341931                             sUser = sUser, sPassword = sPassword),
    19351932                  tdTestResultExec(fRc = True, iExitCode = 0) ],
    1936                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'set', 'ERRORLEVEL=0' ],
     1933                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'set', 'ERRORLEVEL=0' ],
    19371934                             sUser = sUser, sPassword = sPassword),
    19381935                  tdTestResultExec(fRc = True, iExitCode = 0) ],
    1939                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
     1936                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
    19401937                             sUser = sUser, sPassword = sPassword),
    19411938                  tdTestResultExec(fRc = True, iExitCode = 0) ],
    1942                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ],
     1939                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32\\kernel32.dll' ],
    19431940                             sUser = sUser, sPassword = sPassword),
    19441941                  tdTestResultExec(fRc = True, iExitCode = 0) ],
    1945                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
     1942                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
    19461943                             sUser = sUser, sPassword = sPassword),
    19471944                  tdTestResultExec(fRc = True, iExitCode = 1) ],
    1948                 [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
     1945                [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
    19491946                             sUser = sUser, sPassword = sPassword),
    19501947                  tdTestResultExec(fRc = True, iExitCode = 1) ]
    19511948                # FIXME: Failing tests.
    19521949                # With stdout.
    1953                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
     1950                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
    19541951                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
    19551952                #   tdTestResultExec(fRc = True, iExitCode = 0) ],
    1956                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
     1953                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
    19571954                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
    19581955                #   tdTestResultExec(fRc = True, iExitCode = 1) ],
    1959                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
     1956                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
    19601957                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut ]),
    19611958                #   tdTestResultExec(fRc = True, iExitCode = 1) ],
    19621959                # With stderr.
    1963                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
     1960                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
    19641961                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    19651962                #   tdTestResultExec(fRc = True, iExitCode = 0) ],
    1966                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
     1963                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
    19671964                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    19681965                #   tdTestResultExec(fRc = True, iExitCode = 1) ],
    1969                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
     1966                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
    19701967                #              sUser = sUser, sPassword = sPassword, aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    19711968                #   tdTestResultExec(fRc = True, iExitCode = 1) ],
    19721969                # With stdout/stderr.
    1973                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\windows\\system32' ],
     1970                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\windows\\system32' ],
    19741971                #              sUser = sUser, sPassword = sPassword,
    19751972                #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    19761973                #   tdTestResultExec(fRc = True, iExitCode = 0) ],
    1977                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-file' ],
     1974                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-file' ],
    19781975                #              sUser = sUser, sPassword = sPassword,
    19791976                #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
    19801977                #   tdTestResultExec(fRc = True, iExitCode = 1) ],
    1981                 # [ tdTestExec(sCmd = sImage, aArgs = [ '/C', 'dir', 'c:\\nonexisting-dir\\' ],
     1978                # [ tdTestExec(sCmd = sImage, aArgs = [ sImage, '/C', 'dir', 'c:\\nonexisting-dir\\' ],
    19821979                #              sUser = sUser, sPassword = sPassword,
    19831980                #              aFlags = [ vboxcon.ProcessCreateFlag_WaitForStdOut, vboxcon.ProcessCreateFlag_WaitForStdErr ]),
     
    20312028            # waiting for termination.
    20322029            try:
    2033                 curProc = oGuestSession.processCreate(sImage, [], \
     2030                curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \
    20342031                                                      [], [], 30 * 1000);
    20352032                reporter.log('Waiting for process 1 being started ...');
     
    20622059            if fRc:
    20632060                try:
    2064                     curProc = oGuestSession.processCreate(sImage, [], \
     2061                    curProc = oGuestSession.processCreate(sImage, [sImage,] if self.oTstDrv.fpApiVer >= 5.0 else [], \
    20652062                                                          [], [], 5 * 1000);
    20662063                    reporter.log('Waiting for process 2 being started ...');
     
    32823279
    32833280        sCmd = 'c:\\windows\\system32\\cmd.exe';
    3284         aArgs = [ '/C', 'dir', '/S', 'c:\\windows' ];
     3281        aArgs = [ sCmd, '/C', 'dir', '/S', 'c:\\windows' ];
    32853282        aEnv = [];
    32863283        aFlags = [];
    32873284
    32883285        for _ in range(100):
    3289             oProc = oGuestSession.processCreate(sCmd,
    3290                                                 aArgs, aEnv,
    3291                                                 aFlags, 30 * 1000);
     3286            oProc = oGuestSession.processCreate(sCmd, aArgs if self.fpApiVer >= 5.0 else aArgs[1:],
     3287                                                aEnv, aFlags, 30 * 1000);
    32923288
    32933289            aWaitFor = [ vboxcon.ProcessWaitForFlag_Terminate ];
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