os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixPipe.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixPipe.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1493 @@
1.4 +/*
1.5 + * tclUnixPipe.c --
1.6 + *
1.7 + * This file implements the UNIX-specific exec pipeline functions,
1.8 + * the "pipe" channel driver, and the "pid" Tcl command.
1.9 + *
1.10 + * Copyright (c) 1991-1994 The Regents of the University of California.
1.11 + * Copyright (c) 1994-1997 Sun Microsystems, Inc.
1.12 + * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
1.13 + *
1.14 + * See the file "license.terms" for information on usage and redistribution
1.15 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.16 + *
1.17 + * RCS: @(#) $Id: tclUnixPipe.c,v 1.23.2.7 2006/08/02 20:04:40 das Exp $
1.18 + */
1.19 +
1.20 +#include "tclInt.h"
1.21 +#include "tclPort.h"
1.22 +
1.23 +#if defined(__SYMBIAN32__)
1.24 +#include "tclSymbianGlobals.h"
1.25 +#include <spawn.h>
1.26 +#define ADDPARAMTOCHILD 4
1.27 +#endif
1.28 +
1.29 +void TclPrint1(const char* aFmt, const char* aStr);
1.30 +void TclPrint2(const char* aFmt, const char* aStr, int aNum);
1.31 +void TclPrint3(const char* aFmt);
1.32 +
1.33 +
1.34 +#ifdef USE_VFORK
1.35 +#define fork vfork
1.36 +#endif
1.37 +
1.38 +/*
1.39 + * The following macros convert between TclFile's and fd's. The conversion
1.40 + * simple involves shifting fd's up by one to ensure that no valid fd is ever
1.41 + * the same as NULL.
1.42 + */
1.43 +
1.44 +#define MakeFile(fd) ((TclFile)(((int)fd)+1))
1.45 +#define GetFd(file) (((int)file)-1)
1.46 +/*
1.47 + * This structure describes per-instance state of a pipe based channel.
1.48 + */
1.49 +
1.50 +typedef struct PipeState {
1.51 + Tcl_Channel channel;/* Channel associated with this file. */
1.52 + TclFile inFile; /* Output from pipe. */
1.53 + TclFile outFile; /* Input to pipe. */
1.54 + TclFile errorFile; /* Error output from pipe. */
1.55 + int numPids; /* How many processes are attached to this pipe? */
1.56 + Tcl_Pid *pidPtr; /* The process IDs themselves. Allocated by
1.57 + * the creator of the pipe. */
1.58 + int isNonBlocking; /* Nonzero when the pipe is in nonblocking mode.
1.59 + * Used to decide whether to wait for the children
1.60 + * at close time. */
1.61 +} PipeState;
1.62 +
1.63 +/*
1.64 + * Declarations for local procedures defined in this file:
1.65 + */
1.66 +
1.67 +static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
1.68 + int mode));
1.69 +static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
1.70 + Tcl_Interp *interp));
1.71 +static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
1.72 + int direction, ClientData *handlePtr));
1.73 +static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
1.74 + char *buf, int toRead, int *errorCode));
1.75 +static int PipeOutputProc _ANSI_ARGS_((
1.76 + ClientData instanceData, CONST char *buf, int toWrite,
1.77 + int *errorCode));
1.78 +static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
1.79 +static void RestoreSignals _ANSI_ARGS_((void));
1.80 +#ifndef __SYMBIAN32__
1.81 +static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
1.82 +#endif
1.83 +/*
1.84 + * This structure describes the channel type structure for command pipe
1.85 + * based IO:
1.86 + */
1.87 +
1.88 +static Tcl_ChannelType pipeChannelType = {
1.89 + "pipe", /* Type name. */
1.90 + TCL_CHANNEL_VERSION_4, /* v4 channel */
1.91 + PipeCloseProc, /* Close proc. */
1.92 + PipeInputProc, /* Input proc. */
1.93 + PipeOutputProc, /* Output proc. */
1.94 + NULL, /* Seek proc. */
1.95 + NULL, /* Set option proc. */
1.96 + NULL, /* Get option proc. */
1.97 + PipeWatchProc, /* Initialize notifier. */
1.98 + PipeGetHandleProc, /* Get OS handles out of channel. */
1.99 + NULL, /* close2proc. */
1.100 + PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
1.101 + NULL, /* flush proc. */
1.102 + NULL, /* handler proc. */
1.103 + NULL, /* wide seek proc */
1.104 + NULL, /* thread action proc */
1.105 +};
1.106 +
1.107 +/*
1.108 + *----------------------------------------------------------------------
1.109 + *
1.110 + * TclpMakeFile --
1.111 + *
1.112 + * Make a TclFile from a channel.
1.113 + *
1.114 + * Results:
1.115 + * Returns a new TclFile or NULL on failure.
1.116 + *
1.117 + * Side effects:
1.118 + * None.
1.119 + *
1.120 + *----------------------------------------------------------------------
1.121 + */
1.122 +
1.123 +TclFile
1.124 +TclpMakeFile(channel, direction)
1.125 + Tcl_Channel channel; /* Channel to get file from. */
1.126 + int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
1.127 +{
1.128 + ClientData data;
1.129 +
1.130 + if (Tcl_GetChannelHandle(channel, direction, (ClientData *) &data)
1.131 + == TCL_OK) {
1.132 + return MakeFile((int)data);
1.133 + } else {
1.134 + return (TclFile) NULL;
1.135 + }
1.136 +}
1.137 +
1.138 +/*
1.139 + *----------------------------------------------------------------------
1.140 + *
1.141 + * TclpOpenFile --
1.142 + *
1.143 + * Open a file for use in a pipeline.
1.144 + *
1.145 + * Results:
1.146 + * Returns a new TclFile handle or NULL on failure.
1.147 + *
1.148 + * Side effects:
1.149 + * May cause a file to be created on the file system.
1.150 + *
1.151 + *----------------------------------------------------------------------
1.152 + */
1.153 +
1.154 +TclFile
1.155 +TclpOpenFile(fname, mode)
1.156 + CONST char *fname; /* The name of the file to open. */
1.157 + int mode; /* In what mode to open the file? */
1.158 +{
1.159 + int fd;
1.160 + CONST char *native;
1.161 + Tcl_DString ds;
1.162 +
1.163 + native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
1.164 + fd = TclOSopen(native, mode, 0666); /* INTL: Native. */
1.165 + Tcl_DStringFree(&ds);
1.166 + if (fd != -1) {
1.167 + fcntl(fd, F_SETFD, FD_CLOEXEC);
1.168 +
1.169 + /*
1.170 + * If the file is being opened for writing, seek to the end
1.171 + * so we can append to any data already in the file.
1.172 + */
1.173 +
1.174 + if ((mode & O_WRONLY) && !(mode & O_APPEND)) {
1.175 + TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_END);
1.176 + }
1.177 +
1.178 + /*
1.179 + * Increment the fd so it can't be 0, which would conflict with
1.180 + * the NULL return for errors.
1.181 + */
1.182 +
1.183 + return MakeFile(fd);
1.184 + }
1.185 + return NULL;
1.186 +}
1.187 +
1.188 +/*
1.189 + *----------------------------------------------------------------------
1.190 + *
1.191 + * TclpCreateTempFile --
1.192 + *
1.193 + * This function creates a temporary file initialized with an
1.194 + * optional string, and returns a file handle with the file pointer
1.195 + * at the beginning of the file.
1.196 + *
1.197 + * Results:
1.198 + * A handle to a file.
1.199 + *
1.200 + * Side effects:
1.201 + * None.
1.202 + *
1.203 + *----------------------------------------------------------------------
1.204 + */
1.205 +
1.206 +TclFile
1.207 +TclpCreateTempFile(contents)
1.208 + CONST char *contents; /* String to write into temp file, or NULL. */
1.209 +{
1.210 + char fileName[L_tmpnam + 9];
1.211 + CONST char *native;
1.212 + Tcl_DString dstring;
1.213 + int fd;
1.214 +
1.215 + /*
1.216 + * We should also check against making more then TMP_MAX of these.
1.217 + */
1.218 +
1.219 + // Symbian doesn't have a default temp directory, so we use cwd (root of private data cage)
1.220 +#ifdef __SYMBIAN32__
1.221 + if (getcwd(fileName, L_tmpnam) == NULL)
1.222 + {
1.223 + return NULL;
1.224 + }
1.225 + /* TODO - the line bellow is a temporary patch. The defect number is: DEF116621. */
1.226 + fileName[0] = 'c';
1.227 +#else
1.228 + strcpy(fileName, P_tmpdir); /* INTL: Native. */
1.229 +#endif
1.230 + if (fileName[strlen(fileName) - 1] != '/') {
1.231 +#ifdef __SYMBIAN32__
1.232 + strcat(fileName, "\\");
1.233 +#else
1.234 + strcat(fileName, "/"); /* INTL: Native. */
1.235 +#endif
1.236 + }
1.237 + strcat(fileName, "tclXXXXXX");
1.238 + fd = mkstemp(fileName); /* INTL: Native. */
1.239 + if (fd == -1) {
1.240 + return NULL;
1.241 + }
1.242 + fcntl(fd, F_SETFD, FD_CLOEXEC);
1.243 +#ifdef __SYMBIAN32__
1.244 + strcpy(tmpFileName, fileName);
1.245 +#endif
1.246 + unlink(fileName); /* INTL: Native. */
1.247 +
1.248 + if (contents != NULL) {
1.249 + native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring);
1.250 + if (write(fd, native, strlen(native)) == -1) {
1.251 + close(fd);
1.252 + Tcl_DStringFree(&dstring);
1.253 + return NULL;
1.254 + }
1.255 + Tcl_DStringFree(&dstring);
1.256 + TclOSseek(fd, (Tcl_SeekOffset) 0, SEEK_SET);
1.257 + }
1.258 + return MakeFile(fd);
1.259 +}
1.260 +
1.261 +/*
1.262 + *----------------------------------------------------------------------
1.263 + *
1.264 + * TclpTempFileName --
1.265 + *
1.266 + * This function returns unique filename.
1.267 + *
1.268 + * Results:
1.269 + * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure.
1.270 + *
1.271 + * Side effects:
1.272 + * None.
1.273 + *
1.274 + *----------------------------------------------------------------------
1.275 + */
1.276 +
1.277 +Tcl_Obj*
1.278 +TclpTempFileName()
1.279 +{
1.280 + char fileName[L_tmpnam + 9];
1.281 + Tcl_Obj *result = NULL;
1.282 + int fd;
1.283 +
1.284 + /*
1.285 + * We should also check against making more then TMP_MAX of these.
1.286 + */
1.287 +
1.288 + // Symbian doesn't have a default temp directory, so we use cwd (root of private data cage)
1.289 +#ifdef __SYMBIAN32__
1.290 + if (getcwd(fileName, L_tmpnam) == NULL)
1.291 + {
1.292 + return NULL;
1.293 + }
1.294 + /* TODO - the line bellow is a temporary patch. The defect number is: DEF116621. */
1.295 + fileName[0] = 'c';
1.296 +#else
1.297 + strcpy(fileName, P_tmpdir); /* INTL: Native. */
1.298 +#endif
1.299 + if (fileName[strlen(fileName) - 1] != '/') {
1.300 +#ifdef __SYMBIAN32__
1.301 + strcat(fileName, "\\");
1.302 +#else
1.303 + strcat(fileName, "/"); /* INTL: Native. */
1.304 +#endif
1.305 + }
1.306 + strcat(fileName, "tclXXXXXX");
1.307 + fd = mkstemp(fileName); /* INTL: Native. */
1.308 + if (fd == -1) {
1.309 + return NULL;
1.310 + }
1.311 + fcntl(fd, F_SETFD, FD_CLOEXEC);
1.312 + unlink(fileName); /* INTL: Native. */
1.313 +
1.314 + result = TclpNativeToNormalized((ClientData) fileName);
1.315 + close (fd);
1.316 + return result;
1.317 +}
1.318 +
1.319 +/*
1.320 + *----------------------------------------------------------------------
1.321 + *
1.322 + * TclpCreatePipe --
1.323 + *
1.324 + * Creates a pipe - simply calls the pipe() function.
1.325 + *
1.326 + * Results:
1.327 + * Returns 1 on success, 0 on failure.
1.328 + *
1.329 + * Side effects:
1.330 + * Creates a pipe.
1.331 + *
1.332 + *----------------------------------------------------------------------
1.333 + */
1.334 +
1.335 +int
1.336 +TclpCreatePipe(readPipe, writePipe)
1.337 + TclFile *readPipe; /* Location to store file handle for
1.338 + * read side of pipe. */
1.339 + TclFile *writePipe; /* Location to store file handle for
1.340 + * write side of pipe. */
1.341 +{
1.342 + int pipeIds[2];
1.343 +
1.344 + if (pipe(pipeIds) != 0) {
1.345 + return 0;
1.346 + }
1.347 +
1.348 + fcntl(pipeIds[0], F_SETFD, FD_CLOEXEC);
1.349 + fcntl(pipeIds[1], F_SETFD, FD_CLOEXEC);
1.350 +
1.351 + *readPipe = MakeFile(pipeIds[0]);
1.352 + *writePipe = MakeFile(pipeIds[1]);
1.353 + return 1;
1.354 +}
1.355 +
1.356 +/*
1.357 + *----------------------------------------------------------------------
1.358 + *
1.359 + * TclpCloseFile --
1.360 + *
1.361 + * Implements a mechanism to close a UNIX file.
1.362 + *
1.363 + * Results:
1.364 + * Returns 0 on success, or -1 on error, setting errno.
1.365 + *
1.366 + * Side effects:
1.367 + * The file is closed.
1.368 + *
1.369 + *----------------------------------------------------------------------
1.370 + */
1.371 +
1.372 +int
1.373 +TclpCloseFile(file)
1.374 + TclFile file; /* The file to close. */
1.375 +{
1.376 + int fd = GetFd(file);
1.377 +
1.378 + /*
1.379 + * Refuse to close the fds for stdin, stdout and stderr.
1.380 + */
1.381 +
1.382 + if ((fd == 0) || (fd == 1) || (fd == 2)) {
1.383 + return 0;
1.384 + }
1.385 +
1.386 + Tcl_DeleteFileHandler(fd);
1.387 + return close(fd);
1.388 +}
1.389 +
1.390 +/*
1.391 + *---------------------------------------------------------------------------
1.392 + *
1.393 + * TclpCreateProcess --
1.394 + *
1.395 + * Create a child process that has the specified files as its
1.396 + * standard input, output, and error. The child process runs
1.397 + * asynchronously and runs with the same environment variables
1.398 + * as the creating process.
1.399 + *
1.400 + * The path is searched to find the specified executable.
1.401 + *
1.402 + * Results:
1.403 + * The return value is TCL_ERROR and an error message is left in
1.404 + * the interp's result if there was a problem creating the child
1.405 + * process. Otherwise, the return value is TCL_OK and *pidPtr is
1.406 + * filled with the process id of the child process.
1.407 + *
1.408 + * Side effects:
1.409 + * A process is created.
1.410 + *
1.411 + *---------------------------------------------------------------------------
1.412 + */
1.413 +
1.414 + /* ARGSUSED */
1.415 +int
1.416 +TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
1.417 + pidPtr)
1.418 + Tcl_Interp *interp; /* Interpreter in which to leave errors that
1.419 + * occurred when creating the child process.
1.420 + * Error messages from the child process
1.421 + * itself are sent to errorFile. */
1.422 + int argc; /* Number of arguments in following array. */
1.423 + CONST char **argv; /* Array of argument strings in UTF-8.
1.424 + * argv[0] contains the name of the executable
1.425 + * translated using Tcl_TranslateFileName
1.426 + * call). Additional arguments have not been
1.427 + * converted. */
1.428 + TclFile inputFile; /* If non-NULL, gives the file to use as
1.429 + * input for the child process. If inputFile
1.430 + * file is not readable or is NULL, the child
1.431 + * will receive no standard input. */
1.432 + TclFile outputFile; /* If non-NULL, gives the file that
1.433 + * receives output from the child process. If
1.434 + * outputFile file is not writeable or is
1.435 + * NULL, output from the child will be
1.436 + * discarded. */
1.437 + TclFile errorFile; /* If non-NULL, gives the file that
1.438 + * receives errors from the child process. If
1.439 + * errorFile file is not writeable or is NULL,
1.440 + * errors from the child will be discarded.
1.441 + * errorFile may be the same as outputFile. */
1.442 + Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr
1.443 + * is filled with the process id of the child
1.444 + * process. */
1.445 +{
1.446 + TclFile errPipeIn, errPipeOut;
1.447 + int count, status, fd;
1.448 + char errSpace[200 + TCL_INTEGER_SPACE];
1.449 + Tcl_DString *dsArray;
1.450 + char **newArgv = 0;
1.451 + int pid, i;
1.452 +#ifdef __SYMBIAN32__
1.453 + int fd1;
1.454 + int RetVal;
1.455 + char buf[256];
1.456 + int fifoResult;
1.457 + struct timeval tv;
1.458 + fd_set readfds;
1.459 +#endif
1.460 +
1.461 + errPipeIn = NULL;
1.462 + errPipeOut = NULL;
1.463 + pid = -1;
1.464 +
1.465 + /*
1.466 + * Create a pipe that the child can use to return error
1.467 + * information if anything goes wrong.
1.468 + */
1.469 +#ifdef __SYMBIAN32__
1.470 + // change the communication between parent and child process, it just report the failure of child process creation
1.471 +
1.472 + tmpnam(fifoFileName);
1.473 + fifoResult = mkfifo(fifoFileName,S_IXGRP);
1.474 + if(fifoResult == -1)
1.475 + {
1.476 + //fifo creation failure.
1.477 + fprintf(stderr,"\n*** failure mkfifo errno is %d***\n",errno);
1.478 + goto error;
1.479 + }
1.480 + else
1.481 + {
1.482 + int ReadFifoFd = open(fifoFileName,O_RDONLY | O_NONBLOCK);
1.483 +
1.484 + if(ReadFifoFd == -1)
1.485 + {
1.486 + //Failed to open the Fifo
1.487 + printf("\n*** failure Fifo Open ***\n");
1.488 + goto error;
1.489 + }
1.490 + else
1.491 + {
1.492 + errPipeIn = MakeFile(ReadFifoFd);
1.493 + }
1.494 + }
1.495 +
1.496 + //set the stdin,stdout,stderr and pipeid to the child process. the fds are passed to the posix_spawn() in argv
1.497 + argc = argc + ADDPARAMTOCHILD;
1.498 +
1.499 +#else
1.500 + if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
1.501 + Tcl_AppendResult(interp, "couldn't create pipe: ",
1.502 + Tcl_PosixError(interp), (char *) NULL);
1.503 + goto error;
1.504 + }
1.505 +#endif
1.506 +
1.507 + /*
1.508 + * We need to allocate and convert this before the fork
1.509 + * so it is properly deallocated later
1.510 + */
1.511 + dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
1.512 + newArgv = (char **) ckalloc((argc+1) * sizeof(char *));
1.513 + newArgv[argc] = NULL;
1.514 +#ifdef __SYMBIAN32__
1.515 + for (i = 0; i < (argc-ADDPARAMTOCHILD); i++) {
1.516 +#else
1.517 + for (i = 0; i < argc; i++) {
1.518 +#endif
1.519 + newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]);
1.520 + }
1.521 +
1.522 +#ifdef __SYMBIAN32__
1.523 + fprintf(stderr,"\r\n");
1.524 + //set the stdin,stdout,stderr to the child process. the fds pass to the posix_spawn() in argv
1.525 + for (i = argc-ADDPARAMTOCHILD; i < argc; i++)
1.526 + {
1.527 + if(i == (argc-ADDPARAMTOCHILD))
1.528 + {
1.529 + strcpy(buf,fifoFileName);
1.530 + fprintf(stderr,"fifoFileName is %s\r\n", fifoFileName);
1.531 + }
1.532 + else if(i == (argc-ADDPARAMTOCHILD+1))
1.533 + {
1.534 + if (inputFile)
1.535 + {
1.536 + strcpy(buf,inFileName);
1.537 + }
1.538 + else
1.539 + {
1.540 + strcpy(buf,"STD");
1.541 + }
1.542 + fprintf(stderr, "inFileName is %s\r\n", inFileName);
1.543 + }
1.544 + else if(i == (argc-ADDPARAMTOCHILD+2))
1.545 + {
1.546 + if (outputFile)
1.547 + {
1.548 + strcpy(buf,outFileName);
1.549 + }
1.550 + else
1.551 + {
1.552 + strcpy(buf,"STD");
1.553 + }
1.554 + fprintf(stderr, "outFileName is %s\r\n", outFileName);
1.555 + }
1.556 + else if(i == (argc-ADDPARAMTOCHILD+3))
1.557 + {
1.558 + if (errorFile)
1.559 + {
1.560 + strcpy(buf,errFileName);
1.561 + }
1.562 + else
1.563 + {
1.564 + strcpy(buf,"STD");
1.565 + }
1.566 + fprintf(stderr, "errFileName is %s\r\n", errFileName);
1.567 + }
1.568 +
1.569 + newArgv[i] = Tcl_UtfToExternalDString(NULL, buf, -1, &dsArray[i]);
1.570 + }
1.571 +#endif
1.572 +#ifdef USE_VFORK
1.573 + /*
1.574 + * After vfork(), do not call code in the child that changes global state,
1.575 + * because it is using the parent's memory space at that point and writes
1.576 + * might corrupt the parent: so ensure standard channels are initialized in
1.577 + * the parent, otherwise SetupStdFile() might initialize them in the child.
1.578 + */
1.579 + if (!inputFile) {
1.580 + Tcl_GetStdChannel(TCL_STDIN);
1.581 + }
1.582 + if (!outputFile) {
1.583 + Tcl_GetStdChannel(TCL_STDOUT);
1.584 + }
1.585 + if (!errorFile) {
1.586 + Tcl_GetStdChannel(TCL_STDERR);
1.587 + }
1.588 +#endif
1.589 + TclPrint1(" == TclpCreateProcess(), posix_spawn(), process %S\r\n", newArgv[0]);
1.590 +#ifdef __SYMBIAN32__
1.591 + // change fork() using posix_spawn()
1.592 + if (argc > 1)
1.593 + {
1.594 + RetVal= posix_spawn(&pid,newArgv[0],NULL,NULL,newArgv,NULL);
1.595 + }
1.596 + else
1.597 + {
1.598 + RetVal= posix_spawn(&pid,newArgv[0],NULL,NULL,NULL,NULL);
1.599 + }
1.600 + if (RetVal != 0)
1.601 + {
1.602 + pid = -1; //if error, the value of pid is unspecified. ensure we still report the error.
1.603 + }
1.604 +#else
1.605 + pid = fork();
1.606 + if (pid == 0) {
1.607 + int joinThisError = errorFile && (errorFile == outputFile);
1.608 +
1.609 + fd = GetFd(errPipeOut);
1.610 +
1.611 + /*
1.612 + * Set up stdio file handles for the child process.
1.613 + */
1.614 +
1.615 + if (!SetupStdFile(inputFile, TCL_STDIN)
1.616 + || !SetupStdFile(outputFile, TCL_STDOUT)
1.617 + || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
1.618 + || (joinThisError &&
1.619 + ((dup2(1,2) == -1) ||
1.620 + (fcntl(2, F_SETFD, 0) != 0)))) {
1.621 + sprintf(errSpace, "forked process couldn't set up input/output, error: %d\r\n", errno);
1.622 + write(fd, errSpace, (size_t) strlen(errSpace));
1.623 + _exit(1);
1.624 + }
1.625 +
1.626 + /*
1.627 + * Close the input side of the error pipe.
1.628 + */
1.629 +
1.630 + RestoreSignals();
1.631 + execvp(newArgv[0], newArgv); /* INTL: Native. */
1.632 + sprintf(errSpace, "couldn't execute \"%.150s\", error: %d\r\n", argv[0], errno);
1.633 + write(fd, errSpace, (size_t) strlen(errSpace));
1.634 + _exit(1);
1.635 + }
1.636 +#endif
1.637 + TclPrint2(" == TclpCreateProcess(), posix_spawn(), process %S, pid %d\r\n", newArgv[0], (int)pid);
1.638 +
1.639 + //
1.640 + // Free the mem we used for the fork
1.641 + //
1.642 + for (i = 0; i < argc; i++) {
1.643 + Tcl_DStringFree(&dsArray[i]);
1.644 + }
1.645 + ckfree((char *) dsArray);
1.646 + ckfree((char *) newArgv);
1.647 +
1.648 + if (pid == -1) {
1.649 +#ifdef __SYMBIAN32__
1.650 + Tcl_AppendResult(interp, "couldn't posix_spawn child process: ",
1.651 +#else
1.652 + Tcl_AppendResult(interp, "couldn't fork child process: ",
1.653 +#endif
1.654 + Tcl_PosixError(interp), (char *) NULL);
1.655 + goto error;
1.656 + }
1.657 +
1.658 + /*
1.659 + * Read back from the error pipe to see if the child started
1.660 + * up OK. The info in the pipe (if any) consists of a decimal
1.661 + * errno value followed by an error message.
1.662 + */
1.663 + //*
1.664 +#ifdef __SYMBIAN32__
1.665 + TclpCloseFile(errPipeOut);
1.666 + errPipeOut = NULL;
1.667 +#endif
1.668 + fd = GetFd(errPipeIn);
1.669 +#ifdef __SYMBIAN32__
1.670 + TclPrint3(" == TclpCreateProcess(), select()\r\n");
1.671 + tv.tv_sec = 3;
1.672 + tv.tv_usec = 0;
1.673 +
1.674 + FD_ZERO(&readfds);
1.675 + FD_SET(fd, &readfds);
1.676 + // Use select to wait for child process
1.677 + i = select(fd+1, &readfds, NULL, NULL,&tv);
1.678 + if ( i != -1 && FD_ISSET(fd, &readfds))
1.679 + {
1.680 + count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
1.681 + if (count > 0) {
1.682 + char *end;
1.683 + errSpace[count] = 0;
1.684 + errno = strtol(errSpace, &end, 10);
1.685 + if (errno != 0)
1.686 + {
1.687 + Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
1.688 + (char *) NULL);
1.689 + goto error;
1.690 + }
1.691 + }
1.692 + }
1.693 + else
1.694 + {
1.695 + // Process not started properly
1.696 + Tcl_AppendResult(interp, "couldn't read error info from child process: ",
1.697 + Tcl_PosixError(interp), (char *) NULL);
1.698 + goto error;
1.699 + }
1.700 +#else
1.701 + count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));
1.702 + if (count > 0) {
1.703 + char *end;
1.704 + errSpace[count] = 0;
1.705 + errno = strtol(errSpace, &end, 10);
1.706 + Tcl_AppendResult(interp, end, Tcl_PosixError(interp),
1.707 + (char *) NULL);
1.708 + goto error;
1.709 + }
1.710 +#endif
1.711 + TclpCloseFile(errPipeIn);
1.712 +#ifdef __SYMBIAN32__
1.713 + unlink(fifoFileName);
1.714 +#endif
1.715 + *pidPtr = (Tcl_Pid) pid;
1.716 + TclPrint3(" == TclpCreateProcess(), TCL_OK\r\n");
1.717 + return TCL_OK;
1.718 +
1.719 + error:
1.720 + TclPrint2(" == TclpCreateProcess(), TCL_ERROR,%S errno %d\r\n", "", errno);
1.721 + if (pid != -1) {
1.722 + /*
1.723 + * Reap the child process now if an error occurred during its
1.724 + * startup. We don't call this with WNOHANG because that can lead to
1.725 + * defunct processes on an MP system. We shouldn't have to worry
1.726 + * about hanging here, since this is the error case. [Bug: 6148]
1.727 + */
1.728 +
1.729 + Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
1.730 + }
1.731 +
1.732 + if (errPipeIn) {
1.733 + TclpCloseFile(errPipeIn);
1.734 + }
1.735 + if (errPipeOut) {
1.736 + TclpCloseFile(errPipeOut);
1.737 + }
1.738 +#ifdef __SYMBIAN32__
1.739 + unlink(fifoFileName);
1.740 +#endif
1.741 +
1.742 + return TCL_ERROR;
1.743 +}
1.744 +
1.745 +/*
1.746 + *----------------------------------------------------------------------
1.747 + *
1.748 + * RestoreSignals --
1.749 + *
1.750 + * This procedure is invoked in a forked child process just before
1.751 + * exec-ing a new program to restore all signals to their default
1.752 + * settings.
1.753 + *
1.754 + * Results:
1.755 + * None.
1.756 + *
1.757 + * Side effects:
1.758 + * Signal settings get changed.
1.759 + *
1.760 + *----------------------------------------------------------------------
1.761 + */
1.762 +
1.763 +static void
1.764 +RestoreSignals()
1.765 +{
1.766 +// Symbian & PIPS don't support signals.
1.767 +#ifndef __SYMBIAN32__
1.768 +#ifdef SIGABRT
1.769 + signal(SIGABRT, SIG_DFL);
1.770 +#endif
1.771 +#ifdef SIGALRM
1.772 + signal(SIGALRM, SIG_DFL);
1.773 +#endif
1.774 +#ifdef SIGFPE
1.775 + signal(SIGFPE, SIG_DFL);
1.776 +#endif
1.777 +#ifdef SIGHUP
1.778 + signal(SIGHUP, SIG_DFL);
1.779 +#endif
1.780 +#ifdef SIGILL
1.781 + signal(SIGILL, SIG_DFL);
1.782 +#endif
1.783 +#ifdef SIGINT
1.784 + signal(SIGINT, SIG_DFL);
1.785 +#endif
1.786 +#ifdef SIGPIPE
1.787 + signal(SIGPIPE, SIG_DFL);
1.788 +#endif
1.789 +#ifdef SIGQUIT
1.790 + signal(SIGQUIT, SIG_DFL);
1.791 +#endif
1.792 +#ifdef SIGSEGV
1.793 + signal(SIGSEGV, SIG_DFL);
1.794 +#endif
1.795 +#ifdef SIGTERM
1.796 + signal(SIGTERM, SIG_DFL);
1.797 +#endif
1.798 +#ifdef SIGUSR1
1.799 + signal(SIGUSR1, SIG_DFL);
1.800 +#endif
1.801 +#ifdef SIGUSR2
1.802 + signal(SIGUSR2, SIG_DFL);
1.803 +#endif
1.804 +#ifdef SIGCHLD
1.805 + signal(SIGCHLD, SIG_DFL);
1.806 +#endif
1.807 +#ifdef SIGCONT
1.808 + signal(SIGCONT, SIG_DFL);
1.809 +#endif
1.810 +#ifdef SIGTSTP
1.811 + signal(SIGTSTP, SIG_DFL);
1.812 +#endif
1.813 +#ifdef SIGTTIN
1.814 + signal(SIGTTIN, SIG_DFL);
1.815 +#endif
1.816 +#ifdef SIGTTOU
1.817 + signal(SIGTTOU, SIG_DFL);
1.818 +#endif
1.819 +#endif
1.820 +}
1.821 +
1.822 +/*
1.823 + *----------------------------------------------------------------------
1.824 + *
1.825 + * SetupStdFile --
1.826 + *
1.827 + * Set up stdio file handles for the child process, using the
1.828 + * current standard channels if no other files are specified.
1.829 + * If no standard channel is defined, or if no file is associated
1.830 + * with the channel, then the corresponding standard fd is closed.
1.831 + *
1.832 + * Results:
1.833 + * Returns 1 on success, or 0 on failure.
1.834 + *
1.835 + * Side effects:
1.836 + * Replaces stdio fds.
1.837 + *
1.838 + *----------------------------------------------------------------------
1.839 + */
1.840 +#ifdef __SYMBIAN32__
1.841 +int
1.842 +#else
1.843 +static int
1.844 +#endif
1.845 +SetupStdFile(file, type)
1.846 + TclFile file; /* File to dup, or NULL. */
1.847 + int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
1.848 +{
1.849 + Tcl_Channel channel;
1.850 + int fd;
1.851 + int targetFd = 0; /* Initializations here needed only to */
1.852 + int direction = 0; /* prevent warnings about using uninitialized
1.853 + * variables. */
1.854 +
1.855 + switch (type) {
1.856 + case TCL_STDIN:
1.857 + targetFd = 0;
1.858 + direction = TCL_READABLE;
1.859 + break;
1.860 + case TCL_STDOUT:
1.861 + targetFd = 1;
1.862 + direction = TCL_WRITABLE;
1.863 + break;
1.864 + case TCL_STDERR:
1.865 + targetFd = 2;
1.866 + direction = TCL_WRITABLE;
1.867 + break;
1.868 + }
1.869 +
1.870 + if (!file) {
1.871 + channel = Tcl_GetStdChannel(type);
1.872 + if (channel) {
1.873 + file = TclpMakeFile(channel, direction);
1.874 + }
1.875 + }
1.876 + if (file) {
1.877 + fd = GetFd(file);
1.878 + if (fd != targetFd) {
1.879 + if (dup2(fd, targetFd) == -1) {
1.880 + return 0;
1.881 + }
1.882 +
1.883 + /*
1.884 + * Must clear the close-on-exec flag for the target FD, since
1.885 + * some systems (e.g. Ultrix) do not clear the CLOEXEC flag on
1.886 + * the target FD.
1.887 + */
1.888 +
1.889 + fcntl(targetFd, F_SETFD, 0);
1.890 + } else {
1.891 + /*
1.892 + * Since we aren't dup'ing the file, we need to explicitly clear
1.893 + * the close-on-exec flag.
1.894 + */
1.895 +
1.896 + fcntl(fd, F_SETFD, 0);
1.897 + }
1.898 + } else {
1.899 + close(targetFd);
1.900 + }
1.901 + return 1;
1.902 +}
1.903 +
1.904 +/*
1.905 + *----------------------------------------------------------------------
1.906 + *
1.907 + * TclpCreateCommandChannel --
1.908 + *
1.909 + * This function is called by the generic IO level to perform
1.910 + * the platform specific channel initialization for a command
1.911 + * channel.
1.912 + *
1.913 + * Results:
1.914 + * Returns a new channel or NULL on failure.
1.915 + *
1.916 + * Side effects:
1.917 + * Allocates a new channel.
1.918 + *
1.919 + *----------------------------------------------------------------------
1.920 + */
1.921 +
1.922 +Tcl_Channel
1.923 +TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
1.924 + TclFile readFile; /* If non-null, gives the file for reading. */
1.925 + TclFile writeFile; /* If non-null, gives the file for writing. */
1.926 + TclFile errorFile; /* If non-null, gives the file where errors
1.927 + * can be read. */
1.928 + int numPids; /* The number of pids in the pid array. */
1.929 + Tcl_Pid *pidPtr; /* An array of process identifiers.
1.930 + * Allocated by the caller, freed when
1.931 + * the channel is closed or the processes
1.932 + * are detached (in a background exec). */
1.933 +{
1.934 + char channelName[16 + TCL_INTEGER_SPACE];
1.935 + int channelId;
1.936 + PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState));
1.937 + int mode;
1.938 +
1.939 + statePtr->inFile = readFile;
1.940 + statePtr->outFile = writeFile;
1.941 + statePtr->errorFile = errorFile;
1.942 + statePtr->numPids = numPids;
1.943 + statePtr->pidPtr = pidPtr;
1.944 + statePtr->isNonBlocking = 0;
1.945 +
1.946 + mode = 0;
1.947 + if (readFile) {
1.948 + mode |= TCL_READABLE;
1.949 + }
1.950 + if (writeFile) {
1.951 + mode |= TCL_WRITABLE;
1.952 + }
1.953 +
1.954 + /*
1.955 + * Use one of the fds associated with the channel as the
1.956 + * channel id.
1.957 + */
1.958 +
1.959 + if (readFile) {
1.960 + channelId = GetFd(readFile);
1.961 + } else if (writeFile) {
1.962 + channelId = GetFd(writeFile);
1.963 + } else if (errorFile) {
1.964 + channelId = GetFd(errorFile);
1.965 + } else {
1.966 + channelId = 0;
1.967 + }
1.968 +
1.969 + /*
1.970 + * For backward compatibility with previous versions of Tcl, we
1.971 + * use "file%d" as the base name for pipes even though it would
1.972 + * be more natural to use "pipe%d".
1.973 + */
1.974 +
1.975 + sprintf(channelName, "file%d", channelId);
1.976 + statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
1.977 + (ClientData) statePtr, mode);
1.978 + return statePtr->channel;
1.979 +}
1.980 +
1.981 +/*
1.982 + *----------------------------------------------------------------------
1.983 + *
1.984 + * TclGetAndDetachPids --
1.985 + *
1.986 + * This procedure is invoked in the generic implementation of a
1.987 + * background "exec" (An exec when invoked with a terminating "&")
1.988 + * to store a list of the PIDs for processes in a command pipeline
1.989 + * in the interp's result and to detach the processes.
1.990 + *
1.991 + * Results:
1.992 + * None.
1.993 + *
1.994 + * Side effects:
1.995 + * Modifies the interp's result. Detaches processes.
1.996 + *
1.997 + *----------------------------------------------------------------------
1.998 + */
1.999 +
1.1000 +void
1.1001 +TclGetAndDetachPids(interp, chan)
1.1002 + Tcl_Interp *interp;
1.1003 + Tcl_Channel chan;
1.1004 +{
1.1005 + PipeState *pipePtr;
1.1006 + Tcl_ChannelType *chanTypePtr;
1.1007 + int i;
1.1008 + char buf[TCL_INTEGER_SPACE];
1.1009 +
1.1010 + /*
1.1011 + * Punt if the channel is not a command channel.
1.1012 + */
1.1013 +
1.1014 + chanTypePtr = Tcl_GetChannelType(chan);
1.1015 + if (chanTypePtr != &pipeChannelType) {
1.1016 + return;
1.1017 + }
1.1018 +
1.1019 + pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
1.1020 + for (i = 0; i < pipePtr->numPids; i++) {
1.1021 + TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i]));
1.1022 + Tcl_AppendElement(interp, buf);
1.1023 + Tcl_DetachPids(1, &(pipePtr->pidPtr[i]));
1.1024 + }
1.1025 + if (pipePtr->numPids > 0) {
1.1026 + ckfree((char *) pipePtr->pidPtr);
1.1027 + pipePtr->numPids = 0;
1.1028 + }
1.1029 +}
1.1030 +
1.1031 +/*
1.1032 + *----------------------------------------------------------------------
1.1033 + *
1.1034 + * PipeBlockModeProc --
1.1035 + *
1.1036 + * Helper procedure to set blocking and nonblocking modes on a
1.1037 + * pipe based channel. Invoked by generic IO level code.
1.1038 + *
1.1039 + * Results:
1.1040 + * 0 if successful, errno when failed.
1.1041 + *
1.1042 + * Side effects:
1.1043 + * Sets the device into blocking or non-blocking mode.
1.1044 + *
1.1045 + *----------------------------------------------------------------------
1.1046 + */
1.1047 +
1.1048 + /* ARGSUSED */
1.1049 +static int
1.1050 +PipeBlockModeProc(instanceData, mode)
1.1051 + ClientData instanceData; /* Pipe state. */
1.1052 + int mode; /* The mode to set. Can be one of
1.1053 + * TCL_MODE_BLOCKING or
1.1054 + * TCL_MODE_NONBLOCKING. */
1.1055 +{
1.1056 + PipeState *psPtr = (PipeState *) instanceData;
1.1057 + int curStatus;
1.1058 + int fd;
1.1059 +
1.1060 +#ifndef USE_FIONBIO
1.1061 + if (psPtr->inFile) {
1.1062 + fd = GetFd(psPtr->inFile);
1.1063 + curStatus = fcntl(fd, F_GETFL);
1.1064 + if (mode == TCL_MODE_BLOCKING) {
1.1065 + curStatus &= (~(O_NONBLOCK));
1.1066 + } else {
1.1067 + curStatus |= O_NONBLOCK;
1.1068 + }
1.1069 + if (fcntl(fd, F_SETFL, curStatus) < 0) {
1.1070 + return errno;
1.1071 + }
1.1072 + }
1.1073 + if (psPtr->outFile) {
1.1074 + fd = GetFd(psPtr->outFile);
1.1075 + curStatus = fcntl(fd, F_GETFL);
1.1076 + if (mode == TCL_MODE_BLOCKING) {
1.1077 + curStatus &= (~(O_NONBLOCK));
1.1078 + } else {
1.1079 + curStatus |= O_NONBLOCK;
1.1080 + }
1.1081 + if (fcntl(fd, F_SETFL, curStatus) < 0) {
1.1082 + return errno;
1.1083 + }
1.1084 + }
1.1085 +#endif /* !FIONBIO */
1.1086 +
1.1087 +#ifdef USE_FIONBIO
1.1088 + if (psPtr->inFile) {
1.1089 + fd = GetFd(psPtr->inFile);
1.1090 + if (mode == TCL_MODE_BLOCKING) {
1.1091 + curStatus = 0;
1.1092 + } else {
1.1093 + curStatus = 1;
1.1094 + }
1.1095 + if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
1.1096 + return errno;
1.1097 + }
1.1098 + }
1.1099 + if (psPtr->outFile != NULL) {
1.1100 + fd = GetFd(psPtr->outFile);
1.1101 + if (mode == TCL_MODE_BLOCKING) {
1.1102 + curStatus = 0;
1.1103 + } else {
1.1104 + curStatus = 1;
1.1105 + }
1.1106 + if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
1.1107 + return errno;
1.1108 + }
1.1109 + }
1.1110 +#endif /* USE_FIONBIO */
1.1111 +
1.1112 + psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
1.1113 +
1.1114 + return 0;
1.1115 +}
1.1116 +
1.1117 +/*
1.1118 + *----------------------------------------------------------------------
1.1119 + *
1.1120 + * PipeCloseProc --
1.1121 + *
1.1122 + * This procedure is invoked by the generic IO level to perform
1.1123 + * channel-type-specific cleanup when a command pipeline channel
1.1124 + * is closed.
1.1125 + *
1.1126 + * Results:
1.1127 + * 0 on success, errno otherwise.
1.1128 + *
1.1129 + * Side effects:
1.1130 + * Closes the command pipeline channel.
1.1131 + *
1.1132 + *----------------------------------------------------------------------
1.1133 + */
1.1134 +
1.1135 + /* ARGSUSED */
1.1136 +static int
1.1137 +PipeCloseProc(instanceData, interp)
1.1138 + ClientData instanceData; /* The pipe to close. */
1.1139 + Tcl_Interp *interp; /* For error reporting. */
1.1140 +{
1.1141 + PipeState *pipePtr;
1.1142 + Tcl_Channel errChan;
1.1143 + int errorCode, result;
1.1144 +
1.1145 + errorCode = 0;
1.1146 + result = 0;
1.1147 + pipePtr = (PipeState *) instanceData;
1.1148 + if (pipePtr->inFile) {
1.1149 + if (TclpCloseFile(pipePtr->inFile) < 0) {
1.1150 + errorCode = errno;
1.1151 + }
1.1152 + }
1.1153 + if (pipePtr->outFile) {
1.1154 + if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {
1.1155 + errorCode = errno;
1.1156 + }
1.1157 + }
1.1158 +
1.1159 + if (pipePtr->isNonBlocking || TclInExit()) {
1.1160 +
1.1161 + /*
1.1162 + * If the channel is non-blocking or Tcl is being cleaned up, just
1.1163 + * detach the children PIDs, reap them (important if we are in a
1.1164 + * dynamic load module), and discard the errorFile.
1.1165 + */
1.1166 +
1.1167 + Tcl_DetachPids(pipePtr->numPids, pipePtr->pidPtr);
1.1168 + Tcl_ReapDetachedProcs();
1.1169 +
1.1170 + if (pipePtr->errorFile) {
1.1171 + TclpCloseFile(pipePtr->errorFile);
1.1172 + }
1.1173 + } else {
1.1174 +
1.1175 + /*
1.1176 + * Wrap the error file into a channel and give it to the cleanup
1.1177 + * routine.
1.1178 + */
1.1179 +
1.1180 + if (pipePtr->errorFile) {
1.1181 + errChan = Tcl_MakeFileChannel(
1.1182 + (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
1.1183 + } else {
1.1184 + errChan = NULL;
1.1185 + }
1.1186 + result = TclCleanupChildren(interp, pipePtr->numPids, pipePtr->pidPtr,
1.1187 + errChan);
1.1188 + }
1.1189 +
1.1190 + if (pipePtr->numPids != 0) {
1.1191 + ckfree((char *) pipePtr->pidPtr);
1.1192 + }
1.1193 + ckfree((char *) pipePtr);
1.1194 + if (errorCode == 0) {
1.1195 + return result;
1.1196 + }
1.1197 + return errorCode;
1.1198 +}
1.1199 +
1.1200 +/*
1.1201 + *----------------------------------------------------------------------
1.1202 + *
1.1203 + * PipeInputProc --
1.1204 + *
1.1205 + * This procedure is invoked from the generic IO level to read
1.1206 + * input from a command pipeline based channel.
1.1207 + *
1.1208 + * Results:
1.1209 + * The number of bytes read is returned or -1 on error. An output
1.1210 + * argument contains a POSIX error code if an error occurs, or zero.
1.1211 + *
1.1212 + * Side effects:
1.1213 + * Reads input from the input device of the channel.
1.1214 + *
1.1215 + *----------------------------------------------------------------------
1.1216 + */
1.1217 +
1.1218 +static int
1.1219 +PipeInputProc(instanceData, buf, toRead, errorCodePtr)
1.1220 + ClientData instanceData; /* Pipe state. */
1.1221 + char *buf; /* Where to store data read. */
1.1222 + int toRead; /* How much space is available
1.1223 + * in the buffer? */
1.1224 + int *errorCodePtr; /* Where to store error code. */
1.1225 +{
1.1226 + PipeState *psPtr = (PipeState *) instanceData;
1.1227 + int bytesRead; /* How many bytes were actually
1.1228 + * read from the input device? */
1.1229 +
1.1230 + *errorCodePtr = 0;
1.1231 +
1.1232 + /*
1.1233 + * Assume there is always enough input available. This will block
1.1234 + * appropriately, and read will unblock as soon as a short read is
1.1235 + * possible, if the channel is in blocking mode. If the channel is
1.1236 + * nonblocking, the read will never block.
1.1237 + * Some OSes can throw an interrupt error, for which we should
1.1238 + * immediately retry. [Bug #415131]
1.1239 + */
1.1240 +
1.1241 + do {
1.1242 + bytesRead = read (GetFd(psPtr->inFile), buf, (size_t) toRead);
1.1243 + } while ((bytesRead < 0) && (errno == EINTR));
1.1244 +
1.1245 + if (bytesRead < 0) {
1.1246 + *errorCodePtr = errno;
1.1247 + return -1;
1.1248 + } else {
1.1249 + return bytesRead;
1.1250 + }
1.1251 +}
1.1252 +
1.1253 +/*
1.1254 + *----------------------------------------------------------------------
1.1255 + *
1.1256 + * PipeOutputProc--
1.1257 + *
1.1258 + * This procedure is invoked from the generic IO level to write
1.1259 + * output to a command pipeline based channel.
1.1260 + *
1.1261 + * Results:
1.1262 + * The number of bytes written is returned or -1 on error. An
1.1263 + * output argument contains a POSIX error code if an error occurred,
1.1264 + * or zero.
1.1265 + *
1.1266 + * Side effects:
1.1267 + * Writes output on the output device of the channel.
1.1268 + *
1.1269 + *----------------------------------------------------------------------
1.1270 + */
1.1271 +
1.1272 +static int
1.1273 +PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
1.1274 + ClientData instanceData; /* Pipe state. */
1.1275 + CONST char *buf; /* The data buffer. */
1.1276 + int toWrite; /* How many bytes to write? */
1.1277 + int *errorCodePtr; /* Where to store error code. */
1.1278 +{
1.1279 + PipeState *psPtr = (PipeState *) instanceData;
1.1280 + int written;
1.1281 +
1.1282 + *errorCodePtr = 0;
1.1283 +
1.1284 + /*
1.1285 + * Some OSes can throw an interrupt error, for which we should
1.1286 + * immediately retry. [Bug #415131]
1.1287 + */
1.1288 +
1.1289 + do {
1.1290 + written = write(GetFd(psPtr->outFile), buf, (size_t) toWrite);
1.1291 + } while ((written < 0) && (errno == EINTR));
1.1292 +
1.1293 + if (written < 0) {
1.1294 + *errorCodePtr = errno;
1.1295 + return -1;
1.1296 + } else {
1.1297 + return written;
1.1298 + }
1.1299 +}
1.1300 +
1.1301 +/*
1.1302 + *----------------------------------------------------------------------
1.1303 + *
1.1304 + * PipeWatchProc --
1.1305 + *
1.1306 + * Initialize the notifier to watch the fds from this channel.
1.1307 + *
1.1308 + * Results:
1.1309 + * None.
1.1310 + *
1.1311 + * Side effects:
1.1312 + * Sets up the notifier so that a future event on the channel will
1.1313 + * be seen by Tcl.
1.1314 + *
1.1315 + *----------------------------------------------------------------------
1.1316 + */
1.1317 +
1.1318 +static void
1.1319 +PipeWatchProc(instanceData, mask)
1.1320 + ClientData instanceData; /* The pipe state. */
1.1321 + int mask; /* Events of interest; an OR-ed
1.1322 + * combination of TCL_READABLE,
1.1323 + * TCL_WRITABEL and TCL_EXCEPTION. */
1.1324 +{
1.1325 + PipeState *psPtr = (PipeState *) instanceData;
1.1326 + int newmask;
1.1327 +
1.1328 + if (psPtr->inFile) {
1.1329 + newmask = mask & (TCL_READABLE | TCL_EXCEPTION);
1.1330 + if (newmask) {
1.1331 + Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask,
1.1332 + (Tcl_FileProc *) Tcl_NotifyChannel,
1.1333 + (ClientData) psPtr->channel);
1.1334 + } else {
1.1335 + Tcl_DeleteFileHandler(GetFd(psPtr->inFile));
1.1336 + }
1.1337 + }
1.1338 + if (psPtr->outFile) {
1.1339 + newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);
1.1340 + if (newmask) {
1.1341 + Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask,
1.1342 + (Tcl_FileProc *) Tcl_NotifyChannel,
1.1343 + (ClientData) psPtr->channel);
1.1344 + } else {
1.1345 + Tcl_DeleteFileHandler(GetFd(psPtr->outFile));
1.1346 + }
1.1347 + }
1.1348 +}
1.1349 +
1.1350 +/*
1.1351 + *----------------------------------------------------------------------
1.1352 + *
1.1353 + * PipeGetHandleProc --
1.1354 + *
1.1355 + * Called from Tcl_GetChannelHandle to retrieve OS handles from
1.1356 + * inside a command pipeline based channel.
1.1357 + *
1.1358 + * Results:
1.1359 + * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if
1.1360 + * there is no handle for the specified direction.
1.1361 + *
1.1362 + * Side effects:
1.1363 + * None.
1.1364 + *
1.1365 + *----------------------------------------------------------------------
1.1366 + */
1.1367 +
1.1368 +static int
1.1369 +PipeGetHandleProc(instanceData, direction, handlePtr)
1.1370 + ClientData instanceData; /* The pipe state. */
1.1371 + int direction; /* TCL_READABLE or TCL_WRITABLE */
1.1372 + ClientData *handlePtr; /* Where to store the handle. */
1.1373 +{
1.1374 + PipeState *psPtr = (PipeState *) instanceData;
1.1375 +
1.1376 + if (direction == TCL_READABLE && psPtr->inFile) {
1.1377 + *handlePtr = (ClientData) GetFd(psPtr->inFile);
1.1378 + return TCL_OK;
1.1379 + }
1.1380 + if (direction == TCL_WRITABLE && psPtr->outFile) {
1.1381 + *handlePtr = (ClientData) GetFd(psPtr->outFile);
1.1382 + return TCL_OK;
1.1383 + }
1.1384 + return TCL_ERROR;
1.1385 +}
1.1386 +
1.1387 +/*
1.1388 + *----------------------------------------------------------------------
1.1389 + *
1.1390 + * Tcl_WaitPid --
1.1391 + *
1.1392 + * Implements the waitpid system call on Unix systems.
1.1393 + *
1.1394 + * Results:
1.1395 + * Result of calling waitpid.
1.1396 + *
1.1397 + * Side effects:
1.1398 + * Waits for a process to terminate.
1.1399 + *
1.1400 + *----------------------------------------------------------------------
1.1401 + */
1.1402 +
1.1403 +EXPORT_C Tcl_Pid
1.1404 +Tcl_WaitPid(pid, statPtr, options)
1.1405 + Tcl_Pid pid;
1.1406 + int *statPtr;
1.1407 + int options;
1.1408 +{
1.1409 + int result;
1.1410 + pid_t real_pid;
1.1411 +
1.1412 + real_pid = (pid_t) pid;
1.1413 + while (1) {
1.1414 + result = (int) waitpid(real_pid, statPtr, options);
1.1415 + if ((result != -1) || (errno != EINTR)) {
1.1416 + return (Tcl_Pid) result;
1.1417 + }
1.1418 + }
1.1419 +}
1.1420 +
1.1421 +/*
1.1422 + *----------------------------------------------------------------------
1.1423 + *
1.1424 + * Tcl_PidObjCmd --
1.1425 + *
1.1426 + * This procedure is invoked to process the "pid" Tcl command.
1.1427 + * See the user documentation for details on what it does.
1.1428 + *
1.1429 + * Results:
1.1430 + * A standard Tcl result.
1.1431 + *
1.1432 + * Side effects:
1.1433 + * See the user documentation.
1.1434 + *
1.1435 + *----------------------------------------------------------------------
1.1436 + */
1.1437 +
1.1438 + /* ARGSUSED */
1.1439 +int
1.1440 +Tcl_PidObjCmd(dummy, interp, objc, objv)
1.1441 + ClientData dummy; /* Not used. */
1.1442 + Tcl_Interp *interp; /* Current interpreter. */
1.1443 + int objc; /* Number of arguments. */
1.1444 + Tcl_Obj *CONST *objv; /* Argument strings. */
1.1445 +{
1.1446 + Tcl_Channel chan;
1.1447 + Tcl_ChannelType *chanTypePtr;
1.1448 + PipeState *pipePtr;
1.1449 + int i;
1.1450 + Tcl_Obj *resultPtr, *longObjPtr;
1.1451 +
1.1452 + if (objc > 2) {
1.1453 + Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
1.1454 + return TCL_ERROR;
1.1455 + }
1.1456 + if (objc == 1) {
1.1457 + Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) getpid());
1.1458 + } else {
1.1459 + chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
1.1460 + if (chan == (Tcl_Channel) NULL) {
1.1461 + return TCL_ERROR;
1.1462 + }
1.1463 + chanTypePtr = Tcl_GetChannelType(chan);
1.1464 + if (chanTypePtr != &pipeChannelType) {
1.1465 + return TCL_OK;
1.1466 + }
1.1467 + pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan);
1.1468 + resultPtr = Tcl_GetObjResult(interp);
1.1469 + for (i = 0; i < pipePtr->numPids; i++) {
1.1470 + longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i]));
1.1471 + Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr);
1.1472 + }
1.1473 + }
1.1474 + return TCL_OK;
1.1475 +}
1.1476 +
1.1477 +/*
1.1478 + *----------------------------------------------------------------------
1.1479 + *
1.1480 + * TclpFinalizePipes --
1.1481 + *
1.1482 + * Cleans up the pipe subsystem from Tcl_FinalizeThread
1.1483 + *
1.1484 + * Results:
1.1485 + * None.
1.1486 + *
1.1487 + * This procedure carries out no operation on Unix.
1.1488 + *
1.1489 + *----------------------------------------------------------------------
1.1490 + */
1.1491 +
1.1492 +void
1.1493 +TclpFinalizePipes()
1.1494 +{
1.1495 +}
1.1496 +