Changeset 3210 for trunk/src/kmk


Ignore:
Timestamp:
Mar 29, 2018, 4:51:12 PM (7 years ago)
Author:
bird
Message:

kmk_redirect: Added a --stdin-pipe option for tricking a windows rsh implementation into not stopping when stdin is redirected to /dev/null and appears to be empty when read()'ing it.

File:
1 edited

Legend:

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

    r3207 r3210  
    114114{
    115115    kmk_builtin_ctx_printf(pCtx, fIsErr,
    116                            "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>]\n"
     116                           "usage: %s [-[rwa+tb]<fd> <file>] [-d<fd>=<src-fd>] [-c<fd>] [--stdin-pipe]\n"
    117117                           "           [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage]\n"
    118118                           "           [-v] -- <program> [args]\n"
     
    127127                           "\n"
    128128                           "The -d switch duplicate the right hand file descriptor (src-fd) to the left\n"
    129                            "hand side one (fd). The latter is limited to standard handles on windows.\n"
     129                           "hand side one (fd).  The latter is limited to standard handles on windows.\n"
    130130                           "\n"
    131131                           "The -c switch will close the specified file descriptor. Limited to standard\n"
    132132                           "handles on windows.\n"
     133                           "\n"
     134                           "The --stdin-pipe switch will replace stdin with the read end of an anonymous\n"
     135                           "pipe.  This is for tricking things like rsh.exe that blocks reading on stdin.\n"
    133136                           "\n"
    134137                           "The -Z switch zaps the environment.\n"
     
    178181    /** The filename - NULL if close only. */
    179182    const char *pszFilename;
     183    /** The other pipe end, needs closing in cleanup. */
     184    int         fdOtherPipeEnd;
    180185#ifndef USE_POSIX_SPAWN
    181186    /** Saved file descriptor. */
     
    197202    return K_FALSE;
    198203#endif
     204}
     205
     206
     207/**
     208 * Creates a pair of pipe descriptors that does not conflict with any previous
     209 * orders.
     210 *
     211 * The pipe is open with both descriptors being inherited by the child as it's
     212 * supposed to be a dummy pipe for stdin that won't break.
     213 *
     214 * @returns 0 on success, exit code on failure (error message displayed).
     215 * @param   pCtx                The command execution context.
     216 * @param   paFds               Where to return the pipe descriptors
     217 * @param   cOrders             The number of orders.
     218 * @param   paOrders            The order array.
     219 * @param   fdTarget            The target descriptor (0).
     220 */
     221static int kRedirectCreateStdInPipeWithoutConflict(PKMKBUILTINCTX pCtx, int paFds[2],
     222                                                   unsigned cOrders, REDIRECTORDERS *paOrders, int fdTarget)
     223{
     224    struct
     225    {
     226        int     aFds[2];
     227    }           aTries[32];
     228    unsigned    cTries = 0;
     229
     230    while (cTries < K_ELEMENTS(aTries))
     231    {
     232#ifdef _MSC_VER
     233        int rc = _pipe(aTries[cTries].aFds, 0, _O_BINARY);
     234#else
     235        int rc = pipe(aTries[cTries].aFds);
     236#endif
     237        if (rc >= 0)
     238        {
     239            if (   !kRedirectHasConflict(aTries[cTries].aFds[0], cOrders, paOrders)
     240                && !kRedirectHasConflict(aTries[cTries].aFds[1], cOrders, paOrders)
     241#ifndef _MSC_VER
     242                && aTries[cTries].aFds[0] != fdTarget
     243                && aTries[cTries].aFds[1] != fdTarget
     244#endif
     245                )
     246            {
     247                paFds[0] = aTries[cTries].aFds[0];
     248                paFds[1] = aTries[cTries].aFds[1];
     249
     250                while (cTries-- > 0)
     251                {
     252                    close(aTries[cTries].aFds[0]);
     253                    close(aTries[cTries].aFds[1]);
     254                }
     255                return 0;
     256            }
     257        }
     258        else
     259        {
     260            err(pCtx, -1, "failed to create stdin pipe (try #%u)", cTries + 1);
     261            break;
     262        }
     263        cTries++;
     264    }
     265    if (cTries >= K_ELEMENTS(aTries))
     266        errx(pCtx, -1, "failed to find a conflict free pair of pipe descriptor for stdin!");
     267
     268    /* cleanup */
     269    while (cTries-- > 0)
     270    {
     271        close(aTries[cTries].aFds[0]);
     272        close(aTries[cTries].aFds[1]);
     273    }
     274    return 1;
    199275}
    200276
     
    331407            close(paOrders[i].fdSource);
    332408            paOrders[i].fdSource = -1;
     409
     410            if (paOrders[i].fdOtherPipeEnd >= 0)
     411            {
     412                close(paOrders[i].fdOtherPipeEnd);
     413                paOrders[i].fdOtherPipeEnd = -1;
     414            }
     415
    333416            if (   fFailure
    334417                && paOrders[i].fRemoveOnFailure
     
    9201003                                   FALSE /*fInheritHandles*/, CREATE_SUSPENDED, pszzEnv, pszCwd, &StartupInfo, &ProcInfo))
    9211004                {
     1005                    unsigned  i;
     1006
    9221007                    /* Inject the handles and try make it start executing. */
    9231008                    char szErrMsg[128];
     
    9271012                    else if (!ResumeThread(ProcInfo.hThread))
    9281013                        rc = errx(pCtx, 10, "ResumeThread failed: %u", GetLastError());
     1014
     1015                    /* Duplicate the write end of any stdin pipe handles into the child. */
     1016                    for (i = 0; i < cOrders; i++)
     1017                        if (paOrders[cOrders].fdOtherPipeEnd >= 0)
     1018                        {
     1019                            HANDLE hIgnored = INVALID_HANDLE_VALUE;
     1020                            HANDLE hPipeW   = (HANDLE)_get_osfhandle(paOrders[i].fdOtherPipeEnd);
     1021                            if (!DuplicateHandle(GetCurrentProcess(), hPipeW, ProcInfo.hProcess, &hIgnored, 0 /*fDesiredAccess*/,
     1022                                                 TRUE /*fInheritable*/, DUPLICATE_SAME_ACCESS))
     1023                                rc = errx(pCtx, 10, "DuplicateHandle failed on other stdin pipe end %d/%p: %u",
     1024                                          paOrders[i].fdOtherPipeEnd, hPipeW, GetLastError());
     1025                        }
    9291026
    9301027                    /* Kill it if any of that fails. */
     
    13651462                else if (strcmp(pszArg, "verbose") == 0)
    13661463                    chOpt = 'v';
     1464                else if (strcmp(pszArg, "stdin-pipe") == 0)
     1465                    chOpt = 'I';
    13671466                else
    13681467                {
     
    15601659
    15611660            /*
    1562              * Okay, it is some file descriptor opearation.  Make sure we've got room for it.
     1661             * Okay, it is some file descriptor operation.  Make sure we've got room for it.
    15631662             */
    15641663            if (cOrders + 1 < K_ELEMENTS(aOrders))
     
    15691668                aOrders[cOrders].fRemoveOnFailure = 0;
    15701669                aOrders[cOrders].pszFilename      = NULL;
     1670                aOrders[cOrders].fdOtherPipeEnd   = -1;
    15711671#ifndef USE_POSIX_SPAWN
    15721672                aOrders[cOrders].fdSaved          = -1;
     
    16431743#endif
    16441744                    }
     1745                }
     1746            }
     1747            else if (chOpt == 'I')
     1748            {
     1749                /*
     1750                 * Replace stdin with the read end of an anonymous pipe.
     1751                 */
     1752                int aFds[2] = { -1, -1 };
     1753                rcExit = kRedirectCreateStdInPipeWithoutConflict(pCtx, aFds, cOrders, aOrders,  0 /*fdTarget*/);
     1754                if (rcExit == 0)
     1755                {
     1756                    aOrders[cOrders].enmOrder       = kRedirectOrder_Dup;
     1757                    aOrders[cOrders].fdTarget       = 0;
     1758                    aOrders[cOrders].fdSource       = aFds[0];
     1759                    aOrders[cOrders].fdOtherPipeEnd = aFds[1];
     1760                    cOrders++;
     1761#ifdef USE_POSIX_SPAWN
     1762                    rcExit = posix_spawn_file_actions_adddup2(&FileActions, aFds[0], 0);
     1763                    if (rcExit != 0)
     1764                        rcExit = errx(pCtx, 2, "posix_spawn_file_actions_addclose(%d) failed: %s", fd, strerror(rcExit));
     1765#endif
    16451766                }
    16461767            }
Note: See TracChangeset for help on using the changeset viewer.