os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixPipe.c
Update contrib.
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.
9 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * RCS: @(#) $Id: tclUnixPipe.c,v 1.23.2.7 2006/08/02 20:04:40 das Exp $
20 #if defined(__SYMBIAN32__)
21 #include "tclSymbianGlobals.h"
23 #define ADDPARAMTOCHILD 4
26 void TclPrint1(const char* aFmt, const char* aStr);
27 void TclPrint2(const char* aFmt, const char* aStr, int aNum);
28 void TclPrint3(const char* aFmt);
36 * The following macros convert between TclFile's and fd's. The conversion
37 * simple involves shifting fd's up by one to ensure that no valid fd is ever
41 #define MakeFile(fd) ((TclFile)(((int)fd)+1))
42 #define GetFd(file) (((int)file)-1)
44 * This structure describes per-instance state of a pipe based channel.
47 typedef struct PipeState {
48 Tcl_Channel channel;/* Channel associated with this file. */
49 TclFile inFile; /* Output from pipe. */
50 TclFile outFile; /* Input to pipe. */
51 TclFile errorFile; /* Error output from pipe. */
52 int numPids; /* How many processes are attached to this pipe? */
53 Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
54 * the creator of the pipe. */
55 int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode.
56 * Used to decide whether to wait for the children
61 * Declarations for local procedures defined in this file:
64 static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
66 static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
68 static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
69 int direction, ClientData *handlePtr));
70 static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
71 char *buf, int toRead, int *errorCode));
72 static int PipeOutputProc _ANSI_ARGS_((
73 ClientData instanceData, CONST char *buf, int toWrite,
75 static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
76 static void RestoreSignals _ANSI_ARGS_((void));
78 static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
81 * This structure describes the channel type structure for command pipe
85 static Tcl_ChannelType pipeChannelType = {
86 "pipe", /* Type name. */
87 TCL_CHANNEL_VERSION_4, /* v4 channel */
88 PipeCloseProc, /* Close proc. */
89 PipeInputProc, /* Input proc. */
90 PipeOutputProc, /* Output proc. */
91 NULL, /* Seek proc. */
92 NULL, /* Set option proc. */
93 NULL, /* Get option proc. */
94 PipeWatchProc, /* Initialize notifier. */
95 PipeGetHandleProc, /* Get OS handles out of channel. */
96 NULL, /* close2proc. */
97 PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
98 NULL, /* flush proc. */
99 NULL, /* handler proc. */
100 NULL, /* wide seek proc */
101 NULL, /* thread action proc */
105 *----------------------------------------------------------------------
109 * Make a TclFile from a channel.
112 * Returns a new TclFile or NULL on failure.
117 *----------------------------------------------------------------------
121 TclpMakeFile(channel, direction)
122 Tcl_Channel channel; /* Channel to get file from. */
123 int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
127 if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data)
129 return MakeFile((int)data);
131 return (TclFile) NULL;
136 *----------------------------------------------------------------------
140 * Open a file for use in a pipeline.
143 * Returns a new TclFile handle or NULL on failure.
146 * May cause a file to be created on the file system.
148 *----------------------------------------------------------------------
152 TclpOpenFile(fname, mode)
153 CONST char *fname; /* The name of the file to open. */
154 int mode; /* In what mode to open the file? */
160 native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
161 fd = TclOSopen(native, mode, 0666); /* INTL: Native. */
162 Tcl_DStringFree(&ds);
164 fcntl(fd, F_SETFD, FD_CLOEXEC);
167 * If the file is being opened for writing, seek to the end
168 * so we can append to any data already in the file.
171 if ((mode & O_WRONLY) && !(mode & O_APPEND)) {
172 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END);
176 * Increment the fd so it can't be 0, which would conflict with
177 * the NULL return for errors.
186 *----------------------------------------------------------------------
188 * TclpCreateTempFile --
190 * This function creates a temporary file initialized with an
191 * optional string, and returns a file handle with the file pointer
192 * at the beginning of the file.
195 * A handle to a file.
200 *----------------------------------------------------------------------
204 TclpCreateTempFile(contents)
205 CONST char *contents; /* String to write into temp file, or NULL. */
207 char fileName[L_tmpnam + 9];
213 * We should also check against making more then TMP_MAX of these.
216 // Symbian doesn't have a default temp directory, so we use cwd (root of private data cage)
218 if (getcwd(fileName, L_tmpnam) == NULL)
222 /* TODO - the line bellow is a temporary patch. The defect number is: DEF116621. */
225 strcpy(fileName, P_tmpdir); /* INTL: Native. */
227 if (fileName[strlen(fileName) - 1] != '/') {
229 strcat(fileName, "\\");
231 strcat(fileName, "/"); /* INTL: Native. */
234 strcat(fileName, "tclXXXXXX");
235 fd = mkstemp(fileName); /* INTL: Native. */
239 fcntl(fd, F_SETFD, FD_CLOEXEC);
241 strcpy(tmpFileName, fileName);
243 unlink(fileName); /* INTL: Native. */
245 if (contents != NULL) {
246 native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
247 if (write(fd, native, strlen(native)) == -1) {
249 Tcl_DStringFree(&dstring);
252 Tcl_DStringFree(&dstring);
253 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET);
259 *----------------------------------------------------------------------
261 * TclpTempFileName --
263 * This function returns unique filename.
266 * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure.
271 *----------------------------------------------------------------------
277 char fileName[L_tmpnam + 9];
278 Tcl_Obj *result = NULL;
282 * We should also check against making more then TMP_MAX of these.
285 // Symbian doesn't have a default temp directory, so we use cwd (root of private data cage)
287 if (getcwd(fileName, L_tmpnam) == NULL)
291 /* TODO - the line bellow is a temporary patch. The defect number is: DEF116621. */
294 strcpy(fileName, P_tmpdir); /* INTL: Native. */
296 if (fileName[strlen(fileName) - 1] != '/') {
298 strcat(fileName, "\\");
300 strcat(fileName, "/"); /* INTL: Native. */
303 strcat(fileName, "tclXXXXXX");
304 fd = mkstemp(fileName); /* INTL: Native. */
308 fcntl(fd, F_SETFD, FD_CLOEXEC);
309 unlink(fileName); /* INTL: Native. */
311 result = TclpNativeToNormalized((ClientData) fileName);
317 *----------------------------------------------------------------------
321 * Creates a pipe - simply calls the pipe() function.
324 * Returns 1 on success, 0 on failure.
329 *----------------------------------------------------------------------
333 TclpCreatePipe(readPipe, writePipe)
334 TclFile *readPipe; /* Location to store file handle for
335 * read side of pipe. */
336 TclFile *writePipe; /* Location to store file handle for
337 * write side of pipe. */
341 if (pipe(pipeIds) != 0) {
345 fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);
346 fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);
348 *readPipe = MakeFile(pipeIds[0]);
349 *writePipe = MakeFile(pipeIds[1]);
354 *----------------------------------------------------------------------
358 * Implements a mechanism to close a UNIX file.
361 * Returns 0 on success, or -1 on error, setting errno.
364 * The file is closed.
366 *----------------------------------------------------------------------
371 TclFile file; /* The file to close. */
373 int fd = GetFd(file);
376 * Refuse to close the fds for stdin, stdout and stderr.
379 if ((fd == 0) || (fd == 1) || (fd == 2)) {
383 Tcl_DeleteFileHandler(fd);
388 *---------------------------------------------------------------------------
390 * TclpCreateProcess --
392 * Create a child process that has the specified files as its
393 * standard input, output, and error. The child process runs
394 * asynchronously and runs with the same environment variables
395 * as the creating process.
397 * The path is searched to find the specified executable.
400 * The return value is TCL_ERROR and an error message is left in
401 * the interp's result if there was a problem creating the child
402 * process. Otherwise, the return value is TCL_OK and *pidPtr is
403 * filled with the process id of the child process.
406 * A process is created.
408 *---------------------------------------------------------------------------
413 TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
415 Tcl_Interp *interp; /* Interpreter in which to leave errors that
416 * occurred when creating the child process.
417 * Error messages from the child process
418 * itself are sent to errorFile. */
419 int argc; /* Number of arguments in following array. */
420 CONST char **argv; /* Array of argument strings in UTF-8.
421 * argv[0] contains the name of the executable
422 * translated using Tcl_TranslateFileName
423 * call). Additional arguments have not been
425 TclFile inputFile; /* If non-NULL, gives the file to use as
426 * input for the child process. If inputFile
427 * file is not readable or is NULL, the child
428 * will receive no standard input. */
429 TclFile outputFile; /* If non-NULL, gives the file that
430 * receives output from the child process. If
431 * outputFile file is not writeable or is
432 * NULL, output from the child will be
434 TclFile errorFile; /* If non-NULL, gives the file that
435 * receives errors from the child process. If
436 * errorFile file is not writeable or is NULL,
437 * errors from the child will be discarded.
438 * errorFile may be the same as outputFile. */
439 Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr
440 * is filled with the process id of the child
443 TclFile errPipeIn, errPipeOut;
444 int count, status, fd;
445 char errSpace[200 + TCL_INTEGER_SPACE];
446 Tcl_DString *dsArray;
463 * Create a pipe that the child can use to return error
464 * information if anything goes wrong.
467 // change the communication between parent and child process, it just report the failure of child process creation
469 tmpnam(fifoFileName);
470 fifoResult = mkfifo(fifoFileName,S_IXGRP);
473 //fifo creation failure.
474 fprintf(stderr,"\n*** failure mkfifo errno is %d***\n",errno);
479 int ReadFifoFd = open(fifoFileName,O_RDONLY | O_NONBLOCK);
483 //Failed to open the Fifo
484 printf("\n*** failure Fifo Open ***\n");
489 errPipeIn = MakeFile(ReadFifoFd);
493 //set the stdin,stdout,stderr and pipeid to the child process. the fds are passed to the posix_spawn() in argv
494 argc = argc + ADDPARAMTOCHILD;
497 if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
498 Tcl_AppendResult(interp, "couldn't create pipe: ",
499 Tcl_PosixError(interp), (char *) NULL);
505 * We need to allocate and convert this before the fork
506 * so it is properly deallocated later
508 dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
509 newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
510 newArgv[argc] = NULL;
512 for (i = 0; i < (argc-ADDPARAMTOCHILD); i++) {
514 for (i = 0; i < argc; i++) {
516 newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
520 fprintf(stderr,"\r\n");
521 //set the stdin,stdout,stderr to the child process. the fds pass to the posix_spawn() in argv
522 for (i = argc-ADDPARAMTOCHILD; i < argc; i++)
524 if(i == (argc-ADDPARAMTOCHILD))
526 strcpy(buf,fifoFileName);
527 fprintf(stderr,"fifoFileName is %s\r\n", fifoFileName);
529 else if(i == (argc-ADDPARAMTOCHILD+1))
533 strcpy(buf,inFileName);
539 fprintf(stderr, "inFileName is %s\r\n", inFileName);
541 else if(i == (argc-ADDPARAMTOCHILD+2))
545 strcpy(buf,outFileName);
551 fprintf(stderr, "outFileName is %s\r\n", outFileName);
553 else if(i == (argc-ADDPARAMTOCHILD+3))
557 strcpy(buf,errFileName);
563 fprintf(stderr, "errFileName is %s\r\n", errFileName);
566 newArgv[i] = Tcl_UtfToExternalDString(NULL, buf, -1, &dsArray[i]);
571 * After vfork(), do not call code in the child that changes global state,
572 * because it is using the parent's memory space at that point and writes
573 * might corrupt the parent: so ensure standard channels are initialized in
574 * the parent, otherwise SetupStdFile() might initialize them in the child.
577 Tcl_GetStdChannel(TCL_STDIN);
580 Tcl_GetStdChannel(TCL_STDOUT);
583 Tcl_GetStdChannel(TCL_STDERR);
586 TclPrint1(" == TclpCreateProcess(), posix_spawn(), process %S\r\n", newArgv[0]);
588 // change fork() using posix_spawn()
591 RetVal= posix_spawn(&pid,newArgv[0],NULL,NULL,newArgv,NULL);
595 RetVal= posix_spawn(&pid,newArgv[0],NULL,NULL,NULL,NULL);
599 pid = -1; //if error, the value of pid is unspecified. ensure we still report the error.
604 int joinThisError = errorFile && (errorFile == outputFile);
606 fd = GetFd(errPipeOut);
609 * Set up stdio file handles for the child process.
612 if (!SetupStdFile(inputFile, TCL_STDIN)
613 || !SetupStdFile(outputFile, TCL_STDOUT)
614 || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
616 ((dup2(1,2) == -1) ||
617 (fcntl(2, F_SETFD, 0) != 0)))) {
618 sprintf(errSpace, "forked process couldn't set up input/output, error: %d\r\n", errno);
619 write(fd, errSpace, (size_t) strlen(errSpace));
624 * Close the input side of the error pipe.
628 execvp(newArgv[0], newArgv); /* INTL: Native. */
629 sprintf(errSpace, "couldn't execute \"%.150s\", error: %d\r\n", argv[0], errno);
630 write(fd, errSpace, (size_t) strlen(errSpace));
634 TclPrint2(" == TclpCreateProcess(), posix_spawn(), process %S, pid %d\r\n", newArgv[0], (int)pid);
637 // Free the mem we used for the fork
639 for (i = 0; i < argc; i++) {
640 Tcl_DStringFree(&dsArray[i]);
642 ckfree((char *) dsArray);
643 ckfree((char *) newArgv);
647 Tcl_AppendResult(interp, "couldn't posix_spawn child process: ",
649 Tcl_AppendResult(interp, "couldn't fork child process: ",
651 Tcl_PosixError(interp), (char *) NULL);
656 * Read back from the error pipe to see if the child started
657 * up OK. The info in the pipe (if any) consists of a decimal
658 * errno value followed by an error message.
662 TclpCloseFile(errPipeOut);
665 fd = GetFd(errPipeIn);
667 TclPrint3(" == TclpCreateProcess(), select()\r\n");
672 FD_SET(fd, &readfds);
673 // Use select to wait for child process
674 i = select(fd+1, &readfds, NULL, NULL,&tv);
675 if ( i != -1 && FD_ISSET(fd, &readfds))
677 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
681 errno = strtol(errSpace, &end, 10);
684 Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
692 // Process not started properly
693 Tcl_AppendResult(interp, "couldn't read error info from child process: ",
694 Tcl_PosixError(interp), (char *) NULL);
698 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
702 errno = strtol(errSpace, &end, 10);
703 Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
708 TclpCloseFile(errPipeIn);
710 unlink(fifoFileName);
712 *pidPtr = (Tcl_Pid) pid;
713 TclPrint3(" == TclpCreateProcess(), TCL_OK\r\n");
717 TclPrint2(" == TclpCreateProcess(), TCL_ERROR,%S errno %d\r\n", "", errno);
720 * Reap the child process now if an error occurred during its
721 * startup. We don't call this with WNOHANG because that can lead to
722 * defunct processes on an MP system. We shouldn't have to worry
723 * about hanging here, since this is the error case. [Bug: 6148]
726 Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
730 TclpCloseFile(errPipeIn);
733 TclpCloseFile(errPipeOut);
736 unlink(fifoFileName);
743 *----------------------------------------------------------------------
747 * This procedure is invoked in a forked child process just before
748 * exec-ing a new program to restore all signals to their default
755 * Signal settings get changed.
757 *----------------------------------------------------------------------
763 // Symbian & PIPS don't support signals.
764 #ifndef __SYMBIAN32__
766 signal(SIGABRT, SIG_DFL);
769 signal(SIGALRM, SIG_DFL);
772 signal(SIGFPE, SIG_DFL);
775 signal(SIGHUP, SIG_DFL);
778 signal(SIGILL, SIG_DFL);
781 signal(SIGINT, SIG_DFL);
784 signal(SIGPIPE, SIG_DFL);
787 signal(SIGQUIT, SIG_DFL);
790 signal(SIGSEGV, SIG_DFL);
793 signal(SIGTERM, SIG_DFL);
796 signal(SIGUSR1, SIG_DFL);
799 signal(SIGUSR2, SIG_DFL);
802 signal(SIGCHLD, SIG_DFL);
805 signal(SIGCONT, SIG_DFL);
808 signal(SIGTSTP, SIG_DFL);
811 signal(SIGTTIN, SIG_DFL);
814 signal(SIGTTOU, SIG_DFL);
820 *----------------------------------------------------------------------
824 * Set up stdio file handles for the child process, using the
825 * current standard channels if no other files are specified.
826 * If no standard channel is defined, or if no file is associated
827 * with the channel, then the corresponding standard fd is closed.
830 * Returns 1 on success, or 0 on failure.
833 * Replaces stdio fds.
835 *----------------------------------------------------------------------
842 SetupStdFile(file, type)
843 TclFile file; /* File to dup, or NULL. */
844 int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
848 int targetFd = 0; /* Initializations here needed only to */
849 int direction = 0; /* prevent warnings about using uninitialized
855 direction = TCL_READABLE;
859 direction = TCL_WRITABLE;
863 direction = TCL_WRITABLE;
868 channel = Tcl_GetStdChannel(type);
870 file = TclpMakeFile(channel, direction);
875 if (fd != targetFd) {
876 if (dup2(fd, targetFd) == -1) {
881 * Must clear the close-on-exec flag for the target FD, since
882 * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
886 fcntl(targetFd, F_SETFD, 0);
889 * Since we aren't dup'ing the file, we need to explicitly clear
890 * the close-on-exec flag.
893 fcntl(fd, F_SETFD, 0);
902 *----------------------------------------------------------------------
904 * TclpCreateCommandChannel --
906 * This function is called by the generic IO level to perform
907 * the platform specific channel initialization for a command
911 * Returns a new channel or NULL on failure.
914 * Allocates a new channel.
916 *----------------------------------------------------------------------
920 TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
921 TclFile readFile; /* If non-null, gives the file for reading. */
922 TclFile writeFile; /* If non-null, gives the file for writing. */
923 TclFile errorFile; /* If non-null, gives the file where errors
925 int numPids; /* The number of pids in the pid array. */
926 Tcl_Pid *pidPtr; /* An array of process identifiers.
927 * Allocated by the caller, freed when
928 * the channel is closed or the processes
929 * are detached (in a background exec). */
931 char channelName[16 + TCL_INTEGER_SPACE];
933 PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));
936 statePtr->inFile = readFile;
937 statePtr->outFile = writeFile;
938 statePtr->errorFile = errorFile;
939 statePtr->numPids = numPids;
940 statePtr->pidPtr = pidPtr;
941 statePtr->isNonBlocking = 0;
945 mode |= TCL_READABLE;
948 mode |= TCL_WRITABLE;
952 * Use one of the fds associated with the channel as the
957 channelId = GetFd(readFile);
958 } else if (writeFile) {
959 channelId = GetFd(writeFile);
960 } else if (errorFile) {
961 channelId = GetFd(errorFile);
967 * For backward compatibility with previous versions of Tcl, we
968 * use "file%d" as the base name for pipes even though it would
969 * be more natural to use "pipe%d".
972 sprintf(channelName, "file%d", channelId);
973 statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
974 (ClientData) statePtr, mode);
975 return statePtr->channel;
979 *----------------------------------------------------------------------
981 * TclGetAndDetachPids --
983 * This procedure is invoked in the generic implementation of a
984 * background "exec" (An exec when invoked with a terminating "&")
985 * to store a list of the PIDs for processes in a command pipeline
986 * in the interp's result and to detach the processes.
992 * Modifies the interp's result. Detaches processes.
994 *----------------------------------------------------------------------
998 TclGetAndDetachPids(interp, chan)
1003 Tcl_ChannelType *chanTypePtr;
1005 char buf[TCL_INTEGER_SPACE];
1008 * Punt if the channel is not a command channel.
1011 chanTypePtr = Tcl_GetChannelType(chan);
1012 if (chanTypePtr != &pipeChannelType) {
1016 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
1017 for (i = 0; i < pipePtr->numPids; i++) {
1018 TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
1019 Tcl_AppendElement(interp, buf);
1020 Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
1022 if (pipePtr->numPids > 0) {
1023 ckfree((char *) pipePtr->pidPtr);
1024 pipePtr->numPids = 0;
1029 *----------------------------------------------------------------------
1031 * PipeBlockModeProc --
1033 * Helper procedure to set blocking and nonblocking modes on a
1034 * pipe based channel. Invoked by generic IO level code.
1037 * 0 if successful, errno when failed.
1040 * Sets the device into blocking or non-blocking mode.
1042 *----------------------------------------------------------------------
1047 PipeBlockModeProc(instanceData, mode)
1048 ClientData instanceData; /* Pipe state. */
1049 int mode; /* The mode to set. Can be one of
1050 * TCL_MODE_BLOCKING or
1051 * TCL_MODE_NONBLOCKING. */
1053 PipeState *psPtr = (PipeState *) instanceData;
1058 if (psPtr->inFile) {
1059 fd = GetFd(psPtr->inFile);
1060 curStatus = fcntl(fd, F_GETFL);
1061 if (mode == TCL_MODE_BLOCKING) {
1062 curStatus &= (~(O_NONBLOCK));
1064 curStatus |= O_NONBLOCK;
1066 if (fcntl(fd, F_SETFL, curStatus) < 0) {
1070 if (psPtr->outFile) {
1071 fd = GetFd(psPtr->outFile);
1072 curStatus = fcntl(fd, F_GETFL);
1073 if (mode == TCL_MODE_BLOCKING) {
1074 curStatus &= (~(O_NONBLOCK));
1076 curStatus |= O_NONBLOCK;
1078 if (fcntl(fd, F_SETFL, curStatus) < 0) {
1082 #endif /* !FIONBIO */
1085 if (psPtr->inFile) {
1086 fd = GetFd(psPtr->inFile);
1087 if (mode == TCL_MODE_BLOCKING) {
1092 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
1096 if (psPtr->outFile != NULL) {
1097 fd = GetFd(psPtr->outFile);
1098 if (mode == TCL_MODE_BLOCKING) {
1103 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
1107 #endif /* USE_FIONBIO */
1109 psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
1115 *----------------------------------------------------------------------
1119 * This procedure is invoked by the generic IO level to perform
1120 * channel-type-specific cleanup when a command pipeline channel
1124 * 0 on success, errno otherwise.
1127 * Closes the command pipeline channel.
1129 *----------------------------------------------------------------------
1134 PipeCloseProc(instanceData, interp)
1135 ClientData instanceData; /* The pipe to close. */
1136 Tcl_Interp *interp; /* For error reporting. */
1139 Tcl_Channel errChan;
1140 int errorCode, result;
1144 pipePtr = (PipeState *) instanceData;
1145 if (pipePtr->inFile) {
1146 if (TclpCloseFile(pipePtr->inFile) < 0) {
1150 if (pipePtr->outFile) {
1151 if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {
1156 if (pipePtr->isNonBlocking || TclInExit()) {
1159 * If the channel is non-blocking or Tcl is being cleaned up, just
1160 * detach the children PIDs, reap them (important if we are in a
1161 * dynamic load module), and discard the errorFile.
1164 Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
1165 Tcl_ReapDetachedProcs();
1167 if (pipePtr->errorFile) {
1168 TclpCloseFile(pipePtr->errorFile);
1173 * Wrap the error file into a channel and give it to the cleanup
1177 if (pipePtr->errorFile) {
1178 errChan = Tcl_MakeFileChannel(
1179 (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
1183 result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
1187 if (pipePtr->numPids != 0) {
1188 ckfree((char *) pipePtr->pidPtr);
1190 ckfree((char *) pipePtr);
1191 if (errorCode == 0) {
1198 *----------------------------------------------------------------------
1202 * This procedure is invoked from the generic IO level to read
1203 * input from a command pipeline based channel.
1206 * The number of bytes read is returned or -1 on error. An output
1207 * argument contains a POSIX error code if an error occurs, or zero.
1210 * Reads input from the input device of the channel.
1212 *----------------------------------------------------------------------
1216 PipeInputProc(instanceData, buf, toRead, errorCodePtr)
1217 ClientData instanceData; /* Pipe state. */
1218 char *buf; /* Where to store data read. */
1219 int toRead; /* How much space is available
1221 int *errorCodePtr; /* Where to store error code. */
1223 PipeState *psPtr = (PipeState *) instanceData;
1224 int bytesRead; /* How many bytes were actually
1225 * read from the input device? */
1230 * Assume there is always enough input available. This will block
1231 * appropriately, and read will unblock as soon as a short read is
1232 * possible, if the channel is in blocking mode. If the channel is
1233 * nonblocking, the read will never block.
1234 * Some OSes can throw an interrupt error, for which we should
1235 * immediately retry. [Bug #415131]
1239 bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead);
1240 } while ((bytesRead < 0) && (errno == EINTR));
1242 if (bytesRead < 0) {
1243 *errorCodePtr = errno;
1251 *----------------------------------------------------------------------
1255 * This procedure is invoked from the generic IO level to write
1256 * output to a command pipeline based channel.
1259 * The number of bytes written is returned or -1 on error. An
1260 * output argument contains a POSIX error code if an error occurred,
1264 * Writes output on the output device of the channel.
1266 *----------------------------------------------------------------------
1270 PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
1271 ClientData instanceData; /* Pipe state. */
1272 CONST char *buf; /* The data buffer. */
1273 int toWrite; /* How many bytes to write? */
1274 int *errorCodePtr; /* Where to store error code. */
1276 PipeState *psPtr = (PipeState *) instanceData;
1282 * Some OSes can throw an interrupt error, for which we should
1283 * immediately retry. [Bug #415131]
1287 written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite);
1288 } while ((written < 0) && (errno == EINTR));
1291 *errorCodePtr = errno;
1299 *----------------------------------------------------------------------
1303 * Initialize the notifier to watch the fds from this channel.
1309 * Sets up the notifier so that a future event on the channel will
1312 *----------------------------------------------------------------------
1316 PipeWatchProc(instanceData, mask)
1317 ClientData instanceData; /* The pipe state. */
1318 int mask; /* Events of interest; an OR-ed
1319 * combination of TCL_READABLE,
1320 * TCL_WRITABEL and TCL_EXCEPTION. */
1322 PipeState *psPtr = (PipeState *) instanceData;
1325 if (psPtr->inFile) {
1326 newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
1328 Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,
1329 (Tcl_FileProc *) Tcl_NotifyChannel,
1330 (ClientData) psPtr->channel);
1332 Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
1335 if (psPtr->outFile) {
1336 newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
1338 Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,
1339 (Tcl_FileProc *) Tcl_NotifyChannel,
1340 (ClientData) psPtr->channel);
1342 Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
1348 *----------------------------------------------------------------------
1350 * PipeGetHandleProc --
1352 * Called from Tcl_GetChannelHandle to retrieve OS handles from
1353 * inside a command pipeline based channel.
1356 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
1357 * there is no handle for the specified direction.
1362 *----------------------------------------------------------------------
1366 PipeGetHandleProc(instanceData, direction, handlePtr)
1367 ClientData instanceData; /* The pipe state. */
1368 int direction; /* TCL_READABLE or TCL_WRITABLE */
1369 ClientData *handlePtr; /* Where to store the handle. */
1371 PipeState *psPtr = (PipeState *) instanceData;
1373 if (direction == TCL_READABLE && psPtr->inFile) {
1374 *handlePtr = (ClientData) GetFd(psPtr->inFile);
1377 if (direction == TCL_WRITABLE && psPtr->outFile) {
1378 *handlePtr = (ClientData) GetFd(psPtr->outFile);
1385 *----------------------------------------------------------------------
1389 * Implements the waitpid system call on Unix systems.
1392 * Result of calling waitpid.
1395 * Waits for a process to terminate.
1397 *----------------------------------------------------------------------
1401 Tcl_WaitPid(pid, statPtr, options)
1409 real_pid = (pid_t) pid;
1411 result = (int) waitpid(real_pid, statPtr, options);
1412 if ((result != -1) || (errno != EINTR)) {
1413 return (Tcl_Pid) result;
1419 *----------------------------------------------------------------------
1423 * This procedure is invoked to process the "pid" Tcl command.
1424 * See the user documentation for details on what it does.
1427 * A standard Tcl result.
1430 * See the user documentation.
1432 *----------------------------------------------------------------------
1437 Tcl_PidObjCmd(dummy, interp, objc, objv)
1438 ClientData dummy; /* Not used. */
1439 Tcl_Interp *interp; /* Current interpreter. */
1440 int objc; /* Number of arguments. */
1441 Tcl_Obj *CONST *objv; /* Argument strings. */
1444 Tcl_ChannelType *chanTypePtr;
1447 Tcl_Obj *resultPtr, *longObjPtr;
1450 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
1454 Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());
1456 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
1457 if (chan == (Tcl_Channel) NULL) {
1460 chanTypePtr = Tcl_GetChannelType(chan);
1461 if (chanTypePtr != &pipeChannelType) {
1464 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
1465 resultPtr = Tcl_GetObjResult(interp);
1466 for (i = 0; i < pipePtr->numPids; i++) {
1467 longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i]));
1468 Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr);
1475 *----------------------------------------------------------------------
1477 * TclpFinalizePipes --
1479 * Cleans up the pipe subsystem from Tcl_FinalizeThread
1484 * This procedure carries out no operation on Unix.
1486 *----------------------------------------------------------------------