1/* 2 * tclUnixPipe.c -- 3 * 4 * This file implements the UNIX-specific exec pipeline functions, the 5 * "pipe" channel driver, and the "pid" Tcl command. 6 * 7 * Copyright (c) 1991-1994 The Regents of the University of California. 8 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 9 * 10 * See the file "license.terms" for information on usage and redistribution of 11 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id: tclUnixPipe.c,v 1.42.2.1 2010/01/29 09:38:47 nijtmans Exp $ 14 */ 15 16#include "tclInt.h" 17 18#ifdef USE_VFORK 19#define fork vfork 20#endif 21 22/* 23 * The following macros convert between TclFile's and fd's. The conversion 24 * simple involves shifting fd's up by one to ensure that no valid fd is ever 25 * the same as NULL. 26 */ 27 28#define MakeFile(fd) ((TclFile) INT2PTR(((int) (fd)) + 1)) 29#define GetFd(file) (PTR2INT(file) - 1) 30 31/* 32 * This structure describes per-instance state of a pipe based channel. 33 */ 34 35typedef struct PipeState { 36 Tcl_Channel channel; /* Channel associated with this file. */ 37 TclFile inFile; /* Output from pipe. */ 38 TclFile outFile; /* Input to pipe. */ 39 TclFile errorFile; /* Error output from pipe. */ 40 int numPids; /* How many processes are attached to this 41 * pipe? */ 42 Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by 43 * the creator of the pipe. */ 44 int isNonBlocking; /* Nonzero when the pipe is in nonblocking 45 * mode. Used to decide whether to wait for 46 * the children at close time. */ 47} PipeState; 48 49/* 50 * Declarations for local functions defined in this file: 51 */ 52 53static int PipeBlockModeProc(ClientData instanceData, int mode); 54static int PipeCloseProc(ClientData instanceData, 55 Tcl_Interp *interp); 56static int PipeGetHandleProc(ClientData instanceData, 57 int direction, ClientData *handlePtr); 58static int PipeInputProc(ClientData instanceData, char *buf, 59 int toRead, int *errorCode); 60static int PipeOutputProc(ClientData instanceData, 61 const char *buf, int toWrite, int *errorCode); 62static void PipeWatchProc(ClientData instanceData, int mask); 63static void RestoreSignals(void); 64static int SetupStdFile(TclFile file, int type); 65 66/* 67 * This structure describes the channel type structure for command pipe based 68 * I/O: 69 */ 70 71static Tcl_ChannelType pipeChannelType = { 72 "pipe", /* Type name. */ 73 TCL_CHANNEL_VERSION_5, /* v5 channel */ 74 PipeCloseProc, /* Close proc. */ 75 PipeInputProc, /* Input proc. */ 76 PipeOutputProc, /* Output proc. */ 77 NULL, /* Seek proc. */ 78 NULL, /* Set option proc. */ 79 NULL, /* Get option proc. */ 80 PipeWatchProc, /* Initialize notifier. */ 81 PipeGetHandleProc, /* Get OS handles out of channel. */ 82 NULL, /* close2proc. */ 83 PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ 84 NULL, /* flush proc. */ 85 NULL, /* handler proc. */ 86 NULL, /* wide seek proc */ 87 NULL, /* thread action proc */ 88 NULL /* truncation */ 89}; 90 91/* 92 *---------------------------------------------------------------------- 93 * 94 * TclpMakeFile -- 95 * 96 * Make a TclFile from a channel. 97 * 98 * Results: 99 * Returns a new TclFile or NULL on failure. 100 * 101 * Side effects: 102 * None. 103 * 104 *---------------------------------------------------------------------- 105 */ 106 107TclFile 108TclpMakeFile( 109 Tcl_Channel channel, /* Channel to get file from. */ 110 int direction) /* Either TCL_READABLE or TCL_WRITABLE. */ 111{ 112 ClientData data; 113 114 if (Tcl_GetChannelHandle(channel, direction, 115 (ClientData *) &data) == TCL_OK) { 116 return MakeFile(PTR2INT(data)); 117 } else { 118 return (TclFile) NULL; 119 } 120} 121 122/* 123 *---------------------------------------------------------------------- 124 * 125 * TclpOpenFile -- 126 * 127 * Open a file for use in a pipeline. 128 * 129 * Results: 130 * Returns a new TclFile handle or NULL on failure. 131 * 132 * Side effects: 133 * May cause a file to be created on the file system. 134 * 135 *---------------------------------------------------------------------- 136 */ 137 138TclFile 139TclpOpenFile( 140 const char *fname, /* The name of the file to open. */ 141 int mode) /* In what mode to open the file? */ 142{ 143 int fd; 144 const char *native; 145 Tcl_DString ds; 146 147 native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds); 148 fd = TclOSopen(native, mode, 0666); /* INTL: Native. */ 149 Tcl_DStringFree(&ds); 150 if (fd != -1) { 151 fcntl(fd, F_SETFD, FD_CLOEXEC); 152 153 /* 154 * If the file is being opened for writing, seek to the end so we can 155 * append to any data already in the file. 156 */ 157 158 if ((mode & O_WRONLY) && !(mode & O_APPEND)) { 159 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END); 160 } 161 162 /* 163 * Increment the fd so it can't be 0, which would conflict with the 164 * NULL return for errors. 165 */ 166 167 return MakeFile(fd); 168 } 169 return NULL; 170} 171 172/* 173 *---------------------------------------------------------------------- 174 * 175 * TclpCreateTempFile -- 176 * 177 * This function creates a temporary file initialized with an optional 178 * string, and returns a file handle with the file pointer at the 179 * beginning of the file. 180 * 181 * Results: 182 * A handle to a file. 183 * 184 * Side effects: 185 * None. 186 * 187 *---------------------------------------------------------------------- 188 */ 189 190TclFile 191TclpCreateTempFile( 192 const char *contents) /* String to write into temp file, or NULL. */ 193{ 194 char fileName[L_tmpnam + 9]; 195 const char *native; 196 Tcl_DString dstring; 197 int fd; 198 199 /* 200 * We should also check against making more then TMP_MAX of these. 201 */ 202 203 strcpy(fileName, P_tmpdir); /* INTL: Native. */ 204 if (fileName[strlen(fileName) - 1] != '/') { 205 strcat(fileName, "/"); /* INTL: Native. */ 206 } 207 strcat(fileName, "tclXXXXXX"); 208 fd = mkstemp(fileName); /* INTL: Native. */ 209 if (fd == -1) { 210 return NULL; 211 } 212 fcntl(fd, F_SETFD, FD_CLOEXEC); 213 unlink(fileName); /* INTL: Native. */ 214 215 if (contents != NULL) { 216 native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); 217 if (write(fd, native, strlen(native)) == -1) { 218 close(fd); 219 Tcl_DStringFree(&dstring); 220 return NULL; 221 } 222 Tcl_DStringFree(&dstring); 223 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET); 224 } 225 return MakeFile(fd); 226} 227 228/* 229 *---------------------------------------------------------------------- 230 * 231 * TclpTempFileName -- 232 * 233 * This function returns unique filename. 234 * 235 * Results: 236 * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. 237 * 238 * Side effects: 239 * None. 240 * 241 *---------------------------------------------------------------------- 242 */ 243 244Tcl_Obj * 245TclpTempFileName(void) 246{ 247 char fileName[L_tmpnam + 9]; 248 Tcl_Obj *result = NULL; 249 int fd; 250 251 /* 252 * We should also check against making more then TMP_MAX of these. 253 */ 254 255 strcpy(fileName, P_tmpdir); /* INTL: Native. */ 256 if (fileName[strlen(fileName) - 1] != '/') { 257 strcat(fileName, "/"); /* INTL: Native. */ 258 } 259 strcat(fileName, "tclXXXXXX"); 260 fd = mkstemp(fileName); /* INTL: Native. */ 261 if (fd == -1) { 262 return NULL; 263 } 264 fcntl(fd, F_SETFD, FD_CLOEXEC); 265 unlink(fileName); /* INTL: Native. */ 266 267 result = TclpNativeToNormalized((ClientData) fileName); 268 close(fd); 269 return result; 270} 271 272/* 273 *---------------------------------------------------------------------- 274 * 275 * TclpCreatePipe -- 276 * 277 * Creates a pipe - simply calls the pipe() function. 278 * 279 * Results: 280 * Returns 1 on success, 0 on failure. 281 * 282 * Side effects: 283 * Creates a pipe. 284 * 285 *---------------------------------------------------------------------- 286 */ 287 288int 289TclpCreatePipe( 290 TclFile *readPipe, /* Location to store file handle for read side 291 * of pipe. */ 292 TclFile *writePipe) /* Location to store file handle for write 293 * side of pipe. */ 294{ 295 int pipeIds[2]; 296 297 if (pipe(pipeIds) != 0) { 298 return 0; 299 } 300 301 fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC); 302 fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC); 303 304 *readPipe = MakeFile(pipeIds[0]); 305 *writePipe = MakeFile(pipeIds[1]); 306 return 1; 307} 308 309/* 310 *---------------------------------------------------------------------- 311 * 312 * TclpCloseFile -- 313 * 314 * Implements a mechanism to close a UNIX file. 315 * 316 * Results: 317 * Returns 0 on success, or -1 on error, setting errno. 318 * 319 * Side effects: 320 * The file is closed. 321 * 322 *---------------------------------------------------------------------- 323 */ 324 325int 326TclpCloseFile( 327 TclFile file) /* The file to close. */ 328{ 329 int fd = GetFd(file); 330 331 /* 332 * Refuse to close the fds for stdin, stdout and stderr. 333 */ 334 335 if ((fd == 0) || (fd == 1) || (fd == 2)) { 336 return 0; 337 } 338 339 Tcl_DeleteFileHandler(fd); 340 return close(fd); 341} 342 343/* 344 *--------------------------------------------------------------------------- 345 * 346 * TclpCreateProcess -- 347 * 348 * Create a child process that has the specified files as its standard 349 * input, output, and error. The child process runs asynchronously and 350 * runs with the same environment variables as the creating process. 351 * 352 * The path is searched to find the specified executable. 353 * 354 * Results: 355 * The return value is TCL_ERROR and an error message is left in the 356 * interp's result if there was a problem creating the child process. 357 * Otherwise, the return value is TCL_OK and *pidPtr is filled with the 358 * process id of the child process. 359 * 360 * Side effects: 361 * A process is created. 362 * 363 *--------------------------------------------------------------------------- 364 */ 365 366 /* ARGSUSED */ 367int 368TclpCreateProcess( 369 Tcl_Interp *interp, /* Interpreter in which to leave errors that 370 * occurred when creating the child process. 371 * Error messages from the child process 372 * itself are sent to errorFile. */ 373 int argc, /* Number of arguments in following array. */ 374 const char **argv, /* Array of argument strings in UTF-8. 375 * argv[0] contains the name of the executable 376 * translated using Tcl_TranslateFileName 377 * call). Additional arguments have not been 378 * converted. */ 379 TclFile inputFile, /* If non-NULL, gives the file to use as input 380 * for the child process. If inputFile file is 381 * not readable or is NULL, the child will 382 * receive no standard input. */ 383 TclFile outputFile, /* If non-NULL, gives the file that receives 384 * output from the child process. If 385 * outputFile file is not writeable or is 386 * NULL, output from the child will be 387 * discarded. */ 388 TclFile errorFile, /* If non-NULL, gives the file that receives 389 * errors from the child process. If errorFile 390 * file is not writeable or is NULL, errors 391 * from the child will be discarded. errorFile 392 * may be the same as outputFile. */ 393 Tcl_Pid *pidPtr) /* If this function is successful, pidPtr is 394 * filled with the process id of the child 395 * process. */ 396{ 397 TclFile errPipeIn, errPipeOut; 398 int count, status, fd; 399 char errSpace[200 + TCL_INTEGER_SPACE]; 400 Tcl_DString *dsArray; 401 char **newArgv; 402 int pid, i; 403 404 errPipeIn = NULL; 405 errPipeOut = NULL; 406 pid = -1; 407 408 /* 409 * Create a pipe that the child can use to return error information if 410 * anything goes wrong. 411 */ 412 413 if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { 414 Tcl_AppendResult(interp, "couldn't create pipe: ", 415 Tcl_PosixError(interp), NULL); 416 goto error; 417 } 418 419 /* 420 * We need to allocate and convert this before the fork so it is properly 421 * deallocated later 422 */ 423 424 dsArray = (Tcl_DString *) 425 TclStackAlloc(interp, argc * sizeof(Tcl_DString)); 426 newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *)); 427 newArgv[argc] = NULL; 428 for (i = 0; i < argc; i++) { 429 newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); 430 } 431 432#ifdef USE_VFORK 433 /* 434 * After vfork(), do not call code in the child that changes global state, 435 * because it is using the parent's memory space at that point and writes 436 * might corrupt the parent: so ensure standard channels are initialized in 437 * the parent, otherwise SetupStdFile() might initialize them in the child. 438 */ 439 440 if (!inputFile) { 441 Tcl_GetStdChannel(TCL_STDIN); 442 } 443 if (!outputFile) { 444 Tcl_GetStdChannel(TCL_STDOUT); 445 } 446 if (!errorFile) { 447 Tcl_GetStdChannel(TCL_STDERR); 448 } 449#endif 450 451 pid = fork(); 452 if (pid == 0) { 453 size_t len; 454 int joinThisError = errorFile && (errorFile == outputFile); 455 456 fd = GetFd(errPipeOut); 457 458 /* 459 * Set up stdio file handles for the child process. 460 */ 461 462 if (!SetupStdFile(inputFile, TCL_STDIN) 463 || !SetupStdFile(outputFile, TCL_STDOUT) 464 || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR)) 465 || (joinThisError && 466 ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) { 467 sprintf(errSpace, 468 "%dforked process couldn't set up input/output: ", errno); 469 len = strlen(errSpace); 470 if (len != (size_t) write(fd, errSpace, len)) { 471 Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); 472 } 473 _exit(1); 474 } 475 476 /* 477 * Close the input side of the error pipe. 478 */ 479 480 RestoreSignals(); 481 execvp(newArgv[0], newArgv); /* INTL: Native. */ 482 sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]); 483 len = strlen(errSpace); 484 if (len != (size_t) write(fd, errSpace, len)) { 485 Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); 486 } 487 _exit(1); 488 } 489 490 /* 491 * Free the mem we used for the fork 492 */ 493 494 for (i = 0; i < argc; i++) { 495 Tcl_DStringFree(&dsArray[i]); 496 } 497 TclStackFree(interp, newArgv); 498 TclStackFree(interp, dsArray); 499 500 if (pid == -1) { 501 Tcl_AppendResult(interp, "couldn't fork child process: ", 502 Tcl_PosixError(interp), NULL); 503 goto error; 504 } 505 506 /* 507 * Read back from the error pipe to see if the child started up OK. The 508 * info in the pipe (if any) consists of a decimal errno value followed by 509 * an error message. 510 */ 511 512 TclpCloseFile(errPipeOut); 513 errPipeOut = NULL; 514 515 fd = GetFd(errPipeIn); 516 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1)); 517 if (count > 0) { 518 char *end; 519 errSpace[count] = 0; 520 errno = strtol(errSpace, &end, 10); 521 Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL); 522 goto error; 523 } 524 525 TclpCloseFile(errPipeIn); 526 *pidPtr = (Tcl_Pid) INT2PTR(pid); 527 return TCL_OK; 528 529 error: 530 if (pid != -1) { 531 /* 532 * Reap the child process now if an error occurred during its startup. 533 * We don't call this with WNOHANG because that can lead to defunct 534 * processes on an MP system. We shouldn't have to worry about hanging 535 * here, since this is the error case. [Bug: 6148] 536 */ 537 538 Tcl_WaitPid((Tcl_Pid) INT2PTR(pid), &status, 0); 539 } 540 541 if (errPipeIn) { 542 TclpCloseFile(errPipeIn); 543 } 544 if (errPipeOut) { 545 TclpCloseFile(errPipeOut); 546 } 547 return TCL_ERROR; 548} 549 550/* 551 *---------------------------------------------------------------------- 552 * 553 * RestoreSignals -- 554 * 555 * This function is invoked in a forked child process just before 556 * exec-ing a new program to restore all signals to their default 557 * settings. 558 * 559 * Results: 560 * None. 561 * 562 * Side effects: 563 * Signal settings get changed. 564 * 565 *---------------------------------------------------------------------- 566 */ 567 568static void 569RestoreSignals(void) 570{ 571#ifdef SIGABRT 572 signal(SIGABRT, SIG_DFL); 573#endif 574#ifdef SIGALRM 575 signal(SIGALRM, SIG_DFL); 576#endif 577#ifdef SIGFPE 578 signal(SIGFPE, SIG_DFL); 579#endif 580#ifdef SIGHUP 581 signal(SIGHUP, SIG_DFL); 582#endif 583#ifdef SIGILL 584 signal(SIGILL, SIG_DFL); 585#endif 586#ifdef SIGINT 587 signal(SIGINT, SIG_DFL); 588#endif 589#ifdef SIGPIPE 590 signal(SIGPIPE, SIG_DFL); 591#endif 592#ifdef SIGQUIT 593 signal(SIGQUIT, SIG_DFL); 594#endif 595#ifdef SIGSEGV 596 signal(SIGSEGV, SIG_DFL); 597#endif 598#ifdef SIGTERM 599 signal(SIGTERM, SIG_DFL); 600#endif 601#ifdef SIGUSR1 602 signal(SIGUSR1, SIG_DFL); 603#endif 604#ifdef SIGUSR2 605 signal(SIGUSR2, SIG_DFL); 606#endif 607#ifdef SIGCHLD 608 signal(SIGCHLD, SIG_DFL); 609#endif 610#ifdef SIGCONT 611 signal(SIGCONT, SIG_DFL); 612#endif 613#ifdef SIGTSTP 614 signal(SIGTSTP, SIG_DFL); 615#endif 616#ifdef SIGTTIN 617 signal(SIGTTIN, SIG_DFL); 618#endif 619#ifdef SIGTTOU 620 signal(SIGTTOU, SIG_DFL); 621#endif 622} 623 624/* 625 *---------------------------------------------------------------------- 626 * 627 * SetupStdFile -- 628 * 629 * Set up stdio file handles for the child process, using the current 630 * standard channels if no other files are specified. If no standard 631 * channel is defined, or if no file is associated with the channel, then 632 * the corresponding standard fd is closed. 633 * 634 * Results: 635 * Returns 1 on success, or 0 on failure. 636 * 637 * Side effects: 638 * Replaces stdio fds. 639 * 640 *---------------------------------------------------------------------- 641 */ 642 643static int 644SetupStdFile( 645 TclFile file, /* File to dup, or NULL. */ 646 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */ 647{ 648 Tcl_Channel channel; 649 int fd; 650 int targetFd = 0; /* Initializations here needed only to */ 651 int direction = 0; /* prevent warnings about using uninitialized 652 * variables. */ 653 654 switch (type) { 655 case TCL_STDIN: 656 targetFd = 0; 657 direction = TCL_READABLE; 658 break; 659 case TCL_STDOUT: 660 targetFd = 1; 661 direction = TCL_WRITABLE; 662 break; 663 case TCL_STDERR: 664 targetFd = 2; 665 direction = TCL_WRITABLE; 666 break; 667 } 668 669 if (!file) { 670 channel = Tcl_GetStdChannel(type); 671 if (channel) { 672 file = TclpMakeFile(channel, direction); 673 } 674 } 675 if (file) { 676 fd = GetFd(file); 677 if (fd != targetFd) { 678 if (dup2(fd, targetFd) == -1) { 679 return 0; 680 } 681 682 /* 683 * Must clear the close-on-exec flag for the target FD, since some 684 * systems (e.g. Ultrix) do not clear the CLOEXEC flag on the 685 * target FD. 686 */ 687 688 fcntl(targetFd, F_SETFD, 0); 689 } else { 690 /* 691 * Since we aren't dup'ing the file, we need to explicitly clear 692 * the close-on-exec flag. 693 */ 694 695 fcntl(fd, F_SETFD, 0); 696 } 697 } else { 698 close(targetFd); 699 } 700 return 1; 701} 702 703/* 704 *---------------------------------------------------------------------- 705 * 706 * TclpCreateCommandChannel -- 707 * 708 * This function is called by the generic IO level to perform the 709 * platform specific channel initialization for a command channel. 710 * 711 * Results: 712 * Returns a new channel or NULL on failure. 713 * 714 * Side effects: 715 * Allocates a new channel. 716 * 717 *---------------------------------------------------------------------- 718 */ 719 720Tcl_Channel 721TclpCreateCommandChannel( 722 TclFile readFile, /* If non-null, gives the file for reading. */ 723 TclFile writeFile, /* If non-null, gives the file for writing. */ 724 TclFile errorFile, /* If non-null, gives the file where errors 725 * can be read. */ 726 int numPids, /* The number of pids in the pid array. */ 727 Tcl_Pid *pidPtr) /* An array of process identifiers. Allocated 728 * by the caller, freed when the channel is 729 * closed or the processes are detached (in a 730 * background exec). */ 731{ 732 char channelName[16 + TCL_INTEGER_SPACE]; 733 int channelId; 734 PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState)); 735 int mode; 736 737 statePtr->inFile = readFile; 738 statePtr->outFile = writeFile; 739 statePtr->errorFile = errorFile; 740 statePtr->numPids = numPids; 741 statePtr->pidPtr = pidPtr; 742 statePtr->isNonBlocking = 0; 743 744 mode = 0; 745 if (readFile) { 746 mode |= TCL_READABLE; 747 } 748 if (writeFile) { 749 mode |= TCL_WRITABLE; 750 } 751 752 /* 753 * Use one of the fds associated with the channel as the channel id. 754 */ 755 756 if (readFile) { 757 channelId = GetFd(readFile); 758 } else if (writeFile) { 759 channelId = GetFd(writeFile); 760 } else if (errorFile) { 761 channelId = GetFd(errorFile); 762 } else { 763 channelId = 0; 764 } 765 766 /* 767 * For backward compatibility with previous versions of Tcl, we use 768 * "file%d" as the base name for pipes even though it would be more 769 * natural to use "pipe%d". 770 */ 771 772 sprintf(channelName, "file%d", channelId); 773 statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, 774 (ClientData) statePtr, mode); 775 return statePtr->channel; 776} 777 778/* 779 *---------------------------------------------------------------------- 780 * 781 * TclGetAndDetachPids -- 782 * 783 * This function is invoked in the generic implementation of a 784 * background "exec" (an exec when invoked with a terminating "&") to 785 * store a list of the PIDs for processes in a command pipeline in the 786 * interp's result and to detach the processes. 787 * 788 * Results: 789 * None. 790 * 791 * Side effects: 792 * Modifies the interp's result. Detaches processes. 793 * 794 *---------------------------------------------------------------------- 795 */ 796 797void 798TclGetAndDetachPids( 799 Tcl_Interp *interp, /* Interpreter to append the PIDs to. */ 800 Tcl_Channel chan) /* Handle for the pipeline. */ 801{ 802 PipeState *pipePtr; 803 const Tcl_ChannelType *chanTypePtr; 804 int i; 805 char buf[TCL_INTEGER_SPACE]; 806 807 /* 808 * Punt if the channel is not a command channel. 809 */ 810 811 chanTypePtr = Tcl_GetChannelType(chan); 812 if (chanTypePtr != &pipeChannelType) { 813 return; 814 } 815 816 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); 817 for (i = 0; i < pipePtr->numPids; i++) { 818 TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i])); 819 Tcl_AppendElement(interp, buf); 820 Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); 821 } 822 if (pipePtr->numPids > 0) { 823 ckfree((char *) pipePtr->pidPtr); 824 pipePtr->numPids = 0; 825 } 826} 827 828/* 829 *---------------------------------------------------------------------- 830 * 831 * PipeBlockModeProc -- 832 * 833 * Helper function to set blocking and nonblocking modes on a pipe based 834 * channel. Invoked by generic IO level code. 835 * 836 * Results: 837 * 0 if successful, errno when failed. 838 * 839 * Side effects: 840 * Sets the device into blocking or non-blocking mode. 841 * 842 *---------------------------------------------------------------------- 843 */ 844 845 /* ARGSUSED */ 846static int 847PipeBlockModeProc( 848 ClientData instanceData, /* Pipe state. */ 849 int mode) /* The mode to set. Can be one of 850 * TCL_MODE_BLOCKING or 851 * TCL_MODE_NONBLOCKING. */ 852{ 853 PipeState *psPtr = instanceData; 854 855 if (psPtr->inFile) { 856 if (TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { 857 return errno; 858 } 859 } 860 if (psPtr->outFile) { 861 if (TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) { 862 return errno; 863 } 864 } 865 866 psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING); 867 868 return 0; 869} 870 871/* 872 *---------------------------------------------------------------------- 873 * 874 * PipeCloseProc -- 875 * 876 * This function is invoked by the generic IO level to perform 877 * channel-type-specific cleanup when a command pipeline channel is 878 * closed. 879 * 880 * Results: 881 * 0 on success, errno otherwise. 882 * 883 * Side effects: 884 * Closes the command pipeline channel. 885 * 886 *---------------------------------------------------------------------- 887 */ 888 889 /* ARGSUSED */ 890static int 891PipeCloseProc( 892 ClientData instanceData, /* The pipe to close. */ 893 Tcl_Interp *interp) /* For error reporting. */ 894{ 895 PipeState *pipePtr; 896 Tcl_Channel errChan; 897 int errorCode, result; 898 899 errorCode = 0; 900 result = 0; 901 pipePtr = (PipeState *) instanceData; 902 if (pipePtr->inFile) { 903 if (TclpCloseFile(pipePtr->inFile) < 0) { 904 errorCode = errno; 905 } 906 } 907 if (pipePtr->outFile) { 908 if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { 909 errorCode = errno; 910 } 911 } 912 913 if (pipePtr->isNonBlocking || TclInExit()) { 914 /* 915 * If the channel is non-blocking or Tcl is being cleaned up, just 916 * detach the children PIDs, reap them (important if we are in a 917 * dynamic load module), and discard the errorFile. 918 */ 919 920 Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); 921 Tcl_ReapDetachedProcs(); 922 923 if (pipePtr->errorFile) { 924 TclpCloseFile(pipePtr->errorFile); 925 } 926 } else { 927 /* 928 * Wrap the error file into a channel and give it to the cleanup 929 * routine. 930 */ 931 932 if (pipePtr->errorFile) { 933 errChan = Tcl_MakeFileChannel( 934 (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); 935 } else { 936 errChan = NULL; 937 } 938 result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, 939 errChan); 940 } 941 942 if (pipePtr->numPids != 0) { 943 ckfree((char *) pipePtr->pidPtr); 944 } 945 ckfree((char *) pipePtr); 946 if (errorCode == 0) { 947 return result; 948 } 949 return errorCode; 950} 951 952/* 953 *---------------------------------------------------------------------- 954 * 955 * PipeInputProc -- 956 * 957 * This function is invoked from the generic IO level to read input from 958 * a command pipeline based channel. 959 * 960 * Results: 961 * The number of bytes read is returned or -1 on error. An output 962 * argument contains a POSIX error code if an error occurs, or zero. 963 * 964 * Side effects: 965 * Reads input from the input device of the channel. 966 * 967 *---------------------------------------------------------------------- 968 */ 969 970static int 971PipeInputProc( 972 ClientData instanceData, /* Pipe state. */ 973 char *buf, /* Where to store data read. */ 974 int toRead, /* How much space is available in the 975 * buffer? */ 976 int *errorCodePtr) /* Where to store error code. */ 977{ 978 PipeState *psPtr = (PipeState *) instanceData; 979 int bytesRead; /* How many bytes were actually read from the 980 * input device? */ 981 982 *errorCodePtr = 0; 983 984 /* 985 * Assume there is always enough input available. This will block 986 * appropriately, and read will unblock as soon as a short read is 987 * possible, if the channel is in blocking mode. If the channel is 988 * nonblocking, the read will never block. Some OSes can throw an 989 * interrupt error, for which we should immediately retry. [Bug #415131] 990 */ 991 992 do { 993 bytesRead = read(GetFd(psPtr->inFile), buf, (size_t) toRead); 994 } while ((bytesRead < 0) && (errno == EINTR)); 995 996 if (bytesRead < 0) { 997 *errorCodePtr = errno; 998 return -1; 999 } else { 1000 return bytesRead; 1001 } 1002} 1003 1004/* 1005 *---------------------------------------------------------------------- 1006 * 1007 * PipeOutputProc-- 1008 * 1009 * This function is invoked from the generic IO level to write output to 1010 * a command pipeline based channel. 1011 * 1012 * Results: 1013 * The number of bytes written is returned or -1 on error. An output 1014 * argument contains a POSIX error code if an error occurred, or zero. 1015 * 1016 * Side effects: 1017 * Writes output on the output device of the channel. 1018 * 1019 *---------------------------------------------------------------------- 1020 */ 1021 1022static int 1023PipeOutputProc( 1024 ClientData instanceData, /* Pipe state. */ 1025 const char *buf, /* The data buffer. */ 1026 int toWrite, /* How many bytes to write? */ 1027 int *errorCodePtr) /* Where to store error code. */ 1028{ 1029 PipeState *psPtr = (PipeState *) instanceData; 1030 int written; 1031 1032 *errorCodePtr = 0; 1033 1034 /* 1035 * Some OSes can throw an interrupt error, for which we should immediately 1036 * retry. [Bug #415131] 1037 */ 1038 1039 do { 1040 written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite); 1041 } while ((written < 0) && (errno == EINTR)); 1042 1043 if (written < 0) { 1044 *errorCodePtr = errno; 1045 return -1; 1046 } else { 1047 return written; 1048 } 1049} 1050 1051/* 1052 *---------------------------------------------------------------------- 1053 * 1054 * PipeWatchProc -- 1055 * 1056 * Initialize the notifier to watch the fds from this channel. 1057 * 1058 * Results: 1059 * None. 1060 * 1061 * Side effects: 1062 * Sets up the notifier so that a future event on the channel will be 1063 * seen by Tcl. 1064 * 1065 *---------------------------------------------------------------------- 1066 */ 1067 1068static void 1069PipeWatchProc( 1070 ClientData instanceData, /* The pipe state. */ 1071 int mask) /* Events of interest; an OR-ed combination of 1072 * TCL_READABLE, TCL_WRITABLE and 1073 * TCL_EXCEPTION. */ 1074{ 1075 PipeState *psPtr = (PipeState *) instanceData; 1076 int newmask; 1077 1078 if (psPtr->inFile) { 1079 newmask = mask & (TCL_READABLE | TCL_EXCEPTION); 1080 if (newmask) { 1081 Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, 1082 (Tcl_FileProc *) Tcl_NotifyChannel, 1083 (ClientData) psPtr->channel); 1084 } else { 1085 Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); 1086 } 1087 } 1088 if (psPtr->outFile) { 1089 newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); 1090 if (newmask) { 1091 Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, 1092 (Tcl_FileProc *) Tcl_NotifyChannel, 1093 (ClientData) psPtr->channel); 1094 } else { 1095 Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); 1096 } 1097 } 1098} 1099 1100/* 1101 *---------------------------------------------------------------------- 1102 * 1103 * PipeGetHandleProc -- 1104 * 1105 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a 1106 * command pipeline based channel. 1107 * 1108 * Results: 1109 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no 1110 * handle for the specified direction. 1111 * 1112 * Side effects: 1113 * None. 1114 * 1115 *---------------------------------------------------------------------- 1116 */ 1117 1118static int 1119PipeGetHandleProc( 1120 ClientData instanceData, /* The pipe state. */ 1121 int direction, /* TCL_READABLE or TCL_WRITABLE */ 1122 ClientData *handlePtr) /* Where to store the handle. */ 1123{ 1124 PipeState *psPtr = (PipeState *) instanceData; 1125 1126 if (direction == TCL_READABLE && psPtr->inFile) { 1127 *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->inFile)); 1128 return TCL_OK; 1129 } 1130 if (direction == TCL_WRITABLE && psPtr->outFile) { 1131 *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->outFile)); 1132 return TCL_OK; 1133 } 1134 return TCL_ERROR; 1135} 1136 1137/* 1138 *---------------------------------------------------------------------- 1139 * 1140 * Tcl_WaitPid -- 1141 * 1142 * Implements the waitpid system call on Unix systems. 1143 * 1144 * Results: 1145 * Result of calling waitpid. 1146 * 1147 * Side effects: 1148 * Waits for a process to terminate. 1149 * 1150 *---------------------------------------------------------------------- 1151 */ 1152 1153Tcl_Pid 1154Tcl_WaitPid( 1155 Tcl_Pid pid, 1156 int *statPtr, 1157 int options) 1158{ 1159 int result; 1160 pid_t real_pid = (pid_t) PTR2INT(pid); 1161 1162 while (1) { 1163 result = (int) waitpid(real_pid, statPtr, options); 1164 if ((result != -1) || (errno != EINTR)) { 1165 return (Tcl_Pid) INT2PTR(result); 1166 } 1167 } 1168} 1169 1170/* 1171 *---------------------------------------------------------------------- 1172 * 1173 * Tcl_PidObjCmd -- 1174 * 1175 * This function is invoked to process the "pid" Tcl command. See the 1176 * user documentation for details on what it does. 1177 * 1178 * Results: 1179 * A standard Tcl result. 1180 * 1181 * Side effects: 1182 * See the user documentation. 1183 * 1184 *---------------------------------------------------------------------- 1185 */ 1186 1187 /* ARGSUSED */ 1188int 1189Tcl_PidObjCmd( 1190 ClientData dummy, /* Not used. */ 1191 Tcl_Interp *interp, /* Current interpreter. */ 1192 int objc, /* Number of arguments. */ 1193 Tcl_Obj *const *objv) /* Argument strings. */ 1194{ 1195 if (objc > 2) { 1196 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); 1197 return TCL_ERROR; 1198 } 1199 1200 if (objc == 1) { 1201 Tcl_SetObjResult(interp, Tcl_NewLongObj((long) getpid())); 1202 } else { 1203 /* 1204 * Get the channel and make sure that it refers to a pipe. 1205 */ 1206 Tcl_Channel chan; 1207 const Tcl_ChannelType *chanTypePtr; 1208 PipeState *pipePtr; 1209 int i; 1210 Tcl_Obj *resultPtr, *longObjPtr; 1211 1212 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); 1213 if (chan == (Tcl_Channel) NULL) { 1214 return TCL_ERROR; 1215 } 1216 chanTypePtr = Tcl_GetChannelType(chan); 1217 if (chanTypePtr != &pipeChannelType) { 1218 return TCL_OK; 1219 } 1220 1221 /* 1222 * Extract the process IDs from the pipe structure. 1223 */ 1224 1225 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); 1226 resultPtr = Tcl_NewObj(); 1227 for (i = 0; i < pipePtr->numPids; i++) { 1228 longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i])); 1229 Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr); 1230 } 1231 Tcl_SetObjResult(interp, resultPtr); 1232 } 1233 return TCL_OK; 1234} 1235 1236/* 1237 *---------------------------------------------------------------------- 1238 * 1239 * TclpFinalizePipes -- 1240 * 1241 * Cleans up the pipe subsystem from Tcl_FinalizeThread 1242 * 1243 * Results: 1244 * None. 1245 * 1246 * Notes: 1247 * This function carries out no operation on Unix. 1248 * 1249 *---------------------------------------------------------------------- 1250 */ 1251 1252void 1253TclpFinalizePipes(void) 1254{ 1255} 1256 1257/* 1258 * Local Variables: 1259 * mode: c 1260 * c-basic-offset: 4 1261 * fill-column: 78 1262 * End: 1263 */ 1264