如何检测指定的终端设备进行交互工作
How detect assigned terminal device for interactive work
我正在写寻呼机pspg
。在那里我必须解决以下问题。从 stdin
读取后,我应该将 stdin
从之前的管道读取重新分配给从终端读取。
我用过
freopen("/dev/tty", "r", stdin)
但是它不起作用,当从命令中使用寻呼机时没有直接执行什么
su - someuser -c 'export PAGER=pspg psql somedb'
在这种情况下,我得到一个错误:没有这样的设备或地址。
我找到了解决方法 - 现在,代码如下所示:
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);
}
}
在这种情况下,检测分配的终端设备的正确方法是什么?
但是这个变通方法是不正确的。它解决了一个问题,但下一个问题即将到来。当某个用户与当前用户不同时,重新打开会失败并出现错误 Permission denied。所以这个解决方法不能用于我的目的。
less
在这种情况下所做的是回退到 fd 2 (stderr)。如果 stderr 已经从 tty 重定向,它会放弃尝试获取键盘输入,并且只打印整个输入流而不进行分页。
su
的设计不允许任何更好的东西。新用户是 运行 对原用户拥有的 tty 的命令,这个令人不快的事实不能完全隐藏。
这是 su
的一个很好的替代品,没有这个问题:
ssh -t localhost -l username sh -c 'command'
当然,它有更多的开销。
最后,我使用了在 less
pager 中找到的模式,但为了与 ncurses:
一起使用而进行了修改
首先我尝试重新打开一些 tty 相关设备的标准输入:
if (!isatty(fileno(stdin)))
{
if (freopen("/dev/tty", "r", stdin) != NULL)
noatty = false;
/* when tty is not accessible, try to get tty from stdout */
else if (freopen(ttyname(fileno(stdout)), "r", stdin) != NULL)
noatty = false;
else
{
/*
* just ensure stderr is joined to tty, usually when reopen
* of fileno(stdout) fails - probably due permissions.
*/
if (!isatty(fileno(stderr)))
{
fprintf(stderr, "missing a access to terminal device\n");
exit(1);
}
noatty = true;
fclose(stdin);
}
}
else
noatty = false;
当我没有 tty 且无法使用 stdin
时,我正在使用 newterm
函数,允许指定输入流:
if (noatty)
/* use stderr like stdin. This is fallback solution used by less */
newterm(termname(), stdout, stderr);
else
/* stdin is joined with tty, then use usual initialization */
initscr();
我正在写寻呼机pspg
。在那里我必须解决以下问题。从 stdin
读取后,我应该将 stdin
从之前的管道读取重新分配给从终端读取。
我用过
freopen("/dev/tty", "r", stdin)
但是它不起作用,当从命令中使用寻呼机时没有直接执行什么
su - someuser -c 'export PAGER=pspg psql somedb'
在这种情况下,我得到一个错误:没有这样的设备或地址。
我找到了解决方法 - 现在,代码如下所示:
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);
}
}
在这种情况下,检测分配的终端设备的正确方法是什么?
但是这个变通方法是不正确的。它解决了一个问题,但下一个问题即将到来。当某个用户与当前用户不同时,重新打开会失败并出现错误 Permission denied。所以这个解决方法不能用于我的目的。
less
在这种情况下所做的是回退到 fd 2 (stderr)。如果 stderr 已经从 tty 重定向,它会放弃尝试获取键盘输入,并且只打印整个输入流而不进行分页。
su
的设计不允许任何更好的东西。新用户是 运行 对原用户拥有的 tty 的命令,这个令人不快的事实不能完全隐藏。
这是 su
的一个很好的替代品,没有这个问题:
ssh -t localhost -l username sh -c 'command'
当然,它有更多的开销。
最后,我使用了在 less
pager 中找到的模式,但为了与 ncurses:
首先我尝试重新打开一些 tty 相关设备的标准输入:
if (!isatty(fileno(stdin)))
{
if (freopen("/dev/tty", "r", stdin) != NULL)
noatty = false;
/* when tty is not accessible, try to get tty from stdout */
else if (freopen(ttyname(fileno(stdout)), "r", stdin) != NULL)
noatty = false;
else
{
/*
* just ensure stderr is joined to tty, usually when reopen
* of fileno(stdout) fails - probably due permissions.
*/
if (!isatty(fileno(stderr)))
{
fprintf(stderr, "missing a access to terminal device\n");
exit(1);
}
noatty = true;
fclose(stdin);
}
}
else
noatty = false;
当我没有 tty 且无法使用 stdin
时,我正在使用 newterm
函数,允许指定输入流:
if (noatty)
/* use stderr like stdin. This is fallback solution used by less */
newterm(termname(), stdout, stderr);
else
/* stdin is joined with tty, then use usual initialization */
initscr();