Tim*_*Tim 8 tty controlling-terminal pseudoterminal
在 Lubuntu 18.04 上,我在 lxterminal 中运行了一个 shell。它的控制终端是当前的伪终端从机:
$ tty
/dev/pts/2
Run Code Online (Sandbox Code Playgroud)
我想知道我当前的控制终端/dev/pts/2
和/dev/tty
.
/dev/tty
就像我当前的控制终端/dev/pts/2
:
$ echo hello > /dev/tty
hello
$ cat < /dev/tty
world
world
^C
Run Code Online (Sandbox Code Playgroud)但它们似乎是不相关的文件,而不是一个符号链接或硬链接到另一个:
$ ls -lai /dev/tty /dev/pts/2
5 crw--w---- 1 t tty 136, 2 May 31 16:38 /dev/pts/2
13 crw-rw-rw- 1 root tty 5, 0 May 31 16:36 /dev/tty
Run Code Online (Sandbox Code Playgroud)对于不同控制终端的不同会话,if
/dev/tty
保证是它们的控制终端。它如何成为不同的控制终端,而不是符号链接或硬链接?
那么它们之间的关系和区别是什么?任何帮助深表感谢!
这篇文章来自于较早的一个命令`tty`和文件`/dev/tty`的输出都是指当前bash进程的控制终端吗?
Ste*_*itt 13
tty
第 4 节中的联机帮助页声明如下:
文件/dev/tty是一个字符文件,主编号为5,次编号为0,通常模式为0666 和owner.group root.tty。它是进程控制终端的同义词,如果有的话。
除了
ioctl(2)
tty所指的设备支持的ioctl(2)
请求外,TIOCNOTTY
还支持请求。
TIOCNOTTY
将调用进程与其控制终端分离。
如果该进程是会话领导者,则将
SIGHUP
和SIGCONT
信号发送到前台进程组,当前会话中的所有进程都将失去其控制 tty。此
ioctl(2)
调用仅适用于连接到/dev/tty 的文件描述符 。当守护进程在终端被用户调用时,它会被守护进程使用。该进程尝试打开/dev/tty。如果打开成功,则使用 将自身与终端分离TIOCNOTTY
,而如果打开失败,则显然没有附加到终端,不需要分离自身。
这将部分解释为什么/dev/tty
不是控制终端的符号链接:它将支持额外的ioctl
,并且可能没有控制终端(但进程总是可以尝试访问/dev/tty
)。然而,文档是不正确的:额外ioctl
的不仅可以通过 /dev/tty
(参见mosvy 的回答,这也对 的性质给出了更合理的解释/dev/tty
)。
/dev/tty
可以代表不同的控制终端,而不是链接,因为实现它的驱动程序决定了调用进程的控制终端是什么(如果有的话)。
您可以将其视为/dev/tty
控制终端,从而提供仅对控制终端有意义的功能,而/dev/pts/2
等是普通终端,其中一个可能恰好是给定进程的控制终端。
小智 6
/dev/tty
是一个“神奇”的字符设备,打开时会返回当前终端的句柄。
假设控制终端是/dev/pts/1
,则通过via打开的文件描述符/dev/pts/1
和通过via打开的文件描述符/dev/tty
将引用同一个设备;任何写入、读取或其他文件操作在它们中的任何一个上都会以相同的方式进行。
特别是,它们将接受相同的 ioctl 集,并且TIOCNOTTY
不是只能通过/dev/tty
.
ioctl(fd, TIOCNOTTY)
在引用终端的任何文件描述符上的工作方式都是相同的,前提是它是调用它的进程的控制终端。
/dev/tty
描述符是通过打开, /dev/pts/1
, /dev/ptmx
(在这种情况下,ioctl 将作用于其相应的从属设备)获得的,还是最近通过调用 获得的,这并不重要ioctl(master, TIOCGPTPEER, flags)
。
例子:
$ cat <<'EOT' >tiocnotty.c
#include <sys/ioctl.h>
#include <unistd.h>
#include <err.h>
int main(int ac, char **av){
if(ioctl(0, TIOCNOTTY)) err(1, "io(TIOCNOTTY)");
if(ac < 2) return 0;
execvp(av[1], av + 1);
err(1, "execvp %s", av[1]);
}
EOT
$ cc -W -Wall tiocnotty.c -o tiocnotty
$ ./tiocnotty
$ ./tiocnotty </dev/tty
$ tty
/dev/pts/0
$ ./tiocnotty </dev/pts/0
Run Code Online (Sandbox Code Playgroud)
而且,它不会真正将当前进程与 tty“分离”;该进程仍然能够从中读取数据,^C
终端上的 a 将杀死它,等等。它对不是会话领导者的进程的唯一影响是 tty 将不再可通过 访问/dev/tty
,并且将不再是列为控制 tty /proc/PID/stat
:
$ ./tiocnotty cat
^C
$ ./tiocnotty cat
^Z
[2]+ Stopped ./tiocnotty cat
$ ./tiocnotty cat
foo
foo
^D
$ ./tiocnotty cat /dev/tty
cat: /dev/tty: No such device or address
$ ./tiocnotty awk '{print$7}' /proc/self/stat
0
Run Code Online (Sandbox Code Playgroud)
[第7个字段/proc/<pid>/stat
是控制tty的设备id,参见proc(5)
]
如果调用它的进程是会话领导者,它将真正将会话与 tty 分离,并从会话中向前台进程组发送SIGHUP
/对。SIGCONT
但即便如此,终端也不会关闭,并且进程仍然能够从中读取数据(如果它在以下情况下幸存下来)SIGHUP
:
$ script /dev/null -c 'trap "" HUP; exec ./tiocnotty cat'
Script started, file is /dev/null
lol
lol
^C^C^C^C^C # no controlling tty anymore
wtf
wtf
^D # but still reading fine from it
Script done, file is /dev/null
Run Code Online (Sandbox Code Playgroud)
/dev/tty
不是像/dev/stdin
=> /dev/fd/0
=> /proc/self/fd/0
=>这样的符号链接/dev/pts/0
,因为它的发明早于像 procfs 这样的虚拟动态文件系统(并且通常早于符号链接)。许多程序已经开始依赖于其特定的语义(例如,当控制终端不可访问时/dev/tty
失败)。ENODEV