📄 tclunixpipe.c
字号:
/* * tclUnixPipe.c -- * * This file implements the UNIX-specific exec pipeline functions, * the "pipe" channel driver, and the "pid" Tcl command. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclUnixPipe.c,v 1.23 2003/02/21 14:15:58 das Exp $ */#include "tclInt.h"#include "tclPort.h"#ifdef USE_VFORK#define fork vfork#endif/* * The following macros convert between TclFile's and fd's. The conversion * simple involves shifting fd's up by one to ensure that no valid fd is ever * the same as NULL. */#define MakeFile(fd) ((TclFile)(((int)fd)+1))#define GetFd(file) (((int)file)-1)/* * This structure describes per-instance state of a pipe based channel. */typedef struct PipeState { Tcl_Channel channel;/* Channel associated with this file. */ TclFile inFile; /* Output from pipe. */ TclFile outFile; /* Input to pipe. */ TclFile errorFile; /* Error output from pipe. */ int numPids; /* How many processes are attached to this pipe? */ Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by * the creator of the pipe. */ int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode. * Used to decide whether to wait for the children * at close time. */} PipeState;/* * Declarations for local procedures defined in this file: */static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData, int mode));static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));static int PipeInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int PipeOutputProc _ANSI_ARGS_(( ClientData instanceData, CONST char *buf, int toWrite, int *errorCode));static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));static void RestoreSignals _ANSI_ARGS_((void));static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));/* * This structure describes the channel type structure for command pipe * based IO: */static Tcl_ChannelType pipeChannelType = { "pipe", /* Type name. */ TCL_CHANNEL_VERSION_2, /* v2 channel */ PipeCloseProc, /* Close proc. */ PipeInputProc, /* Input proc. */ PipeOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ PipeWatchProc, /* Initialize notifier. */ PipeGetHandleProc, /* Get OS handles out of channel. */ NULL, /* close2proc. */ PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */};/* *---------------------------------------------------------------------- * * TclpMakeFile -- * * Make a TclFile from a channel. * * Results: * Returns a new TclFile or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */TclFileTclpMakeFile(channel, direction) Tcl_Channel channel; /* Channel to get file from. */ int direction; /* Either TCL_READABLE or TCL_WRITABLE. */{ ClientData data; if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data) == TCL_OK) { return MakeFile((int)data); } else { return (TclFile) NULL; }}/* *---------------------------------------------------------------------- * * TclpOpenFile -- * * Open a file for use in a pipeline. * * Results: * Returns a new TclFile handle or NULL on failure. * * Side effects: * May cause a file to be created on the file system. * *---------------------------------------------------------------------- */TclFileTclpOpenFile(fname, mode) CONST char *fname; /* The name of the file to open. */ int mode; /* In what mode to open the file? */{ int fd; CONST char *native; Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds); fd = TclOSopen(native, mode, 0666); /* INTL: Native. */ Tcl_DStringFree(&ds); if (fd != -1) { fcntl(fd, F_SETFD, FD_CLOEXEC); /* * If the file is being opened for writing, seek to the end * so we can append to any data already in the file. */ if (mode & O_WRONLY) { TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END); } /* * Increment the fd so it can't be 0, which would conflict with * the NULL return for errors. */ return MakeFile(fd); } return NULL;}/* *---------------------------------------------------------------------- * * TclpCreateTempFile -- * * This function creates a temporary file initialized with an * optional string, and returns a file handle with the file pointer * at the beginning of the file. * * Results: * A handle to a file. * * Side effects: * None. * *---------------------------------------------------------------------- */TclFileTclpCreateTempFile(contents) CONST char *contents; /* String to write into temp file, or NULL. */{ char fileName[L_tmpnam + 9]; CONST char *native; Tcl_DString dstring; int fd; /* * We should also check against making more then TMP_MAX of these. */ strcpy(fileName, P_tmpdir); /* INTL: Native. */ if (fileName[strlen(fileName) - 1] != '/') { strcat(fileName, "/"); /* INTL: Native. */ } strcat(fileName, "tclXXXXXX"); fd = mkstemp(fileName); /* INTL: Native. */ if (fd == -1) { return NULL; } fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ if (contents != NULL) { native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); if (write(fd, native, strlen(native)) == -1) { close(fd); Tcl_DStringFree(&dstring); return NULL; } Tcl_DStringFree(&dstring); TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET); } return MakeFile(fd);}/* *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns unique filename. * * Results: * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_Obj* TclpTempFileName(){ char fileName[L_tmpnam + 9]; Tcl_Obj *result = NULL; int fd; /* * We should also check against making more then TMP_MAX of these. */ strcpy(fileName, P_tmpdir); /* INTL: Native. */ if (fileName[strlen(fileName) - 1] != '/') { strcat(fileName, "/"); /* INTL: Native. */ } strcat(fileName, "tclXXXXXX"); fd = mkstemp(fileName); /* INTL: Native. */ if (fd == -1) { return NULL; } fcntl(fd, F_SETFD, FD_CLOEXEC); unlink(fileName); /* INTL: Native. */ result = TclpNativeToNormalized((ClientData) fileName); close (fd); return result;}/* *---------------------------------------------------------------------- * * TclpCreatePipe -- * * Creates a pipe - simply calls the pipe() function. * * Results: * Returns 1 on success, 0 on failure. * * Side effects: * Creates a pipe. * *---------------------------------------------------------------------- */intTclpCreatePipe(readPipe, writePipe) TclFile *readPipe; /* Location to store file handle for * read side of pipe. */ TclFile *writePipe; /* Location to store file handle for * write side of pipe. */{ int pipeIds[2]; if (pipe(pipeIds) != 0) { return 0; } fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC); fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC); *readPipe = MakeFile(pipeIds[0]); *writePipe = MakeFile(pipeIds[1]); return 1;}/* *---------------------------------------------------------------------- * * TclpCloseFile -- * * Implements a mechanism to close a UNIX file. * * Results: * Returns 0 on success, or -1 on error, setting errno. * * Side effects: * The file is closed. * *---------------------------------------------------------------------- */intTclpCloseFile(file) TclFile file; /* The file to close. */{ int fd = GetFd(file); /* * Refuse to close the fds for stdin, stdout and stderr. */ if ((fd == 0) || (fd == 1) || (fd == 2)) { return 0; } Tcl_DeleteFileHandler(fd); return close(fd);}/* *--------------------------------------------------------------------------- * * TclpCreateProcess -- * * Create a child process that has the specified files as its * standard input, output, and error. The child process runs * asynchronously and runs with the same environment variables * as the creating process. * * The path is searched to find the specified executable. * * Results: * The return value is TCL_ERROR and an error message is left in * the interp's result if there was a problem creating the child * process. Otherwise, the return value is TCL_OK and *pidPtr is * filled with the process id of the child process. * * Side effects: * A process is created. * *--------------------------------------------------------------------------- */ /* ARGSUSED */intTclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile, pidPtr) Tcl_Interp *interp; /* Interpreter in which to leave errors that * occurred when creating the child process. * Error messages from the child process * itself are sent to errorFile. */ int argc; /* Number of arguments in following array. */ CONST char **argv; /* Array of argument strings in UTF-8. * argv[0] contains the name of the executable * translated using Tcl_TranslateFileName * call). Additional arguments have not been * converted. */ TclFile inputFile; /* If non-NULL, gives the file to use as * input for the child process. If inputFile * file is not readable or is NULL, the child * will receive no standard input. */ TclFile outputFile; /* If non-NULL, gives the file that * receives output from the child process. If * outputFile file is not writeable or is * NULL, output from the child will be * discarded. */ TclFile errorFile; /* If non-NULL, gives the file that * receives errors from the child process. If * errorFile file is not writeable or is NULL, * errors from the child will be discarded. * errorFile may be the same as outputFile. */ Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr * is filled with the process id of the child * process. */{ TclFile errPipeIn, errPipeOut; int joinThisError, count, status, fd; char errSpace[200 + TCL_INTEGER_SPACE]; Tcl_DString *dsArray; char **newArgv; int pid, i; errPipeIn = NULL; errPipeOut = NULL; pid = -1; /* * Create a pipe that the child can use to return error * information if anything goes wrong. */ if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { Tcl_AppendResult(interp, "couldn't create pipe: ", Tcl_PosixError(interp), (char *) NULL); goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -