如何在C中可靠地找到与进程关联的终端名称?

时间:2016-12-08 13:58:30

标签: c terminal posix

请参阅以下代码。

<div class="drop">
  <input type="text" name="class" placeholder="Class" onfocus="dropdown(0)"/>
  <ul class="content">
    <li onclick="input(0)">Option 1</li>
    <li onclick="input(1)">Option 2</li>
    <li onclick="input(2)">Option 3</li>
    <li onclick="input(3)">Option 4</li>
  </ul>
</div>

我按如下方式编译并运行它。

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

int main()
{
    printf("ttyname(0): %s\n", ttyname(0));
    printf("ttyname(1): %s\n", ttyname(1));
    printf("ttyname(2): %s\n", ttyname(2));
    printf("ctermid(NULL): %s\n", ctermid(NULL));

    /* Sleep for sometime so that we can manually run the ps command to
     * see the terminal associated with the process. */
    sleep(10);

    return 0;
}

在另一个终端中,我运行$ gcc foo.c $ ./a.out ttyname(0): /dev/pts/3 ttyname(1): /dev/pts/3 ttyname(2): /dev/pts/3 ctermid(NULL): /dev/tty 命令确认终端名称。

ps

到目前为止一切都很好。我的程序正确打印终端。

但是,当stdin,stdout和stderr被重定向时,我的程序无法输出终端信息。

$ ps -ef | grep a.out | grep -v grep
coder     1498  1473  0 19:19 pts/3    00:00:00 ./a.out

在另一个终端,我运行$ ./a.out < /dev/null > foo.txt 2> /dev/null ,我可以看到ps确实与他的过程相关联。

/dev/pts/3

但在$ ps -ef | grep a.out | grep -v grep coder 1536 1473 0 19:22 pts/3 00:00:00 ./a.out 退出并在./a.out检查其输出后,我看不到这些信息被捕获。

foo.txt

由于{st}在stdin,stdout和stderr重定向时$ cat foo.txt ttyname(0): (null) ttyname(1): (null) ttyname(2): (null) ctermid(NULL): /dev/tty 无法提供任何有意义的信息,因此ctermid() always returns /dev/tty,我能做些什么来可靠地确定与进程关联的终端?我理想地寻找适用于任何标准Unix或Linux系统的解决方案,但如果不可行,那么Linux特定的解决方案也可以。

1 个答案:

答案 0 :(得分:3)

  

当stdin,stdout和stderr被重定向时,我的程序无法输出终端信息

是的,ttyname()返回(a)在指定文件描述符上打开的终端设备的名称。当文件描述符不引用终端时,没有这样的设备。在这种情况下,ttyname()被记录为返回NULL,以及指定文件描述符未与终端关联的任何其他文件。

  

如何可靠地确定与流程关联的终端?

您首先必须自己确定与该过程相关的“终端”是什么意思。原则上,文件描述符0,1和2以及甚至更多可能都连接到不同的终端设备。它们的 none 可能是进程的控制终端,我认为这可能是您实际需要的。

如果进程想要访问其控制终端(假设它有一个),独立于其标准流的重定向,那么它应该打开由{{1返回的字符串命名的设备如果有的话。那个glibc ctermid()总是返回ctermid()是无关紧要的 - 因为设备通常被命名,它作为访问进程控制终端的同义词。

然而,据我所知,没有便携,可靠的方法来确定任何设备(包括控制终端)的与流程无关的名称。内核在设备名称方面本身并不起作用 - 这些名称存在于文件系统中,是为了方便用户空间进程而提供的。此外,任何给定的设备原则上都可以有多个引用它的文件名。

但是,在Linux上,您可以从/proc/self/stat获取进程控制终端的主设备号和次设备号。原则上,您可以解压缩这些数字

  • 将它们转换为相应的传统文件名,大概是在"/dev/tty"的帮助下,或

  • 扫描/proc/devices文件系统以查找匹配的设备文件,并报告其名称。

前者较便宜,但有点投机;后者,如果成功,将返回存在的设备文件的名称,并且肯定会引用所需的设备。

您还可以在此处查看建议:https://unix.stackexchange.com/questions/151812/get-device-node-by-major-minor-numbers-pair,但我发现其中至少有一些不适用于我的系统。