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