VirtualBox

Changeset 34273 in vbox


Ignore:
Timestamp:
Nov 23, 2010 10:14:46 AM (14 years ago)
Author:
vboxsync
Message:

VBoxService/ToolBox: Completed misc todos, updated documentation.

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
3 edited

Legend:

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

    r33854 r34273  
    519519         * mutex because VBoxService might spawn itself to execute some commands.
    520520         */
    521         rc = VBoxServiceToolboxMain(argc - 1, &argv[1]);
    522         if (rc != VERR_NOT_FOUND) /* Internal tool found? Then bail out. */
    523             return rc;
     521        int iExitCode;
     522        if (VBoxServiceToolboxMain(argc - 1, &argv[1], &iExitCode))
     523            return iExitCode;
    524524    }
    525525#endif
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r33540 r34273  
    280280
    281281#ifdef VBOXSERVICE_TOOLBOX
    282 extern int VBoxServiceToolboxMain(int argc, char **argv);
     282extern bool         VBoxServiceToolboxMain(int argc, char **argv, int *piExitCode);
    283283#endif
    284284
    285285#ifdef RT_OS_WINDOWS
    286286# ifdef VBOX_WITH_GUEST_PROPS
    287 extern int VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList);
    288 extern int VBoxServiceWinGetComponentVersions(uint32_t uiClientID);
     287extern int          VBoxServiceVMInfoWinWriteUsers(char **ppszUserList, uint32_t *pcUsersInList);
     288extern int          VBoxServiceWinGetComponentVersions(uint32_t uiClientID);
    289289# endif /* VBOX_WITH_GUEST_PROPS */
    290290#endif /* RT_OS_WINDOWS */
    291291
    292292#ifdef VBOX_WITH_GUEST_CONTROL
    293 extern int  VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms);
    294 extern int  VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms);
    295 extern int  VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
    296 extern int  VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
    297                                           const char *pszArgs, uint32_t uNumArgs,
    298                                           const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
    299                                           const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
    300 extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread);
    301 extern void VBoxServiceControlExecDeletePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf);
    302 extern int  VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    303                                                         uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
    304 extern int  VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    305                                                   uint8_t *pbData, uint32_t cbData, bool fPendingClose, uint32_t *pcbWritten);
     293extern int          VBoxServiceControlExecHandleCmdStartProcess(uint32_t u32ClientId, uint32_t uNumParms);
     294extern int          VBoxServiceControlExecHandleCmdSetInput(uint32_t u32ClientId, uint32_t uNumParms);
     295extern int          VBoxServiceControlExecHandleCmdGetOutput(uint32_t u32ClientId, uint32_t uNumParms);
     296extern int          VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
     297                                                  const char *pszArgs, uint32_t uNumArgs,
     298                                                  const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
     299                                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
     300extern void         VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread);
     301extern void         VBoxServiceControlExecDeletePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf);
     302extern int          VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     303                                                                uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
     304extern int          VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     305                                                          uint8_t *pbData, uint32_t cbData, bool fPendingClose, uint32_t *pcbWritten);
    306306#endif /* VBOX_WITH_GUEST_CONTROL */
    307307
    308308#ifdef VBOXSERVICE_MANAGEMENT
    309 extern uint32_t VBoxServiceBalloonQueryPages(uint32_t cbPage);
     309extern uint32_t     VBoxServiceBalloonQueryPages(uint32_t cbPage);
    310310#endif
    311311#if defined(VBOX_WITH_PAGE_SHARING) && defined(RT_OS_WINDOWS)
    312 extern RTEXITCODE VBoxServicePageSharingInitFork(void);
     312extern RTEXITCODE   VBoxServicePageSharingInitFork(void);
    313313#endif
    314314
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceToolBox.cpp

    r34249 r34273  
    2323
    2424#include <iprt/assert.h>
     25#include <iprt/buildconfig.h>
    2526#include <iprt/dir.h>
    2627#include <iprt/file.h>
     
    2829#include <iprt/list.h>
    2930#include <iprt/mem.h>
     31#include <iprt/message.h>
    3032#include <iprt/path.h>
    3133#include <iprt/string.h>
     
    3739
    3840#include <VBox/VBoxGuestLib.h>
     41#include <VBox/version.h>
    3942#include "VBoxServiceInternal.h"
    4043#include "VBoxServiceUtils.h"
    4144
    42 /** @todo r=bird: Don't use VBoxServiceError here, just use RTMsg**.  */
    43 /** @todo r=bird: 'static' is a wonderful keyword, please use it as much as
    44  *        possible like I've said in the coding guidelines.  Not only does it
    45  *        help wrt to linking, but it also helps understanding what's
    46  *        internal and external interfaces in a source file! */
     45
     46#define CAT_OPT_NO_CONTENT_INDEXED              1000
     47
     48/**
     49 * An file/directory entry. Used to cache
     50 * file names/paths for later processing.
     51 */
     52typedef struct VBOXSERVICETOOLBOXPATHENTRY
     53{
     54    /** Our node. */
     55    RTLISTNODE  Node;
     56    /** Name of the entry. */
     57    char       *pszName;
     58} VBOXSERVICETOOLBOXPATHENTRY, *PVBOXSERVICETOOLBOXPATHENTRY;
    4759
    4860
     
    5062 * Displays a help text to stdout.
    5163 */
    52 void VBoxServiceToolboxShowUsage(void)
     64static void VBoxServiceToolboxShowUsage(void)
    5365{
    5466    RTPrintf("Toolbox Usage:\n"
    5567             "cat [FILE] - Concatenate FILE(s), or standard input, to standard output\n"
     68             "\n"
     69             "mkdir - Make directories\n"
    5670             "\n");
    5771}
     
    5973
    6074/**
    61  *
    62  *
    63  * @return  int
    64  *
     75 * Displays the program's version number.
     76 */
     77static void VBoxServiceToolboxShowVersion(void)
     78{
     79    RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
     80}
     81
     82
     83/**
     84 * Displays an error message because of syntax error.
     85 *
     86 * @return  VERR_INVALID_PARAMETER
    6587 * @param   pszFormat
    6688 */
    67 int VBoxServiceToolboxErrorSyntax(const char *pszFormat, ...)
     89static int VBoxServiceToolboxErrorSyntax(const char *pszFormat, ...)
    6890{
    6991    va_list args;
     
    7395             "Syntax error: %N\n", pszFormat, &args);
    7496    va_end(args);
    75     VBoxServiceToolboxShowUsage();
    7697    return VERR_INVALID_PARAMETER;
    7798}
     
    79100
    80101/**
    81  *
    82  *
    83  * @return  int
    84  *
    85  * @param   hInput
    86  * @param   hOutput
    87  */
    88 int VBoxServiceToolboxCatOutput(RTFILE hInput, RTFILE hOutput)
     102 * Destroys a path buffer list.
     103 *
     104 * @return  IPRT status code.
     105 * @param   pList                   Pointer to list to destroy.
     106 */
     107static void VBoxServiceToolboxPathBufDestroy(PRTLISTNODE pList)
     108{
     109    AssertPtr(pList);
     110    PVBOXSERVICETOOLBOXPATHENTRY pNode = RTListNodeGetFirst(pList, VBOXSERVICETOOLBOXPATHENTRY, Node);
     111    while (pNode)
     112    {
     113        PVBOXSERVICETOOLBOXPATHENTRY pNext = RTListNodeIsLast(pList, &pNode->Node)
     114                                                              ? NULL :
     115                                                                RTListNodeGetNext(&pNode->Node,
     116                                                                                  VBOXSERVICETOOLBOXPATHENTRY, Node);
     117        RTListNodeRemove(&pNode->Node);
     118
     119        RTStrFree(pNode->pszName);
     120
     121        RTMemFree(pNode);
     122        pNode = pNext;
     123    }
     124}
     125
     126
     127/**
     128 * Adds a path entry (file/directory/whatever) to a given path buffer list.
     129 *
     130 * @return  IPRT status code.
     131 * @param   pList                   Pointer to list to add entry to.
     132 * @param   pszName                 Name of entry to add.
     133 */
     134static int VBoxServiceToolboxPathBufAddPathEntry(PRTLISTNODE pList, const char *pszName)
     135{
     136    AssertPtrReturn(pList, VERR_INVALID_PARAMETER);
     137
     138    int rc = VINF_SUCCESS;
     139    PVBOXSERVICETOOLBOXPATHENTRY pNode = (PVBOXSERVICETOOLBOXPATHENTRY)RTMemAlloc(sizeof(VBOXSERVICETOOLBOXPATHENTRY));
     140    if (pNode)
     141    {
     142        pNode->pszName = RTStrDup(pszName);
     143        AssertPtr(pNode->pszName);
     144
     145        /*rc =*/ RTListAppend(pList, &pNode->Node);
     146    }
     147    else
     148        rc = VERR_NO_MEMORY;
     149    return rc;
     150}
     151
     152
     153/**
     154 * Performs the actual output operation of "vbox_cat".
     155 *
     156 * @return  IPRT status code.
     157 * @param   hInput                  Handle of input file (if any) to use;
     158 *                                  else stdin will be used.
     159 * @param   hOutput                 Handle of output file (if any) to use;
     160 *                                  else stdout will be used.
     161 */
     162static int VBoxServiceToolboxCatOutput(RTFILE hInput, RTFILE hOutput)
    89163{
    90164    int rc = VINF_SUCCESS;
     
    93167        rc = RTFileFromNative(&hInput, RTFILE_NATIVE_STDIN);
    94168        if (RT_FAILURE(rc))
    95             VBoxServiceError("cat: Could not translate input file to native handle, rc=%Rrc\n", rc);
     169            RTMsgError("cat: Could not translate input file to native handle, rc=%Rrc\n", rc);
    96170    }
    97171
     
    100174        rc = RTFileFromNative(&hOutput, RTFILE_NATIVE_STDOUT);
    101175        if (RT_FAILURE(rc))
    102             VBoxServiceError("cat: Could not translate output file to native handle, rc=%Rrc\n", rc);
     176            RTMsgError("cat: Could not translate output file to native handle, rc=%Rrc\n", rc);
    103177    }
    104178
     
    130204
    131205
    132 /** @todo r=bird: Again, function headers like this are uslesss and better left
    133  *        out. */
    134 /**
    135  *
    136  *
    137  * @return  int
    138  *
    139  * @param   argc
    140  * @param   argv
    141  */
    142 int VBoxServiceToolboxMkDir(int argc, char **argv)
     206/**
     207 * Main function for tool "vbox_mkdir".
     208 *
     209 * @return  RTEXITCODE.
     210 * @param   argc                    Number of arguments.
     211 * @param   argv                    Pointer to argument array.
     212 */
     213static int VBoxServiceToolboxMkDir(int argc, char **argv)
    143214{
    144215     static const RTGETOPTDEF s_aOptions[] =
     
    152223     RTGETOPTUNION ValueUnion;
    153224     RTGETOPTSTATE GetState;
    154      RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
    155      /** @todo r=bird: Pass RTGETOPTINIT_FLAGS_OPTS_FIRST, our mkdir shall be
    156       *        like the GNU one wrt to option (dash-something) and argument
    157       *        order (dirs). */
     225     RTGetOptInit(&GetState, argc, argv,
     226                  s_aOptions, RT_ELEMENTS(s_aOptions),
     227                  1 /* Index of argv to start with. */, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    158228
    159229     int rc = VINF_SUCCESS;
     
    161231     bool fVerbose = false;
    162232
    163      char szDir[RTPATH_MAX];
    164233     RTFMODE newMode = 0;
    165 #ifdef RT_OS_WINDOWS
    166      RTFMODE fileMode = 0;
    167 #else
    168      RTFMODE fileMode = S_IRWXU | S_IRWXG | S_IRWXO; /** @todo r=bird: We've got RTFS_ defines for these, they are x-platform.  Why 'file' when we're creating directories? */
    169 #endif
     234     RTFMODE dirMode = RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO;
     235
     236     /* Init directory list. */
     237     RTLISTNODE dirList;
     238     RTListInit(&dirList);
    170239
    171240     while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     
    175244         switch (ch)
    176245         {
     246             case 'h':
     247                 VBoxServiceToolboxShowUsage();
     248                 return RTEXITCODE_SUCCESS;
     249
    177250             case 'p':
    178251                 fMakeParentDirs = true;
     
    182255                 rc = RTStrToUInt32Ex(ValueUnion.psz, NULL, 8 /* Base */, &newMode);
    183256                 if (RT_FAILURE(rc)) /* Only octet based values supported right now! */
    184                      VBoxServiceVerbose(0, "mkdir: Mode flag strings not implemented yet!\n");
     257                 {
     258                     RTMsgError("mkdir: Mode flag strings not implemented yet! Use octal numbers instead.\n");
     259                     return RTEXITCODE_SYNTAX;
     260                 }
    185261                 break;
    186262
     
    189265                 break;
    190266
     267             case 'V':
     268                 VBoxServiceToolboxShowVersion();
     269                 return RTEXITCODE_SUCCESS;
     270
    191271             case VINF_GETOPT_NOT_OPTION:
    192272             {
    193                  rc = RTPathAbs(ValueUnion.psz, szDir, sizeof(szDir));
    194                  if (RT_FAILURE(rc))
    195                      VBoxServiceError("mkdir: Could not build absolute directory!\n");
    196                  /** @todo r=bird: you can make multiple directories just by
    197                   *  adding them to the mkdir command line:
    198                   *     "mkdir foo/ foo/bar foo/bar/wiz"
    199                   *  This will now only create foo/bar/wiz, which will fail
    200                   *  because the two previous steps weren't executed.  It
    201                   *  will also leak memory, but that's not important. (Also,
    202                   *  I don't get why we need to call RTPathAbs here as nobody
    203                   *  is going to change the current directory.) */
     273                 /* Add path(s) to buffer. This enables processing multiple paths
     274                  * at once.
     275                  *
     276                  * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     277                  * processing this loop it's safe to immediately exit on syntax errors
     278                  * or showing the help text (see above). */
     279                 rc = VBoxServiceToolboxPathBufAddPathEntry(&dirList, ValueUnion.psz);
    204280                 break;
    205281             }
    206              /** @todo r=bird: Missing handling of the standard options 'V' and
    207               *        'h'. */
    208282
    209283             default:
     
    219293             mode_t umaskMode = umask(0); /* Get current umask. */
    220294             if (newMode)
    221                 fileMode = newMode;
     295                dirMode = newMode;
    222296#endif
    223297         }
    224298
    225          rc = fMakeParentDirs ?
    226                 RTDirCreateFullPath(szDir, fileMode)
    227               : RTDirCreate(szDir, fileMode);
    228 
    229          if (RT_SUCCESS(rc) && fVerbose)
    230              VBoxServiceVerbose(0, "mkdir: Created directory '%s', mode 0x%RTfmode\n", szDir, fileMode); /** @todo r=bird: drop the 0x here, use %#RTfmode instead. */
    231          else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */
     299         PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     300         RTListForEach(&dirList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
    232301         {
    233              PCRTSTATUSMSG pMsg = RTErrGet(rc);
    234              if (pMsg)
    235                  VBoxServiceError("mkdir: Could not create directory: %s\n", pMsg->pszMsgFull);
    236              else
    237                  VBoxServiceError("mkdir: Could not create directory, rc=%Rrc\n", rc);
     302             rc = fMakeParentDirs ?
     303                    RTDirCreateFullPath(pNodeIt->pszName, dirMode)
     304                  : RTDirCreate(pNodeIt->pszName, dirMode);
     305
     306             if (RT_SUCCESS(rc) && fVerbose)
     307                 RTMsgError("mkdir: Created directory 's', mode %#RTfmode\n", pNodeIt->pszName, dirMode);
     308             else if (RT_FAILURE(rc)) /** @todo Add a switch with more helpful error texts! */
     309             {
     310                 PCRTSTATUSMSG pMsg = RTErrGet(rc);
     311                 if (pMsg)
     312                     RTMsgError("mkdir: Could not create directory '%s': %s\n",
     313                                pNodeIt->pszName, pMsg->pszMsgFull);
     314                 else
     315                     RTMsgError("mkdir: Could not create directory '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
     316             }
    238317         }
    239 
    240318     }
    241319     else if (fVerbose)
    242          VBoxServiceError("mkdir: Failed with rc=%Rrc\n", rc);
    243      return rc;
    244 }
    245 
    246 
    247 /**
    248  *
    249  *
    250  * @return  int
    251  *
    252  * @param   argc
    253  * @param   argv
    254  */
    255 int VBoxServiceToolboxCat(int argc, char **argv)
     320         RTMsgError("mkdir: Failed with rc=%Rrc\n", rc);
     321
     322     VBoxServiceToolboxPathBufDestroy(&dirList);
     323     return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     324}
     325
     326
     327/**
     328 * Main function for tool "vbox_cat".
     329 *
     330 * @return  RTEXITCODE.
     331 * @param   argc                    Number of arguments.
     332 * @param   argv                    Pointer to argument array.
     333 */
     334static int VBoxServiceToolboxCat(int argc, char **argv)
    256335{
    257336     static const RTGETOPTDEF s_aOptions[] =
    258337     {
    259          { "--input",     'i', RTGETOPT_REQ_STRING },
    260          { "--output",    'o', RTGETOPT_REQ_STRING },
    261          { "--flags",     'f', RTGETOPT_REQ_STRING }
    262      /** @todo r=bird: Missing options 'A', 'b', 'e', 'E', 'n', 's', 'T',
    263       *        'u', 'v' as found on 'man cat' on a linux system. They must
    264       *        not be implemented, just return an apologetic error message. */
     338         /* Sorted by short ops. */
     339         { "--show-all",            'a',                         RTGETOPT_REQ_NOTHING },
     340         { "--number-nonblank",     'b',                         RTGETOPT_REQ_NOTHING },
     341         { NULL,                    'e',                         RTGETOPT_REQ_NOTHING },
     342         { NULL,                    'E',                         RTGETOPT_REQ_NOTHING },
     343         { "--flags",               'f',                         RTGETOPT_REQ_STRING  },
     344         { "--no-content-indexed",  CAT_OPT_NO_CONTENT_INDEXED,  RTGETOPT_REQ_NOTHING },
     345         { "--number",              'n',                         RTGETOPT_REQ_NOTHING },
     346         { "--output",              'o',                         RTGETOPT_REQ_STRING  },
     347         { "--squeeze-blank",       's',                         RTGETOPT_REQ_NOTHING },
     348         { NULL,                    't',                         RTGETOPT_REQ_NOTHING },
     349         { "--show-tabs",           'T',                         RTGETOPT_REQ_NOTHING },
     350         { NULL,                    'u',                         RTGETOPT_REQ_NOTHING },
     351         { "--show-noneprinting",   'v',                         RTGETOPT_REQ_NOTHING }
    265352     };
    266 
    267353
    268354     int ch;
     
    272358
    273359     int rc = VINF_SUCCESS;
    274      RTFILE hInput = NIL_RTFILE;
    275 
     360     bool fUsageOK = true;
     361
     362     char szOutput[RTPATH_MAX] = { 0 };
    276363     RTFILE hOutput = NIL_RTFILE;
    277364     uint32_t fFlags = RTFILE_O_CREATE_REPLACE /* Output file flags. */
    278365                     | RTFILE_O_WRITE
    279366                     | RTFILE_O_DENY_WRITE;
     367
     368     /* Init directory list. */
     369     RTLISTNODE inputList;
     370     RTListInit(&inputList);
    280371
    281372     while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     
    285376         switch (ch)
    286377         {
    287              /** @todo r=bird: You add a flag --no-content-indexed without a
    288               * short form (use a #define CAT_OPT_NO_CONTENT_INDEXED 1000 for
    289               * iShort). */
    290 
    291              case 'f':
    292                  /* Process flags; no fancy parsing here yet. */
    293                  if (RTStrIStr(ValueUnion.psz, "noindex"))
    294                      fFlags |= RTFILE_O_NOT_CONTENT_INDEXED;
    295                  else
    296                  {
    297                      VBoxServiceError("cat: Unknown flag set!\n");
    298                      rc = VERR_INVALID_PARAMETER;
    299                  }
    300                  break;
     378             case 'a':
     379             case 'b':
     380             case 'e':
     381             case 'E':
     382             case 'n':
     383             case 's':
     384             case 't':
     385             case 'T':
     386             case 'v':
     387                 RTMsgError("cat: Sorry, option '%s' is not implemented yet!\n",
     388                            ValueUnion.pDef->pszLong);
     389                 rc = VERR_INVALID_PARAMETER;
     390                 break;
     391
     392             case 'h':
     393                 VBoxServiceToolboxShowUsage();
     394                 return RTEXITCODE_SUCCESS;
    301395
    302396             case 'o':
    303                  rc = RTFileOpen(&hOutput, ValueUnion.psz, fFlags);
    304                  if (RT_FAILURE(rc))
    305                      VBoxServiceError("cat: Could not create output file \"%s\"! rc=%Rrc\n",
    306                                       ValueUnion.psz, rc);
    307                  break;
    308 
    309                  /** @todo r=bird: Again, there shall be no need for any -i
    310                   *        options since all non-options are input files. */
    311 
    312              case 'i':
     397                 if (!RTStrPrintf(szOutput, sizeof(szOutput), ValueUnion.psz))
     398                     rc = VERR_NO_MEMORY;
     399                 break;
     400
     401             case 'u':
     402                 /* Ignored. */
     403                 break;
     404
     405             case 'V':
     406                 VBoxServiceToolboxShowVersion();
     407                 return RTEXITCODE_SUCCESS;
     408
     409             case CAT_OPT_NO_CONTENT_INDEXED:
     410                 fFlags |= RTFILE_O_NOT_CONTENT_INDEXED;
     411                 break;
     412
    313413             case VINF_GETOPT_NOT_OPTION:
    314414             {
    315                  rc = RTFileOpen(&hInput, ValueUnion.psz,
    316                                  RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
    317                  if (RT_FAILURE(rc))
    318                      VBoxServiceError("cat: Could not open input file \"%s\"! rc=%Rrc\n",
    319                                       ValueUnion.psz, rc);
     415                 /* Add file(s) to buffer. This enables processing multiple paths
     416                  * at once.
     417                  *
     418                  * Since the non-options (RTGETOPTINIT_FLAGS_OPTS_FIRST) come last when
     419                  * processing this loop it's safe to immediately exit on syntax errors
     420                  * or showing the help text (see above). */
     421                 rc = VBoxServiceToolboxPathBufAddPathEntry(&inputList, ValueUnion.psz);
    320422                 break;
    321423             }
    322 
    323              /** @todo r=bird: Missing handling of the standard options 'V' and
    324               *        'h'. */
    325424
    326425             default:
     
    330429
    331430     if (RT_SUCCESS(rc))
    332          rc  = VBoxServiceToolboxCatOutput(hInput, hOutput);
    333 
    334      if (hInput != NIL_RTFILE)
    335          RTFileClose(hInput);
     431     {
     432         if (strlen(szOutput))
     433         {
     434             rc = RTFileOpen(&hOutput, szOutput, fFlags);
     435             if (RT_FAILURE(rc))
     436                 RTMsgError("cat: Could not create output file '%s'! rc=%Rrc\n",
     437                            szOutput, rc);
     438         }
     439
     440         if (RT_SUCCESS(rc))
     441         {
     442             /* Process each input file. */
     443             PVBOXSERVICETOOLBOXPATHENTRY pNodeIt;
     444             RTFILE hInput = NIL_RTFILE;
     445             RTListForEach(&inputList, pNodeIt, VBOXSERVICETOOLBOXPATHENTRY, Node)
     446             {
     447                 rc = RTFileOpen(&hInput, pNodeIt->pszName,
     448                                 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     449                 if (RT_SUCCESS(rc))
     450                 {
     451                     rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
     452                     RTFileClose(hInput);
     453                 }
     454                 else
     455                 {
     456                     PCRTSTATUSMSG pMsg = RTErrGet(rc);
     457                     if (pMsg)
     458                         RTMsgError("cat: Could not open input file '%s': %s\n",
     459                                    pNodeIt->pszName, pMsg->pszMsgFull);
     460                     else
     461                         RTMsgError("cat: Could not open input file '%s', rc=%Rrc\n", pNodeIt->pszName, rc);
     462                 }
     463
     464                 if (RT_FAILURE(rc))
     465                     break;
     466             }
     467
     468             /* If not input files were defined, process stdin. */
     469             if (RTListNodeIsFirst(&inputList, &inputList))
     470                 rc = VBoxServiceToolboxCatOutput(hInput, hOutput);
     471         }
     472     }
     473
    336474     if (hOutput != NIL_RTFILE)
    337475         RTFileClose(hOutput);
    338      return rc;
    339 }
    340 
    341 
    342 /**
    343  * Main routine for toolbox command line handling.
    344  *
    345  * @return  int
    346  *
    347  * @param   argc
    348  * @param   argv
    349  */
    350 int VBoxServiceToolboxMain(int argc, char **argv)
    351 {
    352     /** @todo r=bird: The return type of this function is mixed; both RTEXITCODE
    353      *  and IPRT status code.  That doesn't cut it.  The RTEXITCODE part should
    354      *  be returned separately from the handled-or-unhandled bit.
    355      *
    356      *  Also, please change VBoxServiceToolboxCat and VBoxServiceToolboxMkDir to
    357      *  return RTEXITCODE and use RTMsg* like RTZipTarCmd (and later
    358      *  RTZipGzipCmd). */
    359     int rc = VERR_NOT_FOUND;
     476     VBoxServiceToolboxPathBufDestroy(&inputList);
     477
     478     return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     479}
     480
     481
     482/**
     483 * Entry point for internal toolbox.
     484 *
     485 * @return  True if an internal tool was handled, false if not.
     486 * @param   argc                    Number of arguments.
     487 * @param   argv                    Pointer to argument array.
     488 * @param   piExitCode              Pointer to receive exit code when internal command
     489 *                                  was handled.
     490 */
     491bool VBoxServiceToolboxMain(int argc, char **argv, int *piExitCode)
     492{
    360493    if (argc > 0) /* Do we have at least a main command? */
    361494    {
     
    363496            || !strcmp(argv[0], "vbox_cat"))
    364497        {
    365             rc = VBoxServiceToolboxCat(argc, argv);
     498            *piExitCode = VBoxServiceToolboxCat(argc, argv);
     499            return true;
    366500        }
    367501        else if (   !strcmp(argv[0], "mkdir")
    368502                 || !strcmp(argv[0], "vbox_mkdir"))
    369503        {
    370             rc = VBoxServiceToolboxMkDir(argc, argv);
     504            *piExitCode = VBoxServiceToolboxMkDir(argc, argv);
     505            return true;
    371506        }
    372507    }
    373 
    374     if (rc != VERR_NOT_FOUND)
    375         rc = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    376     return rc;
    377 }
    378 
     508    return false;
     509}
     510
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