⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclunixpipe.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 3 页
字号:
    }    /*     * We need to allocate and convert this before the fork     * so it is properly deallocated later     */    dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));    newArgv = (char **) ckalloc((argc+1) * sizeof(char *));    newArgv[argc] = NULL;    for (i = 0; i < argc; i++) {	newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);    }    joinThisError = errorFile && (errorFile == outputFile);    pid = fork();    if (pid == 0) {	fd = GetFd(errPipeOut);	/*	 * Set up stdio file handles for the child process.	 */	if (!SetupStdFile(inputFile, TCL_STDIN)		|| !SetupStdFile(outputFile, TCL_STDOUT)		|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))		|| (joinThisError &&			((dup2(1,2) == -1) ||			 (fcntl(2, F_SETFD, 0) != 0)))) {	    sprintf(errSpace,		    "%dforked process couldn't set up input/output: ", errno);	    write(fd, errSpace, (size_t) strlen(errSpace));	    _exit(1);	}	/*	 * Close the input side of the error pipe.	 */	RestoreSignals();	execvp(newArgv[0], newArgv);			/* INTL: Native. */	sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);	write(fd, errSpace, (size_t) strlen(errSpace));	_exit(1);    }        /*     * Free the mem we used for the fork     */    for (i = 0; i < argc; i++) {	Tcl_DStringFree(&dsArray[i]);    }    ckfree((char *) dsArray);    ckfree((char *) newArgv);    if (pid == -1) {	Tcl_AppendResult(interp, "couldn't fork child process: ",		Tcl_PosixError(interp), (char *) NULL);	goto error;    }    /*     * Read back from the error pipe to see if the child started     * up OK.  The info in the pipe (if any) consists of a decimal     * errno value followed by an error message.     */    TclpCloseFile(errPipeOut);    errPipeOut = NULL;    fd = GetFd(errPipeIn);    count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));    if (count > 0) {	char *end;	errSpace[count] = 0;	errno = strtol(errSpace, &end, 10);	Tcl_AppendResult(interp, end, Tcl_PosixError(interp),		(char *) NULL);	goto error;    }        TclpCloseFile(errPipeIn);    *pidPtr = (Tcl_Pid) pid;    return TCL_OK;    error:    if (pid != -1) {	/*	 * Reap the child process now if an error occurred during its	 * startup.  We don't call this with WNOHANG because that can lead to	 * defunct processes on an MP system.   We shouldn't have to worry	 * about hanging here, since this is the error case.  [Bug: 6148]	 */	Tcl_WaitPid((Tcl_Pid) pid, &status, 0);    }        if (errPipeIn) {	TclpCloseFile(errPipeIn);    }    if (errPipeOut) {	TclpCloseFile(errPipeOut);    }    return TCL_ERROR;}/* *---------------------------------------------------------------------- * * RestoreSignals -- * *      This procedure is invoked in a forked child process just before *      exec-ing a new program to restore all signals to their default *      settings. * * Results: *      None. * * Side effects: *      Signal settings get changed. * *---------------------------------------------------------------------- */ static voidRestoreSignals(){#ifdef SIGABRT    signal(SIGABRT, SIG_DFL);#endif#ifdef SIGALRM    signal(SIGALRM, SIG_DFL);#endif#ifdef SIGFPE    signal(SIGFPE, SIG_DFL);#endif#ifdef SIGHUP    signal(SIGHUP, SIG_DFL);#endif#ifdef SIGILL    signal(SIGILL, SIG_DFL);#endif#ifdef SIGINT    signal(SIGINT, SIG_DFL);#endif#ifdef SIGPIPE    signal(SIGPIPE, SIG_DFL);#endif#ifdef SIGQUIT    signal(SIGQUIT, SIG_DFL);#endif#ifdef SIGSEGV    signal(SIGSEGV, SIG_DFL);#endif#ifdef SIGTERM    signal(SIGTERM, SIG_DFL);#endif#ifdef SIGUSR1    signal(SIGUSR1, SIG_DFL);#endif#ifdef SIGUSR2    signal(SIGUSR2, SIG_DFL);#endif#ifdef SIGCHLD    signal(SIGCHLD, SIG_DFL);#endif#ifdef SIGCONT    signal(SIGCONT, SIG_DFL);#endif#ifdef SIGTSTP    signal(SIGTSTP, SIG_DFL);#endif#ifdef SIGTTIN    signal(SIGTTIN, SIG_DFL);#endif#ifdef SIGTTOU    signal(SIGTTOU, SIG_DFL);#endif}/* *---------------------------------------------------------------------- * * SetupStdFile -- * *	Set up stdio file handles for the child process, using the *	current standard channels if no other files are specified. *	If no standard channel is defined, or if no file is associated *	with the channel, then the corresponding standard fd is closed. * * Results: *	Returns 1 on success, or 0 on failure. * * Side effects: *	Replaces stdio fds. * *---------------------------------------------------------------------- */static intSetupStdFile(file, type)    TclFile file;		/* File to dup, or NULL. */    int type;			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */{    Tcl_Channel channel;    int fd;    int targetFd = 0;		/* Initializations here needed only to */    int direction = 0;		/* prevent warnings about using uninitialized				 * variables. */    switch (type) {	case TCL_STDIN:	    targetFd = 0;	    direction = TCL_READABLE;	    break;	case TCL_STDOUT:	    targetFd = 1;	    direction = TCL_WRITABLE;	    break;	case TCL_STDERR:	    targetFd = 2;	    direction = TCL_WRITABLE;	    break;    }    if (!file) {	channel = Tcl_GetStdChannel(type);	if (channel) {	    file = TclpMakeFile(channel, direction);	}    }    if (file) {	fd = GetFd(file);	if (fd != targetFd) {	    if (dup2(fd, targetFd) == -1) {		return 0;	    }            /*             * Must clear the close-on-exec flag for the target FD, since             * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on             * the target FD.             */                        fcntl(targetFd, F_SETFD, 0);	} else {	    int result;	    /*	     * Since we aren't dup'ing the file, we need to explicitly clear	     * the close-on-exec flag.	     */	    result = fcntl(fd, F_SETFD, 0);	}    } else {	close(targetFd);    }    return 1;}/* *---------------------------------------------------------------------- * * TclpCreateCommandChannel -- * *	This function is called by the generic IO level to perform *	the platform specific channel initialization for a command *	channel. * * Results: *	Returns a new channel or NULL on failure. * * Side effects: *	Allocates a new channel. * *---------------------------------------------------------------------- */Tcl_ChannelTclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)    TclFile readFile;		/* If non-null, gives the file for reading. */    TclFile writeFile;		/* If non-null, gives the file for writing. */    TclFile errorFile;		/* If non-null, gives the file where errors				 * can be read. */    int numPids;		/* The number of pids in the pid array. */    Tcl_Pid *pidPtr;		/* An array of process identifiers.                                 * Allocated by the caller, freed when                                 * the channel is closed or the processes                                 * are detached (in a background exec). */{    char channelName[16 + TCL_INTEGER_SPACE];    int channelId;    PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));    int mode;    statePtr->inFile = readFile;    statePtr->outFile = writeFile;    statePtr->errorFile = errorFile;    statePtr->numPids = numPids;    statePtr->pidPtr = pidPtr;    statePtr->isNonBlocking = 0;    mode = 0;    if (readFile) {        mode |= TCL_READABLE;    }    if (writeFile) {        mode |= TCL_WRITABLE;    }        /*     * Use one of the fds associated with the channel as the     * channel id.     */    if (readFile) {	channelId = GetFd(readFile);    } else if (writeFile) {	channelId = GetFd(writeFile);    } else if (errorFile) {	channelId = GetFd(errorFile);    } else {	channelId = 0;    }    /*     * For backward compatibility with previous versions of Tcl, we     * use "file%d" as the base name for pipes even though it would     * be more natural to use "pipe%d".     */    sprintf(channelName, "file%d", channelId);    statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,            (ClientData) statePtr, mode);    return statePtr->channel;}/* *---------------------------------------------------------------------- * * TclGetAndDetachPids -- * *	This procedure is invoked in the generic implementation of a *	background "exec" (An exec when invoked with a terminating "&") *	to store a list of the PIDs for processes in a command pipeline *	in the interp's result and to detach the processes. * * Results: *	None. * * Side effects: *	Modifies the interp's result. Detaches processes. * *---------------------------------------------------------------------- */voidTclGetAndDetachPids(interp, chan)    Tcl_Interp *interp;    Tcl_Channel chan;{    PipeState *pipePtr;    Tcl_ChannelType *chanTypePtr;    int i;    char buf[TCL_INTEGER_SPACE];    /*     * Punt if the channel is not a command channel.     */    chanTypePtr = Tcl_GetChannelType(chan);    if (chanTypePtr != &pipeChannelType) {        return;    }    pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);    for (i = 0; i < pipePtr->numPids; i++) {        TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));        Tcl_AppendElement(interp, buf);        Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));    }    if (pipePtr->numPids > 0) {        ckfree((char *) pipePtr->pidPtr);        pipePtr->numPids = 0;    }}/* *---------------------------------------------------------------------- * * PipeBlockModeProc -- * *	Helper procedure to set blocking and nonblocking modes on a *	pipe based channel. Invoked by generic IO level code. * * Results: *	0 if successful, errno when failed. * * Side effects: *	Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */	/* ARGSUSED */static intPipeBlockModeProc(instanceData, mode)    ClientData instanceData;		/* Pipe state. */    int mode;				/* The mode to set. Can be one of                                         * TCL_MODE_BLOCKING or                                         * TCL_MODE_NONBLOCKING. */{    PipeState *psPtr = (PipeState *) instanceData;    int curStatus;    int fd;#ifndef	USE_FIONBIO    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -