nelson@berlioz.nsc.com (Taed Nelson) (02/14/91)
We have a "shell" program which executes programs from within it using the system()/spawn() call. We wanted to trap these errors, so we freopen()ed stdout and stderr to files that we could parse/show to the user from within the "shell". This part works fine. We also want to provide a "subshell" capability to get out to csh or DOS, but clearly we want stdout and stderr to go back to the screen. Unfortunately, freopen() closed the original screen file, so we can't get output to go there. We tried "storing" the FILE struct prior to the freopen(), but that didn't work, we assume because the FILE struct is just a buffer and not a real descriptor of the file. So we need a way to fopen_again(FILE*) or something of the same sort. Or can we get at the real file descriptors, or keep freopen() from closing the original? Help! (Thanks!)
jik@athena.mit.edu (Jonathan I. Kamens) (02/15/91)
It sounds to me like your problem is that you are replacing stdout and stderr too early. If you are running programs in a subprocess and you want the stdout and stderr of those programs to go into a file (or into a pipe from which you can read), then you don't want to close stdout and stderr in the parent before you fork() to start the sub-process; you want to do it after you've fork()ed but before you exec() the sub-process. Now, I realize that if you're using system() right now to start the sub-processes, then you don't have control over this, because system() deals with the fork() and exec() stuff. This means that you're going to have to change the way you're doing things. If you want stdout and stderr to go to a file, then you can do that by simply doing a fork(), then doing the freopen() calls in the child the same way you're doing them in the parent right now, then doing the system() as you're doing now. Since the freopen() calls are in a subprocess, the parent keeps its stdout and stderr. If you do this, don't forget to install a SIGCHLD handler to wait for your children (see the article I posted about that yesterday). Alternatively, you can rewrite system() to do the freopen() calls itself, after its fork() but before its exec(). Pipes are a bit more complicated. You would need to create the pipe in the parent, then do the fork(), then replace fileno(stdout) and fileno(stderr) with the write side of the pipes in the child and close the read sides; in the parent, you close the write sides and read from the read sides to get the output of the subprocess. Then, you do the system() in the child. Of course, there is a much simpler answer to all of this -- you could freopen() /dev/tty on top of stdout and stderr after the subprocess finishes. But this is sloppy programming and I wouldn't recommend it (I'm just mentioning it for completeness). -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8085 Home: 617-782-0710
mike (02/15/91)
In an article, berlioz.nsc.com!nelson (Taed Nelson) writes: | |We have a "shell" program which executes programs from within it using the | system()/spawn() call. We wanted to trap these errors, so we freopen()ed | stdout and stderr to files that we could parse/show to the user from within | the "shell". This part works fine. | |We also want to provide a "subshell" capability to get out to csh or DOS, but | clearly we want stdout and stderr to go back to the screen. Unfortunately, | freopen() closed the original screen file, so we can't get output to go | there. How about using /dev/tty, such as: freopen("/dev/tty","r",stdin); freopen("/dev/tty","w",stdout); freopen("/dev/tty","w",stderr); |(Thanks!) You're welcome. -- Michael Stefanik | Opinions stated are not even my own. Systems Engineer, Briareus Corporation | UUCP: ...!uunet!bria!mike ------------------------------------------------------------------------------- technoignorami (tek'no-ig'no-ram`i) a group of individuals that are constantly found to be saying things like "Well, it works on my DOS machine ..."
gwyn@smoke.brl.mil (Doug Gwyn) (02/15/91)
In article <1991Feb14.035930.20173@berlioz.nsc.com> nelson@berlioz.nsc.com (Taed Nelson) writes: >We have a "shell" program which executes programs from within it using the > system()/spawn() call. We wanted to trap these errors, so we freopen()ed > stdout and stderr to files that we could parse/show to the user from within > the "shell". This part works fine. You were lucky. The UNIX convention is that file descriptors 0, 1, and 2 are the standard I/O/error hooks. While in a given stdio-using program stdin, stdout, and stderr will start out assigned to those file descriptors, there is no guarantee that the same file descriptors will be in use for those stdio streams after the freopen()s. To keep the original file descriptors from being lost by the freopen()s, you can save the value of dup(fileno(stdio_stream_here)), then later use dup2() to move them to the original values 0,1,2.
nelson@berlioz.nsc.com (Taed Nelson) (02/15/91)
In article <15202@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >In article <1991Feb14.035930.20173@berlioz.nsc.com> nelson@berlioz.nsc.com (Taed Nelson) writes: >>We have a "shell" program which executes programs from within it using the >> system()/spawn() call. We wanted to trap these errors, so we freopen()ed > >You were lucky. The UNIX convention is that file descriptors 0, 1, and 2 >are the standard I/O/error hooks. While in a given stdio-using program Actually, we weren't "lucky" -- the man page for freopen() says that this is a common use of the command. Thanks for the replies. What I didn't make clear enough is that we operate under both DOS and Unix; I thought the REAL solution would be applicable to both. Clearly, I forgot about fork() and did not think of using it due to the DOS environment. Our final solution, which works, is to do another freopen() before going to the shell which redirects stdout and stderr back to "CON". I was really happy that that little tidbit was not documented in the manual (actually, pissed off is a more appropriate adjective). I wonder how one would actually open a file named "CON"?