Writing to stdin and reading from stdout (UNIX/LINUX/C Programming)
Asked Answered
A

5

26

I was working on an assignment where a program took a file descriptor as an argument (generally from the parent in an exec call) and read from a file and wrote to a file descriptor, and in my testing, I realized that the program would work from the command-line and not give an error if I used 0, 1 or 2 as the file descriptor. That made sense to me except that I could write to stdin and have it show on the screen.

Is there an explanation for this? I always thought there was some protection on stdin/stdout and you certainly can't fprintf to stdin or fgets from stdout.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    char message[20];
    read(STDOUT_FILENO, message, 20);
    write(STDIN_FILENO, message, 20);

    return 0;
}
Alcoholic answered 12/9, 2011 at 5:54 Comment(3)
Please don't confuse file handles with file descriptors. You may well not be allowed to fprintf to stdin (though I can't find anything in the standard explicitly disallowing it) but that has zero effect on whether you can write to file descriptor 0.Tegucigalpa
What exactly is the difference? Are they not accomplishing the same task?Alcoholic
A carrot and a stick can accomplish the same task, and yet they are not the same thing, just ask your friendly neighbourhood donkey :-) Handles are standard C, descriptors are POSIX.Tegucigalpa
E
22

Attempting to write on a file marked readonly or vice-versa would cause write and read to return -1, and fail. In this specific case, stdin and stdout are actually the same file. In essence, before your program executes (if you don't do any redirection) the shell goes:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

So, stdin, out, and err are all duplicates of the same file descriptor, opened for reading and writing.

Eugenle answered 6/10, 2011 at 20:41 Comment(1)
Correction, this is not done by the shell but the terminal (emulator). The shell will inherit its stdin/stdout handles as any other process.Loader
H
3
read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

Should work. Note - stdout my be a different place from stdin (even on the command line). You can feed output from another process as stdin into you process, or arrange the stdin/stdout to be files.

fprintf/fgets have a buffer - thus reducing the number of system calls.

Hawsehole answered 12/9, 2011 at 6:5 Comment(0)
H
2

Best guess - stdin points to where the input is coming from, your terminal and stdout points to where output should be going, your terminal. Since they both point to the same place they are interchangeable(in this case)?

Hiltner answered 12/9, 2011 at 5:58 Comment(3)
But they may not be your terminal.Hawsehole
@Ed then it will read/write from/to whatever stdin/stdout points to. That was a lot of this/that.Hiltner
Interesting way to think about this, but this doesn’t hold for online interpreters.Varices
P
2

It's very possible that file descriptors 0, 1, and 2 are all open for both reading and writing (and in fact that they all refer to the same underlying "open file description"), in which case what you're doing will work. But as far as I know, there's no guarantee, so it also might not work. I do believe POSIX somewhere specifies that if stderr is connected to the terminal when a program is invoked by the shell, it's supposed to be readable and writable, but I can't find the reference right off..

Generally, I would recommend against ever reading from stdout or stderr unless you're looking for a terminal to read a password from, and stdin has been redirected (not a tty). And I would recommend never writing to stdin - it's dangerous and you could end up clobbering a file the user did not expect to be written to!

Pollywog answered 12/9, 2011 at 13:10 Comment(0)
P
1

If you run a program on UNIX

myapp < input > output

You can open /proc/{pid}/fd/1 and read from it, open /proc/{pid}/fd/0 and write to it and for example, copy output to input. (There is possibly a simpler way to do this, but I know it works)

You can do any manner of things which are plain confusing if you put your mind to it. ;)

Peppermint answered 12/9, 2011 at 7:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.