os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclUnixPipe.c
changeset 0 bde4ae8d615e
     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 +