VirtualBox

Changeset 35916 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Feb 9, 2011 3:04:44 PM (14 years ago)
Author:
vboxsync
Message:

VBoxManageGuestCtrl.cpp: r=bird: Added a bunch of todos, most for the exec command.

File:
1 edited

Legend:

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

    r35907 r35916  
    228228
    229229/**
    230  * Initializes the VM, that is checks whether it's up and
    231  * running, if it can be locked (shared only) and returns a
    232  * valid IGuest pointer on success.
     230 * Initializes the VM for IGuest operations.
     231 *
     232 * That is, checks whether it's up and running, if it can be locked (shared
     233 * only) and returns a valid IGuest pointer on success.
    233234 *
    234235 * @return  IPRT status code.
    235236 * @param   pArg            Our command line argument structure.
    236  * @param   pszNameOrId     The VM's name or UUID to use.
    237  * @param   pGuest          Pointer where to store the IGuest interface.
     237 * @param   pszNameOrId     The VM's name or UUID.
     238 * @param   pGuest          Where to return the IGuest interface pointer.
    238239 */
    239240static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest> *pGuest)
     
    280281}
    281282
     283/* <Missing docuemntation> */
    282284static int handleCtrlExecProgram(HandlerArg *a)
    283285{
    284286    /*
    285      * Check the syntax.  We can deduce the correct syntax from the number of
    286      * arguments.
     287     * Parse arguments.
    287288     */
    288289    if (a->argc < 2) /* At least the command we want to execute in the guest should be present :-). */
     
    301302    };
    302303
    303     int ch;
    304     RTGETOPTUNION ValueUnion;
    305     RTGETOPTSTATE GetState;
     304    int                     ch;
     305    RTGETOPTUNION           ValueUnion;
     306    RTGETOPTSTATE           GetState;
    306307    RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    307308
    308     Utf8Str Utf8Cmd;
    309     uint32_t uFlags = 0;
    310     /* Note: this uses IN_BSTR as it must be BSTR on COM and CBSTR on XPCOM */
     309    Utf8Str                 Utf8Cmd;
     310    uint32_t                fFlags = 0;
    311311    com::SafeArray<IN_BSTR> args;
    312312    com::SafeArray<IN_BSTR> env;
    313     Utf8Str Utf8UserName;
    314     Utf8Str Utf8Password;
    315     uint32_t u32TimeoutMS = 0;
    316     bool fWaitForExit = false;
    317     bool fWaitForStdOut = false;
    318     bool fWaitForStdErr = false;
    319     bool fVerbose = false;
    320 
    321     int vrc = VINF_SUCCESS;
    322     bool fUsageOK = true;
     313    Utf8Str                 Utf8UserName;
     314    Utf8Str                 Utf8Password;
     315    uint32_t                u32TimeoutMS    = 0;
     316    bool                    fWaitForExit    = false;
     317    bool                    fWaitForStdOut = false;
     318    bool                    fWaitForStdErr = false;
     319    bool                    fVerbose        = false;
     320
     321    int                     vrc            = VINF_SUCCESS;
     322    bool                    fUsageOK        = true;
    323323    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
    324324           && RT_SUCCESS(vrc))
     
    360360
    361361            case 'f': /* Flags */
     362                /** @todo r=bird: As stated before, this generic flags stuff
     363                 *        does NOT make sense!  The IgnoreOprphanedProcesses
     364                 *        features should have been added as:
     365                 *  { "--ignore-operhaned-processes", DEFINE, RTGETOPT_REQ_NOTHING }
     366                 *
     367                 *  Please, remove -f in 4.1, replace it with above. */
    362368                /** @todo Needs a bit better processing as soon as we have more flags. */
    363369                /** @todo Add a hidden flag. */
    364370                if (!RTStrICmp(ValueUnion.psz, "ignoreorphanedprocesses"))
    365                     uFlags |= ExecuteProcessFlag_IgnoreOrphanedProcesses;
     371                    fFlags |= ExecuteProcessFlag_IgnoreOrphanedProcesses;
    366372                else
    367373                    fUsageOK = false;
     
    386392            case 'w': /* Wait for ... */
    387393            {
     394                /** @todo r=bird: Same as for -f: Use individual options for
     395                 * indicating what to wait for.  This is unix tradition and
     396                 * much simpler to write code for.  It also avoids people
     397                 * finding out that the following sequence does not work
     398                 * (contrary to what one would expect):
     399                 *      -w stdout,stderr
     400                 *  */
    388401                if (!RTStrICmp(ValueUnion.psz, "exit"))
    389402                    fWaitForExit = true;
     
    405418            case VINF_GETOPT_NOT_OPTION:
    406419            {
     420                /** @todo r=bird: Guess what the following does:
     421                 * VBoxManage guestcontrol exec myvm /bin/ls 1 2 3 4;
     422                 *
     423                 * In 4.1 this SHALL be changed to treat 1 2 3 4 as arguments
     424                 * to /bin/ls.  Drop --arguments and replace it with --image
     425                 * <guest-file>.  The --image defaults to the first argument if
     426                 * not specified.  Users should be encouraged to use '--' to
     427                 * separate 'exec' options from options to the guest
     428                 * program:
     429                 *      VBoxManage guestcontrol myvm exec --image /bin/busybox -- ln -s /foo /bar
     430                 */
    407431                /* The actual command we want to execute on the guest. */
    408432                Utf8Cmd = ValueUnion.psz;
     
    415439    }
    416440
    417     if (!fUsageOK)
     441    if (!fUsageOK) /** @todo r=bird: there is no clean up, so just return directly on failure with a specific message. */
    418442        return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters");
    419443
    420444    if (Utf8Cmd.isEmpty())
    421         return errorSyntax(USAGE_GUESTCONTROL,
    422                            "No command to execute specified!");
     445        return errorSyntax(USAGE_GUESTCONTROL, "No command to execute specified!");
    423446
    424447    if (Utf8UserName.isEmpty())
    425         return errorSyntax(USAGE_GUESTCONTROL,
    426                            "No user name specified!");
    427 
     448        return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
     449
     450    /** @todo r=bird: You don't check vrc here, so if RTGetOptArgvFromString
     451     *  or RTGetOptArgvFromString failed above, you'll ignore it.
     452     *
     453     *  Just simplify the argument parsing to not use unnecessary state
     454     *  variables and instead return directly on error with a specific error
     455     *  message. (See fUsageOk comment above.) */
     456
     457    /*
     458     * <comment missing>
     459     */
    428460    HRESULT rc = S_OK;
    429461    ComPtr<IGuest> guest;
     
    431463    if (RT_SUCCESS(vrc))
    432464    {
    433         ComPtr<IProgress> progress;
    434         ULONG uPID = 0;
    435 
    436465        if (fVerbose)
    437466        {
     
    446475
    447476        /* Execute the process. */
    448         rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(), uFlags,
     477        ComPtr<IProgress> progress;
     478        ULONG uPID = 0;
     479        rc = guest->ExecuteProcess(Bstr(Utf8Cmd).raw(),
     480                                   fFlags,
    449481                                   ComSafeArrayAsInParam(args),
    450482                                   ComSafeArrayAsInParam(env),
    451483                                   Bstr(Utf8UserName).raw(),
    452                                    Bstr(Utf8Password).raw(), u32TimeoutMS,
    453                                    &uPID, progress.asOutParam());
     484                                   Bstr(Utf8Password).raw(),
     485                                   u32TimeoutMS,
     486                                   &uPID,
     487                                   progress.asOutParam());
    454488        if (FAILED(rc))
    455489            vrc = ctrlPrintError(guest, COM_IIDOF(IGuest));
     
    490524
    491525                /* Wait for process to exit ... */
    492                 BOOL fCompleted = FALSE;
    493                 BOOL fCanceled = FALSE;
    494                 int cMilliesSleep = 0;
     526                BOOL fCompleted    = FALSE;
     527                BOOL fCanceled     = FALSE;
     528                int  cMilliesSleep = 0;
    495529                while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
    496530                {
     
    517551                            if (cbOutputData > 0)
    518552                            {
     553/** @todo r=bird: cat'ing binary data from the guest is not going to work
     554 *        reliably if we do conversions like this.  Should probably just
     555 *        write the output as it is by default, but bypassing RTStrWrite and
     556 *        it's automatic translation.  Adding exec options to convert unix2dos
     557 *        and dos2unix.  Use a VFS I/O stream filter for doing this, it's a
     558 *        generic problem and the new VFS APIs will handle it more
     559 *        transparently. (requires writing dos2unix/unix2dos filters ofc) */
    519560                                /* aOutputData has a platform dependent line ending, standardize on
    520561                                 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
     
    565606                    if (   SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled)))
    566607                        && fCanceled)
    567                     {
    568608                        break;
    569                     }
    570609
    571610                    /* Did we run out of time? */
     
    578617
    579618                    /* Don't hog the CPU in a busy loop! */
     619/** @todo r=bird: I believe I already mentioned that this problem is better
     620 * solved by using WaitForCompletion and GetProcessOutput with timeouts.  The
     621 * 1ms hack above is not what I had in mind.  This quick fix must go away.  */
    580622                    if (cbOutputData <= 0)
    581623                    {
     
    586628                    else
    587629                        cMilliesSleep = 0;
    588                 }
     630                } /* while */
    589631
    590632                /* Undo signal handling */
     
    592634                    ctrlSignalHandlerUninstall();
    593635
     636                /* Report status back to the user. */
    594637                if (fCanceled)
    595638                {
     
    603646                    CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
    604647                    if (FAILED(iRc))
    605                     {
    606648                        vrc = ctrlPrintProgressError(progress);
    607                     }
    608649                    else if (fVerbose)
    609650                    {
     
    612653                        if (SUCCEEDED(rc))
    613654                            RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, ctrlExecGetStatus(uRetStatus), uRetFlags);
     655                        /** @todo r=bird: The guest application exit code
     656                         *        should by default be returned by the command.
     657                         *        Non-normal exits and exit codes outside
     658                         *        the portable range (0..127) should be
     659                         *        translated to more portable values.
     660                         *
     661                         *  Alternatively, we could return say exit code 16 if
     662                         *  the guest command failed, 17 if it terminated on a
     663                         *  signal, 18 if it abended and exit code 19 if it
     664                         *  timed out.  This is possibly a better solution.
     665                         *
     666                         *  Think about people using VBoxManage for scripting. */
    614667                    }
    615668                }
     
    624677    }
    625678
    626     if (RT_FAILURE(vrc))
    627         rc = VBOX_E_IPRT_ERROR;
    628     return SUCCEEDED(rc) ? 0 : 1;
     679    if (RT_FAILURE(vrc) || FAILED(rc))
     680        return RTEXITCODE_FAILURE;
     681    return RTEXITCODE_SUCCESS;
    629682}
    630683
     
    709762 * @param   pszFilter           Search filter (e.g. *.pdf).
    710763 * @param   pszDest             Destination directory.
    711  * @param   uFlags              Copy flags.
     764 * @param   fFlags              Copy flags.
    712765 * @param   pcObjects           Where to store the overall objects to
    713766 *                              copy found.
     
    716769static int ctrlCopyDirectoryRead(const char *pszRootDir, const char *pszSubDir,
    717770                                 const char *pszFilter, const char *pszDest,
    718                                  uint32_t uFlags, uint32_t *pcObjects, PRTLISTNODE pList)
     771                                 uint32_t fFlags, uint32_t *pcObjects, PRTLISTNODE pList)
    719772{
    720773    AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER);
     
    762815                        break;
    763816                    }
    764                     if (uFlags & CopyFileFlag_Recursive)
     817                    if (fFlags & CopyFileFlag_Recursive)
    765818                    {
    766819                        char *pszNewSub = NULL;
     
    774827                            rc = ctrlCopyDirectoryRead(pszRootDir, pszNewSub,
    775828                                                       pszFilter, pszDest,
    776                                                        uFlags, pcObjects, pList);
     829                                                       fFlags, pcObjects, pList);
    777830                            RTStrFree(pszNewSub);
    778831                        }
     
    783836
    784837                case RTDIRENTRYTYPE_SYMLINK:
    785                     if (   (uFlags & CopyFileFlag_Recursive)
    786                         && (uFlags & CopyFileFlag_FollowLinks))
     838                    if (   (fFlags & CopyFileFlag_Recursive)
     839                        && (fFlags & CopyFileFlag_FollowLinks))
    787840                    {
    788841                        /* Fall through to next case is intentional. */
     
    852905 * @param   pszSource           Source path on host to use.
    853906 * @param   pszDest             Destination path on guest to use.
    854  * @param   uFlags              Copy flags.
     907 * @param   fFlags              Copy flags.
    855908 * @param   pcObjects           Where to store the count of objects to be copied.
    856909 * @param   pList               Where to store the object list.
    857910 */
    858 static int ctrlCopyInit(const char *pszSource, const char *pszDest, uint32_t uFlags,
     911static int ctrlCopyInit(const char *pszSource, const char *pszDest, uint32_t fFlags,
    859912                        uint32_t *pcObjects, PRTLISTNODE pList)
    860913{
     
    9581011                    rc = ctrlCopyDirectoryRead(pszSourceAbsRoot, NULL /* Sub directory */,
    9591012                                               pszFilter, pszDestAbs,
    960                                                uFlags, pcObjects, pList);
     1013                                               fFlags, pcObjects, pList);
    9611014                    if (RT_SUCCESS(rc) && *pcObjects == 0)
    9621015                        rc = VERR_NOT_FOUND;
     
    9881041 * @param   pszUserName     User name on guest to use for the copy operation.
    9891042 * @param   pszPassword     Password of user account.
    990  * @param   uFlags          Copy flags.
     1043 * @param   fFlags          Copy flags.
    9911044 */
    9921045static int ctrlCopyFileToGuest(IGuest *pGuest, bool fVerbose, const char *pszSource, const char *pszDest,
    9931046                               const char *pszUserName, const char *pszPassword,
    994                                uint32_t uFlags)
     1047                               uint32_t fFlags)
    9951048{
    9961049    AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
     
    10031056    HRESULT rc = pGuest->CopyToGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(),
    10041057                                     Bstr(pszUserName).raw(), Bstr(pszPassword).raw(),
    1005                                      uFlags, progress.asOutParam());
     1058                                     fFlags, progress.asOutParam());
    10061059    if (FAILED(rc))
    10071060        vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
     
    10431096    Utf8Str Utf8UserName;
    10441097    Utf8Str Utf8Password;
    1045     uint32_t uFlags = CopyFileFlag_None;
     1098    uint32_t fFlags = CopyFileFlag_None;
    10461099    bool fVerbose = false;
    10471100    bool fCopyRecursive = false;
     
    10621115
    10631116            case 'F': /* Follow symlinks */
    1064                 uFlags |= CopyFileFlag_FollowLinks;
     1117                fFlags |= CopyFileFlag_FollowLinks;
    10651118                break;
    10661119
     
    10701123
    10711124            case 'R': /* Recursive processing */
    1072                 uFlags |= CopyFileFlag_Recursive;
     1125                fFlags |= CopyFileFlag_Recursive;
    10731126                break;
    10741127
     
    11391192        RTLISTNODE listToCopy;
    11401193        uint32_t cObjects = 0;
    1141         vrc = ctrlCopyInit(Utf8Source.c_str(), Utf8Dest.c_str(), uFlags,
     1194        vrc = ctrlCopyInit(Utf8Source.c_str(), Utf8Dest.c_str(), fFlags,
    11421195                           &cObjects, &listToCopy);
    11431196        if (RT_FAILURE(vrc))
     
    11841237                        if (!fDryRun)
    11851238                            vrc = ctrlCopyFileToGuest(guest, fVerbose, pNode->pszSourcePath, pNode->pszDestPath,
    1186                                                       Utf8UserName.c_str(), Utf8Password.c_str(), uFlags);
     1239                                                      Utf8UserName.c_str(), Utf8Password.c_str(), fFlags);
    11871240                    }
    11881241                    if (RT_FAILURE(vrc))
     
    12281281    Utf8Str Utf8UserName;
    12291282    Utf8Str Utf8Password;
    1230     uint32_t uFlags = CreateDirectoryFlag_None;
     1283    uint32_t fFlags = CreateDirectoryFlag_None;
    12311284    uint32_t uMode = 0;
    12321285    bool fVerbose = false;
     
    12491302
    12501303            case 'P': /* Create parents */
    1251                 uFlags |= CreateDirectoryFlag_Parents;
     1304                fFlags |= CreateDirectoryFlag_Parents;
    12521305                break;
    12531306
     
    13141367            rc = guest->CreateDirectory(Bstr(pNode->pszDestPath).raw(),
    13151368                                        Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(),
    1316                                         uMode, uFlags, progress.asOutParam());
     1369                                        uMode, fFlags, progress.asOutParam());
    13171370            if (FAILED(rc))
    13181371            {
     
    14451498int handleGuestControl(HandlerArg *a)
    14461499{
     1500    /** @todo This command does not follow the syntax where the <uuid|vmname>
     1501     * comes between the command and subcommand.  The commands controlvm,
     1502     * snapshot and debugvm puts it between.  The commands guestproperty,
     1503     * guestcontrol and sharedfolder puts it after (the latter is
     1504     * questionable).
     1505     *
     1506     * I would propose changing guestcontrol and guestproperty to the controlvm
     1507     * syntax in 4.1.  Whether sharedfolder should be changed as well is a bit
     1508     * more open.
     1509     */
     1510
    14471511    HandlerArg arg = *a;
    14481512    arg.argc = a->argc - 1;
     
    14531517
    14541518    /* switch (cmd) */
     1519    /** @todo r=bird: Subcommands are not case insensitive for other commands
     1520     *        like controlvm.  Drop it. */
    14551521    if (   !RTStrICmp(a->argv[0], "exec")
    14561522        || !RTStrICmp(a->argv[0], "execute"))
    1457     {
    14581523        return handleCtrlExecProgram(&arg);
    1459     }
    1460     else if (   !RTStrICmp(a->argv[0], "copyto")
    1461              || !RTStrICmp(a->argv[0], "cp"))
    1462     {
     1524
     1525    if (   !RTStrICmp(a->argv[0], "copyto")
     1526        || !RTStrICmp(a->argv[0], "cp"))
    14631527        return handleCtrlCopyTo(&arg);
    1464     }
    1465     else if (   !RTStrICmp(a->argv[0], "createdirectory")
    1466              || !RTStrICmp(a->argv[0], "createdir")
    1467              || !RTStrICmp(a->argv[0], "mkdir")
    1468              || !RTStrICmp(a->argv[0], "md"))
    1469     {
     1528
     1529    if (   !RTStrICmp(a->argv[0], "createdirectory")
     1530        || !RTStrICmp(a->argv[0], "createdir")
     1531        || !RTStrICmp(a->argv[0], "mkdir")
     1532        || !RTStrICmp(a->argv[0], "md"))
    14701533        return handleCtrlCreateDirectory(&arg);
    1471     }
    1472     else if (   !RTStrICmp(a->argv[0], "updateadditions")
    1473              || !RTStrICmp(a->argv[0], "updateadds"))
    1474     {
     1534
     1535    if (   !RTStrICmp(a->argv[0], "updateadditions")
     1536        || !RTStrICmp(a->argv[0], "updateadds"))
    14751537        return handleCtrlUpdateAdditions(&arg);
    1476     }
    14771538
    14781539    /* default: */
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