Tcl Source Code

Artifact [a80a34f9f0]
Login

Artifact a80a34f9f07dbe5c1cd80c5512d16723386c3798:

Attachment "dup-2.patch" to ticket [2827015fff] added by lars_h 2009-07-29 21:25:21.
Index: tests/exec.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/exec.test,v
retrieving revision 1.33
diff -u -r1.33 exec.test
--- tests/exec.test	8 May 2009 08:13:31 -0000	1.33
+++ tests/exec.test	29 Jul 2009 13:59:12 -0000
@@ -605,6 +605,26 @@
     exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>@1
 } {foo bar}
 
+test exec-15.8 {Bug 2827015: swapping standard error and standard out}\
+  -constraints {exec stdio} -setup {
+    set path(script) [makeFile {
+        puts stdout OUT1
+        puts stderr ERR1
+        puts stdout OUT2
+        puts stderr ERR2
+    } script]
+    set path(script2) [makeFile {
+        exec [info nameofexecutable] [lindex $argv 0] >@stderr 2>@stdout
+        puts separator
+    } script2]
+} -body {
+    exec [interpreter] $path(script2) $path(script)
+} -returnCodes error -result "ERR1\nERR2\nseparator\nOUT1\nOUT2" -cleanup {
+    removeFile $path(script)
+    removeFile $path(script2)
+}
+
+
 test exec-16.1 {flush output before exec} {exec} {
     set f [open $path(gorp.file) w]
     puts $f "First line"
Index: unix/tclUnixPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPipe.c,v
retrieving revision 1.48
diff -u -r1.48 tclUnixPipe.c
--- unix/tclUnixPipe.c	9 Jan 2009 11:21:46 -0000	1.48
+++ unix/tclUnixPipe.c	29 Jul 2009 13:59:13 -0000
@@ -451,31 +451,67 @@
     pid = fork();
     if (pid == 0) {
 	int joinThisError = errorFile && (errorFile == outputFile);
+	int fd0,fd1,fd2;
+	int closeOut=0,closeErr=0;
 
 	fd = GetFd(errPipeOut);
 
 	/*
 	 * Set up stdio file handles for the child process.
 	 */
-
-	if (!SetupStdFile(inputFile, TCL_STDIN)
-		|| !SetupStdFile(outputFile, TCL_STDOUT)
-		|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
-		|| (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));
-	    _exit(1);
-	}
+	fd0 = GetFd(inputFile);
+	fd1 = GetFd(outputFile);
+	fd2 = GetFd(errorFile);
+	
+	if (fd1 == 0) {
+	    outputFile = MakeFile(dup(0));
+	    closeOut = 1;
+        }
+	if (fd2 == 0) {
+	    errorFile = MakeFile(dup(0));
+	    closeErr = 1;
+        }
+	if (!SetupStdFile(inputFile, TCL_STDIN)) {
+            sprintf(errSpace,
+                    "%dforked process couldn't set up input: ", errno);
+	    goto child_error;
+	}
+	
+
+	if (fd2 == 1) {
+	    errorFile = MakeFile(dup(1));
+	    closeErr = 1;
+	}
+	if (!SetupStdFile(outputFile, TCL_STDOUT)) {
+            sprintf(errSpace,
+                    "%dforked process couldn't set up output: ", errno);
+	    goto child_error;
+	}
+
+	if ( !joinThisError ? !SetupStdFile(errorFile, TCL_STDERR)
+            : (dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0) 
+        ) {
+            sprintf(errSpace,
+                    "%dforked process couldn't set up stderr: ", errno);
+	    goto child_error;
+        }
+        
+	if (closeOut) close(GetFd(outputFile));
+	if (closeErr) close(GetFd(errorFile));
 
 	/*
+	 * Anyone know what this comment means:
 	 * Close the input side of the error pipe.
 	 */
 
 	RestoreSignals();
 	execvp(newArgv[0], newArgv);			/* INTL: Native. */
+
+	/* 
+	 * If we get here, then execvp failed. 
+	 */
 	sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
+      child_error:
 	(void)write(fd, errSpace, (size_t) strlen(errSpace));
 	_exit(1);
     }