tclUnixPipe.cGo to the documentation of this file.00001 /* 00002 * tclUnixPipe.c -- 00003 * 00004 * This file implements the UNIX-specific exec pipeline functions, the 00005 * "pipe" channel driver, and the "pid" Tcl command. 00006 * 00007 * Copyright (c) 1991-1994 The Regents of the University of California. 00008 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 00009 * 00010 * See the file "license.terms" for information on usage and redistribution of 00011 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00012 * 00013 * RCS: @(#) $Id: tclUnixPipe.c,v 1.40 2007/12/13 15:28:42 dgp Exp $ 00014 */ 00015 00016 #include "tclInt.h" 00017 00018 #ifdef USE_VFORK 00019 #define fork vfork 00020 #endif 00021 00022 /* 00023 * The following macros convert between TclFile's and fd's. The conversion 00024 * simple involves shifting fd's up by one to ensure that no valid fd is ever 00025 * the same as NULL. 00026 */ 00027 00028 #define MakeFile(fd) ((TclFile)INT2PTR(((int)(fd))+1)) 00029 #define GetFd(file) (PTR2INT(file)-1) 00030 00031 /* 00032 * This structure describes per-instance state of a pipe based channel. 00033 */ 00034 00035 typedef struct PipeState { 00036 Tcl_Channel channel; /* Channel associated with this file. */ 00037 TclFile inFile; /* Output from pipe. */ 00038 TclFile outFile; /* Input to pipe. */ 00039 TclFile errorFile; /* Error output from pipe. */ 00040 int numPids; /* How many processes are attached to this 00041 * pipe? */ 00042 Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by 00043 * the creator of the pipe. */ 00044 int isNonBlocking; /* Nonzero when the pipe is in nonblocking 00045 * mode. Used to decide whether to wait for 00046 * the children at close time. */ 00047 } PipeState; 00048 00049 /* 00050 * Declarations for local functions defined in this file: 00051 */ 00052 00053 static int PipeBlockModeProc(ClientData instanceData, int mode); 00054 static int PipeCloseProc(ClientData instanceData, 00055 Tcl_Interp *interp); 00056 static int PipeGetHandleProc(ClientData instanceData, 00057 int direction, ClientData *handlePtr); 00058 static int PipeInputProc(ClientData instanceData, char *buf, 00059 int toRead, int *errorCode); 00060 static int PipeOutputProc(ClientData instanceData, 00061 const char *buf, int toWrite, int *errorCode); 00062 static void PipeWatchProc(ClientData instanceData, int mask); 00063 static void RestoreSignals(void); 00064 static int SetupStdFile(TclFile file, int type); 00065 00066 /* 00067 * This structure describes the channel type structure for command pipe based 00068 * I/O: 00069 */ 00070 00071 static Tcl_ChannelType pipeChannelType = { 00072 "pipe", /* Type name. */ 00073 TCL_CHANNEL_VERSION_5, /* v5 channel */ 00074 PipeCloseProc, /* Close proc. */ 00075 PipeInputProc, /* Input proc. */ 00076 PipeOutputProc, /* Output proc. */ 00077 NULL, /* Seek proc. */ 00078 NULL, /* Set option proc. */ 00079 NULL, /* Get option proc. */ 00080 PipeWatchProc, /* Initialize notifier. */ 00081 PipeGetHandleProc, /* Get OS handles out of channel. */ 00082 NULL, /* close2proc. */ 00083 PipeBlockModeProc, /* Set blocking or non-blocking mode.*/ 00084 NULL, /* flush proc. */ 00085 NULL, /* handler proc. */ 00086 NULL, /* wide seek proc */ 00087 NULL, /* thread action proc */ 00088 NULL, /* truncation */ 00089 }; 00090 00091 /* 00092 *---------------------------------------------------------------------- 00093 * 00094 * TclpMakeFile -- 00095 * 00096 * Make a TclFile from a channel. 00097 * 00098 * Results: 00099 * Returns a new TclFile or NULL on failure. 00100 * 00101 * Side effects: 00102 * None. 00103 * 00104 *---------------------------------------------------------------------- 00105 */ 00106 00107 TclFile 00108 TclpMakeFile( 00109 Tcl_Channel channel, /* Channel to get file from. */ 00110 int direction) /* Either TCL_READABLE or TCL_WRITABLE. */ 00111 { 00112 ClientData data; 00113 00114 if (Tcl_GetChannelHandle(channel, direction, 00115 (ClientData *) &data) == TCL_OK) { 00116 return MakeFile(PTR2INT(data)); 00117 } else { 00118 return (TclFile) NULL; 00119 } 00120 } 00121 00122 /* 00123 *---------------------------------------------------------------------- 00124 * 00125 * TclpOpenFile -- 00126 * 00127 * Open a file for use in a pipeline. 00128 * 00129 * Results: 00130 * Returns a new TclFile handle or NULL on failure. 00131 * 00132 * Side effects: 00133 * May cause a file to be created on the file system. 00134 * 00135 *---------------------------------------------------------------------- 00136 */ 00137 00138 TclFile 00139 TclpOpenFile( 00140 const char *fname, /* The name of the file to open. */ 00141 int mode) /* In what mode to open the file? */ 00142 { 00143 int fd; 00144 const char *native; 00145 Tcl_DString ds; 00146 00147 native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds); 00148 fd = TclOSopen(native, mode, 0666); /* INTL: Native. */ 00149 Tcl_DStringFree(&ds); 00150 if (fd != -1) { 00151 fcntl(fd, F_SETFD, FD_CLOEXEC); 00152 00153 /* 00154 * If the file is being opened for writing, seek to the end so we can 00155 * append to any data already in the file. 00156 */ 00157 00158 if ((mode & O_WRONLY) && !(mode & O_APPEND)) { 00159 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END); 00160 } 00161 00162 /* 00163 * Increment the fd so it can't be 0, which would conflict with the 00164 * NULL return for errors. 00165 */ 00166 00167 return MakeFile(fd); 00168 } 00169 return NULL; 00170 } 00171 00172 /* 00173 *---------------------------------------------------------------------- 00174 * 00175 * TclpCreateTempFile -- 00176 * 00177 * This function creates a temporary file initialized with an optional 00178 * string, and returns a file handle with the file pointer at the 00179 * beginning of the file. 00180 * 00181 * Results: 00182 * A handle to a file. 00183 * 00184 * Side effects: 00185 * None. 00186 * 00187 *---------------------------------------------------------------------- 00188 */ 00189 00190 TclFile 00191 TclpCreateTempFile( 00192 const char *contents) /* String to write into temp file, or NULL. */ 00193 { 00194 char fileName[L_tmpnam + 9]; 00195 const char *native; 00196 Tcl_DString dstring; 00197 int fd; 00198 00199 /* 00200 * We should also check against making more then TMP_MAX of these. 00201 */ 00202 00203 strcpy(fileName, P_tmpdir); /* INTL: Native. */ 00204 if (fileName[strlen(fileName) - 1] != '/') { 00205 strcat(fileName, "/"); /* INTL: Native. */ 00206 } 00207 strcat(fileName, "tclXXXXXX"); 00208 fd = mkstemp(fileName); /* INTL: Native. */ 00209 if (fd == -1) { 00210 return NULL; 00211 } 00212 fcntl(fd, F_SETFD, FD_CLOEXEC); 00213 unlink(fileName); /* INTL: Native. */ 00214 00215 if (contents != NULL) { 00216 native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); 00217 if (write(fd, native, strlen(native)) == -1) { 00218 close(fd); 00219 Tcl_DStringFree(&dstring); 00220 return NULL; 00221 } 00222 Tcl_DStringFree(&dstring); 00223 TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET); 00224 } 00225 return MakeFile(fd); 00226 } 00227 00228 /* 00229 *---------------------------------------------------------------------- 00230 * 00231 * TclpTempFileName -- 00232 * 00233 * This function returns unique filename. 00234 * 00235 * Results: 00236 * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. 00237 * 00238 * Side effects: 00239 * None. 00240 * 00241 *---------------------------------------------------------------------- 00242 */ 00243 00244 Tcl_Obj * 00245 TclpTempFileName(void) 00246 { 00247 char fileName[L_tmpnam + 9]; 00248 Tcl_Obj *result = NULL; 00249 int fd; 00250 00251 /* 00252 * We should also check against making more then TMP_MAX of these. 00253 */ 00254 00255 strcpy(fileName, P_tmpdir); /* INTL: Native. */ 00256 if (fileName[strlen(fileName) - 1] != '/') { 00257 strcat(fileName, "/"); /* INTL: Native. */ 00258 } 00259 strcat(fileName, "tclXXXXXX"); 00260 fd = mkstemp(fileName); /* INTL: Native. */ 00261 if (fd == -1) { 00262 return NULL; 00263 } 00264 fcntl(fd, F_SETFD, FD_CLOEXEC); 00265 unlink(fileName); /* INTL: Native. */ 00266 00267 result = TclpNativeToNormalized((ClientData) fileName); 00268 close(fd); 00269 return result; 00270 } 00271 00272 /* 00273 *---------------------------------------------------------------------- 00274 * 00275 * TclpCreatePipe -- 00276 * 00277 * Creates a pipe - simply calls the pipe() function. 00278 * 00279 * Results: 00280 * Returns 1 on success, 0 on failure. 00281 * 00282 * Side effects: 00283 * Creates a pipe. 00284 * 00285 *---------------------------------------------------------------------- 00286 */ 00287 00288 int 00289 TclpCreatePipe( 00290 TclFile *readPipe, /* Location to store file handle for read side 00291 * of pipe. */ 00292 TclFile *writePipe) /* Location to store file handle for write 00293 * side of pipe. */ 00294 { 00295 int pipeIds[2]; 00296 00297 if (pipe(pipeIds) != 0) { 00298 return 0; 00299 } 00300 00301 fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC); 00302 fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC); 00303 00304 *readPipe = MakeFile(pipeIds[0]); 00305 *writePipe = MakeFile(pipeIds[1]); 00306 return 1; 00307 } 00308 00309 /* 00310 *---------------------------------------------------------------------- 00311 * 00312 * TclpCloseFile -- 00313 * 00314 * Implements a mechanism to close a UNIX file. 00315 * 00316 * Results: 00317 * Returns 0 on success, or -1 on error, setting errno. 00318 * 00319 * Side effects: 00320 * The file is closed. 00321 * 00322 *---------------------------------------------------------------------- 00323 */ 00324 00325 int 00326 TclpCloseFile( 00327 TclFile file) /* The file to close. */ 00328 { 00329 int fd = GetFd(file); 00330 00331 /* 00332 * Refuse to close the fds for stdin, stdout and stderr. 00333 */ 00334 00335 if ((fd == 0) || (fd == 1) || (fd == 2)) { 00336 return 0; 00337 } 00338 00339 Tcl_DeleteFileHandler(fd); 00340 return close(fd); 00341 } 00342 00343 /* 00344 *--------------------------------------------------------------------------- 00345 * 00346 * TclpCreateProcess -- 00347 * 00348 * Create a child process that has the specified files as its standard 00349 * input, output, and error. The child process runs asynchronously and 00350 * runs with the same environment variables as the creating process. 00351 * 00352 * The path is searched to find the specified executable. 00353 * 00354 * Results: 00355 * The return value is TCL_ERROR and an error message is left in the 00356 * interp's result if there was a problem creating the child process. 00357 * Otherwise, the return value is TCL_OK and *pidPtr is filled with the 00358 * process id of the child process. 00359 * 00360 * Side effects: 00361 * A process is created. 00362 * 00363 *--------------------------------------------------------------------------- 00364 */ 00365 00366 /* ARGSUSED */ 00367 int 00368 TclpCreateProcess( 00369 Tcl_Interp *interp, /* Interpreter in which to leave errors that 00370 * occurred when creating the child process. 00371 * Error messages from the child process 00372 * itself are sent to errorFile. */ 00373 int argc, /* Number of arguments in following array. */ 00374 const char **argv, /* Array of argument strings in UTF-8. 00375 * argv[0] contains the name of the executable 00376 * translated using Tcl_TranslateFileName 00377 * call). Additional arguments have not been 00378 * converted. */ 00379 TclFile inputFile, /* If non-NULL, gives the file to use as input 00380 * for the child process. If inputFile file is 00381 * not readable or is NULL, the child will 00382 * receive no standard input. */ 00383 TclFile outputFile, /* If non-NULL, gives the file that receives 00384 * output from the child process. If 00385 * outputFile file is not writeable or is 00386 * NULL, output from the child will be 00387 * discarded. */ 00388 TclFile errorFile, /* If non-NULL, gives the file that receives 00389 * errors from the child process. If errorFile 00390 * file is not writeable or is NULL, errors 00391 * from the child will be discarded. errorFile 00392 * may be the same as outputFile. */ 00393 Tcl_Pid *pidPtr) /* If this function is successful, pidPtr is 00394 * filled with the process id of the child 00395 * process. */ 00396 { 00397 TclFile errPipeIn, errPipeOut; 00398 int count, status, fd; 00399 char errSpace[200 + TCL_INTEGER_SPACE]; 00400 Tcl_DString *dsArray; 00401 char **newArgv; 00402 int pid, i; 00403 00404 errPipeIn = NULL; 00405 errPipeOut = NULL; 00406 pid = -1; 00407 00408 /* 00409 * Create a pipe that the child can use to return error information if 00410 * anything goes wrong. 00411 */ 00412 00413 if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { 00414 Tcl_AppendResult(interp, "couldn't create pipe: ", 00415 Tcl_PosixError(interp), NULL); 00416 goto error; 00417 } 00418 00419 /* 00420 * We need to allocate and convert this before the fork so it is properly 00421 * deallocated later 00422 */ 00423 00424 dsArray = (Tcl_DString *) 00425 TclStackAlloc(interp, argc * sizeof(Tcl_DString)); 00426 newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *)); 00427 newArgv[argc] = NULL; 00428 for (i = 0; i < argc; i++) { 00429 newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); 00430 } 00431 00432 #ifdef USE_VFORK 00433 /* 00434 * After vfork(), do not call code in the child that changes global state, 00435 * because it is using the parent's memory space at that point and writes 00436 * might corrupt the parent: so ensure standard channels are initialized in 00437 * the parent, otherwise SetupStdFile() might initialize them in the child. 00438 */ 00439 if (!inputFile) { 00440 Tcl_GetStdChannel(TCL_STDIN); 00441 } 00442 if (!outputFile) { 00443 Tcl_GetStdChannel(TCL_STDOUT); 00444 } 00445 if (!errorFile) { 00446 Tcl_GetStdChannel(TCL_STDERR); 00447 } 00448 #endif 00449 pid = fork(); 00450 if (pid == 0) { 00451 int joinThisError = errorFile && (errorFile == outputFile); 00452 00453 fd = GetFd(errPipeOut); 00454 00455 /* 00456 * Set up stdio file handles for the child process. 00457 */ 00458 00459 if (!SetupStdFile(inputFile, TCL_STDIN) 00460 || !SetupStdFile(outputFile, TCL_STDOUT) 00461 || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR)) 00462 || (joinThisError && 00463 ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) { 00464 sprintf(errSpace, 00465 "%dforked process couldn't set up input/output: ", errno); 00466 write(fd, errSpace, (size_t) strlen(errSpace)); 00467 _exit(1); 00468 } 00469 00470 /* 00471 * Close the input side of the error pipe. 00472 */ 00473 00474 RestoreSignals(); 00475 execvp(newArgv[0], newArgv); /* INTL: Native. */ 00476 sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]); 00477 write(fd, errSpace, (size_t) strlen(errSpace)); 00478 _exit(1); 00479 } 00480 00481 /* 00482 * Free the mem we used for the fork 00483 */ 00484 00485 for (i = 0; i < argc; i++) { 00486 Tcl_DStringFree(&dsArray[i]); 00487 } 00488 TclStackFree(interp, newArgv); 00489 TclStackFree(interp, dsArray); 00490 00491 if (pid == -1) { 00492 Tcl_AppendResult(interp, "couldn't fork child process: ", 00493 Tcl_PosixError(interp), NULL); 00494 goto error; 00495 } 00496 00497 /* 00498 * Read back from the error pipe to see if the child started up OK. The 00499 * info in the pipe (if any) consists of a decimal errno value followed by 00500 * an error message. 00501 */ 00502 00503 TclpCloseFile(errPipeOut); 00504 errPipeOut = NULL; 00505 00506 fd = GetFd(errPipeIn); 00507 count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1)); 00508 if (count > 0) { 00509 char *end; 00510 errSpace[count] = 0; 00511 errno = strtol(errSpace, &end, 10); 00512 Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL); 00513 goto error; 00514 } 00515 00516 TclpCloseFile(errPipeIn); 00517 *pidPtr = (Tcl_Pid) INT2PTR(pid); 00518 return TCL_OK; 00519 00520 error: 00521 if (pid != -1) { 00522 /* 00523 * Reap the child process now if an error occurred during its startup. 00524 * We don't call this with WNOHANG because that can lead to defunct 00525 * processes on an MP system. We shouldn't have to worry about hanging 00526 * here, since this is the error case. [Bug: 6148] 00527 */ 00528 00529 Tcl_WaitPid((Tcl_Pid) INT2PTR(pid), &status, 0); 00530 } 00531 00532 if (errPipeIn) { 00533 TclpCloseFile(errPipeIn); 00534 } 00535 if (errPipeOut) { 00536 TclpCloseFile(errPipeOut); 00537 } 00538 return TCL_ERROR; 00539 } 00540 00541 /* 00542 *---------------------------------------------------------------------- 00543 * 00544 * RestoreSignals -- 00545 * 00546 * This function is invoked in a forked child process just before 00547 * exec-ing a new program to restore all signals to their default 00548 * settings. 00549 * 00550 * Results: 00551 * None. 00552 * 00553 * Side effects: 00554 * Signal settings get changed. 00555 * 00556 *---------------------------------------------------------------------- 00557 */ 00558 00559 static void 00560 RestoreSignals(void) 00561 { 00562 #ifdef SIGABRT 00563 signal(SIGABRT, SIG_DFL); 00564 #endif 00565 #ifdef SIGALRM 00566 signal(SIGALRM, SIG_DFL); 00567 #endif 00568 #ifdef SIGFPE 00569 signal(SIGFPE, SIG_DFL); 00570 #endif 00571 #ifdef SIGHUP 00572 signal(SIGHUP, SIG_DFL); 00573 #endif 00574 #ifdef SIGILL 00575 signal(SIGILL, SIG_DFL); 00576 #endif 00577 #ifdef SIGINT 00578 signal(SIGINT, SIG_DFL); 00579 #endif 00580 #ifdef SIGPIPE 00581 signal(SIGPIPE, SIG_DFL); 00582 #endif 00583 #ifdef SIGQUIT 00584 signal(SIGQUIT, SIG_DFL); 00585 #endif 00586 #ifdef SIGSEGV 00587 signal(SIGSEGV, SIG_DFL); 00588 #endif 00589 #ifdef SIGTERM 00590 signal(SIGTERM, SIG_DFL); 00591 #endif 00592 #ifdef SIGUSR1 00593 signal(SIGUSR1, SIG_DFL); 00594 #endif 00595 #ifdef SIGUSR2 00596 signal(SIGUSR2, SIG_DFL); 00597 #endif 00598 #ifdef SIGCHLD 00599 signal(SIGCHLD, SIG_DFL); 00600 #endif 00601 #ifdef SIGCONT 00602 signal(SIGCONT, SIG_DFL); 00603 #endif 00604 #ifdef SIGTSTP 00605 signal(SIGTSTP, SIG_DFL); 00606 #endif 00607 #ifdef SIGTTIN 00608 signal(SIGTTIN, SIG_DFL); 00609 #endif 00610 #ifdef SIGTTOU 00611 signal(SIGTTOU, SIG_DFL); 00612 #endif 00613 } 00614 00615 /* 00616 *---------------------------------------------------------------------- 00617 * 00618 * SetupStdFile -- 00619 * 00620 * Set up stdio file handles for the child process, using the current 00621 * standard channels if no other files are specified. If no standard 00622 * channel is defined, or if no file is associated with the channel, then 00623 * the corresponding standard fd is closed. 00624 * 00625 * Results: 00626 * Returns 1 on success, or 0 on failure. 00627 * 00628 * Side effects: 00629 * Replaces stdio fds. 00630 * 00631 *---------------------------------------------------------------------- 00632 */ 00633 00634 static int 00635 SetupStdFile( 00636 TclFile file, /* File to dup, or NULL. */ 00637 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */ 00638 { 00639 Tcl_Channel channel; 00640 int fd; 00641 int targetFd = 0; /* Initializations here needed only to */ 00642 int direction = 0; /* prevent warnings about using uninitialized 00643 * variables. */ 00644 00645 switch (type) { 00646 case TCL_STDIN: 00647 targetFd = 0; 00648 direction = TCL_READABLE; 00649 break; 00650 case TCL_STDOUT: 00651 targetFd = 1; 00652 direction = TCL_WRITABLE; 00653 break; 00654 case TCL_STDERR: 00655 targetFd = 2; 00656 direction = TCL_WRITABLE; 00657 break; 00658 } 00659 00660 if (!file) { 00661 channel = Tcl_GetStdChannel(type); 00662 if (channel) { 00663 file = TclpMakeFile(channel, direction); 00664 } 00665 } 00666 if (file) { 00667 fd = GetFd(file); 00668 if (fd != targetFd) { 00669 if (dup2(fd, targetFd) == -1) { 00670 return 0; 00671 } 00672 00673 /* 00674 * Must clear the close-on-exec flag for the target FD, since some 00675 * systems (e.g. Ultrix) do not clear the CLOEXEC flag on the 00676 * target FD. 00677 */ 00678 00679 fcntl(targetFd, F_SETFD, 0); 00680 } else { 00681 /* 00682 * Since we aren't dup'ing the file, we need to explicitly clear 00683 * the close-on-exec flag. 00684 */ 00685 00686 fcntl(fd, F_SETFD, 0); 00687 } 00688 } else { 00689 close(targetFd); 00690 } 00691 return 1; 00692 } 00693 00694 /* 00695 *---------------------------------------------------------------------- 00696 * 00697 * TclpCreateCommandChannel -- 00698 * 00699 * This function is called by the generic IO level to perform the 00700 * platform specific channel initialization for a command channel. 00701 * 00702 * Results: 00703 * Returns a new channel or NULL on failure. 00704 * 00705 * Side effects: 00706 * Allocates a new channel. 00707 * 00708 *---------------------------------------------------------------------- 00709 */ 00710 00711 Tcl_Channel 00712 TclpCreateCommandChannel( 00713 TclFile readFile, /* If non-null, gives the file for reading. */ 00714 TclFile writeFile, /* If non-null, gives the file for writing. */ 00715 TclFile errorFile, /* If non-null, gives the file where errors 00716 * can be read. */ 00717 int numPids, /* The number of pids in the pid array. */ 00718 Tcl_Pid *pidPtr) /* An array of process identifiers. Allocated 00719 * by the caller, freed when the channel is 00720 * closed or the processes are detached (in a 00721 * background exec). */ 00722 { 00723 char channelName[16 + TCL_INTEGER_SPACE]; 00724 int channelId; 00725 PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState)); 00726 int mode; 00727 00728 statePtr->inFile = readFile; 00729 statePtr->outFile = writeFile; 00730 statePtr->errorFile = errorFile; 00731 statePtr->numPids = numPids; 00732 statePtr->pidPtr = pidPtr; 00733 statePtr->isNonBlocking = 0; 00734 00735 mode = 0; 00736 if (readFile) { 00737 mode |= TCL_READABLE; 00738 } 00739 if (writeFile) { 00740 mode |= TCL_WRITABLE; 00741 } 00742 00743 /* 00744 * Use one of the fds associated with the channel as the channel id. 00745 */ 00746 00747 if (readFile) { 00748 channelId = GetFd(readFile); 00749 } else if (writeFile) { 00750 channelId = GetFd(writeFile); 00751 } else if (errorFile) { 00752 channelId = GetFd(errorFile); 00753 } else { 00754 channelId = 0; 00755 } 00756 00757 /* 00758 * For backward compatibility with previous versions of Tcl, we use 00759 * "file%d" as the base name for pipes even though it would be more 00760 * natural to use "pipe%d". 00761 */ 00762 00763 sprintf(channelName, "file%d", channelId); 00764 statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, 00765 (ClientData) statePtr, mode); 00766 return statePtr->channel; 00767 } 00768 00769 /* 00770 *---------------------------------------------------------------------- 00771 * 00772 * TclGetAndDetachPids -- 00773 * 00774 * This function is invoked in the generic implementation of a 00775 * background "exec" (an exec when invoked with a terminating "&") to 00776 * store a list of the PIDs for processes in a command pipeline in the 00777 * interp's result and to detach the processes. 00778 * 00779 * Results: 00780 * None. 00781 * 00782 * Side effects: 00783 * Modifies the interp's result. Detaches processes. 00784 * 00785 *---------------------------------------------------------------------- 00786 */ 00787 00788 void 00789 TclGetAndDetachPids( 00790 Tcl_Interp *interp, /* Interpreter to append the PIDs to. */ 00791 Tcl_Channel chan) /* Handle for the pipeline. */ 00792 { 00793 PipeState *pipePtr; 00794 const Tcl_ChannelType *chanTypePtr; 00795 int i; 00796 char buf[TCL_INTEGER_SPACE]; 00797 00798 /* 00799 * Punt if the channel is not a command channel. 00800 */ 00801 00802 chanTypePtr = Tcl_GetChannelType(chan); 00803 if (chanTypePtr != &pipeChannelType) { 00804 return; 00805 } 00806 00807 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); 00808 for (i = 0; i < pipePtr->numPids; i++) { 00809 TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i])); 00810 Tcl_AppendElement(interp, buf); 00811 Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); 00812 } 00813 if (pipePtr->numPids > 0) { 00814 ckfree((char *) pipePtr->pidPtr); 00815 pipePtr->numPids = 0; 00816 } 00817 } 00818 00819 /* 00820 *---------------------------------------------------------------------- 00821 * 00822 * PipeBlockModeProc -- 00823 * 00824 * Helper function to set blocking and nonblocking modes on a pipe based 00825 * channel. Invoked by generic IO level code. 00826 * 00827 * Results: 00828 * 0 if successful, errno when failed. 00829 * 00830 * Side effects: 00831 * Sets the device into blocking or non-blocking mode. 00832 * 00833 *---------------------------------------------------------------------- 00834 */ 00835 00836 /* ARGSUSED */ 00837 static int 00838 PipeBlockModeProc( 00839 ClientData instanceData, /* Pipe state. */ 00840 int mode) /* The mode to set. Can be one of 00841 * TCL_MODE_BLOCKING or 00842 * TCL_MODE_NONBLOCKING. */ 00843 { 00844 PipeState *psPtr = (PipeState *) instanceData; 00845 int curStatus; 00846 int fd; 00847 00848 #ifndef USE_FIONBIO 00849 if (psPtr->inFile) { 00850 fd = GetFd(psPtr->inFile); 00851 curStatus = fcntl(fd, F_GETFL); 00852 if (mode == TCL_MODE_BLOCKING) { 00853 curStatus &= (~(O_NONBLOCK)); 00854 } else { 00855 curStatus |= O_NONBLOCK; 00856 } 00857 if (fcntl(fd, F_SETFL, curStatus) < 0) { 00858 return errno; 00859 } 00860 } 00861 if (psPtr->outFile) { 00862 fd = GetFd(psPtr->outFile); 00863 curStatus = fcntl(fd, F_GETFL); 00864 if (mode == TCL_MODE_BLOCKING) { 00865 curStatus &= (~(O_NONBLOCK)); 00866 } else { 00867 curStatus |= O_NONBLOCK; 00868 } 00869 if (fcntl(fd, F_SETFL, curStatus) < 0) { 00870 return errno; 00871 } 00872 } 00873 #endif /* !FIONBIO */ 00874 00875 #ifdef USE_FIONBIO 00876 if (psPtr->inFile) { 00877 fd = GetFd(psPtr->inFile); 00878 if (mode == TCL_MODE_BLOCKING) { 00879 curStatus = 0; 00880 } else { 00881 curStatus = 1; 00882 } 00883 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) { 00884 return errno; 00885 } 00886 } 00887 if (psPtr->outFile != NULL) { 00888 fd = GetFd(psPtr->outFile); 00889 if (mode == TCL_MODE_BLOCKING) { 00890 curStatus = 0; 00891 } else { 00892 curStatus = 1; 00893 } 00894 if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) { 00895 return errno; 00896 } 00897 } 00898 #endif /* USE_FIONBIO */ 00899 00900 psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING); 00901 00902 return 0; 00903 } 00904 00905 /* 00906 *---------------------------------------------------------------------- 00907 * 00908 * PipeCloseProc -- 00909 * 00910 * This function is invoked by the generic IO level to perform 00911 * channel-type-specific cleanup when a command pipeline channel is 00912 * closed. 00913 * 00914 * Results: 00915 * 0 on success, errno otherwise. 00916 * 00917 * Side effects: 00918 * Closes the command pipeline channel. 00919 * 00920 *---------------------------------------------------------------------- 00921 */ 00922 00923 /* ARGSUSED */ 00924 static int 00925 PipeCloseProc( 00926 ClientData instanceData, /* The pipe to close. */ 00927 Tcl_Interp *interp) /* For error reporting. */ 00928 { 00929 PipeState *pipePtr; 00930 Tcl_Channel errChan; 00931 int errorCode, result; 00932 00933 errorCode = 0; 00934 result = 0; 00935 pipePtr = (PipeState *) instanceData; 00936 if (pipePtr->inFile) { 00937 if (TclpCloseFile(pipePtr->inFile) < 0) { 00938 errorCode = errno; 00939 } 00940 } 00941 if (pipePtr->outFile) { 00942 if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) { 00943 errorCode = errno; 00944 } 00945 } 00946 00947 if (pipePtr->isNonBlocking || TclInExit()) { 00948 /* 00949 * If the channel is non-blocking or Tcl is being cleaned up, just 00950 * detach the children PIDs, reap them (important if we are in a 00951 * dynamic load module), and discard the errorFile. 00952 */ 00953 00954 Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr); 00955 Tcl_ReapDetachedProcs(); 00956 00957 if (pipePtr->errorFile) { 00958 TclpCloseFile(pipePtr->errorFile); 00959 } 00960 } else { 00961 /* 00962 * Wrap the error file into a channel and give it to the cleanup 00963 * routine. 00964 */ 00965 00966 if (pipePtr->errorFile) { 00967 errChan = Tcl_MakeFileChannel( 00968 (ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); 00969 } else { 00970 errChan = NULL; 00971 } 00972 result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr, 00973 errChan); 00974 } 00975 00976 if (pipePtr->numPids != 0) { 00977 ckfree((char *) pipePtr->pidPtr); 00978 } 00979 ckfree((char *) pipePtr); 00980 if (errorCode == 0) { 00981 return result; 00982 } 00983 return errorCode; 00984 } 00985 00986 /* 00987 *---------------------------------------------------------------------- 00988 * 00989 * PipeInputProc -- 00990 * 00991 * This function is invoked from the generic IO level to read input from 00992 * a command pipeline based channel. 00993 * 00994 * Results: 00995 * The number of bytes read is returned or -1 on error. An output 00996 * argument contains a POSIX error code if an error occurs, or zero. 00997 * 00998 * Side effects: 00999 * Reads input from the input device of the channel. 01000 * 01001 *---------------------------------------------------------------------- 01002 */ 01003 01004 static int 01005 PipeInputProc( 01006 ClientData instanceData, /* Pipe state. */ 01007 char *buf, /* Where to store data read. */ 01008 int toRead, /* How much space is available in the 01009 * buffer? */ 01010 int *errorCodePtr) /* Where to store error code. */ 01011 { 01012 PipeState *psPtr = (PipeState *) instanceData; 01013 int bytesRead; /* How many bytes were actually read from the 01014 * input device? */ 01015 01016 *errorCodePtr = 0; 01017 01018 /* 01019 * Assume there is always enough input available. This will block 01020 * appropriately, and read will unblock as soon as a short read is 01021 * possible, if the channel is in blocking mode. If the channel is 01022 * nonblocking, the read will never block. Some OSes can throw an 01023 * interrupt error, for which we should immediately retry. [Bug #415131] 01024 */ 01025 01026 do { 01027 bytesRead = read(GetFd(psPtr->inFile), buf, (size_t) toRead); 01028 } while ((bytesRead < 0) && (errno == EINTR)); 01029 01030 if (bytesRead < 0) { 01031 *errorCodePtr = errno; 01032 return -1; 01033 } else { 01034 return bytesRead; 01035 } 01036 } 01037 01038 /* 01039 *---------------------------------------------------------------------- 01040 * 01041 * PipeOutputProc-- 01042 * 01043 * This function is invoked from the generic IO level to write output to 01044 * a command pipeline based channel. 01045 * 01046 * Results: 01047 * The number of bytes written is returned or -1 on error. An output 01048 * argument contains a POSIX error code if an error occurred, or zero. 01049 * 01050 * Side effects: 01051 * Writes output on the output device of the channel. 01052 * 01053 *---------------------------------------------------------------------- 01054 */ 01055 01056 static int 01057 PipeOutputProc( 01058 ClientData instanceData, /* Pipe state. */ 01059 const char *buf, /* The data buffer. */ 01060 int toWrite, /* How many bytes to write? */ 01061 int *errorCodePtr) /* Where to store error code. */ 01062 { 01063 PipeState *psPtr = (PipeState *) instanceData; 01064 int written; 01065 01066 *errorCodePtr = 0; 01067 01068 /* 01069 * Some OSes can throw an interrupt error, for which we should immediately 01070 * retry. [Bug #415131] 01071 */ 01072 01073 do { 01074 written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite); 01075 } while ((written < 0) && (errno == EINTR)); 01076 01077 if (written < 0) { 01078 *errorCodePtr = errno; 01079 return -1; 01080 } else { 01081 return written; 01082 } 01083 } 01084 01085 /* 01086 *---------------------------------------------------------------------- 01087 * 01088 * PipeWatchProc -- 01089 * 01090 * Initialize the notifier to watch the fds from this channel. 01091 * 01092 * Results: 01093 * None. 01094 * 01095 * Side effects: 01096 * Sets up the notifier so that a future event on the channel will be 01097 * seen by Tcl. 01098 * 01099 *---------------------------------------------------------------------- 01100 */ 01101 01102 static void 01103 PipeWatchProc( 01104 ClientData instanceData, /* The pipe state. */ 01105 int mask) /* Events of interest; an OR-ed combination of 01106 * TCL_READABLE, TCL_WRITABLE and 01107 * TCL_EXCEPTION. */ 01108 { 01109 PipeState *psPtr = (PipeState *) instanceData; 01110 int newmask; 01111 01112 if (psPtr->inFile) { 01113 newmask = mask & (TCL_READABLE | TCL_EXCEPTION); 01114 if (newmask) { 01115 Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, 01116 (Tcl_FileProc *) Tcl_NotifyChannel, 01117 (ClientData) psPtr->channel); 01118 } else { 01119 Tcl_DeleteFileHandler(GetFd(psPtr->inFile)); 01120 } 01121 } 01122 if (psPtr->outFile) { 01123 newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION); 01124 if (newmask) { 01125 Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, 01126 (Tcl_FileProc *) Tcl_NotifyChannel, 01127 (ClientData) psPtr->channel); 01128 } else { 01129 Tcl_DeleteFileHandler(GetFd(psPtr->outFile)); 01130 } 01131 } 01132 } 01133 01134 /* 01135 *---------------------------------------------------------------------- 01136 * 01137 * PipeGetHandleProc -- 01138 * 01139 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a 01140 * command pipeline based channel. 01141 * 01142 * Results: 01143 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no 01144 * handle for the specified direction. 01145 * 01146 * Side effects: 01147 * None. 01148 * 01149 *---------------------------------------------------------------------- 01150 */ 01151 01152 static int 01153 PipeGetHandleProc( 01154 ClientData instanceData, /* The pipe state. */ 01155 int direction, /* TCL_READABLE or TCL_WRITABLE */ 01156 ClientData *handlePtr) /* Where to store the handle. */ 01157 { 01158 PipeState *psPtr = (PipeState *) instanceData; 01159 01160 if (direction == TCL_READABLE && psPtr->inFile) { 01161 *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->inFile)); 01162 return TCL_OK; 01163 } 01164 if (direction == TCL_WRITABLE && psPtr->outFile) { 01165 *handlePtr = (ClientData) INT2PTR(GetFd(psPtr->outFile)); 01166 return TCL_OK; 01167 } 01168 return TCL_ERROR; 01169 } 01170 01171 /* 01172 *---------------------------------------------------------------------- 01173 * 01174 * Tcl_WaitPid -- 01175 * 01176 * Implements the waitpid system call on Unix systems. 01177 * 01178 * Results: 01179 * Result of calling waitpid. 01180 * 01181 * Side effects: 01182 * Waits for a process to terminate. 01183 * 01184 *---------------------------------------------------------------------- 01185 */ 01186 01187 Tcl_Pid 01188 Tcl_WaitPid( 01189 Tcl_Pid pid, 01190 int *statPtr, 01191 int options) 01192 { 01193 int result; 01194 pid_t real_pid; 01195 01196 real_pid = (pid_t) PTR2INT(pid); 01197 while (1) { 01198 result = (int) waitpid(real_pid, statPtr, options); 01199 if ((result != -1) || (errno != EINTR)) { 01200 return (Tcl_Pid) INT2PTR(result); 01201 } 01202 } 01203 } 01204 01205 /* 01206 *---------------------------------------------------------------------- 01207 * 01208 * Tcl_PidObjCmd -- 01209 * 01210 * This function is invoked to process the "pid" Tcl command. See the 01211 * user documentation for details on what it does. 01212 * 01213 * Results: 01214 * A standard Tcl result. 01215 * 01216 * Side effects: 01217 * See the user documentation. 01218 * 01219 *---------------------------------------------------------------------- 01220 */ 01221 01222 /* ARGSUSED */ 01223 int 01224 Tcl_PidObjCmd( 01225 ClientData dummy, /* Not used. */ 01226 Tcl_Interp *interp, /* Current interpreter. */ 01227 int objc, /* Number of arguments. */ 01228 Tcl_Obj *const *objv) /* Argument strings. */ 01229 { 01230 if (objc > 2) { 01231 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); 01232 return TCL_ERROR; 01233 } 01234 if (objc == 1) { 01235 Tcl_SetObjResult(interp, Tcl_NewLongObj((long) getpid())); 01236 } else { 01237 Tcl_Channel chan; 01238 const Tcl_ChannelType *chanTypePtr; 01239 PipeState *pipePtr; 01240 int i; 01241 Tcl_Obj *resultPtr, *longObjPtr; 01242 01243 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); 01244 if (chan == (Tcl_Channel) NULL) { 01245 return TCL_ERROR; 01246 } 01247 chanTypePtr = Tcl_GetChannelType(chan); 01248 if (chanTypePtr != &pipeChannelType) { 01249 return TCL_OK; 01250 } 01251 pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); 01252 resultPtr = Tcl_NewObj(); 01253 for (i = 0; i < pipePtr->numPids; i++) { 01254 longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i])); 01255 Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr); 01256 } 01257 Tcl_SetObjResult(interp, resultPtr); 01258 } 01259 return TCL_OK; 01260 } 01261 01262 /* 01263 *---------------------------------------------------------------------- 01264 * 01265 * TclpFinalizePipes -- 01266 * 01267 * Cleans up the pipe subsystem from Tcl_FinalizeThread 01268 * 01269 * Results: 01270 * None. 01271 * 01272 * Notes: 01273 * This function carries out no operation on Unix. 01274 * 01275 *---------------------------------------------------------------------- 01276 */ 01277 01278 void 01279 TclpFinalizePipes(void) 01280 { 01281 } 01282 01283 /* 01284 * Local Variables: 01285 * mode: c 01286 * c-basic-offset: 4 01287 * fill-column: 78 01288 * End: 01289 */
Generated on Wed Mar 12 12:18:26 2008 by 1.5.1 |