clinuxunixposixsystems-programming

How the redirection like "./a.out 0 < /dev/tty" is possible at 85p of APUE 3e


I was reading APUE(Advanced Programming in the UNIX Environment) 3e.

And there is an example code to explain how fcntl() works like below.
(I changed some of the headers included and some parts of code to be independent from this book's library. And in order to have the code to rely only on the standard libraries.)

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

int main(int argc, char *argv[])
{
        int val;
        if (argc != 2) {
                fprintf(stderr, "usage: %s <descriptor#>\n", argv[0]);
                exit(1);
        }

        if ((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0) {
                perror("fcntl error for fd");
                exit(1);
        }

        switch (val & O_ACCMODE) {
        case O_RDONLY:
                printf("read only");
                break;
        case O_WRONLY:
                printf("write only");
                break;
        case O_RDWR:
                printf("read write");
                break;
        default:
                fprintf(stderr, "unknown access mode\n");
                //exit(1);
        }

        if (val & O_APPEND)
                printf(", append");
        if (val & O_NONBLOCK)
                printf(", nonblocking");
        if (val & O_SYNC)
                printf(", synchronous writes");

#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
        if (val & O_FSYNC)
                printf(", synchronous writes");
#endif

        putchar('\n');
        exit(0);
}

After making a binary based on this code, the book (85 page) gives some example to test the file status flags, from the given file descriptor as argument. And one of them is like following.

$ ./a.out 0 < /dev/tty

and its result is

read only

But where I got some curiosity about the redirection operator above is: 0 is given as the single command argument to the program, and it uses only argv[1] but anything else.

Then, how redirected /dev/tty could be delivered to the program?

Does /dev/tty in the command line above overwrite the argument 0 or something?


Solution

  • how redirected /dev/tty could be delivered to the program?

    It's not. < and /dev/tty aren't passed as arguments; they tell the shell to redirect the child's stdin (fd 0).

    The shell does something similar to

    pid_t pid = fork();
    if ( pid == 0 ) {
       int for_stdin = open( "/dev/tty", O_RDONLY );
       dup2( for_stdin, 0 );
       close( for_stdin );
       execlp( "./a.out", "0", NULL );
    }