4 * This file implements the UNIX-specific exec pipeline functions,
5 * the "pipe" channel driver, and the "pid" Tcl command.
7 * Copyright (c) 1991-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
20 * The following macros convert between TclFile's and fd's. The conversion
21 * simple involves shifting fd's up by one to ensure that no valid fd is ever
25 #define MakeFile(fd) ((TclFile)(((int)fd)+1))
26 #define GetFd(file) (((int)file)-1)
29 * This structure describes per-instance state of a pipe based channel.
32 typedef struct PipeState {
33 Tcl_Channel channel;/* Channel associated with this file. */
34 TclFile inFile; /* Output from pipe. */
35 TclFile outFile; /* Input to pipe. */
36 TclFile errorFile; /* Error output from pipe. */
37 int numPids; /* How many processes are attached to this pipe? */
38 Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
39 * the creator of the pipe. */
40 int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode.
41 * Used to decide whether to wait for the children
46 * Declarations for local procedures defined in this file:
49 static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
51 static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
53 static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
54 int direction, ClientData *handlePtr));
55 static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
56 char *buf, int toRead, int *errorCode));
57 static int PipeOutputProc _ANSI_ARGS_((
58 ClientData instanceData, CONST char *buf, int toWrite,
60 static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
61 static void RestoreSignals _ANSI_ARGS_((void));
62 static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
65 * This structure describes the channel type structure for command pipe
69 static Tcl_ChannelType pipeChannelType = {
70 "pipe", /* Type name. */
71 TCL_CHANNEL_VERSION_2, /* v2 channel */
72 PipeCloseProc, /* Close proc. */
73 PipeInputProc, /* Input proc. */
74 PipeOutputProc, /* Output proc. */
75 NULL, /* Seek proc. */
76 NULL, /* Set option proc. */
77 NULL, /* Get option proc. */
78 PipeWatchProc, /* Initialize notifier. */
79 PipeGetHandleProc, /* Get OS handles out of channel. */
80 NULL, /* close2proc. */
81 PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
82 NULL, /* flush proc. */
83 NULL, /* handler proc. */
87 *----------------------------------------------------------------------
91 * Make a TclFile from a channel.
94 * Returns a new TclFile or NULL on failure.
99 *----------------------------------------------------------------------
103 TclpMakeFile(channel, direction)
104 Tcl_Channel channel; /* Channel to get file from. */
105 int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
109 if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data)
111 return MakeFile((int)data);
113 return (TclFile) NULL;
118 *----------------------------------------------------------------------
122 * Open a file for use in a pipeline.
125 * Returns a new TclFile handle or NULL on failure.
128 * May cause a file to be created on the file system.
130 *----------------------------------------------------------------------
134 TclpOpenFile(fname, mode)
135 CONST char *fname; /* The name of the file to open. */
136 int mode; /* In what mode to open the file? */
142 native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
143 fd = TclOSopen(native, mode, 0666); /* INTL: Native. */
144 Tcl_DStringFree(&ds);
146 fcntl(fd, F_SETFD, FD_CLOEXEC);
149 * If the file is being opened for writing, seek to the end
150 * so we can append to any data already in the file.
153 if (mode & O_WRONLY) {
154 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END);
158 * Increment the fd so it can't be 0, which would conflict with
159 * the NULL return for errors.
168 *----------------------------------------------------------------------
170 * TclpCreateTempFile --
172 * This function creates a temporary file initialized with an
173 * optional string, and returns a file handle with the file pointer
174 * at the beginning of the file.
177 * A handle to a file.
182 *----------------------------------------------------------------------
186 TclpCreateTempFile(contents)
187 CONST char *contents; /* String to write into temp file, or NULL. */
189 char fileName[L_tmpnam + 9];
195 * We should also check against making more then TMP_MAX of these.
198 strcpy(fileName, P_tmpdir); /* INTL: Native. */
199 if (fileName[strlen(fileName) - 1] != '/') {
200 strcat(fileName, "/"); /* INTL: Native. */
202 strcat(fileName, "tclXXXXXX");
203 fd = mkstemp(fileName); /* INTL: Native. */
207 fcntl(fd, F_SETFD, FD_CLOEXEC);
208 unlink(fileName); /* INTL: Native. */
210 if (contents != NULL) {
211 native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
212 if (write(fd, native, strlen(native)) == -1) {
214 Tcl_DStringFree(&dstring);
217 Tcl_DStringFree(&dstring);
218 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET);
224 *----------------------------------------------------------------------
226 * TclpTempFileName --
228 * This function returns unique filename.
231 * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure.
236 *----------------------------------------------------------------------
242 char fileName[L_tmpnam + 9];
243 Tcl_Obj *result = NULL;
247 * We should also check against making more then TMP_MAX of these.
250 strcpy(fileName, P_tmpdir); /* INTL: Native. */
251 if (fileName[strlen(fileName) - 1] != '/') {
252 strcat(fileName, "/"); /* INTL: Native. */
254 strcat(fileName, "tclXXXXXX");
255 fd = mkstemp(fileName); /* INTL: Native. */
259 fcntl(fd, F_SETFD, FD_CLOEXEC);
260 unlink(fileName); /* INTL: Native. */
262 result = TclpNativeToNormalized((ClientData) fileName);
268 *----------------------------------------------------------------------
272 * Creates a pipe - simply calls the pipe() function.
275 * Returns 1 on success, 0 on failure.
280 *----------------------------------------------------------------------
284 TclpCreatePipe(readPipe, writePipe)
285 TclFile *readPipe; /* Location to store file handle for
286 * read side of pipe. */
287 TclFile *writePipe; /* Location to store file handle for
288 * write side of pipe. */
292 if (pipe(pipeIds) != 0) {
296 fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);
297 fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);
299 *readPipe = MakeFile(pipeIds[0]);
300 *writePipe = MakeFile(pipeIds[1]);
305 *----------------------------------------------------------------------
309 * Implements a mechanism to close a UNIX file.
312 * Returns 0 on success, or -1 on error, setting errno.
315 * The file is closed.
317 *----------------------------------------------------------------------
322 TclFile file; /* The file to close. */
324 int fd = GetFd(file);
327 * Refuse to close the fds for stdin, stdout and stderr.
330 if ((fd == 0) || (fd == 1) || (fd == 2)) {
334 Tcl_DeleteFileHandler(fd);
339 *---------------------------------------------------------------------------
341 * TclpCreateProcess --
343 * Create a child process that has the specified files as its
344 * standard input, output, and error. The child process runs
345 * asynchronously and runs with the same environment variables
346 * as the creating process.
348 * The path is searched to find the specified executable.
351 * The return value is TCL_ERROR and an error message is left in
352 * the interp's result if there was a problem creating the child
353 * process. Otherwise, the return value is TCL_OK and *pidPtr is
354 * filled with the process id of the child process.
357 * A process is created.
359 *---------------------------------------------------------------------------
364 TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
366 Tcl_Interp *interp; /* Interpreter in which to leave errors that
367 * occurred when creating the child process.
368 * Error messages from the child process
369 * itself are sent to errorFile. */
370 int argc; /* Number of arguments in following array. */
371 CONST char **argv; /* Array of argument strings in UTF-8.
372 * argv[0] contains the name of the executable
373 * translated using Tcl_TranslateFileName
374 * call). Additional arguments have not been
376 TclFile inputFile; /* If non-NULL, gives the file to use as
377 * input for the child process. If inputFile
378 * file is not readable or is NULL, the child
379 * will receive no standard input. */
380 TclFile outputFile; /* If non-NULL, gives the file that
381 * receives output from the child process. If
382 * outputFile file is not writeable or is
383 * NULL, output from the child will be
385 TclFile errorFile; /* If non-NULL, gives the file that
386 * receives errors from the child process. If
387 * errorFile file is not writeable or is NULL,
388 * errors from the child will be discarded.
389 * errorFile may be the same as outputFile. */
390 Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr
391 * is filled with the process id of the child
394 TclFile errPipeIn, errPipeOut;
395 int joinThisError, count, status, fd;
396 char errSpace[200 + TCL_INTEGER_SPACE];
397 Tcl_DString *dsArray;
406 * Create a pipe that the child can use to return error
407 * information if anything goes wrong.
410 if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
411 Tcl_AppendResult(interp, "couldn't create pipe: ",
412 Tcl_PosixError(interp), (char *) NULL);
417 * We need to allocate and convert this before the fork
418 * so it is properly deallocated later
420 dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
421 newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
422 newArgv[argc] = NULL;
423 for (i = 0; i < argc; i++) {
424 newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
427 joinThisError = errorFile && (errorFile == outputFile);
430 fd = GetFd(errPipeOut);
433 * Set up stdio file handles for the child process.
436 if (!SetupStdFile(inputFile, TCL_STDIN)
437 || !SetupStdFile(outputFile, TCL_STDOUT)
438 || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
440 ((dup2(1,2) == -1) ||
441 (fcntl(2, F_SETFD, 0) != 0)))) {
443 "%dforked process couldn't set up input/output: ", errno);
444 write(fd, errSpace, (size_t) strlen(errSpace));
449 * Close the input side of the error pipe.
453 execvp(newArgv[0], newArgv); /* INTL: Native. */
454 sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
455 write(fd, errSpace, (size_t) strlen(errSpace));
460 * Free the mem we used for the fork
462 for (i = 0; i < argc; i++) {
463 Tcl_DStringFree(&dsArray[i]);
465 ckfree((char *) dsArray);
466 ckfree((char *) newArgv);
469 Tcl_AppendResult(interp, "couldn't fork child process: ",
470 Tcl_PosixError(interp), (char *) NULL);
475 * Read back from the error pipe to see if the child started
476 * up OK. The info in the pipe (if any) consists of a decimal
477 * errno value followed by an error message.
480 TclpCloseFile(errPipeOut);
483 fd = GetFd(errPipeIn);
484 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
488 errno = strtol(errSpace, &end, 10);
489 Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
494 TclpCloseFile(errPipeIn);
495 *pidPtr = (Tcl_Pid) pid;
501 * Reap the child process now if an error occurred during its
502 * startup. We don't call this with WNOHANG because that can lead to
503 * defunct processes on an MP system. We shouldn't have to worry
504 * about hanging here, since this is the error case. [Bug: 6148]
507 Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
511 TclpCloseFile(errPipeIn);
514 TclpCloseFile(errPipeOut);
520 *----------------------------------------------------------------------
524 * This procedure is invoked in a forked child process just before
525 * exec-ing a new program to restore all signals to their default
532 * Signal settings get changed.
534 *----------------------------------------------------------------------
541 signal(SIGABRT, SIG_DFL);
544 signal(SIGALRM, SIG_DFL);
547 signal(SIGFPE, SIG_DFL);
550 signal(SIGHUP, SIG_DFL);
553 signal(SIGILL, SIG_DFL);
556 signal(SIGINT, SIG_DFL);
559 signal(SIGPIPE, SIG_DFL);
562 signal(SIGQUIT, SIG_DFL);
565 signal(SIGSEGV, SIG_DFL);
568 signal(SIGTERM, SIG_DFL);
571 signal(SIGUSR1, SIG_DFL);
574 signal(SIGUSR2, SIG_DFL);
577 signal(SIGCHLD, SIG_DFL);
580 signal(SIGCONT, SIG_DFL);
583 signal(SIGTSTP, SIG_DFL);
586 signal(SIGTTIN, SIG_DFL);
589 signal(SIGTTOU, SIG_DFL);
594 *----------------------------------------------------------------------
598 * Set up stdio file handles for the child process, using the
599 * current standard channels if no other files are specified.
600 * If no standard channel is defined, or if no file is associated
601 * with the channel, then the corresponding standard fd is closed.
604 * Returns 1 on success, or 0 on failure.
607 * Replaces stdio fds.
609 *----------------------------------------------------------------------
613 SetupStdFile(file, type)
614 TclFile file; /* File to dup, or NULL. */
615 int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
619 int targetFd = 0; /* Initializations here needed only to */
620 int direction = 0; /* prevent warnings about using uninitialized
626 direction = TCL_READABLE;
630 direction = TCL_WRITABLE;
634 direction = TCL_WRITABLE;
639 channel = Tcl_GetStdChannel(type);
641 file = TclpMakeFile(channel, direction);
646 if (fd != targetFd) {
647 if (dup2(fd, targetFd) == -1) {
652 * Must clear the close-on-exec flag for the target FD, since
653 * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
657 fcntl(targetFd, F_SETFD, 0);
662 * Since we aren't dup'ing the file, we need to explicitly clear
663 * the close-on-exec flag.
666 result = fcntl(fd, F_SETFD, 0);
675 *----------------------------------------------------------------------
677 * TclpCreateCommandChannel --
679 * This function is called by the generic IO level to perform
680 * the platform specific channel initialization for a command
684 * Returns a new channel or NULL on failure.
687 * Allocates a new channel.
689 *----------------------------------------------------------------------
693 TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
694 TclFile readFile; /* If non-null, gives the file for reading. */
695 TclFile writeFile; /* If non-null, gives the file for writing. */
696 TclFile errorFile; /* If non-null, gives the file where errors
698 int numPids; /* The number of pids in the pid array. */
699 Tcl_Pid *pidPtr; /* An array of process identifiers.
700 * Allocated by the caller, freed when
701 * the channel is closed or the processes
702 * are detached (in a background exec). */
704 char channelName[16 + TCL_INTEGER_SPACE];
706 PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));
709 statePtr->inFile = readFile;
710 statePtr->outFile = writeFile;
711 statePtr->errorFile = errorFile;
712 statePtr->numPids = numPids;
713 statePtr->pidPtr = pidPtr;
714 statePtr->isNonBlocking = 0;
718 mode |= TCL_READABLE;
721 mode |= TCL_WRITABLE;
725 * Use one of the fds associated with the channel as the
730 channelId = GetFd(readFile);
731 } else if (writeFile) {
732 channelId = GetFd(writeFile);
733 } else if (errorFile) {
734 channelId = GetFd(errorFile);
740 * For backward compatibility with previous versions of Tcl, we
741 * use "file%d" as the base name for pipes even though it would
742 * be more natural to use "pipe%d".
745 sprintf(channelName, "file%d", channelId);
746 statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
747 (ClientData) statePtr, mode);
748 return statePtr->channel;
752 *----------------------------------------------------------------------
754 * TclGetAndDetachPids --
756 * This procedure is invoked in the generic implementation of a
757 * background "exec" (An exec when invoked with a terminating "&")
758 * to store a list of the PIDs for processes in a command pipeline
759 * in the interp's result and to detach the processes.
765 * Modifies the interp's result. Detaches processes.
767 *----------------------------------------------------------------------
771 TclGetAndDetachPids(interp, chan)
776 Tcl_ChannelType *chanTypePtr;
778 char buf[TCL_INTEGER_SPACE];
781 * Punt if the channel is not a command channel.
784 chanTypePtr = Tcl_GetChannelType(chan);
785 if (chanTypePtr != &pipeChannelType) {
789 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
790 for (i = 0; i < pipePtr->numPids; i++) {
791 TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
792 Tcl_AppendElement(interp, buf);
793 Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
795 if (pipePtr->numPids > 0) {
796 ckfree((char *) pipePtr->pidPtr);
797 pipePtr->numPids = 0;
802 *----------------------------------------------------------------------
804 * PipeBlockModeProc --
806 * Helper procedure to set blocking and nonblocking modes on a
807 * pipe based channel. Invoked by generic IO level code.
810 * 0 if successful, errno when failed.
813 * Sets the device into blocking or non-blocking mode.
815 *----------------------------------------------------------------------
820 PipeBlockModeProc(instanceData, mode)
821 ClientData instanceData; /* Pipe state. */
822 int mode; /* The mode to set. Can be one of
823 * TCL_MODE_BLOCKING or
824 * TCL_MODE_NONBLOCKING. */
826 PipeState *psPtr = (PipeState *) instanceData;
832 fd = GetFd(psPtr->inFile);
833 curStatus = fcntl(fd, F_GETFL);
834 if (mode == TCL_MODE_BLOCKING) {
835 curStatus &= (~(O_NONBLOCK));
837 curStatus |= O_NONBLOCK;
839 if (fcntl(fd, F_SETFL, curStatus) < 0) {
843 if (psPtr->outFile) {
844 fd = GetFd(psPtr->outFile);
845 curStatus = fcntl(fd, F_GETFL);
846 if (mode == TCL_MODE_BLOCKING) {
847 curStatus &= (~(O_NONBLOCK));
849 curStatus |= O_NONBLOCK;
851 if (fcntl(fd, F_SETFL, curStatus) < 0) {
855 #endif /* !FIONBIO */
859 fd = GetFd(psPtr->inFile);
860 if (mode == TCL_MODE_BLOCKING) {
865 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
869 if (psPtr->outFile != NULL) {
870 fd = GetFd(psPtr->outFile);
871 if (mode == TCL_MODE_BLOCKING) {
876 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
880 #endif /* USE_FIONBIO */
882 psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
888 *----------------------------------------------------------------------
892 * This procedure is invoked by the generic IO level to perform
893 * channel-type-specific cleanup when a command pipeline channel
897 * 0 on success, errno otherwise.
900 * Closes the command pipeline channel.
902 *----------------------------------------------------------------------
907 PipeCloseProc(instanceData, interp)
908 ClientData instanceData; /* The pipe to close. */
909 Tcl_Interp *interp; /* For error reporting. */
913 int errorCode, result;
917 pipePtr = (PipeState *) instanceData;
918 if (pipePtr->inFile) {
919 if (TclpCloseFile(pipePtr->inFile) < 0) {
923 if (pipePtr->outFile) {
924 if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {
929 if (pipePtr->isNonBlocking || TclInExit()) {
932 * If the channel is non-blocking or Tcl is being cleaned up, just
933 * detach the children PIDs, reap them (important if we are in a
934 * dynamic load module), and discard the errorFile.
937 Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
938 Tcl_ReapDetachedProcs();
940 if (pipePtr->errorFile) {
941 TclpCloseFile(pipePtr->errorFile);
946 * Wrap the error file into a channel and give it to the cleanup
950 if (pipePtr->errorFile) {
951 errChan = Tcl_MakeFileChannel(
952 (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
956 result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
960 if (pipePtr->numPids != 0) {
961 ckfree((char *) pipePtr->pidPtr);
963 ckfree((char *) pipePtr);
964 if (errorCode == 0) {
971 *----------------------------------------------------------------------
975 * This procedure is invoked from the generic IO level to read
976 * input from a command pipeline based channel.
979 * The number of bytes read is returned or -1 on error. An output
980 * argument contains a POSIX error code if an error occurs, or zero.
983 * Reads input from the input device of the channel.
985 *----------------------------------------------------------------------
989 PipeInputProc(instanceData, buf, toRead, errorCodePtr)
990 ClientData instanceData; /* Pipe state. */
991 char *buf; /* Where to store data read. */
992 int toRead; /* How much space is available
994 int *errorCodePtr; /* Where to store error code. */
996 PipeState *psPtr = (PipeState *) instanceData;
997 int bytesRead; /* How many bytes were actually
998 * read from the input device? */
1003 * Assume there is always enough input available. This will block
1004 * appropriately, and read will unblock as soon as a short read is
1005 * possible, if the channel is in blocking mode. If the channel is
1006 * nonblocking, the read will never block.
1007 * Some OSes can throw an interrupt error, for which we should
1008 * immediately retry. [Bug #415131]
1012 bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead);
1013 } while ((bytesRead < 0) && (errno == EINTR));
1015 if (bytesRead < 0) {
1016 *errorCodePtr = errno;
1024 *----------------------------------------------------------------------
1028 * This procedure is invoked from the generic IO level to write
1029 * output to a command pipeline based channel.
1032 * The number of bytes written is returned or -1 on error. An
1033 * output argument contains a POSIX error code if an error occurred,
1037 * Writes output on the output device of the channel.
1039 *----------------------------------------------------------------------
1043 PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
1044 ClientData instanceData; /* Pipe state. */
1045 CONST char *buf; /* The data buffer. */
1046 int toWrite; /* How many bytes to write? */
1047 int *errorCodePtr; /* Where to store error code. */
1049 PipeState *psPtr = (PipeState *) instanceData;
1055 * Some OSes can throw an interrupt error, for which we should
1056 * immediately retry. [Bug #415131]
1060 written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite);
1061 } while ((written < 0) && (errno == EINTR));
1064 *errorCodePtr = errno;
1072 *----------------------------------------------------------------------
1076 * Initialize the notifier to watch the fds from this channel.
1082 * Sets up the notifier so that a future event on the channel will
1085 *----------------------------------------------------------------------
1089 PipeWatchProc(instanceData, mask)
1090 ClientData instanceData; /* The pipe state. */
1091 int mask; /* Events of interest; an OR-ed
1092 * combination of TCL_READABLE,
1093 * TCL_WRITABEL and TCL_EXCEPTION. */
1095 PipeState *psPtr = (PipeState *) instanceData;
1098 if (psPtr->inFile) {
1099 newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
1101 Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,
1102 (Tcl_FileProc *) Tcl_NotifyChannel,
1103 (ClientData) psPtr->channel);
1105 Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
1108 if (psPtr->outFile) {
1109 newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
1111 Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,
1112 (Tcl_FileProc *) Tcl_NotifyChannel,
1113 (ClientData) psPtr->channel);
1115 Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
1121 *----------------------------------------------------------------------
1123 * PipeGetHandleProc --
1125 * Called from Tcl_GetChannelHandle to retrieve OS handles from
1126 * inside a command pipeline based channel.
1129 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
1130 * there is no handle for the specified direction.
1135 *----------------------------------------------------------------------
1139 PipeGetHandleProc(instanceData, direction, handlePtr)
1140 ClientData instanceData; /* The pipe state. */
1141 int direction; /* TCL_READABLE or TCL_WRITABLE */
1142 ClientData *handlePtr; /* Where to store the handle. */
1144 PipeState *psPtr = (PipeState *) instanceData;
1146 if (direction == TCL_READABLE && psPtr->inFile) {
1147 *handlePtr = (ClientData) GetFd(psPtr->inFile);
1150 if (direction == TCL_WRITABLE && psPtr->outFile) {
1151 *handlePtr = (ClientData) GetFd(psPtr->outFile);
1158 *----------------------------------------------------------------------
1162 * Implements the waitpid system call on Unix systems.
1165 * Result of calling waitpid.
1168 * Waits for a process to terminate.
1170 *----------------------------------------------------------------------
1174 Tcl_WaitPid(pid, statPtr, options)
1182 real_pid = (pid_t) pid;
1184 result = (int) waitpid(real_pid, statPtr, options);
1185 if ((result != -1) || (errno != EINTR)) {
1186 return (Tcl_Pid) result;
1192 *----------------------------------------------------------------------
1196 * This procedure is invoked to process the "pid" Tcl command.
1197 * See the user documentation for details on what it does.
1200 * A standard Tcl result.
1203 * See the user documentation.
1205 *----------------------------------------------------------------------
1210 Tcl_PidObjCmd(dummy, interp, objc, objv)
1211 ClientData dummy; /* Not used. */
1212 Tcl_Interp *interp; /* Current interpreter. */
1213 int objc; /* Number of arguments. */
1214 Tcl_Obj *CONST *objv; /* Argument strings. */
1217 Tcl_ChannelType *chanTypePtr;
1220 Tcl_Obj *resultPtr, *longObjPtr;
1223 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
1227 Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());
1229 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
1230 if (chan == (Tcl_Channel) NULL) {
1233 chanTypePtr = Tcl_GetChannelType(chan);
1234 if (chanTypePtr != &pipeChannelType) {
1237 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
1238 resultPtr = Tcl_GetObjResult(interp);
1239 for (i = 0; i < pipePtr->numPids; i++) {
1240 longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i]));
1241 Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr);