tclUnixPipe.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:33k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUnixPipe.c --
  3.  *
  4.  * This file implements the UNIX-specific exec pipeline functions,
  5.  * the "pipe" channel driver, and the "pid" Tcl command.
  6.  *
  7.  * Copyright (c) 1991-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tclUnixPipe.c,v 1.23.2.7 2006/08/02 20:04:40 das Exp $
  14.  */
  15. #include "tclInt.h"
  16. #include "tclPort.h"
  17. #ifdef USE_VFORK
  18. #define fork vfork
  19. #endif
  20. /*
  21.  * The following macros convert between TclFile's and fd's.  The conversion
  22.  * simple involves shifting fd's up by one to ensure that no valid fd is ever
  23.  * the same as NULL.
  24.  */
  25. #define MakeFile(fd) ((TclFile)(((int)fd)+1))
  26. #define GetFd(file) (((int)file)-1)
  27. /*
  28.  * This structure describes per-instance state of a pipe based channel.
  29.  */
  30. typedef struct PipeState {
  31.     Tcl_Channel channel;/* Channel associated with this file. */
  32.     TclFile inFile; /* Output from pipe. */
  33.     TclFile outFile; /* Input to pipe. */
  34.     TclFile errorFile; /* Error output from pipe. */
  35.     int numPids; /* How many processes are attached to this pipe? */
  36.     Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
  37.                          * the creator of the pipe. */
  38.     int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode.
  39.                          * Used to decide whether to wait for the children
  40.                          * at close time. */
  41. } PipeState;
  42. /*
  43.  * Declarations for local procedures defined in this file:
  44.  */
  45. static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
  46.     int mode));
  47. static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
  48.     Tcl_Interp *interp));
  49. static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
  50.     int direction, ClientData *handlePtr));
  51. static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
  52.     char *buf, int toRead, int *errorCode));
  53. static int PipeOutputProc _ANSI_ARGS_((
  54.     ClientData instanceData, CONST char *buf, int toWrite,
  55.     int *errorCode));
  56. static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
  57. static void RestoreSignals _ANSI_ARGS_((void));
  58. static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
  59. /*
  60.  * This structure describes the channel type structure for command pipe
  61.  * based IO:
  62.  */
  63. static Tcl_ChannelType pipeChannelType = {
  64.     "pipe", /* Type name. */
  65.     TCL_CHANNEL_VERSION_4, /* v4 channel */
  66.     PipeCloseProc, /* Close proc. */
  67.     PipeInputProc, /* Input proc. */
  68.     PipeOutputProc, /* Output proc. */
  69.     NULL, /* Seek proc. */
  70.     NULL, /* Set option proc. */
  71.     NULL, /* Get option proc. */
  72.     PipeWatchProc, /* Initialize notifier. */
  73.     PipeGetHandleProc, /* Get OS handles out of channel. */
  74.     NULL, /* close2proc. */
  75.     PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
  76.     NULL, /* flush proc. */
  77.     NULL, /* handler proc. */
  78.     NULL,                       /* wide seek proc */
  79.     NULL,                       /* thread action proc */
  80. };
  81. /*
  82.  *----------------------------------------------------------------------
  83.  *
  84.  * TclpMakeFile --
  85.  *
  86.  * Make a TclFile from a channel.
  87.  *
  88.  * Results:
  89.  * Returns a new TclFile or NULL on failure.
  90.  *
  91.  * Side effects:
  92.  * None.
  93.  *
  94.  *----------------------------------------------------------------------
  95.  */
  96. TclFile
  97. TclpMakeFile(channel, direction)
  98.     Tcl_Channel channel; /* Channel to get file from. */
  99.     int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
  100. {
  101.     ClientData data;
  102.     if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data)
  103.     == TCL_OK) {
  104. return MakeFile((int)data);
  105.     } else {
  106. return (TclFile) NULL;
  107.     }
  108. }
  109. /*
  110.  *----------------------------------------------------------------------
  111.  *
  112.  * TclpOpenFile --
  113.  *
  114.  * Open a file for use in a pipeline.  
  115.  *
  116.  * Results:
  117.  * Returns a new TclFile handle or NULL on failure.
  118.  *
  119.  * Side effects:
  120.  * May cause a file to be created on the file system.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124. TclFile
  125. TclpOpenFile(fname, mode)
  126.     CONST char *fname; /* The name of the file to open. */
  127.     int mode; /* In what mode to open the file? */
  128. {
  129.     int fd;
  130.     CONST char *native;
  131.     Tcl_DString ds;
  132.     native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
  133.     fd = TclOSopen(native, mode, 0666); /* INTL: Native. */
  134.     Tcl_DStringFree(&ds);
  135.     if (fd != -1) {
  136.         fcntl(fd, F_SETFD, FD_CLOEXEC);
  137. /*
  138.  * If the file is being opened for writing, seek to the end
  139.  * so we can append to any data already in the file.
  140.  */
  141. if ((mode & O_WRONLY) && !(mode & O_APPEND)) {
  142.     TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END);
  143. }
  144. /*
  145.  * Increment the fd so it can't be 0, which would conflict with
  146.  * the NULL return for errors.
  147.  */
  148. return MakeFile(fd);
  149.     }
  150.     return NULL;
  151. }
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * TclpCreateTempFile --
  156.  *
  157.  * This function creates a temporary file initialized with an
  158.  * optional string, and returns a file handle with the file pointer
  159.  * at the beginning of the file.
  160.  *
  161.  * Results:
  162.  * A handle to a file.
  163.  *
  164.  * Side effects:
  165.  * None.
  166.  *
  167.  *----------------------------------------------------------------------
  168.  */
  169. TclFile
  170. TclpCreateTempFile(contents)
  171.     CONST char *contents; /* String to write into temp file, or NULL. */
  172. {
  173.     char fileName[L_tmpnam + 9];
  174.     CONST char *native;
  175.     Tcl_DString dstring;
  176.     int fd;
  177.     /*
  178.      * We should also check against making more then TMP_MAX of these.
  179.      */
  180.     strcpy(fileName, P_tmpdir); /* INTL: Native. */
  181.     if (fileName[strlen(fileName) - 1] != '/') {
  182. strcat(fileName, "/"); /* INTL: Native. */
  183.     }
  184.     strcat(fileName, "tclXXXXXX");
  185.     fd = mkstemp(fileName); /* INTL: Native. */
  186.     if (fd == -1) {
  187. return NULL;
  188.     }
  189.     fcntl(fd, F_SETFD, FD_CLOEXEC);
  190.     unlink(fileName); /* INTL: Native. */
  191.     if (contents != NULL) {
  192. native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
  193. if (write(fd, native, strlen(native)) == -1) {
  194.     close(fd);
  195.     Tcl_DStringFree(&dstring);
  196.     return NULL;
  197. }
  198. Tcl_DStringFree(&dstring);
  199. TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET);
  200.     }
  201.     return MakeFile(fd);
  202. }
  203. /*
  204.  *----------------------------------------------------------------------
  205.  *
  206.  * TclpTempFileName --
  207.  *
  208.  * This function returns unique filename.
  209.  *
  210.  * Results:
  211.  * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure.
  212.  *
  213.  * Side effects:
  214.  * None.
  215.  *
  216.  *----------------------------------------------------------------------
  217.  */
  218. Tcl_Obj* 
  219. TclpTempFileName()
  220. {
  221.     char fileName[L_tmpnam + 9];
  222.     Tcl_Obj *result = NULL;
  223.     int fd;
  224.     /*
  225.      * We should also check against making more then TMP_MAX of these.
  226.      */
  227.     strcpy(fileName, P_tmpdir); /* INTL: Native. */
  228.     if (fileName[strlen(fileName) - 1] != '/') {
  229. strcat(fileName, "/"); /* INTL: Native. */
  230.     }
  231.     strcat(fileName, "tclXXXXXX");
  232.     fd = mkstemp(fileName); /* INTL: Native. */
  233.     if (fd == -1) {
  234. return NULL;
  235.     }
  236.     fcntl(fd, F_SETFD, FD_CLOEXEC);
  237.     unlink(fileName); /* INTL: Native. */
  238.     result = TclpNativeToNormalized((ClientData) fileName);
  239.     close (fd);
  240.     return result;
  241. }
  242. /*
  243.  *----------------------------------------------------------------------
  244.  *
  245.  * TclpCreatePipe --
  246.  *
  247.  *      Creates a pipe - simply calls the pipe() function.
  248.  *
  249.  * Results:
  250.  *      Returns 1 on success, 0 on failure. 
  251.  *
  252.  * Side effects:
  253.  *      Creates a pipe.
  254.  *
  255.  *----------------------------------------------------------------------
  256.  */
  257. int
  258. TclpCreatePipe(readPipe, writePipe)
  259.     TclFile *readPipe; /* Location to store file handle for
  260.  * read side of pipe. */
  261.     TclFile *writePipe; /* Location to store file handle for
  262.  * write side of pipe. */
  263. {
  264.     int pipeIds[2];
  265.     if (pipe(pipeIds) != 0) {
  266. return 0;
  267.     }
  268.     fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);
  269.     fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);
  270.     *readPipe = MakeFile(pipeIds[0]);
  271.     *writePipe = MakeFile(pipeIds[1]);
  272.     return 1;
  273. }
  274. /*
  275.  *----------------------------------------------------------------------
  276.  *
  277.  * TclpCloseFile --
  278.  *
  279.  * Implements a mechanism to close a UNIX file.
  280.  *
  281.  * Results:
  282.  * Returns 0 on success, or -1 on error, setting errno.
  283.  *
  284.  * Side effects:
  285.  * The file is closed.
  286.  *
  287.  *----------------------------------------------------------------------
  288.  */
  289. int
  290. TclpCloseFile(file)
  291.     TclFile file; /* The file to close. */
  292. {
  293.     int fd = GetFd(file);
  294.     /*
  295.      * Refuse to close the fds for stdin, stdout and stderr.
  296.      */
  297.     
  298.     if ((fd == 0) || (fd == 1) || (fd == 2)) {
  299.         return 0;
  300.     }
  301.     
  302.     Tcl_DeleteFileHandler(fd);
  303.     return close(fd);
  304. }
  305. /*
  306.  *---------------------------------------------------------------------------
  307.  *
  308.  * TclpCreateProcess --
  309.  *
  310.  * Create a child process that has the specified files as its 
  311.  * standard input, output, and error.  The child process runs
  312.  * asynchronously and runs with the same environment variables
  313.  * as the creating process.
  314.  *
  315.  * The path is searched to find the specified executable.  
  316.  *
  317.  * Results:
  318.  * The return value is TCL_ERROR and an error message is left in
  319.  * the interp's result if there was a problem creating the child 
  320.  * process.  Otherwise, the return value is TCL_OK and *pidPtr is
  321.  * filled with the process id of the child process.
  322.  * 
  323.  * Side effects:
  324.  * A process is created.
  325.  *
  326.  *---------------------------------------------------------------------------
  327.  */
  328.     /* ARGSUSED */
  329. int
  330. TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile, 
  331. pidPtr)
  332.     Tcl_Interp *interp; /* Interpreter in which to leave errors that
  333.  * occurred when creating the child process.
  334.  * Error messages from the child process
  335.  * itself are sent to errorFile. */
  336.     int argc; /* Number of arguments in following array. */
  337.     CONST char **argv; /* Array of argument strings in UTF-8.
  338.  * argv[0] contains the name of the executable
  339.  * translated using Tcl_TranslateFileName
  340.  * call).  Additional arguments have not been
  341.  * converted. */
  342.     TclFile inputFile; /* If non-NULL, gives the file to use as
  343.  * input for the child process.  If inputFile
  344.  * file is not readable or is NULL, the child
  345.  * will receive no standard input. */
  346.     TclFile outputFile; /* If non-NULL, gives the file that
  347.  * receives output from the child process.  If
  348.  * outputFile file is not writeable or is
  349.  * NULL, output from the child will be
  350.  * discarded. */
  351.     TclFile errorFile; /* If non-NULL, gives the file that
  352.  * receives errors from the child process.  If
  353.  * errorFile file is not writeable or is NULL,
  354.  * errors from the child will be discarded.
  355.  * errorFile may be the same as outputFile. */
  356.     Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr
  357.  * is filled with the process id of the child
  358.  * process. */
  359. {
  360.     TclFile errPipeIn, errPipeOut;
  361.     int count, status, fd;
  362.     char errSpace[200 + TCL_INTEGER_SPACE];
  363.     Tcl_DString *dsArray;
  364.     char **newArgv;
  365.     int pid, i;
  366.     
  367.     errPipeIn = NULL;
  368.     errPipeOut = NULL;
  369.     pid = -1;
  370.     /*
  371.      * Create a pipe that the child can use to return error
  372.      * information if anything goes wrong.
  373.      */
  374.     if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
  375. Tcl_AppendResult(interp, "couldn't create pipe: ",
  376. Tcl_PosixError(interp), (char *) NULL);
  377. goto error;
  378.     }
  379.     /*
  380.      * We need to allocate and convert this before the fork
  381.      * so it is properly deallocated later
  382.      */
  383.     dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
  384.     newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
  385.     newArgv[argc] = NULL;
  386.     for (i = 0; i < argc; i++) {
  387. newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
  388.     }
  389. #ifdef USE_VFORK
  390.     /*
  391.      * After vfork(), do not call code in the child that changes global state,
  392.      * because it is using the parent's memory space at that point and writes
  393.      * might corrupt the parent: so ensure standard channels are initialized in
  394.      * the parent, otherwise SetupStdFile() might initialize them in the child.
  395.      */
  396.     if (!inputFile) {
  397. Tcl_GetStdChannel(TCL_STDIN);
  398.     }
  399.     if (!outputFile) {
  400.         Tcl_GetStdChannel(TCL_STDOUT);
  401.     }
  402.     if (!errorFile) {
  403.         Tcl_GetStdChannel(TCL_STDERR);
  404.     }
  405. #endif
  406.     pid = fork();
  407.     if (pid == 0) {
  408. int joinThisError = errorFile && (errorFile == outputFile);
  409. fd = GetFd(errPipeOut);
  410. /*
  411.  * Set up stdio file handles for the child process.
  412.  */
  413. if (!SetupStdFile(inputFile, TCL_STDIN)
  414. || !SetupStdFile(outputFile, TCL_STDOUT)
  415. || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
  416. || (joinThisError &&
  417. ((dup2(1,2) == -1) ||
  418.  (fcntl(2, F_SETFD, 0) != 0)))) {
  419.     sprintf(errSpace,
  420.     "%dforked process couldn't set up input/output: ", errno);
  421.     write(fd, errSpace, (size_t) strlen(errSpace));
  422.     _exit(1);
  423. }
  424. /*
  425.  * Close the input side of the error pipe.
  426.  */
  427. RestoreSignals();
  428. execvp(newArgv[0], newArgv); /* INTL: Native. */
  429. sprintf(errSpace, "%dcouldn't execute "%.150s": ", errno, argv[0]);
  430. write(fd, errSpace, (size_t) strlen(errSpace));
  431. _exit(1);
  432.     }
  433.     
  434.     /*
  435.      * Free the mem we used for the fork
  436.      */
  437.     for (i = 0; i < argc; i++) {
  438. Tcl_DStringFree(&dsArray[i]);
  439.     }
  440.     ckfree((char *) dsArray);
  441.     ckfree((char *) newArgv);
  442.     if (pid == -1) {
  443. Tcl_AppendResult(interp, "couldn't fork child process: ",
  444. Tcl_PosixError(interp), (char *) NULL);
  445. goto error;
  446.     }
  447.     /*
  448.      * Read back from the error pipe to see if the child started
  449.      * up OK.  The info in the pipe (if any) consists of a decimal
  450.      * errno value followed by an error message.
  451.      */
  452.     TclpCloseFile(errPipeOut);
  453.     errPipeOut = NULL;
  454.     fd = GetFd(errPipeIn);
  455.     count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
  456.     if (count > 0) {
  457. char *end;
  458. errSpace[count] = 0;
  459. errno = strtol(errSpace, &end, 10);
  460. Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
  461. (char *) NULL);
  462. goto error;
  463.     }
  464.     
  465.     TclpCloseFile(errPipeIn);
  466.     *pidPtr = (Tcl_Pid) pid;
  467.     return TCL_OK;
  468.     error:
  469.     if (pid != -1) {
  470. /*
  471.  * Reap the child process now if an error occurred during its
  472.  * startup.  We don't call this with WNOHANG because that can lead to
  473.  * defunct processes on an MP system.   We shouldn't have to worry
  474.  * about hanging here, since this is the error case.  [Bug: 6148]
  475.  */
  476. Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
  477.     }
  478.     
  479.     if (errPipeIn) {
  480. TclpCloseFile(errPipeIn);
  481.     }
  482.     if (errPipeOut) {
  483. TclpCloseFile(errPipeOut);
  484.     }
  485.     return TCL_ERROR;
  486. }
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * RestoreSignals --
  491.  *
  492.  *      This procedure is invoked in a forked child process just before
  493.  *      exec-ing a new program to restore all signals to their default
  494.  *      settings.
  495.  *
  496.  * Results:
  497.  *      None.
  498.  *
  499.  * Side effects:
  500.  *      Signal settings get changed.
  501.  *
  502.  *----------------------------------------------------------------------
  503.  */
  504.  
  505. static void
  506. RestoreSignals()
  507. {
  508. #ifdef SIGABRT
  509.     signal(SIGABRT, SIG_DFL);
  510. #endif
  511. #ifdef SIGALRM
  512.     signal(SIGALRM, SIG_DFL);
  513. #endif
  514. #ifdef SIGFPE
  515.     signal(SIGFPE, SIG_DFL);
  516. #endif
  517. #ifdef SIGHUP
  518.     signal(SIGHUP, SIG_DFL);
  519. #endif
  520. #ifdef SIGILL
  521.     signal(SIGILL, SIG_DFL);
  522. #endif
  523. #ifdef SIGINT
  524.     signal(SIGINT, SIG_DFL);
  525. #endif
  526. #ifdef SIGPIPE
  527.     signal(SIGPIPE, SIG_DFL);
  528. #endif
  529. #ifdef SIGQUIT
  530.     signal(SIGQUIT, SIG_DFL);
  531. #endif
  532. #ifdef SIGSEGV
  533.     signal(SIGSEGV, SIG_DFL);
  534. #endif
  535. #ifdef SIGTERM
  536.     signal(SIGTERM, SIG_DFL);
  537. #endif
  538. #ifdef SIGUSR1
  539.     signal(SIGUSR1, SIG_DFL);
  540. #endif
  541. #ifdef SIGUSR2
  542.     signal(SIGUSR2, SIG_DFL);
  543. #endif
  544. #ifdef SIGCHLD
  545.     signal(SIGCHLD, SIG_DFL);
  546. #endif
  547. #ifdef SIGCONT
  548.     signal(SIGCONT, SIG_DFL);
  549. #endif
  550. #ifdef SIGTSTP
  551.     signal(SIGTSTP, SIG_DFL);
  552. #endif
  553. #ifdef SIGTTIN
  554.     signal(SIGTTIN, SIG_DFL);
  555. #endif
  556. #ifdef SIGTTOU
  557.     signal(SIGTTOU, SIG_DFL);
  558. #endif
  559. }
  560. /*
  561.  *----------------------------------------------------------------------
  562.  *
  563.  * SetupStdFile --
  564.  *
  565.  * Set up stdio file handles for the child process, using the
  566.  * current standard channels if no other files are specified.
  567.  * If no standard channel is defined, or if no file is associated
  568.  * with the channel, then the corresponding standard fd is closed.
  569.  *
  570.  * Results:
  571.  * Returns 1 on success, or 0 on failure.
  572.  *
  573.  * Side effects:
  574.  * Replaces stdio fds.
  575.  *
  576.  *----------------------------------------------------------------------
  577.  */
  578. static int
  579. SetupStdFile(file, type)
  580.     TclFile file; /* File to dup, or NULL. */
  581.     int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
  582. {
  583.     Tcl_Channel channel;
  584.     int fd;
  585.     int targetFd = 0; /* Initializations here needed only to */
  586.     int direction = 0; /* prevent warnings about using uninitialized
  587.  * variables. */
  588.     switch (type) {
  589. case TCL_STDIN:
  590.     targetFd = 0;
  591.     direction = TCL_READABLE;
  592.     break;
  593. case TCL_STDOUT:
  594.     targetFd = 1;
  595.     direction = TCL_WRITABLE;
  596.     break;
  597. case TCL_STDERR:
  598.     targetFd = 2;
  599.     direction = TCL_WRITABLE;
  600.     break;
  601.     }
  602.     if (!file) {
  603. channel = Tcl_GetStdChannel(type);
  604. if (channel) {
  605.     file = TclpMakeFile(channel, direction);
  606. }
  607.     }
  608.     if (file) {
  609. fd = GetFd(file);
  610. if (fd != targetFd) {
  611.     if (dup2(fd, targetFd) == -1) {
  612. return 0;
  613.     }
  614.             /*
  615.              * Must clear the close-on-exec flag for the target FD, since
  616.              * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
  617.              * the target FD.
  618.              */
  619.             
  620.             fcntl(targetFd, F_SETFD, 0);
  621. } else {
  622.     /*
  623.      * Since we aren't dup'ing the file, we need to explicitly clear
  624.      * the close-on-exec flag.
  625.      */
  626.    fcntl(fd, F_SETFD, 0);
  627. }
  628.     } else {
  629. close(targetFd);
  630.     }
  631.     return 1;
  632. }
  633. /*
  634.  *----------------------------------------------------------------------
  635.  *
  636.  * TclpCreateCommandChannel --
  637.  *
  638.  * This function is called by the generic IO level to perform
  639.  * the platform specific channel initialization for a command
  640.  * channel.
  641.  *
  642.  * Results:
  643.  * Returns a new channel or NULL on failure.
  644.  *
  645.  * Side effects:
  646.  * Allocates a new channel.
  647.  *
  648.  *----------------------------------------------------------------------
  649.  */
  650. Tcl_Channel
  651. TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
  652.     TclFile readFile; /* If non-null, gives the file for reading. */
  653.     TclFile writeFile; /* If non-null, gives the file for writing. */
  654.     TclFile errorFile; /* If non-null, gives the file where errors
  655.  * can be read. */
  656.     int numPids; /* The number of pids in the pid array. */
  657.     Tcl_Pid *pidPtr; /* An array of process identifiers.
  658.                                  * Allocated by the caller, freed when
  659.                                  * the channel is closed or the processes
  660.                                  * are detached (in a background exec). */
  661. {
  662.     char channelName[16 + TCL_INTEGER_SPACE];
  663.     int channelId;
  664.     PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));
  665.     int mode;
  666.     statePtr->inFile = readFile;
  667.     statePtr->outFile = writeFile;
  668.     statePtr->errorFile = errorFile;
  669.     statePtr->numPids = numPids;
  670.     statePtr->pidPtr = pidPtr;
  671.     statePtr->isNonBlocking = 0;
  672.     mode = 0;
  673.     if (readFile) {
  674.         mode |= TCL_READABLE;
  675.     }
  676.     if (writeFile) {
  677.         mode |= TCL_WRITABLE;
  678.     }
  679.     
  680.     /*
  681.      * Use one of the fds associated with the channel as the
  682.      * channel id.
  683.      */
  684.     if (readFile) {
  685. channelId = GetFd(readFile);
  686.     } else if (writeFile) {
  687. channelId = GetFd(writeFile);
  688.     } else if (errorFile) {
  689. channelId = GetFd(errorFile);
  690.     } else {
  691. channelId = 0;
  692.     }
  693.     /*
  694.      * For backward compatibility with previous versions of Tcl, we
  695.      * use "file%d" as the base name for pipes even though it would
  696.      * be more natural to use "pipe%d".
  697.      */
  698.     sprintf(channelName, "file%d", channelId);
  699.     statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
  700.             (ClientData) statePtr, mode);
  701.     return statePtr->channel;
  702. }
  703. /*
  704.  *----------------------------------------------------------------------
  705.  *
  706.  * TclGetAndDetachPids --
  707.  *
  708.  * This procedure is invoked in the generic implementation of a
  709.  * background "exec" (An exec when invoked with a terminating "&")
  710.  * to store a list of the PIDs for processes in a command pipeline
  711.  * in the interp's result and to detach the processes.
  712.  *
  713.  * Results:
  714.  * None.
  715.  *
  716.  * Side effects:
  717.  * Modifies the interp's result. Detaches processes.
  718.  *
  719.  *----------------------------------------------------------------------
  720.  */
  721. void
  722. TclGetAndDetachPids(interp, chan)
  723.     Tcl_Interp *interp;
  724.     Tcl_Channel chan;
  725. {
  726.     PipeState *pipePtr;
  727.     Tcl_ChannelType *chanTypePtr;
  728.     int i;
  729.     char buf[TCL_INTEGER_SPACE];
  730.     /*
  731.      * Punt if the channel is not a command channel.
  732.      */
  733.     chanTypePtr = Tcl_GetChannelType(chan);
  734.     if (chanTypePtr != &pipeChannelType) {
  735.         return;
  736.     }
  737.     pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
  738.     for (i = 0; i < pipePtr->numPids; i++) {
  739.         TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
  740.         Tcl_AppendElement(interp, buf);
  741.         Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
  742.     }
  743.     if (pipePtr->numPids > 0) {
  744.         ckfree((char *) pipePtr->pidPtr);
  745.         pipePtr->numPids = 0;
  746.     }
  747. }
  748. /*
  749.  *----------------------------------------------------------------------
  750.  *
  751.  * PipeBlockModeProc --
  752.  *
  753.  * Helper procedure to set blocking and nonblocking modes on a
  754.  * pipe based channel. Invoked by generic IO level code.
  755.  *
  756.  * Results:
  757.  * 0 if successful, errno when failed.
  758.  *
  759.  * Side effects:
  760.  * Sets the device into blocking or non-blocking mode.
  761.  *
  762.  *----------------------------------------------------------------------
  763.  */
  764. /* ARGSUSED */
  765. static int
  766. PipeBlockModeProc(instanceData, mode)
  767.     ClientData instanceData; /* Pipe state. */
  768.     int mode; /* The mode to set. Can be one of
  769.                                          * TCL_MODE_BLOCKING or
  770.                                          * TCL_MODE_NONBLOCKING. */
  771. {
  772.     PipeState *psPtr = (PipeState *) instanceData;
  773.     int curStatus;
  774.     int fd;
  775. #ifndef USE_FIONBIO    
  776.     if (psPtr->inFile) {
  777.         fd = GetFd(psPtr->inFile);
  778.         curStatus = fcntl(fd, F_GETFL);
  779.         if (mode == TCL_MODE_BLOCKING) {
  780.             curStatus &= (~(O_NONBLOCK));
  781.         } else {
  782.             curStatus |= O_NONBLOCK;
  783.         }
  784.         if (fcntl(fd, F_SETFL, curStatus) < 0) {
  785.             return errno;
  786.         }
  787.     }
  788.     if (psPtr->outFile) {
  789.         fd = GetFd(psPtr->outFile);
  790.         curStatus = fcntl(fd, F_GETFL);
  791.         if (mode == TCL_MODE_BLOCKING) {
  792.             curStatus &= (~(O_NONBLOCK));
  793.         } else {
  794.             curStatus |= O_NONBLOCK;
  795.         }
  796.         if (fcntl(fd, F_SETFL, curStatus) < 0) {
  797.             return errno;
  798.         }
  799.     }
  800. #endif /* !FIONBIO */
  801. #ifdef USE_FIONBIO
  802.     if (psPtr->inFile) {
  803.         fd = GetFd(psPtr->inFile);
  804.         if (mode == TCL_MODE_BLOCKING) {
  805.             curStatus = 0;
  806.         } else {
  807.             curStatus = 1;
  808.         }
  809.         if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
  810.             return errno;
  811.         }
  812.     }
  813.     if (psPtr->outFile != NULL) {
  814.         fd = GetFd(psPtr->outFile);
  815.         if (mode == TCL_MODE_BLOCKING) {
  816.             curStatus = 0;
  817.         } else {
  818.             curStatus = 1;
  819.         }
  820.         if (ioctl(fd, (int) FIONBIO,  &curStatus) < 0) {
  821.             return errno;
  822.         }
  823.     }
  824. #endif /* USE_FIONBIO */
  825.     psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
  826.     return 0;
  827. }
  828. /*
  829.  *----------------------------------------------------------------------
  830.  *
  831.  * PipeCloseProc --
  832.  *
  833.  * This procedure is invoked by the generic IO level to perform
  834.  * channel-type-specific cleanup when a command pipeline channel
  835.  * is closed.
  836.  *
  837.  * Results:
  838.  * 0 on success, errno otherwise.
  839.  *
  840.  * Side effects:
  841.  * Closes the command pipeline channel.
  842.  *
  843.  *----------------------------------------------------------------------
  844.  */
  845. /* ARGSUSED */
  846. static int
  847. PipeCloseProc(instanceData, interp)
  848.     ClientData instanceData; /* The pipe to close. */
  849.     Tcl_Interp *interp; /* For error reporting. */
  850. {
  851.     PipeState *pipePtr;
  852.     Tcl_Channel errChan;
  853.     int errorCode, result;
  854.     errorCode = 0;
  855.     result = 0;
  856.     pipePtr = (PipeState *) instanceData;
  857.     if (pipePtr->inFile) {
  858. if (TclpCloseFile(pipePtr->inFile) < 0) {
  859.     errorCode = errno;
  860. }
  861.     }
  862.     if (pipePtr->outFile) {
  863. if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {
  864.     errorCode = errno;
  865. }
  866.     }
  867.     if (pipePtr->isNonBlocking || TclInExit()) {
  868.     
  869. /*
  870.          * If the channel is non-blocking or Tcl is being cleaned up, just
  871.          * detach the children PIDs, reap them (important if we are in a
  872.          * dynamic load module), and discard the errorFile.
  873.          */
  874.         
  875.         Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
  876.         Tcl_ReapDetachedProcs();
  877.         if (pipePtr->errorFile) {
  878.     TclpCloseFile(pipePtr->errorFile);
  879.         }
  880.     } else {
  881.         
  882. /*
  883.          * Wrap the error file into a channel and give it to the cleanup
  884.          * routine.
  885.          */
  886.         if (pipePtr->errorFile) {
  887.     errChan = Tcl_MakeFileChannel(
  888. (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
  889.         } else {
  890.             errChan = NULL;
  891.         }
  892.         result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
  893.                 errChan);
  894.     }
  895.     if (pipePtr->numPids != 0) {
  896.         ckfree((char *) pipePtr->pidPtr);
  897.     }
  898.     ckfree((char *) pipePtr);
  899.     if (errorCode == 0) {
  900.         return result;
  901.     }
  902.     return errorCode;
  903. }
  904. /*
  905.  *----------------------------------------------------------------------
  906.  *
  907.  * PipeInputProc --
  908.  *
  909.  * This procedure is invoked from the generic IO level to read
  910.  * input from a command pipeline based channel.
  911.  *
  912.  * Results:
  913.  * The number of bytes read is returned or -1 on error. An output
  914.  * argument contains a POSIX error code if an error occurs, or zero.
  915.  *
  916.  * Side effects:
  917.  * Reads input from the input device of the channel.
  918.  *
  919.  *----------------------------------------------------------------------
  920.  */
  921. static int
  922. PipeInputProc(instanceData, buf, toRead, errorCodePtr)
  923.     ClientData instanceData; /* Pipe state. */
  924.     char *buf; /* Where to store data read. */
  925.     int toRead; /* How much space is available
  926.                                          * in the buffer? */
  927.     int *errorCodePtr; /* Where to store error code. */
  928. {
  929.     PipeState *psPtr = (PipeState *) instanceData;
  930.     int bytesRead; /* How many bytes were actually
  931.                                          * read from the input device? */
  932.     *errorCodePtr = 0;
  933.     
  934.     /*
  935.      * Assume there is always enough input available. This will block
  936.      * appropriately, and read will unblock as soon as a short read is
  937.      * possible, if the channel is in blocking mode. If the channel is
  938.      * nonblocking, the read will never block.
  939.      * Some OSes can throw an interrupt error, for which we should
  940.      * immediately retry. [Bug #415131]
  941.      */
  942.     do {
  943. bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead);
  944.     } while ((bytesRead < 0) && (errno == EINTR));
  945.     if (bytesRead < 0) {
  946. *errorCodePtr = errno;
  947. return -1;
  948.     } else {
  949. return bytesRead;
  950.     }
  951. }
  952. /*
  953.  *----------------------------------------------------------------------
  954.  *
  955.  * PipeOutputProc--
  956.  *
  957.  * This procedure is invoked from the generic IO level to write
  958.  * output to a command pipeline based channel.
  959.  *
  960.  * Results:
  961.  * The number of bytes written is returned or -1 on error. An
  962.  * output argument contains a POSIX error code if an error occurred,
  963.  * or zero.
  964.  *
  965.  * Side effects:
  966.  * Writes output on the output device of the channel.
  967.  *
  968.  *----------------------------------------------------------------------
  969.  */
  970. static int
  971. PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
  972.     ClientData instanceData; /* Pipe state. */
  973.     CONST char *buf; /* The data buffer. */
  974.     int toWrite; /* How many bytes to write? */
  975.     int *errorCodePtr; /* Where to store error code. */
  976. {
  977.     PipeState *psPtr = (PipeState *) instanceData;
  978.     int written;
  979.     *errorCodePtr = 0;
  980.     /*
  981.      * Some OSes can throw an interrupt error, for which we should
  982.      * immediately retry. [Bug #415131]
  983.      */
  984.     do {
  985. written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite);
  986.     } while ((written < 0) && (errno == EINTR));
  987.     if (written < 0) {
  988. *errorCodePtr = errno;
  989. return -1;
  990.     } else {
  991. return written;
  992.     }
  993. }
  994. /*
  995.  *----------------------------------------------------------------------
  996.  *
  997.  * PipeWatchProc --
  998.  *
  999.  * Initialize the notifier to watch the fds from this channel.
  1000.  *
  1001.  * Results:
  1002.  * None.
  1003.  *
  1004.  * Side effects:
  1005.  * Sets up the notifier so that a future event on the channel will
  1006.  * be seen by Tcl.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010. static void
  1011. PipeWatchProc(instanceData, mask)
  1012.     ClientData instanceData; /* The pipe state. */
  1013.     int mask; /* Events of interest; an OR-ed
  1014.                                          * combination of TCL_READABLE,
  1015.                                          * TCL_WRITABEL and TCL_EXCEPTION. */
  1016. {
  1017.     PipeState *psPtr = (PipeState *) instanceData;
  1018.     int newmask;
  1019.     if (psPtr->inFile) {
  1020. newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
  1021. if (newmask) {
  1022.     Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,
  1023.     (Tcl_FileProc *) Tcl_NotifyChannel,
  1024.     (ClientData) psPtr->channel);
  1025. } else {
  1026.     Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
  1027. }
  1028.     }
  1029.     if (psPtr->outFile) {
  1030. newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
  1031. if (newmask) {
  1032.     Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,
  1033.     (Tcl_FileProc *) Tcl_NotifyChannel,
  1034.     (ClientData) psPtr->channel);
  1035. } else {
  1036.     Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
  1037. }
  1038.     }
  1039. }
  1040. /*
  1041.  *----------------------------------------------------------------------
  1042.  *
  1043.  * PipeGetHandleProc --
  1044.  *
  1045.  * Called from Tcl_GetChannelHandle to retrieve OS handles from
  1046.  * inside a command pipeline based channel.
  1047.  *
  1048.  * Results:
  1049.  * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
  1050.  * there is no handle for the specified direction. 
  1051.  *
  1052.  * Side effects:
  1053.  * None.
  1054.  *
  1055.  *----------------------------------------------------------------------
  1056.  */
  1057. static int
  1058. PipeGetHandleProc(instanceData, direction, handlePtr)
  1059.     ClientData instanceData; /* The pipe state. */
  1060.     int direction; /* TCL_READABLE or TCL_WRITABLE */
  1061.     ClientData *handlePtr; /* Where to store the handle.  */
  1062. {
  1063.     PipeState *psPtr = (PipeState *) instanceData;
  1064.     if (direction == TCL_READABLE && psPtr->inFile) {
  1065. *handlePtr = (ClientData) GetFd(psPtr->inFile);
  1066. return TCL_OK;
  1067.     }
  1068.     if (direction == TCL_WRITABLE && psPtr->outFile) {
  1069. *handlePtr = (ClientData) GetFd(psPtr->outFile);
  1070. return TCL_OK;
  1071.     }
  1072.     return TCL_ERROR;
  1073. }
  1074. /*
  1075.  *----------------------------------------------------------------------
  1076.  *
  1077.  * Tcl_WaitPid --
  1078.  *
  1079.  * Implements the waitpid system call on Unix systems.
  1080.  *
  1081.  * Results:
  1082.  * Result of calling waitpid.
  1083.  *
  1084.  * Side effects:
  1085.  * Waits for a process to terminate.
  1086.  *
  1087.  *----------------------------------------------------------------------
  1088.  */
  1089. Tcl_Pid
  1090. Tcl_WaitPid(pid, statPtr, options)
  1091.     Tcl_Pid pid;
  1092.     int *statPtr;
  1093.     int options;
  1094. {
  1095.     int result;
  1096.     pid_t real_pid;
  1097.     real_pid = (pid_t) pid;
  1098.     while (1) {
  1099. result = (int) waitpid(real_pid, statPtr, options);
  1100. if ((result != -1) || (errno != EINTR)) {
  1101.     return (Tcl_Pid) result;
  1102. }
  1103.     }
  1104. }
  1105. /*
  1106.  *----------------------------------------------------------------------
  1107.  *
  1108.  * Tcl_PidObjCmd --
  1109.  *
  1110.  * This procedure is invoked to process the "pid" Tcl command.
  1111.  * See the user documentation for details on what it does.
  1112.  *
  1113.  * Results:
  1114.  * A standard Tcl result.
  1115.  *
  1116.  * Side effects:
  1117.  * See the user documentation.
  1118.  *
  1119.  *----------------------------------------------------------------------
  1120.  */
  1121. /* ARGSUSED */
  1122. int
  1123. Tcl_PidObjCmd(dummy, interp, objc, objv)
  1124.     ClientData dummy; /* Not used. */
  1125.     Tcl_Interp *interp; /* Current interpreter. */
  1126.     int objc; /* Number of arguments. */
  1127.     Tcl_Obj *CONST *objv; /* Argument strings. */
  1128. {
  1129.     Tcl_Channel chan;
  1130.     Tcl_ChannelType *chanTypePtr;
  1131.     PipeState *pipePtr;
  1132.     int i;
  1133.     Tcl_Obj *resultPtr, *longObjPtr;
  1134.     if (objc > 2) {
  1135. Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
  1136. return TCL_ERROR;
  1137.     }
  1138.     if (objc == 1) {
  1139. Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());
  1140.     } else {
  1141.         chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
  1142.         if (chan == (Tcl_Channel) NULL) {
  1143.     return TCL_ERROR;
  1144. }
  1145. chanTypePtr = Tcl_GetChannelType(chan);
  1146. if (chanTypePtr != &pipeChannelType) {
  1147.     return TCL_OK;
  1148. }
  1149.         pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
  1150. resultPtr = Tcl_GetObjResult(interp);
  1151.         for (i = 0; i < pipePtr->numPids; i++) {
  1152.     longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i]));
  1153.     Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr);
  1154. }
  1155.     }
  1156.     return TCL_OK;
  1157. }
  1158. /*
  1159.  *----------------------------------------------------------------------
  1160.  *
  1161.  * TclpFinalizePipes --
  1162.  *
  1163.  * Cleans up the pipe subsystem from Tcl_FinalizeThread
  1164.  *
  1165.  * Results:
  1166.  * None.
  1167.  *
  1168.  * This procedure carries out no operation on Unix.
  1169.  *
  1170.  *----------------------------------------------------------------------
  1171.  */
  1172. void
  1173. TclpFinalizePipes()
  1174. {
  1175. }