Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!iuvax!bsu-cs!dhesi From: dhesi@bsu-cs.bsu.edu (Rahul Dhesi) Newsgroups: comp.sys.ibm.pc Subject: Re: MS-DOS puzzle #1 Summary: answer Message-ID: <8167@bsu-cs.bsu.edu> Date: 11 Jul 89 03:58:57 GMT Reply-To: dhesi@bsu-cs.bsu.edu (Rahul Dhesi) Organization: CS Dept, Ball St U, Muncie, Indiana Lines: 101 In article <6893@bsu-cs.bsu.edu> a long time ago I wrote: >Here is a puzzle. First read the question and answer. Then solve >the puzzle that follows. > > Question: Why does COMMAND.COM allow redirection of standard > input and standard output, but not standard error? > > Answer: MS-DOS, unlike UNIX, doesn't have a fork() system call; > therefore the MS-DOS command interpreter, unlike the > UNIX shell, can't redirect standard error. > >THE PUZZLE. Does the above make any sense? If it does, why? If it >does not, what is the real answer to the question? > >I have an answer already, which I will post after a while. Here is my answer, which I am posting "after a while" as promised. Yes, the answer above does make a little sense. It may not be the complete reason why the MS-DOS command interpreter will redirect standard output but not standard error. If you have a fork() system call, you can redirect I/O as follows (some details omitted): pid = fork(); if (pid == 0) { /* child */ redirect file descriptors as needed; execute new program; } else { /* parent */ wait for child to exit; } In the above scheme, only the file descriptors of the child process are ever redirected. The parent's fds are left completely untouched. The MS-DOS command interpreter can't use fork(). In order to redirect a file descriptor for a child process, it must redirect its own file descriptor before the EXEC, and save the old file descriptor somewhere. One way of doing this is to use dup2() to create a duplicate high-numbered fd. So for example, it could save the current standard output fd (normally 1) as fd number 15, then close fd 1 and reopen it attached to a file for output, and it has redirected standard output to go to a file. Then the command interpreter executes the command as a subprocess using the EXEC system call. After the subprocess returns, it can do another dup2() to get a duplicate of fd 15 into fd 1. This restores the original standard output. But if it does this, then the new process has an extra open file handle available to it, since EXEC duplicates all open files. (MS-DOS has no close-on-exec flag.) This is risky. A badly-designed program could write garbage to fd 15 (which was not really supposed to be open at all). Perhaps the COMMAND.COM designer felt that enough was enough. Even if he had to supply extra fds to a subprocess that might mess with them without knowing they were open, he wasn't about to let standard error (which you absolutely HAVE to have to print error messages) get messed up by a rogue subprocess. There is another possibility. Maybe COMMAND.COM uses some undocumented feature of the MS-DOS kernel to redirect standard output. Maybe they only had enough bits left over in the PSP two handle two redirected fds but not three. It could be, for example, that COMMAND.COM first loads the new program, then changes its PSP to the new PSP using an "undocumented" system call, does the I/O redirection, and then jumps to the new program. For some undocumented reason, redirection of standard error doesn't work (a bug in the undocumented system call, which is why instead of documenting it in a later version, Microsoft created a new one instead?). The final possibility is that the COMMAND.COM designer didn't want to take the risk of the standard error stream suddenly freezing. When you initially open a device for output, it is in a mode in which it stops accepting any further writes as soon as it sees a control Z. (The original objective was apparently to prevent trailing garbage in CP/M files showing up at odd times.) It wouldn't do to let the standard error stream freeze up like this, for then where would you print error messages like "Stream frozen due to control-Z -- System Halted"?? On earlier MS-DOS versions, the command echo ^Z (that's a real control Z) produces an odd error message (try it). It wouldn't do to not be able to print this odd message in case somebody did something like echo 2>&1 ^Z instead. The above speculation may or may not be based on many facts, but it *is* based surely on *one* important fact: If it weren't for the absence of fork(), we wouldn't even have to wonder why COMMAND.COM won't redirect standard error. -- Rahul Dhesi UUCP: ...!{iuvax,pur-ee}!bsu-cs!dhesi