diff options
Diffstat (limited to 'unix/tclUnixPipe.c')
| -rw-r--r-- | unix/tclUnixPipe.c | 281 | 
1 files changed, 152 insertions, 129 deletions
| diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index 0d92556..9c21b28 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -9,8 +9,6 @@   *   * See the file "license.terms" for information on usage and redistribution of   * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclUnixPipe.c,v 1.48 2009/01/09 11:21:46 dkf Exp $   */  #include "tclInt.h" @@ -25,8 +23,8 @@   * the same as NULL.   */ -#define MakeFile(fd)	((TclFile)INT2PTR(((int)(fd))+1)) -#define GetFd(file)	(PTR2INT(file)-1) +#define MakeFile(fd)	((TclFile) INT2PTR(((int) (fd)) + 1)) +#define GetFd(file)	(PTR2INT(file) - 1)  /*   * This structure describes per-instance state of a pipe based channel. @@ -53,8 +51,6 @@ typedef struct PipeState {  static int		PipeBlockModeProc(ClientData instanceData, int mode);  static int		PipeClose2Proc(ClientData instanceData,  			    Tcl_Interp *interp, int flags); -/* static int		PipeCloseProc(ClientData instanceData, -   Tcl_Interp *interp); */  static int		PipeGetHandleProc(ClientData instanceData,  			    int direction, ClientData *handlePtr);  static int		PipeInputProc(ClientData instanceData, char *buf, @@ -70,7 +66,7 @@ static int		SetupStdFile(TclFile file, int type);   * I/O:   */ -static Tcl_ChannelType pipeChannelType = { +static const Tcl_ChannelType pipeChannelType = {      "pipe",			/* Type name. */      TCL_CHANNEL_VERSION_5,	/* v5 channel */      TCL_CLOSE2PROC,		/* Close proc. */ @@ -87,7 +83,7 @@ static Tcl_ChannelType pipeChannelType = {      NULL,			/* handler proc. */      NULL,			/* wide seek proc */      NULL,			/* thread action proc */ -    NULL,			/* truncation */ +    NULL			/* truncation */  };  /* @@ -113,12 +109,11 @@ TclpMakeFile(  {      ClientData data; -    if (Tcl_GetChannelHandle(channel, direction, -	    (ClientData *) &data) == TCL_OK) { -	return MakeFile(PTR2INT(data)); -    } else { -	return (TclFile) NULL; +    if (Tcl_GetChannelHandle(channel, direction, &data) != TCL_OK) { +	return NULL;      } + +    return MakeFile(PTR2INT(data));  }  /* @@ -193,30 +188,18 @@ TclFile  TclpCreateTempFile(      const char *contents)	/* String to write into temp file, or NULL. */  { -    char fileName[L_tmpnam + 9]; -    const char *native; -    Tcl_DString dstring; -    int fd; - -    /* -     * We should also check against making more then TMP_MAX of these. -     */ +    int fd = TclUnixOpenTemporaryFile(NULL, NULL, NULL, NULL); -    strcpy(fileName, P_tmpdir);				/* INTL: Native. */ -    if (fileName[strlen(fileName) - 1] != '/') { -	strcat(fileName, "/");				/* INTL: Native. */ -    } -    strcat(fileName, "tclXXXXXX"); -    fd = mkstemp(fileName);				/* INTL: Native. */      if (fd == -1) {  	return NULL;      }      fcntl(fd, F_SETFD, FD_CLOEXEC); -    unlink(fileName);					/* INTL: Native. */ -      if (contents != NULL) { +	Tcl_DString dstring; +	char *native; +  	native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); -	if (write(fd, native, strlen(native)) == -1) { +	if (write(fd, native, Tcl_DStringLength(&dstring)) == -1) {  	    close(fd);  	    Tcl_DStringFree(&dstring);  	    return NULL; @@ -246,29 +229,53 @@ TclpCreateTempFile(  Tcl_Obj *  TclpTempFileName(void)  { -    char fileName[L_tmpnam + 9]; -    Tcl_Obj *result = NULL; +    Tcl_Obj *nameObj = Tcl_NewObj();      int fd; -    /* -     * We should also check against making more then TMP_MAX of these. -     */ - -    strcpy(fileName, P_tmpdir);		/* INTL: Native. */ -    if (fileName[strlen(fileName) - 1] != '/') { -	strcat(fileName, "/");		/* INTL: Native. */ -    } -    strcat(fileName, "tclXXXXXX"); -    fd = mkstemp(fileName);		/* INTL: Native. */ +    Tcl_IncrRefCount(nameObj); +    fd = TclUnixOpenTemporaryFile(NULL, NULL, NULL, nameObj);      if (fd == -1) { +	Tcl_DecrRefCount(nameObj);  	return NULL;      } -    fcntl(fd, F_SETFD, FD_CLOEXEC); -    unlink(fileName);			/* INTL: Native. */ -    result = TclpNativeToNormalized((ClientData) fileName); +    fcntl(fd, F_SETFD, FD_CLOEXEC); +    TclpObjDeleteFile(nameObj);      close(fd); -    return result; +    return nameObj; +} + +/* + *---------------------------------------------------------------------------- + * + * TclpTempFileNameForLibrary -- + * + *	Constructs a file name in the native file system where a dynamically + *	loaded library may be placed. + * + * Results: + *	Returns the constructed file name. If an error occurs, returns NULL + *	and leaves an error message in the interpreter result. + * + * On Unix, it works to load a shared object from a file of any name, so this + * function is merely a thin wrapper around TclpTempFileName(). + *	 + *---------------------------------------------------------------------------- + */ + +Tcl_Obj * +TclpTempFileNameForLibrary( +    Tcl_Interp *interp,		/* Tcl interpreter. */ +    Tcl_Obj *path)		/* Path name of the library in the VFS. */ +{ +    Tcl_Obj *retval = TclpTempFileName(); + +    if (retval == NULL) { +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"couldn't create temporary file: %s", +		Tcl_PosixError(interp))); +    } +    return retval;  }  /* @@ -413,8 +420,8 @@ TclpCreateProcess(       */      if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { -	Tcl_AppendResult(interp, "couldn't create pipe: ", -		Tcl_PosixError(interp), NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"couldn't create pipe: %s", Tcl_PosixError(interp)));  	goto error;      } @@ -423,9 +430,8 @@ TclpCreateProcess(       * deallocated later       */ -    dsArray = (Tcl_DString *) -	    TclStackAlloc(interp, argc * sizeof(Tcl_DString)); -    newArgv = (char **) TclStackAlloc(interp, (argc+1) * sizeof(char *)); +    dsArray = TclStackAlloc(interp, argc * sizeof(Tcl_DString)); +    newArgv = TclStackAlloc(interp, (argc+1) * sizeof(char *));      newArgv[argc] = NULL;      for (i = 0; i < argc; i++) {  	newArgv[i] = Tcl_UtfToExternalDString(NULL, argv[i], -1, &dsArray[i]); @@ -435,9 +441,11 @@ TclpCreateProcess(      /*       * After vfork(), do not call code in the child that changes global state,       * because it is using the parent's memory space at that point and writes -     * might corrupt the parent: so ensure standard channels are initialized in -     * the parent, otherwise SetupStdFile() might initialize them in the child. +     * might corrupt the parent: so ensure standard channels are initialized +     * in the parent, otherwise SetupStdFile() might initialize them in the +     * child.       */ +      if (!inputFile) {  	Tcl_GetStdChannel(TCL_STDIN);      } @@ -448,8 +456,10 @@ TclpCreateProcess(          Tcl_GetStdChannel(TCL_STDERR);      }  #endif +      pid = fork();      if (pid == 0) { +	size_t len;  	int joinThisError = errorFile && (errorFile == outputFile);  	fd = GetFd(errPipeOut); @@ -464,8 +474,11 @@ TclpCreateProcess(  		|| (joinThisError &&  			((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {  	    sprintf(errSpace, -		    "%dforked process couldn't set up input/output: ", errno); -	    (void)write(fd, errSpace, (size_t) strlen(errSpace)); +		    "%dforked process couldn't set up input/output", errno); +	    len = strlen(errSpace); +	    if (len != (size_t) write(fd, errSpace, len)) { +		    Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); +	    }  	    _exit(1);  	} @@ -475,8 +488,11 @@ TclpCreateProcess(  	RestoreSignals();  	execvp(newArgv[0], newArgv);			/* INTL: Native. */ -	sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]); -	(void)write(fd, errSpace, (size_t) strlen(errSpace)); +	sprintf(errSpace, "%dcouldn't execute \"%.150s\"", errno, argv[0]); +	len = strlen(errSpace); +	if (len != (size_t) write(fd, errSpace, len)) { +	    Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); +	}  	_exit(1);      } @@ -491,8 +507,8 @@ TclpCreateProcess(      TclStackFree(interp, dsArray);      if (pid == -1) { -	Tcl_AppendResult(interp, "couldn't fork child process: ", -		Tcl_PosixError(interp), NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		"couldn't fork child process: %s", Tcl_PosixError(interp)));  	goto error;      } @@ -509,9 +525,11 @@ TclpCreateProcess(      count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1));      if (count > 0) {  	char *end; +  	errSpace[count] = 0;  	errno = strtol(errSpace, &end, 10); -	Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s: %s", +		end, Tcl_PosixError(interp)));  	goto error;      } @@ -724,7 +742,7 @@ TclpCreateCommandChannel(  {      char channelName[16 + TCL_INTEGER_SPACE];      int channelId; -    PipeState *statePtr = (PipeState *) ckalloc((unsigned) sizeof(PipeState)); +    PipeState *statePtr = ckalloc(sizeof(PipeState));      int mode;      statePtr->inFile = readFile; @@ -764,7 +782,7 @@ TclpCreateCommandChannel(      sprintf(channelName, "file%d", channelId);      statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName, -	    (ClientData) statePtr, mode); +	    statePtr, mode);      return statePtr->channel;  } @@ -776,43 +794,40 @@ TclpCreateCommandChannel(   *	System dependent interface to create a pipe for the [chan pipe]   *	command. Stolen from TclX.   * - * Parameters: - *   o interp - Errors returned in result. - *   o rchan, wchan - Returned read and write side. - *   o flags - Reserved for future use.   * Results: - *   TCL_OK or TCL_ERROR. + *	TCL_OK or TCL_ERROR. + * + * Side effects: + *	Registers two channels.   *   *----------------------------------------------------------------------   */ +  int  Tcl_CreatePipe( -    Tcl_Interp *interp, -    Tcl_Channel *rchan, -    Tcl_Channel *wchan, -    int flags) +    Tcl_Interp *interp,		/* Errors returned in result. */ +    Tcl_Channel *rchan,		/* Returned read side. */ +    Tcl_Channel *wchan,		/* Returned write side. */ +    int flags)			/* Reserved for future use. */  {      int fileNums[2];      if (pipe(fileNums) < 0) { -	Tcl_AppendResult(interp, "pipe creation failed: ", -		Tcl_PosixError(interp), NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf("pipe creation failed: %s", +		Tcl_PosixError(interp)));  	return TCL_ERROR;      }      fcntl(fileNums[0], F_SETFD, FD_CLOEXEC);      fcntl(fileNums[1], F_SETFD, FD_CLOEXEC); -    *rchan = Tcl_MakeFileChannel((ClientData) INT2PTR(fileNums[0]), -	    TCL_READABLE); +    *rchan = Tcl_MakeFileChannel(INT2PTR(fileNums[0]), TCL_READABLE);      Tcl_RegisterChannel(interp, *rchan); -    *wchan = Tcl_MakeFileChannel((ClientData) INT2PTR(fileNums[1]), -	    TCL_WRITABLE); +    *wchan = Tcl_MakeFileChannel(INT2PTR(fileNums[1]), TCL_WRITABLE);      Tcl_RegisterChannel(interp, *wchan);      return TCL_OK;  } -  /*   *---------------------------------------------------------------------- @@ -840,8 +855,8 @@ TclGetAndDetachPids(  {      PipeState *pipePtr;      const Tcl_ChannelType *chanTypePtr; +    Tcl_Obj *pidsObj;      int i; -    char buf[TCL_INTEGER_SPACE];      /*       * Punt if the channel is not a command channel. @@ -852,14 +867,16 @@ TclGetAndDetachPids(  	return;      } -    pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); +    pipePtr = Tcl_GetChannelInstanceData(chan); +    TclNewObj(pidsObj);      for (i = 0; i < pipePtr->numPids; i++) { -	TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i])); -	Tcl_AppendElement(interp, buf); -	Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); +	Tcl_ListObjAppendElement(NULL, pidsObj, Tcl_NewIntObj( +		PTR2INT(pipePtr->pidPtr[i]))); +	Tcl_DetachPids(1, &pipePtr->pidPtr[i]);      } +    Tcl_SetObjResult(interp, pidsObj);      if (pipePtr->numPids > 0) { -	ckfree((char *) pipePtr->pidPtr); +	ckfree(pipePtr->pidPtr);  	pipePtr->numPids = 0;      }  } @@ -891,15 +908,13 @@ PipeBlockModeProc(  {      PipeState *psPtr = instanceData; -    if (psPtr->inFile) { -	if (TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { -	    return errno; -	} +    if (psPtr->inFile +	    && TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) { +	return errno;      } -    if (psPtr->outFile) { -	if (TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) { -	    return errno; -	} +    if (psPtr->outFile +	    && TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) { +	return errno;      }      psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING); @@ -930,31 +945,35 @@ PipeClose2Proc(      Tcl_Interp *interp,		/* For error reporting. */      int flags)			/* Flags that indicate which side to close. */  { -    PipeState *pipePtr= (PipeState *) instanceData; +    PipeState *pipePtr = instanceData;      Tcl_Channel errChan;      int errorCode, result;      errorCode = 0;      result = 0; -    if (((!flags)||(flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) { +    if (((!flags) || (flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) {  	if (TclpCloseFile(pipePtr->inFile) < 0) {  	    errorCode = errno;  	} else { -	    pipePtr->inFile=NULL; +	    pipePtr->inFile = NULL;  	}      } -    if (((!flags)||(flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL) && (errorCode == 0)) { +    if (((!flags) || (flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL) +	    && (errorCode == 0)) {  	if (TclpCloseFile(pipePtr->outFile) < 0) {  	    errorCode = errno;  	} else { -	    pipePtr->outFile=NULL; +	    pipePtr->outFile = NULL;  	}      } -    /* if half-closing, stop here. */ +    /* +     * If half-closing, stop here. +     */ +      if (flags) { -		return errorCode; +	return errorCode;      }      if (pipePtr->isNonBlocking || TclInExit()) { @@ -978,7 +997,8 @@ PipeClose2Proc(  	if (pipePtr->errorFile) {  	    errChan = Tcl_MakeFileChannel( -		(ClientData) INT2PTR(GetFd(pipePtr->errorFile)), TCL_READABLE); +		    INT2PTR(GetFd(pipePtr->errorFile)), +		    TCL_READABLE);  	} else {  	    errChan = NULL;  	} @@ -987,9 +1007,9 @@ PipeClose2Proc(      }      if (pipePtr->numPids != 0) { -	ckfree((char *) pipePtr->pidPtr); +	ckfree(pipePtr->pidPtr);      } -    ckfree((char *) pipePtr); +    ckfree(pipePtr);      if (errorCode == 0) {  	return result;      } @@ -1022,7 +1042,7 @@ PipeInputProc(  				 * buffer? */      int *errorCodePtr)		/* Where to store error code. */  { -    PipeState *psPtr = (PipeState *) instanceData; +    PipeState *psPtr = instanceData;      int bytesRead;		/* How many bytes were actually read from the  				 * input device? */ @@ -1043,9 +1063,8 @@ PipeInputProc(      if (bytesRead < 0) {  	*errorCodePtr = errno;  	return -1; -    } else { -	return bytesRead;      } +    return bytesRead;  }  /* @@ -1073,7 +1092,7 @@ PipeOutputProc(      int toWrite,		/* How many bytes to write? */      int *errorCodePtr)		/* Where to store error code. */  { -    PipeState *psPtr = (PipeState *) instanceData; +    PipeState *psPtr = instanceData;      int written;      *errorCodePtr = 0; @@ -1090,9 +1109,8 @@ PipeOutputProc(      if (written < 0) {  	*errorCodePtr = errno;  	return -1; -    } else { -	return written;      } +    return written;  }  /* @@ -1119,15 +1137,14 @@ PipeWatchProc(  				 * TCL_READABLE, TCL_WRITABLE and  				 * TCL_EXCEPTION. */  { -    PipeState *psPtr = (PipeState *) instanceData; +    PipeState *psPtr = instanceData;      int newmask;      if (psPtr->inFile) {  	newmask = mask & (TCL_READABLE | TCL_EXCEPTION);  	if (newmask) {  	    Tcl_CreateFileHandler(GetFd(psPtr->inFile), mask, -		    (Tcl_FileProc *) Tcl_NotifyChannel, -		    (ClientData) psPtr->channel); +		    (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel);  	} else {  	    Tcl_DeleteFileHandler(GetFd(psPtr->inFile));  	} @@ -1136,8 +1153,7 @@ PipeWatchProc(  	newmask = mask & (TCL_WRITABLE | TCL_EXCEPTION);  	if (newmask) {  	    Tcl_CreateFileHandler(GetFd(psPtr->outFile), mask, -		    (Tcl_FileProc *) Tcl_NotifyChannel, -		    (ClientData) psPtr->channel); +		    (Tcl_FileProc *) Tcl_NotifyChannel, psPtr->channel);  	} else {  	    Tcl_DeleteFileHandler(GetFd(psPtr->outFile));  	} @@ -1168,14 +1184,14 @@ PipeGetHandleProc(      int direction,		/* TCL_READABLE or TCL_WRITABLE */      ClientData *handlePtr)	/* Where to store the handle. */  { -    PipeState *psPtr = (PipeState *) instanceData; +    PipeState *psPtr = instanceData;      if (direction == TCL_READABLE && psPtr->inFile) { -	*handlePtr = (ClientData) INT2PTR(GetFd(psPtr->inFile)); +	*handlePtr = INT2PTR(GetFd(psPtr->inFile));  	return TCL_OK;      }      if (direction == TCL_WRITABLE && psPtr->outFile) { -	*handlePtr = (ClientData) INT2PTR(GetFd(psPtr->outFile)); +	*handlePtr = INT2PTR(GetFd(psPtr->outFile));  	return TCL_OK;      }      return TCL_ERROR; @@ -1204,9 +1220,8 @@ Tcl_WaitPid(      int options)  {      int result; -    pid_t real_pid; +    pid_t real_pid = (pid_t) PTR2INT(pid); -    real_pid = (pid_t) PTR2INT(pid);      while (1) {  	result = (int) waitpid(real_pid, statPtr, options);  	if ((result != -1) || (errno != EINTR)) { @@ -1240,32 +1255,40 @@ Tcl_PidObjCmd(      int objc,			/* Number of arguments. */      Tcl_Obj *const *objv)	/* Argument strings. */  { +    Tcl_Channel chan; +    PipeState *pipePtr; +    int i; +    Tcl_Obj *resultPtr; +      if (objc > 2) {  	Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");  	return TCL_ERROR;      } +      if (objc == 1) {  	Tcl_SetObjResult(interp, Tcl_NewLongObj((long) getpid()));      } else { -	Tcl_Channel chan; -	const Tcl_ChannelType *chanTypePtr; -	PipeState *pipePtr; -	int i; -	Tcl_Obj *resultPtr, *longObjPtr; +	/* +	 * Get the channel and make sure that it refers to a pipe. +	 */  	chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); -	if (chan == (Tcl_Channel) NULL) { +	if (chan == NULL) {  	    return TCL_ERROR;  	} -	chanTypePtr = Tcl_GetChannelType(chan); -	if (chanTypePtr != &pipeChannelType) { +	if (Tcl_GetChannelType(chan) != &pipeChannelType) {  	    return TCL_OK;  	} -	pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); + +	/* +	 * Extract the process IDs from the pipe structure. +	 */ + +	pipePtr = Tcl_GetChannelInstanceData(chan);  	resultPtr = Tcl_NewObj();  	for (i = 0; i < pipePtr->numPids; i++) { -	    longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i])); -	    Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr); +	    Tcl_ListObjAppendElement(NULL, resultPtr, +		    Tcl_NewIntObj(PTR2INT(TclpGetPid(pipePtr->pidPtr[i]))));  	}  	Tcl_SetObjResult(interp, resultPtr);      } | 
