4 * Originally taken from tclPipe.c and tclUnixPipe.c in the Tcl
5 * distribution, implements the former Tcl_CreatePipeline API.
6 * This file contains the generic portion of the command channel
7 * driver as well as various utility routines used in managing
10 * Copyright (c) 1997 by Sun Microsystems, Inc.
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
23 #if (TCL_MAJOR_VERSION == 7)
24 typedef pid_t Tcl_Pid;
26 #define FILEHANDLER_USES_TCLFILES 1
29 Tcl_GetChannelHandle(channel, direction, clientDataPtr)
32 ClientData *clientDataPtr;
36 file = Tcl_GetChannelFile(channel, direction);
40 *clientDataPtr = (ClientData)Tcl_GetFileInfo(file, NULL);
46 #endif /* TCL_MAJOR_VERSION == 7 */
49 *----------------------------------------------------------------------
53 * Open a file for use in a pipeline.
56 * Returns a new TclFile handle or NULL on failure.
59 * May cause a file to be created on the file system.
61 *----------------------------------------------------------------------
66 char *fname; /* The name of the file to open. */
67 int mode; /* In what mode to open the file? */
71 fd = open(fname, mode, 0666);
73 fcntl(fd, F_SETFD, FD_CLOEXEC);
76 * If the file is being opened for writing, seek to the end
77 * so we can append to any data already in the file.
80 if (mode & O_WRONLY) {
81 lseek(fd, 0, SEEK_END);
89 *----------------------------------------------------------------------
93 * This function creates a temporary file initialized with an
94 * optional string, and returns a file handle with the file pointer
95 * at the beginning of the file.
103 *----------------------------------------------------------------------
107 CreateTempFile(contents)
108 char *contents; /* String to write into temp file, or NULL. */
110 char fileName[L_tmpnam];
112 size_t length = (contents == NULL) ? 0 : strlen(contents);
115 fd = OpenFile(fileName, O_RDWR | O_CREAT | O_TRUNC);
118 if ((fd >= 0) && (length > 0)) {
120 if (write(fd, contents, length) != -1) {
122 } else if (errno != EINTR) {
127 lseek(fd, 0, SEEK_SET);
133 *----------------------------------------------------------------------
137 * Creates a pipe - simply calls the pipe() function.
140 * Returns 1 on success, 0 on failure.
145 *----------------------------------------------------------------------
149 CreatePipe(inFilePtr, outFilePtr)
150 int *inFilePtr; /* (out) Descriptor for read side of pipe. */
151 int *outFilePtr; /* (out) Descriptor for write side of pipe. */
155 if (pipe(pipeIds) != 0) {
158 fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);
159 fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);
161 *inFilePtr = pipeIds[0];
162 *outFilePtr = pipeIds[1];
167 *----------------------------------------------------------------------
171 * Implements a mechanism to close a UNIX file.
174 * Returns 0 on success, or -1 on error, setting errno.
177 * The file is closed.
179 *----------------------------------------------------------------------
184 int fd; /* File descriptor to be closed. */
186 if ((fd == 0) || (fd == 1) || (fd == 2)) {
187 return 0; /* Don't close stdin, stdout or stderr. */
189 #if (TCL_MAJOR_VERSION > 7)
190 Tcl_DeleteFileHandler(fd);
196 *----------------------------------------------------------------------
200 * This procedure is invoked in a forked child process just before
201 * exec-ing a new program to restore all signals to their default
208 * Signal settings get changed.
210 *----------------------------------------------------------------------
217 signal(SIGABRT, SIG_DFL);
220 signal(SIGALRM, SIG_DFL);
223 signal(SIGFPE, SIG_DFL);
226 signal(SIGHUP, SIG_DFL);
229 signal(SIGILL, SIG_DFL);
232 signal(SIGINT, SIG_DFL);
235 signal(SIGPIPE, SIG_DFL);
238 signal(SIGQUIT, SIG_DFL);
241 signal(SIGSEGV, SIG_DFL);
244 signal(SIGTERM, SIG_DFL);
247 signal(SIGUSR1, SIG_DFL);
250 signal(SIGUSR2, SIG_DFL);
253 signal(SIGCHLD, SIG_DFL);
256 signal(SIGCONT, SIG_DFL);
259 signal(SIGTSTP, SIG_DFL);
262 signal(SIGTTIN, SIG_DFL);
265 signal(SIGTTOU, SIG_DFL);
270 *----------------------------------------------------------------------
274 * Set up stdio file handles for the child process, using the
275 * current standard channels if no other files are specified.
276 * If no standard channel is defined, or if no file is associated
277 * with the channel, then the corresponding standard fd is closed.
280 * Returns 1 on success, or 0 on failure.
283 * Replaces stdio fds.
285 *----------------------------------------------------------------------
289 SetupStdFile(fd, type)
290 int fd; /* File descriptor to dup, or -1. */
291 int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
293 int targetFd = 0; /* Initializations here needed only to */
294 int direction = 0; /* prevent warnings about using uninitialized
300 direction = TCL_READABLE;
304 direction = TCL_WRITABLE;
308 direction = TCL_WRITABLE;
314 channel = Tcl_GetStdChannel(type);
316 Tcl_GetChannelHandle(channel, direction, (ClientData *)&fd);
320 if (fd != targetFd) {
321 if (dup2(fd, targetFd) == -1) {
325 * Must clear the close-on-exec flag for the target FD, since
326 * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
330 fcntl(targetFd, F_SETFD, 0);
333 * Since we aren't dup'ing the file, we need to explicitly clear
334 * the close-on-exec flag.
336 fcntl(fd, F_SETFD, 0);
345 *----------------------------------------------------------------------
349 * Create a child process that has the specified files as its
350 * standard input, output, and error. The child process runs
351 * asynchronously and runs with the same environment variables
352 * as the creating process.
354 * The path is searched to find the specified executable.
357 * The return value is TCL_ERROR and an error message is left in
358 * interp->result if there was a problem creating the child
359 * process. Otherwise, the return value is TCL_OK and *pidPtr is
360 * filled with the process id of the child process.
363 * A process is created.
365 *----------------------------------------------------------------------
370 CreateProcess(interp, argc, argv, inputFile, outputFile, errorFile, pidPtr)
371 Tcl_Interp *interp; /* Interpreter in which to leave errors that
372 * occurred when creating the child process.
373 * Error messages from the child process
374 * itself are sent to errorFile. */
375 int argc; /* Number of arguments in following array. */
376 char **argv; /* Array of argument strings. argv[0]
377 * contains the name of the executable
378 * converted to native format (using the
379 * Tcl_TranslateFileName call). Additional
380 * arguments have not been converted. */
381 int inputFile; /* If non-NULL, gives the file to use as
382 * input for the child process. If inputFile
383 * file is not readable or is NULL, the child
384 * will receive no standard input. */
385 int outputFile; /* If non-NULL, gives the file that
386 * receives output from the child process. If
387 * outputFile file is not writeable or is
388 * NULL, output from the child will be
390 int errorFile; /* If non-NULL, gives the file that
391 * receives errors from the child process. If
392 * errorFile file is not writeable or is NULL,
393 * errors from the child will be discarded.
394 * errorFile may be the same as outputFile. */
395 int *pidPtr; /* If this procedure is successful, pidPtr
396 * is filled with the process id of the child
399 int errPipeIn, errPipeOut;
400 int joinThisError, count, status, fd;
404 * declarations for utf-8 handling, copied verbatim from tclUnixPipe 8.4.4
406 Tcl_DString *dsArray;
410 errPipeIn = errPipeOut = -1;
414 * Create a pipe that the child can use to return error
415 * information if anything goes wrong.
418 if (CreatePipe(&errPipeIn, &errPipeOut) == 0) {
419 Tcl_AppendResult(interp, "can't create pipe: ",
420 Tcl_PosixError(interp), (char *)NULL);
424 /* Proper handling of utf-8 to system encoding: copied verbatim
425 * from tclUnixPipe (8.4.4)
426 * We need to allocate and convert this before the fork
427 * so it is properly deallocated later
429 dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
430 newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
431 newArgv[argc] = NULL;
432 for (i = 0; i < argc; i++) {
433 newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
436 joinThisError = (errorFile == outputFile);
442 * Set up stdio file handles for the child process.
445 if (!SetupStdFile(inputFile, TCL_STDIN) ||
446 !SetupStdFile(outputFile, TCL_STDOUT) ||
447 (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR)) ||
449 ((dup2(1, 2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
450 sprintf(errSpace, "%dforked process can't set up input/output: ",
452 write(fd, errSpace, (size_t) strlen(errSpace));
456 * Close the input side of the error pipe.
460 /* execvp(argv[0], &argv[0]); not good for utf-8 */
461 execvp(newArgv[0], newArgv); /* INTL: Native. */
462 sprintf(errSpace, "%dcan't execute \"%.150s\": ", errno, argv[0]);
463 write(fd, errSpace, (size_t) strlen(errSpace));
468 * Free the mem we used for the fork (again verbatim copy from
471 for (i = 0; i < argc; i++) {
472 Tcl_DStringFree(&dsArray[i]);
474 ckfree((char *) dsArray);
475 ckfree((char *) newArgv);
478 Tcl_AppendResult(interp, "can't fork child process: ",
479 Tcl_PosixError(interp), (char *)NULL);
483 * Read back from the error pipe to see if the child started
484 * up OK. The info in the pipe (if any) consists of a decimal
485 * errno value followed by an error message.
488 CloseFile(errPipeOut);
492 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
497 errno = strtol(errSpace, &end, 10);
498 Tcl_AppendResult(interp, end, Tcl_PosixError(interp), (char *)NULL);
501 CloseFile(errPipeIn);
508 * Reap the child process now if an error occurred during its
511 Tcl_WaitPid((Tcl_Pid)pid, &status, WNOHANG);
513 if (errPipeIn >= 0) {
514 CloseFile(errPipeIn);
516 if (errPipeOut >= 0) {
517 CloseFile(errPipeOut);
523 *----------------------------------------------------------------------
527 * This procedure does much of the work of parsing redirection
528 * operators. It handles "@" if specified and allowed, and a file
529 * name, and opens the file if necessary.
532 * The return value is the descriptor number for the file. If an
533 * error occurs then NULL is returned and an error message is left
534 * in interp->result. Several arguments are side-effected; see
535 * the argument list below for details.
540 *----------------------------------------------------------------------
544 FileForRedirect(interp, spec, atOK, arg, nextArg, flags, skipPtr, closePtr)
545 Tcl_Interp *interp; /* Intepreter to use for error reporting. */
546 char *spec; /* Points to character just after
547 * redirection character. */
548 char *arg; /* Pointer to entire argument containing
549 * spec: used for error reporting. */
550 int atOK; /* Non-zero means that '@' notation can be
551 * used to specify a channel, zero means that
553 char *nextArg; /* Next argument in argc/argv array, if needed
554 * for file name or channel name. May be
556 int flags; /* Flags to use for opening file or to
557 * specify mode for channel. */
558 int *skipPtr; /* Filled with 1 if redirection target was
559 * in spec, 2 if it was in nextArg. */
560 int *closePtr; /* Filled with one if the caller should
561 * close the file when done with it, zero
564 int writing = (flags & O_WRONLY);
570 if ((atOK != 0) && (*spec == '@')) {
579 if (*spec == '1' && spec[1] == 0) {
582 chan = Tcl_GetChannel(interp, spec, NULL);
586 direction = (writing) ? TCL_WRITABLE : TCL_READABLE;
587 if (Tcl_GetChannelHandle(chan, direction, (ClientData *)&fd) != TCL_OK) {
591 Tcl_AppendResult(interp, "channel \"", Tcl_GetChannelName(chan),
592 "\" wasn't opened for ",
593 ((writing) ? "writing" : "reading"), (char *)NULL);
598 * Be sure to flush output to the file, so that anything
599 * written by the child appears after stuff we've already
606 Tcl_DString nameString;
615 name = Tcl_TranslateFileName(interp, spec, &nameString);
618 fd = OpenFile(name, flags);
622 Tcl_DStringFree(&nameString);
624 Tcl_AppendResult(interp, "can't ",
625 ((writing) ? "write" : "read"), " file \"", spec, "\": ",
626 Tcl_PosixError(interp), (char *)NULL);
634 Tcl_AppendResult(interp, "can't specify \"", arg,
635 "\" as last word in command", (char *)NULL);
640 *----------------------------------------------------------------------
642 * Blt_CreatePipeline --
644 * Given an argc/argv array, instantiate a pipeline of processes
645 * as described by the argv.
648 * The return value is a count of the number of new processes
649 * created, or -1 if an error occurred while creating the pipeline.
650 * *pidArrayPtr is filled in with the address of a dynamically
651 * allocated array giving the ids of all of the processes. It
652 * is up to the caller to free this array when it isn't needed
653 * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in
654 * with the file id for the input pipe for the pipeline (if any):
655 * the caller must eventually close this file. If outPipePtr
656 * isn't NULL, then *outPipePtr is filled in with the file id
657 * for the output pipe from the pipeline: the caller must close
658 * this file. If errPipePtr isn't NULL, then *errPipePtr is filled
659 * with a file id that may be used to read error output after the
660 * pipeline completes.
663 * Processes and pipes are created.
665 *----------------------------------------------------------------------
669 Blt_CreatePipeline(interp, argc, argv, pidArrayPtr, inPipePtr,
670 outPipePtr, errPipePtr)
671 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
672 int argc; /* Number of entries in argv. */
673 char **argv; /* Array of strings describing commands in
674 * pipeline plus I/O redirection with <,
675 * <<, >, etc. Argv[argc] must be NULL. */
676 int **pidArrayPtr; /* Word at *pidArrayPtr gets filled in with
677 * address of array of pids for processes
678 * in pipeline (first pid is first process
680 int *inPipePtr; /* If non-NULL, input to the pipeline comes
681 * from a pipe (unless overridden by
682 * redirection in the command). The file
683 * id with which to write to this pipe is
684 * stored at *inPipePtr. NULL means command
685 * specified its own input source. */
686 int *outPipePtr; /* If non-NULL, output to the pipeline goes
687 * to a pipe, unless overriden by redirection
688 * in the command. The file id with which to
689 * read frome this pipe is stored at
690 * *outPipePtr. NULL means command specified
691 * its own output sink. */
692 int *errPipePtr; /* If non-NULL, all stderr output from the
693 * pipeline will go to a temporary file
694 * created here, and a descriptor to read
695 * the file will be left at *errPipePtr.
696 * The file will be removed already, so
697 * closing this descriptor will be the end
698 * of the file. If this is NULL, then
699 * all stderr output goes to our stderr.
700 * If the pipeline specifies redirection
701 * then the file will still be created
702 * but it will never get any data. */
704 int *pidPtr = NULL; /* Points to malloc-ed array holding all
705 * the pids of child processes. */
706 int nPids; /* Actual number of processes that exist
707 * at *pidPtr right now. */
708 int cmdCount; /* Count of number of distinct commands
709 * found in argc/argv. */
710 char *inputLiteral = NULL; /* If non-null, then this points to a
711 * string containing input data (specified
712 * via <<) to be piped to the first process
713 * in the pipeline. */
714 int inputFd = -1; /* If != NULL, gives file to use as input for
715 * first process in pipeline (specified via <
717 int inputClose = 0; /* If non-zero, then inputFd should be
718 * closed when cleaning up. */
719 int outputFd = -1; /* Writable file for output from last command
720 * in pipeline (could be file or pipe). NULL
721 * means use stdout. */
722 int outputClose = 0; /* If non-zero, then outputFd should be
723 * closed when cleaning up. */
724 int errorFd = -1; /* Writable file for error output from all
725 * commands in pipeline. NULL means use
727 int errorClose = 0; /* If non-zero, then errorFd should be
728 * closed when cleaning up. */
730 int skip, lastBar, lastArg, i, j, atOK, flags, errorToOutput;
731 Tcl_DString execBuffer;
733 int curInFd, curOutFd, curErrFd;
735 if (inPipePtr != NULL) {
738 if (outPipePtr != NULL) {
741 if (errPipePtr != NULL) {
744 Tcl_DStringInit(&execBuffer);
746 pipeIn = curInFd = curOutFd = -1;
750 * First, scan through all the arguments to figure out the structure
751 * of the pipeline. Process all of the input and output redirection
752 * arguments and remove them from the argument list in the pipeline.
753 * Count the number of distinct processes (it's the number of "|"
754 * arguments plus one) but don't remove the "|" arguments because
755 * they'll be used in the second pass to seperate the individual
756 * child processes. Cannot start the child processes in this pass
757 * because the redirection symbols may appear anywhere in the
758 * command line -- e.g., the '<' that specifies the input to the
759 * entire pipe may appear at the very end of the argument list.
764 for (i = 0; i < argc; i++) {
776 if ((i == (lastBar + 1)) || (i == (argc - 1))) {
777 Tcl_AppendResult(interp,
778 "illegal use of | or |& in command",
788 if (inputClose != 0) {
794 inputLiteral = p + 1;
796 if (*inputLiteral == '\0') {
797 inputLiteral = argv[i + 1];
798 if (inputLiteral == NULL) {
799 Tcl_AppendResult(interp, "can't specify \"", argv[i],
800 "\" as last word in command", (char *)NULL);
807 inputFd = FileForRedirect(interp, p, 1, argv[i], argv[i + 1],
808 O_RDONLY, &skip, &inputClose);
817 flags = O_WRONLY | O_CREAT | O_TRUNC;
822 flags = O_WRONLY | O_CREAT;
825 if (errorClose != 0) {
832 if (outputClose != 0) {
836 outputFd = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1],
837 flags, &skip, &outputClose);
853 flags = O_WRONLY | O_CREAT | O_TRUNC;
857 flags = O_WRONLY | O_CREAT;
859 if (errorClose != 0) {
863 errorFd = FileForRedirect(interp, p, atOK, argv[i], argv[i + 1],
864 flags, &skip, &errorClose);
872 for (j = i + skip; j < argc; j++) {
873 argv[j - skip] = argv[j];
881 if (inputLiteral != NULL) {
883 * The input for the first process is immediate data coming from
884 * Tcl. Create a temporary file for it and put the data into the
887 inputFd = CreateTempFile(inputLiteral);
889 Tcl_AppendResult(interp,
890 "can't create input file for command: ",
891 Tcl_PosixError(interp), (char *)NULL);
895 } else if (inPipePtr != NULL) {
897 * The input for the first process in the pipeline is to
898 * come from a pipe that can be written from by the caller.
901 if (CreatePipe(&inputFd, inPipePtr) == 0) {
902 Tcl_AppendResult(interp,
903 "can't create input pipe for command: ",
904 Tcl_PosixError(interp), (char *)NULL);
910 * The input for the first process comes from stdin.
916 if (outputFd == -1) {
917 if (outPipePtr != NULL) {
919 * Output from the last process in the pipeline is to go to a
920 * pipe that can be read by the caller.
923 if (CreatePipe(outPipePtr, &outputFd) == 0) {
924 Tcl_AppendResult(interp,
925 "can't create output pipe for command: ",
926 Tcl_PosixError(interp), (char *)NULL);
932 * The output for the last process goes to stdout.
938 if (errPipePtr != NULL) {
940 * Stderr from the last process in the pipeline is to go to a
941 * pipe that can be read by the caller.
943 if (CreatePipe(errPipePtr, &errorFd) == 0) {
944 Tcl_AppendResult(interp,
945 "can't create error pipe for command: ",
946 Tcl_PosixError(interp), (char *)NULL);
952 * Errors from the pipeline go to stderr.
958 * Scan through the argc array, creating a process for each
959 * group of arguments between the "|" characters.
962 Tcl_ReapDetachedProcs();
963 pidPtr = Blt_Malloc((unsigned)(cmdCount * sizeof(int)));
967 lastArg = 0; /* Suppress compiler warning */
968 for (i = 0; i < argc; i = lastArg + 1) {
973 * Convert the program name into native form.
976 argv[i] = Tcl_TranslateFileName(interp, argv[i], &execBuffer);
977 if (argv[i] == NULL) {
981 * Find the end of the current segment of the pipeline.
984 for (lastArg = i; lastArg < argc; lastArg++) {
985 if (argv[lastArg][0] == '|') {
986 if (argv[lastArg][1] == '\0') {
989 if ((argv[lastArg][1] == '&') && (argv[lastArg][2] == '\0')) {
995 argv[lastArg] = NULL;
998 * If this is the last segment, use the specified outputFile.
999 * Otherwise create an intermediate pipe. pipeIn will become the
1000 * curInFile for the next segment of the pipe.
1003 if (lastArg == argc) {
1004 curOutFd = outputFd;
1006 if (CreatePipe(&pipeIn, &curOutFd) == 0) {
1007 Tcl_AppendResult(interp, "can't create pipe: ",
1008 Tcl_PosixError(interp), (char *)NULL);
1013 if (joinThisError != 0) {
1014 curErrFd = curOutFd;
1019 if (CreateProcess(interp, lastArg - i, argv + i,
1020 curInFd, curOutFd, curErrFd, &pid) != TCL_OK) {
1023 Tcl_DStringFree(&execBuffer);
1025 pidPtr[nPids] = pid;
1030 * Close off our copies of file descriptors that were set up for
1031 * this child, then set up the input for the next child.
1034 if ((curInFd >= 0) && (curInFd != inputFd)) {
1040 if ((curOutFd >= 0) && (curOutFd != outputFd)) {
1041 CloseFile(curOutFd);
1046 *pidArrayPtr = pidPtr;
1049 * All done. Cleanup open files lying around and then return.
1053 Tcl_DStringFree(&execBuffer);
1059 CloseFile(outputFd);
1067 * An error occurred. There could have been extra files open, such
1068 * as pipes between children. Clean them all up. Detach any child
1069 * processes that have been created.
1076 if ((curOutFd >= 0) && (curOutFd != outputFd)) {
1077 CloseFile(curOutFd);
1079 if ((curInFd >= 0) && (curInFd != inputFd)) {
1082 if ((inPipePtr != NULL) && (*inPipePtr >= 0)) {
1083 CloseFile(*inPipePtr);
1086 if ((outPipePtr != NULL) && (*outPipePtr >= 0)) {
1087 CloseFile(*outPipePtr);
1090 if ((errPipePtr != NULL) && (*errPipePtr >= 0)) {
1091 CloseFile(*errPipePtr);
1094 if (pidPtr != NULL) {
1095 for (i = 0; i < nPids; i++) {
1096 if (pidPtr[i] != -1) {
1097 #if (TCL_MAJOR_VERSION == 7)
1098 Tcl_DetachPids(1, &pidPtr[i]);
1100 Tcl_DetachPids(1, (Tcl_Pid *)&pidPtr[i]);