VirtualBox

Changeset 2840 in kBuild


Ignore:
Timestamp:
Aug 25, 2016 9:47:04 PM (9 years ago)
Author:
bird
Message:

work in progress

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/submit.c

    r2837 r2840  
    11/* $Id$ */
    22/** @file
    3  * kmk_redirect - Do simple program <-> file redirection (++).
     3 * kMk Builtin command - submit job to a kWorker.
    44 */
    55
     
    3030# define _POSIX_C_SOURCE 1 /* 10.4 sdk and unsetenv */
    3131#endif
    32 #include "config.h"
     32#include "make.h"
     33#include "job.h"
     34#include "variable.h"
     35#include "pathstuff.h"
    3336#include <stdio.h>
    3437#include <stdlib.h>
    3538#include <string.h>
    3639#include <errno.h>
    37 #include <fcntl.h>
     40#ifdef HAVE_ALLOCA_H
     41# include <alloca.h>
     42#endif
    3843#if defined(_MSC_VER)
    3944# include <ctype.h>
     
    4550#endif
    4651
     52#include "kmkbuiltin.h"
     53#include "err.h"
     54
    4755#ifdef __OS2__
    4856# define INCL_BASE
     
    5361#endif
    5462
     63/*********************************************************************************************************************************
     64*   Structures and Typedefs                                                                                                      *
     65*********************************************************************************************************************************/
     66typedef struct WORKERINSTANCE *PWORKERINSTANCE;
     67typedef struct WORKERINSTANCE
     68{
     69    /** Pointer to the next worker instance. */
     70    PWORKERINSTANCE         pNext;
     71    /** Pointer to the previous worker instance. */
     72    PWORKERINSTANCE         pPrev;
     73    /** 32 or 64. */
     74    unsigned                cBits;
     75    /** The process handle. */
     76    HANDLE                  hProcess;
     77
     78} WORKERINSTANCE;
     79
    5580
    5681/*********************************************************************************************************************************
    5782*   Global Variables                                                                                                             *
    5883*********************************************************************************************************************************/
    59 /** Number of times the '-v' switch was seen. */
    60 static unsigned g_cVerbosity = 0;
    61 
    62 
    63 #if defined(_MSC_VER)
    64 
    65 /**
    66  * Checks if this is an Watcom option where we must just pass thru the string
    67  * as-is.
    68  *
    69  * This is currnetly only used for -d (defining macros).
    70  *
    71  * @returns 1 if pass-thru, 0 if not.
    72  * @param   pszArg          The argument to consider.
    73  */
    74 static int isWatcomPassThruOption(const char *pszArg)
    75 {
    76     char ch = *pszArg++;
    77     if (ch != '-' && ch != '/')
    78         return 0;
    79     ch = *pszArg++;
    80     switch (ch)
    81     {
    82         /* Example: -d+VAR="string-value" */
    83         case 'd':
    84             if (ch == '+')
    85                 ch = *pszArg++;
    86             if (!isalpha(ch) && ch != '_')
    87                 return 0;
    88             return 1;
    89 
    90         default:
    91             return 0;
    92     }
    93 }
    94 
    95 
    96 /**
    97  * Replaces arguments in need of quoting.
    98  *
    99  * This will "leak" the original and/or the replacement string, depending on
    100  * how you look at it.
    101  *
    102  * For details on how MSC parses the command line, see "Parsing C Command-Line
    103  * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
    104  *
    105  * @param   argc                The argument count.
    106  * @param   argv                The argument vector.
    107  * @param   fWatcomBrainDamage  Set if we're catering for wcc, wcc386 or similar
    108  *                              OpenWatcom tools.  They seem to follow some
    109  *                              ancient or home made quoting convention.
    110  * @param   pStdErr             For verbose debug info.
    111  */
    112 static void quoteArguments(int argc, char **argv, int fWatcomBrainDamage, FILE *pStdErr)
    113 {
    114     int i;
    115     for (i = 0; i < argc; i++)
    116     {
    117         const char *pszOrgOrg = argv[i];
    118         const char *pszOrg    = pszOrgOrg;
    119         size_t      cchOrg    = strlen(pszOrg);
    120         const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
    121         const char *pszProblem = NULL;
    122         if (   pszQuotes
    123             || cchOrg == 0
    124             || (pszProblem = (const char *)memchr(pszOrg, ' ',  cchOrg)) != NULL
    125             || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
    126             || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
    127             || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
    128             || (pszProblem = (const char *)memchr(pszOrg, '&',  cchOrg)) != NULL
    129             || (pszProblem = (const char *)memchr(pszOrg, '>',  cchOrg)) != NULL
    130             || (pszProblem = (const char *)memchr(pszOrg, '<',  cchOrg)) != NULL
    131             || (pszProblem = (const char *)memchr(pszOrg, '|',  cchOrg)) != NULL
    132             || (pszProblem = (const char *)memchr(pszOrg, '%',  cchOrg)) != NULL
    133             || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
    134             || (   !fWatcomBrainDamage
    135                 && (pszProblem = (const char *)memchr(pszOrg, '=',  cchOrg)) != NULL)
    136             )
    137         {
    138             char   ch;
    139             int    fComplicated = pszQuotes || (cchOrg > 0 && pszOrg[cchOrg - 1] == '\\');
    140             size_t cchNew       = fComplicated ? cchOrg * 2 + 2 : cchOrg + 2;
    141             char  *pszNew       = (char *)malloc(cchNew + 1 /*term*/ + 3 /*passthru hack*/);
    142 
    143             argv[i] = pszNew;
    144 
    145             /* Watcom does not grok stuff like "-i=c:\program files\watcom\h",
    146                it think it's a source specification. In that case the quote
    147                must follow the equal sign. */
    148             if (fWatcomBrainDamage)
    149             {
    150                 size_t cchUnquoted  = 0;
    151                 if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
    152                     cchUnquoted = 1;
    153                 else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
    154                 {
    155                     if (isWatcomPassThruOption(pszOrg))
    156                         cchUnquoted = strlen(pszOrg) + 1;
    157                     else
    158                     {
    159                         const char *pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg); /* For -i=dir and similar. */
    160                         if (   pszNeedQuoting == NULL
    161                             || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
    162                             pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
    163                         else
    164                             pszNeedQuoting++;
    165                         cchUnquoted = pszNeedQuoting - pszOrg;
    166                     }
    167                 }
    168                 if (cchUnquoted)
    169                 {
    170                     memcpy(pszNew, pszOrg, cchUnquoted);
    171                     pszNew += cchUnquoted;
    172                     pszOrg += cchUnquoted;
    173                     cchOrg -= cchUnquoted;
    174                 }
    175             }
    176 
    177             *pszNew++ = '"';
    178             if (fComplicated)
    179             {
    180                 while ((ch = *pszOrg++) != '\0')
    181                 {
    182                     if (ch == '"')
    183                     {
    184                         *pszNew++ = '\\';
    185                         *pszNew++ = '"';
    186                     }
    187                     else if (ch == '\\')
    188                     {
    189                         /* Backslashes are a bit complicated, they depends on
    190                            whether a quotation mark follows them or not.  They
    191                            only require escaping if one does. */
    192                         unsigned cSlashes = 1;
    193                         while ((ch = *pszOrg) == '\\')
    194                         {
    195                             pszOrg++;
    196                             cSlashes++;
    197                         }
    198                         if (ch == '"' || ch == '\0') /* We put a " at the EOS. */
    199                         {
    200                             while (cSlashes-- > 0)
    201                             {
    202                                 *pszNew++ = '\\';
    203                                 *pszNew++ = '\\';
    204                             }
    205                         }
    206                         else
    207                             while (cSlashes-- > 0)
    208                                 *pszNew++ = '\\';
    209                     }
    210                     else
    211                         *pszNew++ = ch;
    212                 }
    213             }
    214             else
    215             {
    216                 memcpy(pszNew, pszOrg, cchOrg);
    217                 pszNew += cchOrg;
    218             }
    219             *pszNew++ = '"';
    220             *pszNew = '\0';
    221         }
    222 
    223         if (g_cVerbosity > 0)
    224         {
    225             if (argv[i] == pszOrgOrg)
    226                 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", i, pszOrgOrg);
    227             else
    228             {
    229                 fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", i, argv[i]);
    230                 fprintf(pStdErr, "kmk_redirect: debug:(orig[%i]=%s<eos>)\n", i, pszOrgOrg);
    231             }
    232         }
    233     }
    234 
    235     /*for (i = 0; i < argc; i++) fprintf(stderr, "argv[%u]=%s;;\n", i, argv[i]);*/
    236 }
    237 
    238 
    239 /** Used by safeCloseFd. */
    240 static void __cdecl ignore_invalid_parameter(const wchar_t *a, const wchar_t *b, const wchar_t *c, unsigned d, uintptr_t e)
    241 {
    242 }
    243 
    244 #endif /* _MSC_VER */
    245 
    246 
    247 /**
    248  * Safely works around MS CRT's pedantic close() function.
    249  *
    250  * @param   fd      The file handle.
    251  */
    252 static void safeCloseFd(int fd)
    253 {
    254 #ifdef _MSC_VER
    255     _invalid_parameter_handler pfnOld = _get_invalid_parameter_handler();
    256     _set_invalid_parameter_handler(ignore_invalid_parameter);
    257     close(fd);
    258     _set_invalid_parameter_handler(pfnOld);
    259 #else
    260     close(fd);
    261 #endif
    262 }
    263 
    264 
    265 static const char *name(const char *pszName)
    266 {
    267     const char *psz = strrchr(pszName, '/');
    268 #if defined(_MSC_VER) || defined(__OS2__)
    269     const char *psz2 = strrchr(pszName, '\\');
    270     if (!psz2)
    271         psz2 = strrchr(pszName, ':');
    272     if (psz2 && (!psz || psz2 > psz))
    273         psz = psz2;
    274 #endif
    275     return psz ? psz + 1 : pszName;
    276 }
     84static PWORKERINSTANCE g_pIdleHead;
     85static PWORKERINSTANCE g_pIdleTail;
     86
    27787
    27888
     
    28090{
    28191    fprintf(pOut,
    282             "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage] [-v] -- <program> [args]\n"
     92            "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
     93            "           [-C|--chdir <dir>] [--wcc-brain-damage]\n"
     94            "           [-3|--32-bit] [-6|--64-bit] [-v] -- <program> [args]\n"
    28395            "   or: %s --help\n"
    28496            "   or: %s --version\n"
    28597            "\n"
    286             "The rwa+tb is like for fopen, if not specified it defaults to w+.\n"
    287             "The <fd> is either a number or an alias for the standard handles:\n"
    288             "   i = stdin\n"
    289             "   o = stdout\n"
    290             "   e = stderr\n"
     98            "Options:\n"
     99            "  -Z, --zap-env, -i, --ignore-environment\n"
     100            "    Zaps the environment. Position dependent.\n"
     101            "  -E, --set <var>=[value]\n"
     102            "    Sets an enviornment variable putenv fashion. Position dependent.\n"
     103            "  -U, --unset <var>\n"
     104            "    Removes an environment variable. Position dependent.\n"
     105            "  -C, --chdir <dir>\n"
     106            "    Specifies the current directory for the program.  Relative paths\n"
     107            "    are relative to the previous -C option.  Default is getcwd value.\n"
     108            "  -3, --32-bit\n"
     109            "    Selects a 32-bit kWorker process. Default: kmk bit count\n"
     110            "  -6, --64-bit\n"
     111            "    Selects a 64-bit kWorker process. Default: kmk bit count\n"
     112            "  --wcc-brain-damage\n"
     113            "    Works around wcc and wcc386 (Open Watcom) not following normal\n"
     114            "    quoting conventions on Windows, OS/2, and DOS.\n"
     115            "  -v,--verbose\n"
     116            "    More verbose execution.\n"
     117            "  -V,--version\n"
     118            "    Show the version number.\n"
     119            "  -h,--help\n"
     120            "    Show this usage information.\n"
    291121            "\n"
    292             "The -c switch will close the specified file descriptor.\n"
    293             "\n"
    294             "The -Z switch zaps the environment.\n"
    295             "\n"
    296             "The -E switch is for making changes to the environment in a putenv\n"
    297             "fashion.\n"
    298             "\n"
    299             "The -C switch is for changing the current directory. This takes immediate\n"
    300             "effect, so be careful where you put it.\n"
    301             "\n"
    302             "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
    303             "not following normal quoting conventions on Windows, OS/2, and DOS.\n"
    304             "\n"
    305             "The -v switch is for making the thing more verbose.\n"
    306             "\n"
    307             "This command was originally just a quick hack to avoid invoking the shell\n"
    308             "on Windows (cygwin) where forking is very expensive and has exhibited\n"
    309             "stability issues on SMP machines.  It has since grown into something like\n"
    310             "/usr/bin/env on steroids.\n"
    311122            ,
    312123            argv0, argv0, argv0);
     
    315126
    316127
    317 int main(int argc, char **argv, char **envp)
     128int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild)
    318129{
    319     int i;
    320 #if defined(_MSC_VER)
    321     intptr_t rc;
    322 #else
    323     int j;
    324 #endif
    325     FILE *pStdErr = stderr;
    326     FILE *pStdOut = stdout;
    327     int fWatcomBrainDamage = 0;
     130    int             rcExit = 0;
     131    int             iArg;
     132    unsigned        cAllocatedEnvVars;
     133    unsigned        iEnvVar;
     134    unsigned        cEnvVars;
     135    char          **papszEnv = NULL;
     136    const char     *pszCwd = NULL;
     137    unsigned        cBitsWorker = 0;
     138    int             fWatcomBrainDamage = 0;
     139    int             cVerbosity = 0;
     140    size_t const    cbCwdBuf = GET_PATH_MAX;
     141    PATH_VAR(szCwd);
     142
     143    g_progname = argv[0];
    328144
    329145    /*
    330      * Parse arguments.
     146     * Create default program environment.
    331147     */
    332     if (argc <= 1)
    333         return usage(pStdErr, name(argv[0]));
    334     for (i = 1; i < argc; i++)
     148    if (getcwd_fs(szCwd, cbCwdBuf) != NULL)
     149    { /* likely */ }
     150    else
     151        return err(1, "getcwd_fs failed\n");
     152
     153    papszEnv = pChild->environment;
     154    if (papszEnv)
     155        pChild->environment = papszEnv = target_environment(pChild->file);
     156    cEnvVars = 0;
     157    while (papszEnv[cEnvVars] != NULL)
     158        cEnvVars++;
     159    cAllocatedEnvVars = cEnvVars;
     160
     161    /*
     162     * Parse the command line.
     163     */
     164    for (iArg = 1; iArg < argc; iArg++)
    335165    {
    336         if (argv[i][0] == '-')
     166        const char *pszArg = argv[iArg];
     167        if (*pszArg == '-')
    337168        {
    338             int fd;
    339             int fdOpened;
    340             int fOpen;
    341             char *psz = &argv[i][1];
    342             if (*psz == '-')
     169            char chOpt = *++pszArg;
     170            if (chOpt != '-')
    343171            {
    344                 /* '--' ? */
    345                 if (!psz[1])
    346                 {
    347                     i++;
    348                     break;
    349                 }
    350 
    351                 /* convert to short. */
    352                 if (!strcmp(psz, "-help"))
    353                     psz = "h";
    354                 else if (!strcmp(psz, "-version"))
    355                     psz = "V";
    356                 else if (!strcmp(psz, "-env"))
    357                     psz = "E";
    358                 else if (!strcmp(psz, "-chdir"))
    359                     psz = "C";
    360                 else if (!strcmp(psz, "-zap-env"))
    361                     psz = "Z";
    362                 else if (!strcmp(psz, "-close"))
    363                     psz = "c";
    364                 else if (!strcmp(psz, "-wcc-brain-damage"))
    365                 {
    366                     fWatcomBrainDamage = 1;
    367                     continue;
    368                 }
    369             }
    370 
    371             /*
    372              * Deal with the obligatory help and version switches first.
    373              */
    374             if (*psz == 'h')
    375             {
    376                 usage(pStdOut, name(argv[0]));
    377                 return 0;
    378             }
    379             if (*psz == 'V')
    380             {
    381                 printf("kmk_redirect - kBuild version %d.%d.%d (r%u)\n"
    382                        "Copyright (C) 2007-2012 knut st. osmundsen\n",
    383                        KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
    384                        KBUILD_SVN_REV);
    385                 return 0;
    386             }
    387 
    388             /*
    389              * Environment switch?
    390              */
    391             if (*psz == 'E')
    392             {
    393                 psz++;
    394                 if (*psz == ':' || *psz == '=')
    395                     psz++;
     172                if (chOpt != '\0')
     173                { /* likely */ }
    396174                else
    397175                {
    398                     if (i + 1 >= argc)
    399                     {
    400                         fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
    401                         return 1;
    402                     }
    403                     psz = argv[++i];
    404                 }
    405 #ifdef __OS2__
    406                 if (    !strncmp(psz, "BEGINLIBPATH=",  sizeof("BEGINLIBPATH=") - 1)
    407                     ||  !strncmp(psz, "ENDLIBPATH=",    sizeof("ENDLIBPATH=") - 1)
    408                     ||  !strncmp(psz, "LIBPATHSTRICT=", sizeof("LIBPATHSTRICT=") - 1))
    409                 {
    410                     ULONG ulVar = *psz == 'B' ? BEGIN_LIBPATH
    411                                 : *psz == 'E' ? END_LIBPATH
    412                                 :               LIBPATHSTRICT;
    413                     const char *pszVal = strchr(psz, '=') + 1;
    414                     APIRET rc = DosSetExtLIBPATH(pszVal, ulVar);
    415                     if (rc)
    416                     {
    417                         fprintf(pStdErr, "%s: error: DosSetExtLibPath(\"%s\", %.*s (%lu)): %lu\n",
    418                                 name(argv[0]), pszVal, pszVal - psz - 1, psz, ulVar, rc);
    419                         return 1;
    420                     }
    421                 }
    422                 else
    423 #endif /* __OS2__ */
    424                 {
    425                     const char *pchEqual = strchr(psz, '=');
    426                     if (pchEqual && pchEqual[1] != '\0')
    427                     {
    428                         if (putenv(psz))
    429                         {
    430                             fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
    431                             return 1;
    432                         }
    433                     }
    434                     else
    435                     {
    436                         size_t cchVar = pchEqual ? (size_t)(pchEqual - psz) : strlen(psz);
    437                         char *pszCopy = (char *)malloc(cchVar + 2);
    438                         memcpy(pszCopy, psz, cchVar);
    439 
    440 #if defined(_MSC_VER) || defined(__OS2__)
    441                         pszCopy[cchVar] = '=';
    442                         pszCopy[cchVar + 1] = '\0';
    443                         if (putenv(pszCopy))
    444                         {
    445                             fprintf(pStdErr, "%s: error: putenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
    446                             return 1;
    447                         }
    448 #else
    449                         pszCopy[cchVar] = '\0';
    450                         if (unsetenv(pszCopy))
    451                         {
    452                             fprintf(pStdErr, "%s: error: unsetenv(\"%s\"): %s\n", name(argv[0]), pszCopy, strerror(errno));
    453                             return 1;
    454                         }
    455 #endif
    456                         free(pszCopy);
    457                     }
    458                 }
    459                 continue;
    460             }
    461 
    462             /*
    463              * Change directory switch?
    464              */
    465             if (*psz == 'C')
    466             {
    467                 psz++;
    468                 if (*psz == ':' || *psz == '=')
    469                     psz++;
    470                 else
    471                 {
    472                     if (i + 1 >= argc)
    473                     {
    474                         fprintf(pStdErr, "%s: syntax error: no argument for %s\n", name(argv[0]), argv[i]);
    475                         return 1;
    476                     }
    477                     psz = argv[++i];
    478                 }
    479                 if (!chdir(psz))
    480                     continue;
    481 #ifdef _MSC_VER
    482                 {
    483                     /* drop trailing slash if any. */
    484                     size_t cch = strlen(psz);
    485                     if (    cch > 2
    486                         &&  (psz[cch - 1] == '/' || psz[cch - 1] == '\\')
    487                         &&  psz[cch - 1] != ':')
    488                     {
    489                         int rc2;
    490                         char *pszCopy = strdup(psz);
    491                         do  pszCopy[--cch] = '\0';
    492                         while (    cch > 2
    493                                &&  (pszCopy[cch - 1] == '/' || pszCopy[cch - 1] == '\\')
    494                                &&  pszCopy[cch - 1] != ':');
    495                         rc2 = chdir(pszCopy);
    496                         free(pszCopy);
    497                         if (!rc2)
    498                             continue;
    499                     }
    500                 }
    501 #endif
    502                 fprintf(pStdErr, "%s: error: chdir(\"%s\"): %s\n", name(argv[0]), psz, strerror(errno));
    503                 return 1;
    504             }
    505 
    506             /*
    507              * Zap environment switch?
    508              * This is a bit of a hack.
    509              */
    510             if (*psz == 'Z')
    511             {
    512                 unsigned j = 0;
    513                 while (envp[j] != NULL)
    514                     j++;
    515                 while (j-- > 0)
    516                 {
    517                     char *pszEqual = strchr(envp[j], '=');
    518                     char *pszCopy;
    519 
    520                     if (pszEqual)
    521                         *pszEqual = '\0';
    522                     pszCopy = strdup(envp[j]);
    523                     if (pszEqual)
    524                         *pszEqual = '=';
    525 
    526 #if defined(_MSC_VER) || defined(__OS2__)
    527                     putenv(pszCopy);
    528 #else
    529                     unsetenv(pszCopy);
    530 #endif
    531                     free(pszCopy);
    532                 }
    533                 continue;
    534             }
    535 
    536             /*
    537              * Verbose operation switch?
    538              */
    539             if (*psz == 'v')
    540             {
    541                 g_cVerbosity++;
    542                 continue;
    543             }
    544 
    545             /*
    546              * Close the specified file descriptor (no stderr/out/in aliases).
    547              */
    548             if (*psz == 'c')
    549             {
    550                 psz++;
    551                 if (!*psz)
    552                 {
    553                     i++;
    554                     if (i >= argc)
    555                     {
    556                         fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
    557                         return 1;
    558                     }
    559                     psz = argv[i];
    560                 }
    561 
    562                 fd = (int)strtol(psz, &psz, 0);
    563                 if (!fd || *psz)
    564                 {
    565                     fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
    566                     return 1;
    567 
    568                 }
    569                 if (fd < 0)
    570                 {
    571                     fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
    572                     return 1;
    573                 }
    574                 /** @todo deal with stderr */
    575                 safeCloseFd(fd);
    576                 continue;
    577             }
    578 
    579             /*
    580              * Parse a file descriptor argument.
    581              */
    582 
    583             /* mode */
    584             switch (*psz)
    585             {
    586                 case 'r':
    587                     psz++;
    588                     if (*psz == '+')
    589                     {
    590                         fOpen = O_RDWR;
    591                         psz++;
    592                     }
    593                     else
    594                         fOpen = O_RDONLY;
    595                     break;
    596 
    597                 case 'w':
    598                     psz++;
    599                     if (*psz == '+')
    600                     {
    601                         psz++;
    602                         fOpen = O_RDWR | O_CREAT | O_TRUNC;
    603                     }
    604                     else
    605                         fOpen = O_WRONLY | O_CREAT | O_TRUNC;
    606                     break;
    607 
    608                 case 'a':
    609                     psz++;
    610                     if (*psz == '+')
    611                     {
    612                         psz++;
    613                         fOpen = O_RDWR | O_CREAT | O_APPEND;
    614                     }
    615                     else
    616                         fOpen = O_WRONLY | O_CREAT | O_APPEND;
    617                     break;
    618 
    619                 case 'i': /* make sure stdin is read-only. */
    620                     fOpen = O_RDONLY;
    621                     break;
    622 
    623                 case '+':
    624                     fprintf(pStdErr, "%s: syntax error: Unexpected '+' in '%s'\n", name(argv[0]), argv[i]);
    625                     return 1;
    626 
    627                 default:
    628                     fOpen = O_RDWR | O_CREAT | O_TRUNC;
    629                     break;
    630             }
    631 
    632             /* binary / text modifiers */
    633             switch (*psz)
    634             {
    635                 case 'b':
    636 #ifdef O_BINARY
    637                     fOpen |= O_BINARY;
    638 #endif
    639                     psz++;
    640                     break;
    641 
    642                 case 't':
    643 #ifdef O_TEXT
    644                     fOpen |= O_TEXT;
    645 #endif
    646                     psz++;
    647                     break;
    648 
    649                 default:
    650 #ifdef O_BINARY
    651                     fOpen |= O_BINARY;
    652 #endif
    653                     break;
    654 
    655             }
    656 
    657             /* convert to file descriptor number */
    658             switch (*psz)
    659             {
    660                 case 'i':
    661                     fd = 0;
    662                     psz++;
    663                     break;
    664 
    665                 case 'o':
    666                     fd = 1;
    667                     psz++;
    668                     break;
    669 
    670                 case 'e':
    671                     fd = 2;
    672                     psz++;
    673                     break;
    674 
    675                 case '0':
    676                     if (!psz[1])
    677                     {
    678                         fd = 0;
    679                         psz++;
    680                         break;
    681                     }
    682                 case '1':
    683                 case '2':
    684                 case '3':
    685                 case '4':
    686                 case '5':
    687                 case '6':
    688                 case '7':
    689                 case '8':
    690                 case '9':
    691                     fd = (int)strtol(psz, &psz, 0);
    692                     if (!fd)
    693                     {
    694                         fprintf(pStdErr, "%s: error: failed to convert '%s' to a number\n", name(argv[0]), argv[i]);
    695                         return 1;
    696 
    697                     }
    698                     if (fd < 0)
    699                     {
    700                         fprintf(pStdErr, "%s: error: negative fd %d (%s)\n", name(argv[0]), fd, argv[i]);
    701                         return 1;
    702                     }
    703                     break;
    704 
    705                 /*
    706                  * Invalid argument.
    707                  */
    708                 default:
    709                     fprintf(pStdErr, "%s: error: failed to convert '%s' ('%s') to a file descriptor\n", name(argv[0]), psz, argv[i]);
    710                     return 1;
    711             }
    712 
    713             /*
    714              * Check for the filename.
    715              */
    716             if (*psz)
    717             {
    718                 if (*psz != ':' && *psz != '=')
    719                 {
    720                     fprintf(pStdErr, "%s: syntax error: characters following the file descriptor: '%s' ('%s')\n", name(argv[0]), psz, argv[i]);
    721                     return 1;
    722                 }
    723                 psz++;
     176                    errx(1, "Incomplete option: '-'");
     177                    return usage(stderr, argv[0]);
     178                }
    724179            }
    725180            else
    726181            {
    727                 i++;
    728                 if (i >= argc)
    729                 {
    730                     fprintf(pStdErr, "%s: syntax error: missing filename argument.\n", name(argv[0]));
    731                     return 1;
    732                 }
    733                 psz = argv[i];
     182                pszArg++;
     183
     184                /* '--' indicates where the bits to execute start. */
     185                if (*pszArg == '\0')
     186                {
     187                    iArg++;
     188                    break;
     189                }
     190
     191                if (strcmp(pszArg, "watcom-brain-damage") == 0)
     192                {
     193                    fWatcomBrainDamage = 1;
     194                    continue;
     195                }
     196
     197                /* convert to short. */
     198                if (strcmp(pszArg, "help") == 0)
     199                    chOpt = 'h';
     200                else if (strcmp(pszArg, "version") == 0)
     201                    chOpt = 'V';
     202                else if (strcmp(pszArg, "set") == 0)
     203                    chOpt = 'E';
     204                else if (strcmp(pszArg, "unset") == 0)
     205                    chOpt = 'U';
     206                else if (   strcmp(pszArg, "zap-env") == 0
     207                         || strcmp(pszArg, "ignore-environment") == 0 /* GNU env compatibility. */ )
     208                    chOpt = 'Z';
     209                else if (strcmp(pszArg, "chdir") == 0)
     210                    chOpt = 'C';
     211                else if (strcmp(pszArg, "32-bit") == 0)
     212                    chOpt = '3';
     213                else if (strcmp(pszArg, "64-bit") == 0)
     214                    chOpt = '6';
     215                else if (strcmp(pszArg, "verbose") == 0)
     216                    chOpt = 'v';
     217                else
     218                {
     219                    errx(1, "Unknown option: '%s'", pszArg - 2);
     220                    return usage(stderr, argv[0]);
     221                }
     222                pszArg = "";
    734223            }
    735224
    736             /*
    737              * Setup the redirection.
    738              */
    739             if (fd == fileno(pStdErr))
     225            do
    740226            {
    741                 /*
    742                  * Move stderr to a new location, making it close on exec.
    743                  * If pStdOut has already teamed up with pStdErr, update it too.
    744                  */
    745                 FILE *pNew;
    746                 fdOpened = dup(fileno(pStdErr));
    747                 if (fdOpened == -1)
    748                 {
    749                     fprintf(pStdErr, "%s: error: failed to dup stderr (%d): %s\n", name(argv[0]), fileno(pStdErr), strerror(errno));
    750                     return 1;
    751                 }
    752 #ifdef _MSC_VER
    753                 /** @todo figure out how to make the handle close-on-exec. We'll simply close it for now.
    754                  * SetHandleInformation + set FNOINHERIT in CRT.
    755                  */
     227                /* Get option value first, if the option takes one. */
     228                const char *pszValue = NULL;
     229                switch (chOpt)
     230                {
     231                    case 'E':
     232                    case 'U':
     233                    case 'C':
     234                        if (*pszArg != '\0')
     235                            pszValue = pszArg + (*pszArg == ':' || *pszArg == '=');
     236                        else if (++iArg < argc)
     237                            pszValue = argv[iArg];
     238                        else
     239                        {
     240                            errx(1, "Option -%c requires an value!", chOpt);
     241                            return usage(stderr, argv[0]);
     242                        }
     243                        break;
     244                }
     245
     246                switch (chOpt)
     247                {
     248                    case 'Z':
     249                    case 'i': /* GNU env compatibility. */
     250                        for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
     251                            free(papszEnv[iEnvVar]);
     252                        papszEnv[0] = NULL;
     253                        cEnvVars = 0;
     254                        break;
     255
     256                    case 'E':
     257                    {
     258                        const char *pszEqual = strchr(pszValue, '=');
     259                        if (pszEqual)
     260                        {
     261                            size_t const cchVar = pszValue - pszEqual;
     262                            for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
     263                                if (   strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
     264                                    && papszEnv[iEnvVar][cchVar] == '=')
     265                                {
     266                                    if (cVerbosity > 0)
     267                                        fprintf(stderr, "kSubmit: replacing '%s' with '%s'\n", papszEnv[iEnvVar], pszValue);
     268                                    free(papszEnv[iEnvVar]);
     269                                    papszEnv[iEnvVar] = xstrdup(pszValue);
     270                                    break;
     271                                }
     272                            if (iEnvVar == cEnvVars)
     273                            {
     274                                /* Append new variable. We probably need to resize the vector. */
     275                                if ((cEnvVars + 2) > cAllocatedEnvVars)
     276                                {
     277                                    cAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
     278                                    pChild->environment = papszEnv = (char **)xrealloc(papszEnv,
     279                                                                                       cAllocatedEnvVars * sizeof(papszEnv[0]));
     280                                }
     281                                papszEnv[cEnvVars++] = xstrdup(pszValue);
     282                                papszEnv[cEnvVars]   = NULL;
     283                                if (cVerbosity > 0)
     284                                    fprintf(stderr, "kSubmit: added '%s'\n", papszEnv[iEnvVar]);
     285                            }
     286                            else
     287                            {
     288                                /* Check for duplicates. */
     289                                for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
     290                                    if (   strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
     291                                        && papszEnv[iEnvVar][cchVar] == '=')
     292                                    {
     293                                        if (cVerbosity > 0)
     294                                            fprintf(stderr, "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
     295                                        free(papszEnv[iEnvVar]);
     296                                        cEnvVars--;
     297                                        if (iEnvVar != cEnvVars)
     298                                            papszEnv[iEnvVar] = papszEnv[cEnvVars];
     299                                        papszEnv[cEnvVars] = NULL;
     300                                        iEnvVar--;
     301                                    }
     302                            }
     303                        }
     304                        else
     305                            return errx(1, "Missing '=': -E %s", pszValue);
     306                        break;
     307                    }
     308
     309                    case 'U':
     310                    {
     311                        if (strchr(pszValue, '=') == NULL)
     312                        {
     313                            unsigned     cRemoved = 0;
     314                            size_t const cchVar = strlen(pszValue);
     315                            for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
     316                                if (   strncmp(papszEnv[iEnvVar], pszValue, cchVar) == 0
     317                                    && papszEnv[iEnvVar][cchVar] == '=')
     318                                {
     319                                    if (cVerbosity > 0)
     320                                        fprintf(stderr, !cRemoved ? "kSubmit: removing '%s'\n"
     321                                                : "kSubmit: removing duplicate '%s'\n", papszEnv[iEnvVar]);
     322                                    free(papszEnv[iEnvVar]);
     323                                    cEnvVars--;
     324                                    if (iEnvVar != cEnvVars)
     325                                        papszEnv[iEnvVar] = papszEnv[cEnvVars];
     326                                    papszEnv[cEnvVars] = NULL;
     327                                    cRemoved++;
     328                                    iEnvVar--;
     329                                }
     330                            if (cVerbosity > 0 && !cRemoved)
     331                                fprintf(stderr, "kSubmit: not found '%s'\n", pszValue);
     332                        }
     333                        else
     334                            return errx(1, "Found invalid variable name character '=' in: -U %s", pszValue);
     335                        break;
     336                    }
     337
     338                    case 'C':
     339                    {
     340                        size_t cchNewCwd = strlen(pszValue);
     341                        size_t offDst;
     342                        if (cchNewCwd)
     343                        {
     344#ifdef HAVE_DOS_PATHS
     345                            if (*pszValue == '/' || *pszValue == '\\')
     346                            {
     347                                if (pszValue[1] == '/' || pszValue[1] == '\\')
     348                                    offDst = 0; /* UNC */
     349                                else if (szCwd[1] == ':' && isalpha(szCwd[0]))
     350                                    offDst = 2; /* Take drive letter from CWD. */
     351                                else
     352                                    return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", szCwd, pszValue);
     353                            }
     354                            else if (   pszValue[1] == ':'
     355                                     && isalpha(pszValue[0]))
     356                            {
     357                                if (pszValue[2] == '/'|| pszValue[2] == '\\')
     358                                    offDst = 0; /* DOS style absolute path. */
     359                                else if (   szCwd[1] == ':'
     360                                         && tolower(szCwd[0]) == tolower(pszValue[0]) )
     361                                {
     362                                    pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
     363                                    cchNewCwd -= 2;
     364                                    offDst = strlen(szCwd);
     365                                }
     366                                else
     367                                {
     368                                    /* Get current CWD on the specified drive and append value. */
     369                                    int iDrive = tolower(pszValue[0]) - 'a' + 1;
     370                                    if (!_getdcwd(iDrive, szCwd, cbCwdBuf))
     371                                        return err(1, "_getdcwd(%d,,) failed", iDrive);
     372                                    pszValue += 2;
     373                                    cchNewCwd -= 2;
     374                                }
     375                            }
    756376#else
    757                 if (fcntl(fdOpened, F_SETFD, FD_CLOEXEC) == -1)
    758                 {
    759                     fprintf(pStdErr, "%s: error: failed to make stderr (%d) close-on-exec: %s\n", name(argv[0]), fdOpened, strerror(errno));
    760                     return 1;
    761                 }
    762 #endif
    763 
    764                 pNew = fdopen(fdOpened, "w");
    765                 if (!pNew)
    766                 {
    767                     fprintf(pStdErr, "%s: error: failed to fdopen the new stderr (%d): %s\n", name(argv[0]), fdOpened, strerror(errno));
    768                     return 1;
    769                 }
    770                 if (pStdOut == pStdErr)
    771                     pStdOut = pNew;
    772                 pStdErr = pNew;
    773             }
    774             else if (fd == 1 && pStdOut != pStdErr)
    775                 pStdOut = pStdErr;
    776 
    777             /*
    778              * Close and open the new file descriptor.
    779              */
    780             safeCloseFd(fd);
    781 #if defined(_MSC_VER)
    782             if (!strcmp(psz, "/dev/null"))
    783                 psz = (char *)"nul";
    784 #endif
    785             fdOpened = open(psz, fOpen, 0666);
    786             if (fdOpened == -1)
    787             {
    788                 fprintf(pStdErr, "%s: error: failed to open '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
    789                 return 1;
    790             }
    791             if (fdOpened != fd)
    792             {
    793                 /* move it (dup2 returns 0 on MSC). */
    794                 if (dup2(fdOpened, fd) == -1)
    795                 {
    796                     fprintf(pStdErr, "%s: error: failed to dup '%s' as %d: %s\n", name(argv[0]), psz, fd, strerror(errno));
    797                     return 1;
    798                 }
    799                 close(fdOpened);
    800             }
     377                            if (*pszValue == '/')
     378                                offDst = 0;
     379#endif
     380                            else
     381                                offDst = strlen(szCwd); /* Relative path, append to the existing CWD value. */
     382
     383                            /* Do the copying. */
     384#ifdef HAVE_DOS_PATHS
     385                            if (offDst > 0 && szCwd[offDst - 1] != '/' && szCwd[offDst - 1] != '\\')
     386#else
     387                            if (offDst > 0 && szCwd[offDst - 1] != '/')
     388#endif
     389                                 szCwd[offDst++] = '/';
     390                            if (offDst + cchNewCwd >= cbCwdBuf)
     391                                return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, szCwd, pszValue);
     392                            memcpy(&szCwd[offDst], pszValue, cchNewCwd + 1);
     393                        }
     394                        /* else: relative, no change - quitely ignore. */
     395                        break;
     396                    }
     397
     398                    case '3':
     399                        cBitsWorker = 32;
     400                        break;
     401
     402                    case '6':
     403                        cBitsWorker = 64;
     404                        break;
     405
     406                    case 'v':
     407                        cVerbosity++;
     408                        break;
     409
     410                    case 'h':
     411                        usage(stdout, argv[0]);
     412                        return 0;
     413
     414                    case 'V':
     415                        printf("kmk_submit - kBuild version %d.%d.%d (r%u)\n"
     416                               "Copyright (C) 2007-2016 knut st. osmundsen\n",
     417                               KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
     418                               KBUILD_SVN_REV);
     419                        return 0;
     420                }
     421            } while ((chOpt = *pszArg++) != '\0');
    801422        }
    802423        else
    803424        {
    804             fprintf(pStdErr, "%s: syntax error: Invalid argument '%s'.\n", name(argv[0]), argv[i]);
    805             return usage(pStdErr, name(argv[0]));
     425            errx(1, "Unknown argument: '%s'", pszArg);
     426            return usage(stderr, argv[0]);
    806427        }
    807428    }
    808429
    809430    /*
    810      * Make sure there's something to execute.
     431     * Check that we've got something to execute.
    811432     */
    812     if (i >= argc)
     433    if (iArg < argc)
    813434    {
    814         fprintf(pStdErr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
    815         return usage(pStdErr, name(argv[0]));
     435
    816436    }
    817 
    818 #if defined(_MSC_VER)
    819     if (fileno(pStdErr) != 2) /* no close-on-exec flag on windows */
     437    else
    820438    {
    821         fclose(pStdErr);
    822         pStdErr = NULL;
     439        errx(1, "Nothing to executed!");
     440        rcExit = usage(stderr, argv[0]);
    823441    }
    824442
    825     /* MSC is a PITA since it refuses to quote the arguments... */
    826     quoteArguments(argc - i, &argv[i], fWatcomBrainDamage, pStdErr);
    827     rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
    828     if (rc == -1 && pStdErr)
    829     {
    830         fprintf(pStdErr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
    831         rc = 1;
    832     }
    833     return rc;
    834 #else
    835     if (g_cVerbosity > 0)
    836         for (j = i; j < argc; j++)
    837             fprintf(pStdErr, "kmk_redirect: debug: argv[%i]=%s<eos>\n", j - i, argv[j]);
    838     execvp(argv[i], &argv[i]);
    839     fprintf(pStdErr, "%s: error: _execvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
    840     return 1;
    841 #endif
     443    return rcExit;
    842444}
    843445
     446
     447
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