summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixPipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixPipe.c')
-rw-r--r--unix/tclUnixPipe.c568
1 files changed, 310 insertions, 258 deletions
diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c
index 3dcf829..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.31 2005/07/28 10:55:37 dkf Exp $
*/
#include "tclInt.h"
@@ -25,8 +23,8 @@
* the same as NULL.
*/
-#define MakeFile(fd) ((TclFile)(((int)fd)+1))
-#define GetFd(file) (((int)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.
@@ -47,33 +45,31 @@ typedef struct PipeState {
} PipeState;
/*
- * Declarations for local procedures defined in this file:
+ * Declarations for local functions defined in this file:
*/
-static int PipeBlockModeProc _ANSI_ARGS_((ClientData instanceData,
- int mode));
-static int PipeCloseProc _ANSI_ARGS_((ClientData instanceData,
- Tcl_Interp *interp));
-static int PipeGetHandleProc _ANSI_ARGS_((ClientData instanceData,
- int direction, ClientData *handlePtr));
-static int PipeInputProc _ANSI_ARGS_((ClientData instanceData,
- char *buf, int toRead, int *errorCode));
-static int PipeOutputProc _ANSI_ARGS_((
- ClientData instanceData, CONST char *buf, int toWrite,
- int *errorCode));
-static void PipeWatchProc _ANSI_ARGS_((ClientData instanceData, int mask));
-static void RestoreSignals _ANSI_ARGS_((void));
-static int SetupStdFile _ANSI_ARGS_((TclFile file, int type));
+static int PipeBlockModeProc(ClientData instanceData, int mode);
+static int PipeClose2Proc(ClientData instanceData,
+ Tcl_Interp *interp, int flags);
+static int PipeGetHandleProc(ClientData instanceData,
+ int direction, ClientData *handlePtr);
+static int PipeInputProc(ClientData instanceData, char *buf,
+ int toRead, int *errorCode);
+static int PipeOutputProc(ClientData instanceData,
+ const char *buf, int toWrite, int *errorCode);
+static void PipeWatchProc(ClientData instanceData, int mask);
+static void RestoreSignals(void);
+static int SetupStdFile(TclFile file, int type);
/*
* This structure describes the channel type structure for command pipe based
* I/O:
*/
-static Tcl_ChannelType pipeChannelType = {
+static const Tcl_ChannelType pipeChannelType = {
"pipe", /* Type name. */
- TCL_CHANNEL_VERSION_4, /* v4 channel */
- PipeCloseProc, /* Close proc. */
+ TCL_CHANNEL_VERSION_5, /* v5 channel */
+ TCL_CLOSE2PROC, /* Close proc. */
PipeInputProc, /* Input proc. */
PipeOutputProc, /* Output proc. */
NULL, /* Seek proc. */
@@ -81,12 +77,13 @@ static Tcl_ChannelType pipeChannelType = {
NULL, /* Get option proc. */
PipeWatchProc, /* Initialize notifier. */
PipeGetHandleProc, /* Get OS handles out of channel. */
- NULL, /* close2proc. */
+ PipeClose2Proc, /* close2proc. */
PipeBlockModeProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
NULL, /* wide seek proc */
NULL, /* thread action proc */
+ NULL /* truncation */
};
/*
@@ -106,18 +103,17 @@ static Tcl_ChannelType pipeChannelType = {
*/
TclFile
-TclpMakeFile(channel, direction)
- Tcl_Channel channel; /* Channel to get file from. */
- int direction; /* Either TCL_READABLE or TCL_WRITABLE. */
+TclpMakeFile(
+ Tcl_Channel channel, /* Channel to get file from. */
+ int direction) /* Either TCL_READABLE or TCL_WRITABLE. */
{
ClientData data;
- if (Tcl_GetChannelHandle(channel, direction,
- (ClientData *) &data) == TCL_OK) {
- return MakeFile((int) data);
- } else {
- return (TclFile) NULL;
+ if (Tcl_GetChannelHandle(channel, direction, &data) != TCL_OK) {
+ return NULL;
}
+
+ return MakeFile(PTR2INT(data));
}
/*
@@ -137,12 +133,12 @@ TclpMakeFile(channel, direction)
*/
TclFile
-TclpOpenFile(fname, mode)
- CONST char *fname; /* The name of the file to open. */
- int mode; /* In what mode to open the file? */
+TclpOpenFile(
+ const char *fname, /* The name of the file to open. */
+ int mode) /* In what mode to open the file? */
{
int fd;
- CONST char *native;
+ const char *native;
Tcl_DString ds;
native = Tcl_UtfToExternalDString(NULL, fname, -1, &ds);
@@ -189,33 +185,21 @@ TclpOpenFile(fname, mode)
*/
TclFile
-TclpCreateTempFile(contents)
- CONST char *contents; /* String to write into temp file, or NULL. */
+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;
@@ -243,31 +227,55 @@ TclpCreateTempFile(contents)
*/
Tcl_Obj *
-TclpTempFileName()
+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;
}
/*
@@ -287,10 +295,10 @@ TclpTempFileName()
*/
int
-TclpCreatePipe(readPipe, writePipe)
- TclFile *readPipe; /* Location to store file handle for read side
+TclpCreatePipe(
+ TclFile *readPipe, /* Location to store file handle for read side
* of pipe. */
- TclFile *writePipe; /* Location to store file handle for write
+ TclFile *writePipe) /* Location to store file handle for write
* side of pipe. */
{
int pipeIds[2];
@@ -324,8 +332,8 @@ TclpCreatePipe(readPipe, writePipe)
*/
int
-TclpCloseFile(file)
- TclFile file; /* The file to close. */
+TclpCloseFile(
+ TclFile file) /* The file to close. */
{
int fd = GetFd(file);
@@ -366,38 +374,37 @@ TclpCloseFile(file)
/* ARGSUSED */
int
-TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
- pidPtr)
- Tcl_Interp *interp; /* Interpreter in which to leave errors that
+TclpCreateProcess(
+ Tcl_Interp *interp, /* Interpreter in which to leave errors that
* occurred when creating the child process.
* Error messages from the child process
* itself are sent to errorFile. */
- int argc; /* Number of arguments in following array. */
- CONST char **argv; /* Array of argument strings in UTF-8.
+ int argc, /* Number of arguments in following array. */
+ const char **argv, /* Array of argument strings in UTF-8.
* argv[0] contains the name of the executable
* translated using Tcl_TranslateFileName
* call). Additional arguments have not been
* converted. */
- TclFile inputFile; /* If non-NULL, gives the file to use as input
+ TclFile inputFile, /* If non-NULL, gives the file to use as input
* for the child process. If inputFile file is
* not readable or is NULL, the child will
* receive no standard input. */
- TclFile outputFile; /* If non-NULL, gives the file that receives
+ TclFile outputFile, /* If non-NULL, gives the file that receives
* output from the child process. If
* outputFile file is not writeable or is
* NULL, output from the child will be
* discarded. */
- TclFile errorFile; /* If non-NULL, gives the file that receives
+ TclFile errorFile, /* If non-NULL, gives the file that receives
* errors from the child process. If errorFile
* file is not writeable or is NULL, errors
* from the child will be discarded. errorFile
* may be the same as outputFile. */
- Tcl_Pid *pidPtr; /* If this procedure is successful, pidPtr is
+ Tcl_Pid *pidPtr) /* If this function is successful, pidPtr is
* filled with the process id of the child
* process. */
{
TclFile errPipeIn, errPipeOut;
- int joinThisError, count, status, fd;
+ int count, status, fd;
char errSpace[200 + TCL_INTEGER_SPACE];
Tcl_DString *dsArray;
char **newArgv;
@@ -413,8 +420,8 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
*/
if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) {
- Tcl_AppendResult(interp, "couldn't create pipe: ",
- Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't create pipe: %s", Tcl_PosixError(interp)));
goto error;
}
@@ -423,16 +430,38 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
* deallocated later
*/
- dsArray = (Tcl_DString *) ckalloc(argc * sizeof(Tcl_DString));
- newArgv = (char **) ckalloc((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]);
}
- joinThisError = errorFile && (errorFile == outputFile);
+#ifdef USE_VFORK
+ /*
+ * 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.
+ */
+
+ if (!inputFile) {
+ Tcl_GetStdChannel(TCL_STDIN);
+ }
+ if (!outputFile) {
+ Tcl_GetStdChannel(TCL_STDOUT);
+ }
+ if (!errorFile) {
+ Tcl_GetStdChannel(TCL_STDERR);
+ }
+#endif
+
pid = fork();
if (pid == 0) {
+ size_t len;
+ int joinThisError = errorFile && (errorFile == outputFile);
+
fd = GetFd(errPipeOut);
/*
@@ -445,8 +474,11 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
|| (joinThisError &&
((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
sprintf(errSpace,
- "%dforked process couldn't set up input/output: ", errno);
- 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);
}
@@ -456,8 +488,11 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
RestoreSignals();
execvp(newArgv[0], newArgv); /* INTL: Native. */
- sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
- 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);
}
@@ -468,12 +503,12 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
for (i = 0; i < argc; i++) {
Tcl_DStringFree(&dsArray[i]);
}
- ckfree((char *) dsArray);
- ckfree((char *) newArgv);
+ TclStackFree(interp, newArgv);
+ TclStackFree(interp, dsArray);
if (pid == -1) {
- Tcl_AppendResult(interp, "couldn't fork child process: ",
- Tcl_PosixError(interp), (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "couldn't fork child process: %s", Tcl_PosixError(interp)));
goto error;
}
@@ -490,15 +525,16 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
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),
- (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s: %s",
+ end, Tcl_PosixError(interp)));
goto error;
}
TclpCloseFile(errPipeIn);
- *pidPtr = (Tcl_Pid) pid;
+ *pidPtr = (Tcl_Pid) INT2PTR(pid);
return TCL_OK;
error:
@@ -510,7 +546,7 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
* here, since this is the error case. [Bug: 6148]
*/
- Tcl_WaitPid((Tcl_Pid) pid, &status, 0);
+ Tcl_WaitPid((Tcl_Pid) INT2PTR(pid), &status, 0);
}
if (errPipeIn) {
@@ -527,7 +563,7 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
*
* RestoreSignals --
*
- * This procedure is invoked in a forked child process just before
+ * This function is invoked in a forked child process just before
* exec-ing a new program to restore all signals to their default
* settings.
*
@@ -541,7 +577,7 @@ TclpCreateProcess(interp, argc, argv, inputFile, outputFile, errorFile,
*/
static void
-RestoreSignals()
+RestoreSignals(void)
{
#ifdef SIGABRT
signal(SIGABRT, SIG_DFL);
@@ -616,9 +652,9 @@ RestoreSignals()
*/
static int
-SetupStdFile(file, type)
- TclFile file; /* File to dup, or NULL. */
- int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
+SetupStdFile(
+ TclFile file, /* File to dup, or NULL. */
+ int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR */
{
Tcl_Channel channel;
int fd;
@@ -693,20 +729,20 @@ SetupStdFile(file, type)
*/
Tcl_Channel
-TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
- TclFile readFile; /* If non-null, gives the file for reading. */
- TclFile writeFile; /* If non-null, gives the file for writing. */
- TclFile errorFile; /* If non-null, gives the file where errors
+TclpCreateCommandChannel(
+ TclFile readFile, /* If non-null, gives the file for reading. */
+ TclFile writeFile, /* If non-null, gives the file for writing. */
+ TclFile errorFile, /* If non-null, gives the file where errors
* can be read. */
- int numPids; /* The number of pids in the pid array. */
- Tcl_Pid *pidPtr; /* An array of process identifiers. Allocated
+ int numPids, /* The number of pids in the pid array. */
+ Tcl_Pid *pidPtr) /* An array of process identifiers. Allocated
* by the caller, freed when the channel is
* closed or the processes are detached (in a
* background exec). */
{
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;
@@ -746,16 +782,59 @@ TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
sprintf(channelName, "file%d", channelId);
statePtr->channel = Tcl_CreateChannel(&pipeChannelType, channelName,
- (ClientData) statePtr, mode);
+ statePtr, mode);
return statePtr->channel;
}
/*
*----------------------------------------------------------------------
*
+ * Tcl_CreatePipe --
+ *
+ * System dependent interface to create a pipe for the [chan pipe]
+ * command. Stolen from TclX.
+ *
+ * Results:
+ * TCL_OK or TCL_ERROR.
+ *
+ * Side effects:
+ * Registers two channels.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_CreatePipe(
+ 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_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(INT2PTR(fileNums[0]), TCL_READABLE);
+ Tcl_RegisterChannel(interp, *rchan);
+ *wchan = Tcl_MakeFileChannel(INT2PTR(fileNums[1]), TCL_WRITABLE);
+ Tcl_RegisterChannel(interp, *wchan);
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclGetAndDetachPids --
*
- * This procedure is invoked in the generic implementation of a
+ * This function is invoked in the generic implementation of a
* background "exec" (an exec when invoked with a terminating "&") to
* store a list of the PIDs for processes in a command pipeline in the
* interp's result and to detach the processes.
@@ -770,14 +849,14 @@ TclpCreateCommandChannel(readFile, writeFile, errorFile, numPids, pidPtr)
*/
void
-TclGetAndDetachPids(interp, chan)
- Tcl_Interp *interp; /* Interpreter to append the PIDs to. */
- Tcl_Channel chan; /* Handle for the pipeline. */
+TclGetAndDetachPids(
+ Tcl_Interp *interp, /* Interpreter to append the PIDs to. */
+ Tcl_Channel chan) /* Handle for the pipeline. */
{
PipeState *pipePtr;
- Tcl_ChannelType *chanTypePtr;
+ const Tcl_ChannelType *chanTypePtr;
+ Tcl_Obj *pidsObj;
int i;
- char buf[TCL_INTEGER_SPACE];
/*
* Punt if the channel is not a command channel.
@@ -788,14 +867,16 @@ TclGetAndDetachPids(interp, chan)
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;
}
}
@@ -805,7 +886,7 @@ TclGetAndDetachPids(interp, chan)
*
* PipeBlockModeProc --
*
- * Helper procedure to set blocking and nonblocking modes on a pipe based
+ * Helper function to set blocking and nonblocking modes on a pipe based
* channel. Invoked by generic IO level code.
*
* Results:
@@ -819,67 +900,22 @@ TclGetAndDetachPids(interp, chan)
/* ARGSUSED */
static int
-PipeBlockModeProc(instanceData, mode)
- ClientData instanceData; /* Pipe state. */
- int mode; /* The mode to set. Can be one of
+PipeBlockModeProc(
+ ClientData instanceData, /* Pipe state. */
+ int mode) /* The mode to set. Can be one of
* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
- PipeState *psPtr = (PipeState *) instanceData;
- int curStatus;
- int fd;
+ PipeState *psPtr = instanceData;
-#ifndef USE_FIONBIO
- if (psPtr->inFile) {
- fd = GetFd(psPtr->inFile);
- curStatus = fcntl(fd, F_GETFL);
- if (mode == TCL_MODE_BLOCKING) {
- curStatus &= (~(O_NONBLOCK));
- } else {
- curStatus |= O_NONBLOCK;
- }
- if (fcntl(fd, F_SETFL, curStatus) < 0) {
- return errno;
- }
+ if (psPtr->inFile
+ && TclUnixSetBlockingMode(GetFd(psPtr->inFile), mode) < 0) {
+ return errno;
}
- if (psPtr->outFile) {
- fd = GetFd(psPtr->outFile);
- curStatus = fcntl(fd, F_GETFL);
- if (mode == TCL_MODE_BLOCKING) {
- curStatus &= (~(O_NONBLOCK));
- } else {
- curStatus |= O_NONBLOCK;
- }
- if (fcntl(fd, F_SETFL, curStatus) < 0) {
- return errno;
- }
+ if (psPtr->outFile
+ && TclUnixSetBlockingMode(GetFd(psPtr->outFile), mode) < 0) {
+ return errno;
}
-#endif /* !FIONBIO */
-
-#ifdef USE_FIONBIO
- if (psPtr->inFile) {
- fd = GetFd(psPtr->inFile);
- if (mode == TCL_MODE_BLOCKING) {
- curStatus = 0;
- } else {
- curStatus = 1;
- }
- if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
- return errno;
- }
- }
- if (psPtr->outFile != NULL) {
- fd = GetFd(psPtr->outFile);
- if (mode == TCL_MODE_BLOCKING) {
- curStatus = 0;
- } else {
- curStatus = 1;
- }
- if (ioctl(fd, (int) FIONBIO, &curStatus) < 0) {
- return errno;
- }
- }
-#endif /* USE_FIONBIO */
psPtr->isNonBlocking = (mode == TCL_MODE_NONBLOCKING);
@@ -889,11 +925,10 @@ PipeBlockModeProc(instanceData, mode)
/*
*----------------------------------------------------------------------
*
- * PipeCloseProc --
+ * PipeClose2Proc
*
- * This procedure is invoked by the generic IO level to perform
- * channel-type-specific cleanup when a command pipeline channel is
- * closed.
+ * This function is invoked by the generic IO level to perform
+ * pipeline-type-specific half or full-close.
*
* Results:
* 0 on success, errno otherwise.
@@ -904,29 +939,42 @@ PipeBlockModeProc(instanceData, mode)
*----------------------------------------------------------------------
*/
- /* ARGSUSED */
static int
-PipeCloseProc(instanceData, interp)
- ClientData instanceData; /* The pipe to close. */
- Tcl_Interp *interp; /* For error reporting. */
+PipeClose2Proc(
+ ClientData instanceData, /* The pipe to close. */
+ Tcl_Interp *interp, /* For error reporting. */
+ int flags) /* Flags that indicate which side to close. */
{
- PipeState *pipePtr;
+ PipeState *pipePtr = instanceData;
Tcl_Channel errChan;
int errorCode, result;
errorCode = 0;
result = 0;
- pipePtr = (PipeState *) instanceData;
- if (pipePtr->inFile) {
+
+ if (((!flags) || (flags & TCL_CLOSE_READ)) && (pipePtr->inFile != NULL)) {
if (TclpCloseFile(pipePtr->inFile) < 0) {
errorCode = errno;
+ } else {
+ pipePtr->inFile = NULL;
}
}
- if (pipePtr->outFile) {
- if ((TclpCloseFile(pipePtr->outFile) < 0) && (errorCode == 0)) {
+ if (((!flags) || (flags & TCL_CLOSE_WRITE)) && (pipePtr->outFile != NULL)
+ && (errorCode == 0)) {
+ if (TclpCloseFile(pipePtr->outFile) < 0) {
errorCode = errno;
+ } else {
+ pipePtr->outFile = NULL;
}
}
+
+ /*
+ * If half-closing, stop here.
+ */
+
+ if (flags) {
+ return errorCode;
+ }
if (pipePtr->isNonBlocking || TclInExit()) {
/*
@@ -949,7 +997,8 @@ PipeCloseProc(instanceData, interp)
if (pipePtr->errorFile) {
errChan = Tcl_MakeFileChannel(
- (ClientData) GetFd(pipePtr->errorFile), TCL_READABLE);
+ INT2PTR(GetFd(pipePtr->errorFile)),
+ TCL_READABLE);
} else {
errChan = NULL;
}
@@ -958,9 +1007,9 @@ PipeCloseProc(instanceData, interp)
}
if (pipePtr->numPids != 0) {
- ckfree((char *) pipePtr->pidPtr);
+ ckfree(pipePtr->pidPtr);
}
- ckfree((char *) pipePtr);
+ ckfree(pipePtr);
if (errorCode == 0) {
return result;
}
@@ -972,7 +1021,7 @@ PipeCloseProc(instanceData, interp)
*
* PipeInputProc --
*
- * This procedure is invoked from the generic IO level to read input from
+ * This function is invoked from the generic IO level to read input from
* a command pipeline based channel.
*
* Results:
@@ -986,14 +1035,14 @@ PipeCloseProc(instanceData, interp)
*/
static int
-PipeInputProc(instanceData, buf, toRead, errorCodePtr)
- ClientData instanceData; /* Pipe state. */
- char *buf; /* Where to store data read. */
- int toRead; /* How much space is available in the
+PipeInputProc(
+ ClientData instanceData, /* Pipe state. */
+ char *buf, /* Where to store data read. */
+ int toRead, /* How much space is available in the
* buffer? */
- int *errorCodePtr; /* Where to store error code. */
+ 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? */
@@ -1014,9 +1063,8 @@ PipeInputProc(instanceData, buf, toRead, errorCodePtr)
if (bytesRead < 0) {
*errorCodePtr = errno;
return -1;
- } else {
- return bytesRead;
}
+ return bytesRead;
}
/*
@@ -1024,7 +1072,7 @@ PipeInputProc(instanceData, buf, toRead, errorCodePtr)
*
* PipeOutputProc--
*
- * This procedure is invoked from the generic IO level to write output to
+ * This function is invoked from the generic IO level to write output to
* a command pipeline based channel.
*
* Results:
@@ -1038,13 +1086,13 @@ PipeInputProc(instanceData, buf, toRead, errorCodePtr)
*/
static int
-PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
- ClientData instanceData; /* Pipe state. */
- CONST char *buf; /* The data buffer. */
- int toWrite; /* How many bytes to write? */
- int *errorCodePtr; /* Where to store error code. */
+PipeOutputProc(
+ ClientData instanceData, /* Pipe state. */
+ const char *buf, /* The data buffer. */
+ 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;
@@ -1061,9 +1109,8 @@ PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
if (written < 0) {
*errorCodePtr = errno;
return -1;
- } else {
- return written;
}
+ return written;
}
/*
@@ -1084,21 +1131,20 @@ PipeOutputProc(instanceData, buf, toWrite, errorCodePtr)
*/
static void
-PipeWatchProc(instanceData, mask)
- ClientData instanceData; /* The pipe state. */
- int mask; /* Events of interest; an OR-ed combination of
+PipeWatchProc(
+ ClientData instanceData, /* The pipe state. */
+ int mask) /* Events of interest; an OR-ed combination of
* 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));
}
@@ -1107,8 +1153,7 @@ PipeWatchProc(instanceData, mask)
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));
}
@@ -1134,19 +1179,19 @@ PipeWatchProc(instanceData, mask)
*/
static int
-PipeGetHandleProc(instanceData, direction, handlePtr)
- ClientData instanceData; /* The pipe state. */
- int direction; /* TCL_READABLE or TCL_WRITABLE */
- ClientData *handlePtr; /* Where to store the handle. */
+PipeGetHandleProc(
+ ClientData instanceData, /* The pipe state. */
+ 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) GetFd(psPtr->inFile);
+ *handlePtr = INT2PTR(GetFd(psPtr->inFile));
return TCL_OK;
}
if (direction == TCL_WRITABLE && psPtr->outFile) {
- *handlePtr = (ClientData) GetFd(psPtr->outFile);
+ *handlePtr = INT2PTR(GetFd(psPtr->outFile));
return TCL_OK;
}
return TCL_ERROR;
@@ -1169,19 +1214,18 @@ PipeGetHandleProc(instanceData, direction, handlePtr)
*/
Tcl_Pid
-Tcl_WaitPid(pid, statPtr, options)
- Tcl_Pid pid;
- int *statPtr;
- int options;
+Tcl_WaitPid(
+ Tcl_Pid pid,
+ int *statPtr,
+ int options)
{
int result;
- pid_t real_pid;
+ pid_t real_pid = (pid_t) PTR2INT(pid);
- real_pid = (pid_t) pid;
while (1) {
result = (int) waitpid(real_pid, statPtr, options);
if ((result != -1) || (errno != EINTR)) {
- return (Tcl_Pid) result;
+ return (Tcl_Pid) INT2PTR(result);
}
}
}
@@ -1191,7 +1235,7 @@ Tcl_WaitPid(pid, statPtr, options)
*
* Tcl_PidObjCmd --
*
- * This procedure is invoked to process the "pid" Tcl command. See the
+ * This function is invoked to process the "pid" Tcl command. See the
* user documentation for details on what it does.
*
* Results:
@@ -1205,38 +1249,46 @@ Tcl_WaitPid(pid, statPtr, options)
/* ARGSUSED */
int
-Tcl_PidObjCmd(dummy, interp, objc, objv)
- ClientData dummy; /* Not used. */
- Tcl_Interp *interp; /* Current interpreter. */
- int objc; /* Number of arguments. */
- Tcl_Obj *CONST *objv; /* Argument strings. */
+Tcl_PidObjCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ 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;
- 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);
}
@@ -1254,13 +1306,13 @@ Tcl_PidObjCmd(dummy, interp, objc, objv)
* None.
*
* Notes:
- * This procedure carries out no operation on Unix.
+ * This function carries out no operation on Unix.
*
*----------------------------------------------------------------------
*/
void
-TclpFinalizePipes()
+TclpFinalizePipes(void)
{
}