How detect assigned terminal device for interactive work

Viewed 300

I am writing pager pspg. There I have to solve following issue. After reading from stdin I should to reassign stdin from previous reading from pipe to reading from terminal.

I used

freopen("/dev/tty", "r", stdin) 

But it doesn't work, when pager was used from command what was not executed directly

su - someuser -c 'export PAGER=pspg psql somedb'

In this case, I got a error: No such device or address.

I found a workaround - now, the code looks like:

if (freopen("/dev/tty", "r", stdin) == NULL)
{
    /*
     * try to reopen pty.
     * Workaround from:
     * https://cboard.cprogramming.com/c-programming/172533-how-read-pipe-while-keeping-interactive-keyboard-c.html
     */
    if (freopen(ttyname(fileno(stdout)), "r", stdin) == NULL)
    {
        fprintf(stderr, "cannot to reopen stdin: %s\n", strerror(errno));
        exit(1);
    }
}

What is a correct way to detect assigned terminal device in this case?

But this workaround is not correct. It fixed one issue, but next is comming. When someuser is different than current user, then reopen fails with error Permission denied. So this workaround cannot be used for my purposes.

2 Answers

What less does in this situation is fall back to fd 2 (stderr). If stderr has been redirected away from the tty, it gives up on trying to get keyboard input, and just prints the whole input stream without paging.

The design of su doesn't allow for anything better. The new user is running a command on a tty owned by the original user, and that unpleasant fact can't be entirely hidden.

Here's a nice substitute for su that doesn't have this problem:

ssh -t localhost -l username sh -c 'command'

It has a little more overhead, of course.

Related