Take action if login is redirected

I want to know how I need to perform an action in a C program if my input was redirected. For example, say I have a compiled program "prog" and I redirect the input "input.txt" there (I do ./prog < input.txt

).

How do you find this in your code?

+3


source to share


1 answer


You cannot, in general, tell if the input was redirected; but you can differentiate depending on the type of stdin file. If there was no redirect, it will be the terminal; or it could be configured as a pipe cat foo | ./prog

or redirect from a regular file (like your example) or a redirect from one of several types of special files ( ./prog </dev/sda1

redirecting it from a special file block, etc.).

So, if you want to determine if stdin is a terminal (TTY), you can use isatty

:

#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
    if (isatty(STDIN_FILENO))
        printf("stdin is a tty\n");
    else
        printf("stdin is not a tty\n");

    return 0;
}

      

If you want to distinguish between other cases (eg pipe, block special file, etc.), you can use fstat

some more information about the file to extract. Note that this doesn't actually tell you if it's a terminal, you still need it for that isatty

(which is a wrapper around ioctl

that fetches terminal information, at least on Linux). You can add the following program above (along with #include <sys/stat.h>

) for more information on what the stdin file is.



if (fstat(STDIN_FILENO, &sb) == 0) {
    if (S_ISBLK(sb.st_mode))
        printf("stdin is a block special file\n");
    else if (S_ISCHR(sb.st_mode))
        printf("stdin is a character special file\n");
    else if (S_ISDIR(sb.st_mode))
        printf("stdin is a directory\n");
    else if (S_ISFIFO(sb.st_mode))
        printf("stdin is a FIFO (pipe)\n");
    else if (S_ISREG(sb.st_mode))
        printf("stdin is a regular file\n");
    else if (S_ISLNK(sb.st_mode))
        printf("stdin is a symlink\n");
    else if (S_ISSOCK(sb.st_mode))
        printf("stdin is a socket\n");
} else {
    printf("failed to stat stdin\n");
}

      

Note that you will never see the symbolic link from the redirect, since the shell has already flattened the symbolic link before opening the file on behalf of your program; and I was unable to get Bash to open a Unix domain socket. But everything else is possible, including, surprisingly, the catalog.

$ ./isatty 
stdin is a tty
stdin is a character special file
$ ./isatty < ./isatty
stdin is not a tty
stdin is a regular file
$ sudo sh -c './isatty < /dev/sda'
stdin is not a tty
stdin is a block special file
$ sudo sh -c './isatty < /dev/console'
stdin is a tty
stdin is a character special file
$ cat isatty | ./isatty 
stdin is not a tty
stdin is a FIFO (pipe)
$ mkfifo fifo
$ echo > fifo &  # Need to do this or else opening the fifo for read will block
[1] 27931
$ ./isatty < fifo
stdin is not a tty
stdin is a FIFO (pipe)
[1]+  Done                    echo > fifo
$ ./isatty < .
stdin is not a tty
stdin is a directory
$ socat /dev/null UNIX-LISTEN:./unix-socket &
[1] 28044
$ ./isatty < ./unix-socket 
bash: ./unix-socket: No such device or address
$ kill $!
[1]+  Exit 143                socat /dev/null UNIX-LISTEN:./unix-socket
$ ln -s isatty symlink
$ ./isatty < symlink
stdin is not a tty
stdin is a regular file
$ ln -s no-such-file broken-link
$ ./isatty < broken-link 
bash: broken-link: No such file or directory

      

+6


source







All Articles