这几天我一直在尝试了解 TTY 设备驱动程序如何在 Linux 机器上工作,但仍然无法理解这个想法。
当我们打开一个终端通过 ssh 连接到服务器时,我知道它很可能会使用伪 tty;它的作用就像终端中的 TTY 一样,处理输入的命令。
既然它使用伪类型 tty,那么在幕后它是否仍然使用 tty 技术向控制台发送命令?
通俗地说,无论使用什么终端,TTY 是否总是用于向控制台发送命令?它是万物终端的主要驱动力吗?
我了解处理输入和输出的 tty 字符设备以及向主/从设备发送信号的一堆东西。我还知道过去使用的是tty。今天,当打开我们的终端时,关于所使用的操作系统/程序是否仍然使用它?
我的知识无处不在。我对 Linux 的了解非常有限。希望获得有关 TTY 在当今 Linux 发行版中如何工作的外行解释。
答案1
我正在使用哪个 tty?
tty
- 打印连接到标准输入的终端的文件名
--man tty
例如:
$ tty
/dev/pts/0
什么类型那是tty吗?哪个设备驱动它是由什么实施的?
设备驱动程序的概念是特定于操作系统的。你特意询问了Linux,但当我试图回答这个问题时,我仍然发现了一堆特殊情况。因此,如果我们查找具体示例,我们可以更快地得到答案。
/dev/pts/0
pts/0
是第一个伪终端设备,或“pty”。 pts
表示伪终端从机。
这奴隶伪终端的行为就像一个模拟的 tty 设备。终端仿真器喜欢gnome-terminal
通过控制来工作掌握伪终端的末尾。例如,当您在窗口内按 Enter 键时gnome-terminal
,它会向主设备写入一个“换行”字符。然后在从设备上接收“换行”字符。
pty 的两端并不完全对称。将 Control-C 的字符写入主设备,可以发送信号 SIGINT 来中断使用从设备的进程。反之则不然。无论终端内部的程序写入什么字符,都不会向 发送中断信号gnome-terminal
。主设备的行为与真正的 tty 不同。
/dev/ttyS0
ttyS0
是第一个串行端口您计算机上的设备。如果有人有旧物理终端,这是他们可以插入的端口类型。这里没有狡猾的隐喻!它的工作方式仍然与历史 Unix 上的 TTY 设备相同。如果你仔细看的话,你仍然可以购买带串口的电脑:)。[1]
上面的 Control-C 示例同样适用于串行终端。如果在终端上按 Control-C,则串行端口将接收该字符,并且使用串行设备的进程可能会收到 SIGINT 并被中断。这是任何用作 tty 的设备的一个共同因素。
有一个相当大的集合常见的 TTY 行为,这需要同样适用于 Linux 将实现的多种类型的 TTY 设备。如果两个终端设备复制大量代码,那么维护起来就会非常困难,并且会浪费宝贵的 RAM。
在包括 Linux 在内的一些 Unix/类 Unix 系统中,类似的行为据说是在“线路规则”中实现的。与在伪终端从机上一样,使用相同的“线路规则”在串行端口上实现此行为。 Linux 将实现这种行为的线路规则称为TTY
......但是我们不要太在意确切的术语。关键是它是一大块共享代码。
/*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
* or rs-channels. It also implements echoing, cooked mode etc.
--https://elixir.bootlin.com/linux/v4.17/source/drivers/tty/tty_io.c[3000行]
* n_tty.c --- implements the N_TTY line discipline.
*
* This code used to be in tty_io.c, but things are getting hairy
* enough that it made sense to split things off. (The N_TTY
* processing has changed so much that it's hardly recognizable,
* anyway...)
*
* Note that the open routine for N_TTY is guaranteed never to return
* an error. This is because Linux will fall back to setting a line
* to N_TTY if it can not switch to any other line discipline.
*
* Written by Theodore Ts'o, Copyright 1994.
--https://elixir.bootlin.com/linux/v4.17/source/drivers/tty/n_tty.c[2500行]
[1] 也就是说,串行端口的实际使用往往不再涉及物理终端。一个示例用途是在没有图形硬件的简单设备上访问控制台。我们可以将设备连接到具有串行端口和终端仿真程序的PC。可以找到执行此操作的说明这里。
请注意,PC 上打开串行端口的程序将不是希望受到 tty 设备行为的影响,例如 Control-C -> 中断信号。该程序希望它表现得像一个 pty master,而不是像一个 pty Slave。此类程序将使用等效的命令有效地禁用常见的 tty 行为stty raw -echo
。
如果您查找ttyS0
,您可能会发现您的 PC 具有功能齐全的串行硬件...尽管外部没有串行端口。某些台式机主板包含串行端口引脚,您可以单独购买并使用带状电缆连接。一些商用笔记本电脑支持带有串行端口的扩展坞。
某些驱动程序可能提供行为相同但名称不同的串行端口。 ttyUSB0
Linux 上通常用于 USB 设备,它为没有内置串行端口的 PC 提供串行端口。
/dev/tty1
tty1
是 PC 上的第一个虚拟终端。第一个 tty 是文本控制台,在启动时显示消息。如果您使用图形启动plymouth
,则按 Escape 键会将 VT 切换回文本模式,以便您查看启动消息。
在大多数 Linux PC 上,您可以在至少 6 或 7 个 tty 之间切换。如果您使用图形界面,它将在特定的 tty 上运行。切换到不同的 tty 可能会显示基于文本的登录提示。
您可能已经注意到此编号与其他类型的 tty 不一致:-)。 tty0
保留以引用当前活动的 VT,保留tty1
为第一个 VT。
要在纯粹基于文本的安装中在 VT 之间切换,请使用例如 alt+f2 切换到 VT2。图形界面完全覆盖这些组合键,例如 alt+f4 通常被保留来关闭窗口。相反,图形界面已经制定了一种约定,即 ctrl+alt+f2 将切换到 VT2 等。从文本控制台切换时,此组合键也适用。
如何检查使用的是哪个设备驱动程序
$ ls -l /dev/ttyS0
crw-rw----. 1 root dialout 4, 64 Jun 9 13:17 /dev/ttyS0
^ c = character device ^ 4, 64 is the major, minor
number of the device
$ ls -l /sys/dev/char/4:64
lrwxrwxrwx. 1 root root 0 Jun 9 14:17 /sys/dev/char/4:64 ->
../../devices/platform/serial8250/tty/ttyS0
这是一个符号链接文件。它向我们展示了该设备的规范/sys
路径是/sys/devices/platform/serial8250/tty/ttyS0
。它是该类的设备tty
,并且是 的子级/sys/devices/platform/serial8250/
。我们可以找到父设备的驱动程序名称:
$ ls -l /sys/devices/platform/serial8250/driver
lrwxrwxrwx. 1 root root 0 Jun 9 13:17 /sys/devices/platform/serial8250/driver ->
../../../bus/platform/drivers/serial8250
该串行驱动程序似乎没有将自己报告为属于可加载内核模块...因为该驱动程序内置于我的主内核中。
$ ls -l /sys/bus/platform/drivers/serial8250/module
ls: cannot access '/sys/bus/platform/drivers/serial8250/module': No such file or directory
$ grep 8250 /boot/config-`uname -r`
CONFIG_SERIAL_8250=y
...
$ ls -l /dev/tty1
crw--w----. 1 gdm tty 4, 1 Jun 9 13:18 /dev/tty1
$ ls -l /sys/dev/char/4:1
lrwxrwxrwx. 1 root root 0 Jun 9 15:57 /sys/dev/char/4:1 ->
../../devices/virtual/tty/tty1
虚拟终端设备是虚拟的:它们不注册为硬件设备的子设备。我们无法询问哪个驱动程序绑定到硬件设备,因为没有一个:-)。
$ ls -l /dev/pts/0
crw--w----. 1 alan tty 136, 0 Jun 9 15:52 /dev/pts/0
$ ls -l /sys/dev/char/136:0
ls: cannot access '/sys/dev/char/136:0': No such file or directory
Linux 设备通常会列在其中/sys
。对于非虚拟设备,这使得可以查找其设备驱动程序。然而,ptys 是虚拟的:不是任何硬件设备的子设备。这意味着不可能询问哪个驱动程序绑定到其硬件设备。
但我无法以正常方式向您确认这一点,因为 pty 从设备/sys
首先没有在其中列出。这是 Linux 中的一个非常特殊的情况。有一个文件系统类型devpts
,安装在/dev/pts/
,它在现代 Linux 系统上提供 pty 设备节点。最近,可以有多个独立的devpts
安装,例如在容器中运行其他 Linux 操作系统systemd-nspawn。通常设备通过编号来标识,分为主要编号和次要编号。但是,我可以看到代表一个的相同设备号完全独立的 pty 设备,取决于devpts
它打开的文件系统。这个特殊情况2016年造成了一些问题。
答案2
ssh
并非在每种情况下都分配 TTY。如果用命令调用则没有:
ssh user@host tty
not a tty
这是可以的,因为通常命令只需要stdin
, stdout
, 和stderr
。
tty 的分配可以用-t
或强制执行-tt
。