0

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?

woniok
  • 159
  • 4
  • 9
  • @jdigital So, you mean the redirected `0 < /dev/tty` is the argument for the program, not `0`? – woniok Oct 15 '22 at 04:07
  • @TedLyngmo Thanks. But still I don't understand what you mean exactly. I think the problem is my English reading skill. When I run the same program without the redirection, (`./a.out 0`) the result is `read write`. And I'm stuck at the reason why results are different. – woniok Oct 15 '22 at 04:20
  • 3
    The `< /dev/tty` syntax tells the shell to open `/dev/tty` as input, on file descriptor `0`, before executing your program. When your program is started by the shell, file descriptor `0` is already open for input from `/dev/tty`. It has nothing to do with the `0` in the command line argument, which is solely up to your program to interpret. When your program calls `fcntl` with file descriptor `0`, which you passed on the command line, it acts on the already-open file descriptor `0`. – Tom Karzes Oct 15 '22 at 04:35
  • @TomKarzes I stand corrected. woniok, disregard what I previously said. – Ted Lyngmo Oct 15 '22 at 04:37
  • @TomKarzes Thanks! your reply explains well about what I was wondering! But, if I wanted to learn about the underlying mechanism of redirection operators in such case more detail, could you give me some references? – woniok Oct 15 '22 at 05:37
  • Ted, still I am grateful about your interests and participation on my issue :) – woniok Oct 15 '22 at 05:39
  • While I was thinking about your reply, @TomKarzes, I came up with the idea that `1`is omitted when we use the output redirection operator `1<`. Is it an analogous situation to that? – woniok Oct 15 '22 at 06:07
  • 1
    @woniok The default input redirection `< file` uses fd 0, i.e. stdin. The default output redirection `> file` uses fd 1, i.e. stdout. Standard error is fd 2, i.e. stderr. Different shells have different syntax for specifying these, but most allow you do indicate the file descriptor. Writing a simple shell that supports input and output redirection is a common programming assignment in CS classes. After parsing the input line, it just needs to set up its file descriptors and pipes, do the appropriate forks/execs, etc. – Tom Karzes Oct 15 '22 at 06:23
  • @TomKarzes, Thank you for additional explanation! I got your point clearly now! I shamed myself that I had majored in CS. It's not strange that I got C+ in the OS class then... – woniok Oct 15 '22 at 08:10
  • 1
    @TedLyngmo Thank you for your participation. – woniok Oct 15 '22 at 08:10

1 Answers1

1

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 );
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Great. I got another clear point from your answer, ikegami! Though @TomKarzes had given me the clear interpretation for the sentence `./a.out 0 < /dev/tty`, your code gave me the clear view of what happens while it's running. Thanks. – woniok Oct 15 '22 at 08:15