Can I get back stdout after redirection?

mike.stefanik mike at bria.UUCP
Sat May 4 14:32:47 AEST 1991


In an article, pefv700 at perv.pe.utexas.edu writes:
>From what I understand, with
>
>% cmd > file
>
>the typical shell will do something like (omitting error checking)
>
>    fd = fopen("file", "w");
>    close(1);
>    dup(fd);

Acutally, I am more than a little suprised that no one has caught this
thus far ... you are mixing apples and oranges here.  The fopen()
subroutine does not hand back a descriptor that can be used with dup()
and close() -- it hands back a pointer to a "stream" which is used
with fprintf(), fclose(), etc.

What you mean is:

	fd = open("file",O_WRONLY|O_CREAT|O_TRUNC,0666);
	close(1);
	dup(fd);

>Since the shell has already closed stdout's file descriptor, is it not
>possible to reopen it?  (Also, how did stdout get opened in the first
>place?  The shell inherited it from its parent, didn't it?)

Assuming that we are talking about a login shell, the shell inherits
stdin, stdout and stderr (descriptors 0, 1 and 2 respectively) from
the process that invoked it ... namely /bin/login ( /bin/login likewise
inherited these descriptors from /etc/getty )

Acutally, the above algorithm that you provide has a problem, namely
that once you close the descriptor (in this case, stdout) you have no
idea how to reopen it after the redirector has completed.  Several
people have mentioned /dev/tty ... but this is NOT a solution.  What
happens when this instance of the shell was not writing to /dev/tty, but
a regular file instead?

The solution is to use dup() to duplicate the stdout descriptor, and
then use dup2() to force duplication of the file descriptor over stdout.
When the redirection is complete, you need only dup2() the original
descriptor that you preserved.

IMHO, it is an ugly practice to take "advantage" of the fact that dup()
will always return the lowest file descriptor.  Here is how I do it:

#include <stdio.h>
#include <fcntl.h>

#define STDIN	0	/* the standard input descriptor */
#define STDOUT	1	/* the standard output descriptor */
#define STDERR	2	/* the standard error descriptor */

main()
{
int oldout, fd;

	puts("writing output of /bin/ls to outputfile");

	/*
	 *  first we create the file that we are going to redirect
	 *  output to;  some stuff folks might claim that creat()
	 *  is archaic, but I like it nonetheless
	*/

	if ( (fd = creat("outputfile",0666)) == -1 ) {
		perror("open");
		return 1;
		}

	/*
	 *  now we make a duplicate of the *current* standard output
	 *  descriptor; this is how we can put things back correctly
	 *  after the redirection
	*/

	oldout = dup(STDOUT);

	/*
	 *  now we force the duplication of the file descriptor
	 *  over the standard output descriptor; the standard output
	 *  descriptor is closed, but since we have `oldout' which
	 *  points to the original standard output, we don't care
	*/

	if ( dup2(fd,STDOUT) == -1 ) {
		perror("dup2");
		return 1;
		}

	/*
	 *  close the file descriptor because we don't need it any more
	 *  (standard output is now that file)
	*/

	close(fd);

	/*
	 *  execute some command that generates output so that we
	 *  know that this really works
	*/

	if ( fork() )
		wait(NULL);
	else
		execlp("/bin/ls","ls","-l",NULL);

	/*
	 *  since we're done, we need to put the original descriptor
	 *  for standard output back in place;  it is forced over
	 *  the current stdout descriptor (which will close the file)
	 *  and stdout is back to whatever it was before
	*/

	if ( dup2(oldout,STDOUT) == -1 ) {
		perror("dup2");
		return 1;
		}

	/*
	 *  the `oldout' is no longer needed, so we close it
	*/

	close(oldout);

	/*
	 *  just to make sure that things are back the way that
	 *  they should be :-)
	*/

	puts("the output of /bin/ls has been successfully redirected");

	return 0;
}

Just some kibbles for thought.
-- 
Michael Stefanik, MGI Inc, Los Angeles | Opinions stated are never realistic
Title of the week: Systems Engineer    | UUCP: ...!uunet!bria!mike
-------------------------------------------------------------------------------
If MS-DOS didn't exist, who would UNIX programmers have to make fun of?



More information about the Comp.unix.programmer mailing list