pefv700@perv.pe.utexas.edu (05/01/91)
The subject says it all. 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); 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?) Thanks, Chris
jik@athena.mit.edu (Jonathan I. Kamens) (05/01/91)
In article <48186@ut-emx.uucp>, pefv700@perv.pe.utexas.edu writes: |> Since the shell has already closed stdout's file descriptor, is it not |> possible to reopen it? You can't get back stdout per se. However, if stdout was pointing to your terminal before the shell closed it, you can open "/dev/tty" to get a file descriptor to write to the terminal. |> (Also, how did stdout get opened in the first |> place? The shell inherited it from its parent, didn't it?) Yes. -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8085 Home: 617-782-0710
matteo@ghost.unimi.it (Matteo Gelosa) (05/02/91)
pefv700@perv.pe.utexas.edu writes: > The subject says it all. > From what I understand, with > % cmd > file > the typical shell will do something like (omitting error checking) > fd = fopen("file", "w"); < fd = open("file", O_WRONLY)_; probably you wanted to write this... > 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?) There is a special file named "/dev/tty", that always refers to your current tty. Simply you have to reopen it if you want to send your output back to your tty. A lot of programs that have to communicate only with a tty device do it to avoid redirection. Try with this... < #define STDOUT 1 /* I know 1 is standard output but it looks nicer */ < fd = open("/dev/tty", O_RDWR); /* open /dev/tty */ < close(STDOUT); /* close old redirection */ < dup(fd); /* re-redirect standard output to tty */ Matteo. ---- Matteo Gelosa Phone : +39-2-7575242 Universita' Statale di Milano Fax : +39-2-76110556 Dipartimento di Scienze dell'Informazione Telex : 335199 - MIDSII Via Moretto da Brescia, 9 E-Mail : matteo@ghost.unimi.it I-20133 Milano - Italy - `92 Europe
matteo@ghost.unimi.it (Matteo Gelosa) (05/02/91)
I was forgettin' something important... If you wanna work with file descriptor you have to do like I wrote, but if you wanna work with stdio buffers you can do it in a very simpler way just calling... freopen("/dev/tty", "w", stdout); Matteo.
meissner@osf.org (Michael Meissner) (05/04/91)
In article <1991May02.125231.20488@ghost.unimi.it> matteo@ghost.unimi.it (Matteo Gelosa) writes: | > 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?) | | There is a special file named "/dev/tty", that always refers | to your current tty. Simply you have to reopen it if you want | to send your output back to your tty. | A lot of programs that have to communicate only with a tty | device do it to avoid redirection. | Try with this... However, /dev/tty is not the same thing as stdout (though for many users it winds up at the same location). If you need to restore your original stdout after redirection, the only way is not to close your last handle on it. I would recomend: orig_stdout = dup (fileno (stdout)); if (orig_stdout < 0) { perror ("dup"); abort (); } if (freopen ("newfile", "a", stdout) != stdout) { perror ("newfile"); abort (); } /* whatever */ fclose (stdout); if (fdopen (orig_stdout, "w") == 0) { perror ("fdopen"); abort (); } for the adventuresome, you can play games with dup behind stdio's back, but it's not something I recomend..... -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA, 02142 Considering the flames and intolerance, shouldn't USENET be spelled ABUSENET?
mike@bria.UUCP (mike.stefanik) (05/04/91)
In an article, pefv700@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?