原文地址:
对于Linux内核tty设备的一点理解 作者:
tekkamanninja
虽然一直做嵌入式Linux,宿主机和开发板通信天天都在用tty设备通信,但是其实自己对TTY设备及终端的概念认识几乎是0。对于Linux内核的终端、tty、控制台等概念的认识很模糊。由于在学习的时候碰到了重定向console的问题,所以借机学习下tty的知识。以下是我对tty的认识总结,信息来源于网络和内核文档。参考资料见文章末尾。
tty一词源于Teletypes,或Teletypewriters,它是最早出现的一种终端设备,类似电传打字机,由Teletype公司生产。最初tty是指连接到Unix系统上的物理或者虚拟终端。终端是一种字符型设备,通常使用tty来统称各种类型的终端设备。随着时间的推移,当通过串行口能够建立起终端连接后,这个名字也用来指任何的串口设备。它还有多种类,例如串口(ttySn、ttySACn、ttyOn)、USB到串口的转换器(ttyUSBn),还有需要特殊处理才能正常工作的调制解调器(比如传统的WinModem类设备)等。tty虚拟设备支持虚拟控制台,它能通过键盘及网络连接或者通过xterm会话登录到计算机上。
-
其实起初终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念。
-
终端为主机提供了人机接口,每个人都通过终端使用主机的资源。终端有字符终端和图形终端两种。一台主机可以连很多终端。
-
控制台是一种特殊的人机接口, 是人控制主机的第一人机接口。而主机对于控制台的信任度高于其他终端。
对此还可以结合内核启动代码中init进程打开/dev/console和执行两次sys_dup(0),以及标准输入、标准输出、标准出错,还有就是进程fork后的标准输入输出的复制情况来一起理解。
-
而个人计算机只有控制台,没有终端。当然愿意的话,可以在串口上连一两台字符哑终端。但是linux按POSIX标准把个人计算机当成小型机来用,在控制台上通过getty软件虚拟了六个字符哑终端(或者叫虚拟控制台终端tty1-tty6)(数量可以在/etc/inittab里自己调整)和一个图型终端, 在虚拟图形终端中又可以通过软件(如rxvt)再虚拟无限多个伪终端(pts/0等)。但这全是虚拟的,虽然用起来一样,但实际上没有物理实体。所以在个人计算机上,只有一个实际的控制台,没有终端,所有终端都是在控制台上用软件模拟的。要把个人计算机当主机再通过串口或网卡外连真正的物理终端也可以,论成本,谁会怎么做呢。
终端按照其自身能力分类,可以分为:
1、哑终端(瘦客户端)
早期的计算机终端是通过串行RS-232通信的,它只能解释有限数量的控制码(CR,LF等),但没有能力处理执行特殊的转义序列功能(如清行、清屏或控制光标的位置)。简单来说就是处理能力有限的终端机,他们一般基本上只具有和机械电传打字机类似的有限功能。这种类型的终端称为哑终端。现在仍然在现代类Unix系统上得到支持,通过设置环境变量TERM=dumb。哑终端有时用来指任何类型的通过RS-232连接的传统计算机终端,不对数据进行本地处理或本地执行用户程序的串行通信终端。哑终端有时也指功能有限,只有单 {MOD}文本处理能力或直接传输每一个键入的字符而不等待主机轮询的公共计算机终端。
2、智能终端(胖客户端)
智能终端就是有能力处理转义序列,也就是说处理能力较强的终端机。
Linux系统的终端设备一般有以下几种:
/dev/console是系统控制台,是与操作系统交互的设备。系统所产生的信息会发送到该设备上。平时我们看到的PC只有一个屏幕和键盘,它其实就是控制台。目前只有在单用户模式下,才允许用户登录控制台/dev/console。(可以在单用户模式下输入tty命令进行确认)。
console有缓冲的概念,为内核提供打印输出。内核把要打印的内容装入缓冲区__log_buff,然后由console来决定打印到哪里(比如是tty0还是ttySn等)。console指向激活的终端。历史上,console指主机本身的屏幕和键盘,而tty指用电缆链接的其它位置的控制台。
某些情况下console和tty0是一致的,就是当前所使用的是虚拟终端,也是激活虚拟终端。所以有些资料中称/dev/console是到/dev/tty0的符号链接,但是这样说现在看来是不对的:根据内核文档,在2.1.71之前,/dev/console根据不同系统设定,符号链接到/dev/tty0或者其他tty*上,在2.1.71版本之后则完全由内核代码内部控制它的映射。
如果一个终端设备要实现console功能,必须向内核注册一个struct console结构,一般的串口驱动中都会有。如果设备要实现tty功能,必须要内核的tty子系统注册一个struct
tty_driver结构,注册函数在drivers/tty/tty_io.c中。一个设备可以同时实现console和tty_driver,一般串口都这么做。
这是应用程序中的概念,如果当前进程有控制终端(Controlling Terminal),那么/dev/tty就是当前进程控制台的设备文件。对于你登录的shell,/dev/tty就是你使用的控制台,设备号是(5,0)。不过它并不指任何物理意义上的控制台,/dev/tty会映射到当前设备(使用命令“tty”可以查看它具体对应哪个实际物理控制台设备)。输出到/dev/tty的内容只会显示在当前工作终端上(无论是登录在ttyn中还是pty中)。你如果在控制台界面下(即字符界面下)那么dev/tty就是映射到dev/tty1-6之间的一个(取决于你当前的控制台号),但是如果你现在是在图形界面(Xwindows),那么你会发现现在的/dev/tty映射到的是/dev/pts的伪终端上。/dev/tty有些类似于到实际所使用终端设备的一个联接。
你可以输入命令 “tty",将显示当前映射终端如:/dev/tty1或者/dev/pts/0等。也可以使用命令“ps -ax”来查看其他进程与哪个控制终端相连。
在当前终端中输入 echo “tekkaman” > /dev/tty ,都会直接显示在当前的终端中。
/dev/ttyn是进程虚拟控制台,他们共享同一个真实的物理控制台。
如果在进程里打开一个这样的文件且该文件不是其他进程的控制台时,那该文件就是这个进程的控制台。进程printf数据会输出到这里。在PC上,用户可以使用alt+Fn切换控制台,看起来感觉存在多个屏幕,这种虚拟控制台对应tty1~n,其中 :
/dev/tty1等代表第一个虚拟控制台
例如当使用ALT+F2进行切换时,系统的虚拟控制台为/dev/tty2 ,当前控制台(/dev/tty)则指向/dev/tty2
在UNIX系统中,计算机显示器通常被称为控制台(Console)。它仿真了类型为Linux的一种终端,并且有一些设备特殊文件与之相关联:tty0、tty1、tty2等。当你在控制台上登录时,使用的是tty1。使用Alt+[F1—F6]组合键时,我们就可以切换到tty2、tty3等上面去。
你可以登录到不同的虚拟控制台上去,因而可以让系统同时有几个不同的会话存在。
而比较特殊的是/dev/tty0,他代表当前虚拟控制台,是当前所使用虚拟控制台的一个别名。因此不管当前正在使用哪个虚拟控制台(注意:这里是虚拟控制台,不包括伪终端),系统信息都会发送到/dev/tty0上。只有系统或超级用户root可以向/dev/tty0进行写操作。tty0是系统自动打开的,但不用于用户登录。在Framebuffer设备没有启用的系统中,可以使用/dev/tty0访问显卡。
伪终端(Pseudo Terminal)是终端的发展,为满足现在需求(比如网络登陆、xwindow窗口的管理)。它是成对出现的逻辑终端设备(即master和slave设备, 对master的操作会反映到slave上)。它多用于模拟终端程序,是远程登陆(telnet、ssh、xterm等)后创建的控制台设备。
历史上,有两套伪终端软件接口:
BSD接口:较简单,master为/dev/pty[p-za-e][0-9a-f] ;slave为 /dev/tty[p-za-e][0-9a-f]
,它们都是配对的出现的。例如/dev/ptyp3和/dev/ttyp3。但由于在编程时要找到一个合适的终端需要逐个尝试,所以逐渐被放弃。
Unix 98接口:使用一个/dev/ptmx作为master设备,在每次打开操作时会得到一个master设备fd,并在/dev/pts/目录下得到一个slave设备(如 /dev/pts/3和/dev/ptmx),这样就避免了逐个尝试的麻烦。由于可能有好几千个用户登陆,所以/dev/pts/*是动态生成的,不象其他设备文件是构建系统时就已经产生的硬盘节点(如果未使用devfs、udev、mdev等)
。第一个用户登陆,设备文件为/dev/pts/0,第二个为/dev/pts/1,以此类推。它们并不与实际物理设备直接相关。现在大多数系统是通过此接口实现pty。
我们在X Window下打开的终端或使用telnet 或ssh等方式登录Linux主机,此时均通过pty设备。例如,如果某人在网上使用telnet程序连接到你的计算机上,则telnet程序就可能会打开/dev/ptmx设备获取一个fd。此时一个getty程序就应该运行在对应的/dev/pts/*上。当telnet从远端获取了一个字符时,该字符就会通过ptmx、pts/*传递给
getty程序,而getty程序就会通过pts/*、ptmx和telnet程序往网络上返回“login:”字符串信息。这样,登录程序与telnet程序就通过“伪终端”进行通信。
-
telnet<--->/dev/ptmx(master)<--->pts/*(slave)<--->getty
如果一个程序把 pts/*看作是一个串行端口设备,则它对该端口的读/写操作会反映在该逻辑终端设备对的另一个/dev/ptmx上,而/dev/ptmx则是另一个程序用于读写操作的逻辑设备。这样,两个程序就可以通过这种逻辑设备进行互相交流,这很象是逻辑设备对之间的管道操作。对于pts/*,任何设计成使用一个串行端口设备的程序都可以使用该逻辑设备。但对于使用/dev/ptmx的程序,则需要专门设计来使用/dev/ptmx逻辑设备。
通过使用适当的软件,就可以把两个甚至多个伪终端设备连接到同一个物理串行端口上。
-
实验:
-
1、在X下打开一个或N个终端窗口
-
2、#ls /dev/pts/*
-
3、关闭这个X下的终端窗口,再次运行;比较两次输出信息就明白了。
-
输出为/dev/ptmx /dev/pts/1存在一(master)对多(slave)的情况
串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作是一个字符设备。有段时间串行端口设备通常被称为终端设备,那时它的最大用途就是用来连接终端,所以这些串行端口所对应的设备名称是/dev/tts/0(或/dev/ttyS0)、/dev/tts/1(或/dev
/ttyS1)等,设备号分别是(4,0)、(4,1)等(对应于win系统下的COM1、COM2等)。若要向一个端口发送数据,可以在命令行上把标准输出重定向到这些特殊文件名上即可。
例如,在命令行提示符下键入:echo tekkaman> /dev/ttyS1会把“tekkaman”发送到连接在ttyS1(COM2)端口的设备上。
在2.6以后的内核中,部分三星芯片(例如S3C24x0等)将串口终端设备节点命名为ttySACn。TI的Omap系列芯片从2.6.37开始芯片自带的UART设备开始使用专有的的omap-uart驱动,故设备节点命名为ttyOn,以区别于使用8250驱动时的设备名“ttySn”。
还针对很多不同的字符设备存在有很多其它种类的终端设备特殊文件,例如针对ISDN设备的/dev/ttyIn终端设备等。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
其实在理解以上概念的时候,如果了解终端的发展历程,就可以比较容易理解tty、终端的概念。所以请大家阅读最后推荐的wiki英文网页,有助于理解上面的概念。当然,内核文档也是必不可少的参考资料,我顺手翻译了一下。
内核文档/Documentation/devices.txt翻译节选:
-
**** 终端设备
-
-
Terminal, or TTY devices are a special class of character devices. A
-
terminal device is any device that could act as a controlling terminal
-
for a session; this includes virtual consoles, serial ports, and
-
pseudoterminals .
-
终端或这TTY设备是一类特殊的字符设备。
-
一个终端设备是任何对于一个会话可以作为控制终端的设备。
-
这包括虚拟控制台、串口和伪终端(PTYs)。
-
-
All terminal devices share a common set of capabilities known as line
-
disciplines; these include the common terminal line discipline as well
-
as SLIP and PPP modes.
-
所有终端设备共享一系列常规能力-线路规程。
-
这包含常见的终端线路规程,例如SLIP和PPP模式。
-
-
All terminal devices are named similarly; this section explains the
-
naming and use of the various types of TTYs. Note that the naming
-
conventions include several historical warts; some of these are
-
Linux-specific, some were inherited from other systems, and some
-
reflect Linux outgrowing a borrowed convention.
-
所有终端设备的命名都比较简单。本节介绍不同类型TTY的命名和用途。
-
注意命名的约定包含了一些历史需求:
-
某些是Linux特定的,
-
某些是从其他的系统中继承下来的,
-
还有一些则反映了Linux从借鉴来的约定中发展而来的。
-
-
A hash mark (#) in a device name is used here to indicate a decimal
-
number without leading zeroes.
-
设备名中的(#)标志用于标识一个不以0开头的10进制数。
-
-
Virtual consoles and the console device
-
虚拟控制台和控制台设备
-
-
Virtual consoles are full-screen terminal displays on the system video
-
monitor. Virtual consoles are named /dev/tty#, with numbering
-
starting at /dev/tty1; /dev/tty0 is the current virtual console.
-
/dev/tty0 is the device that should be used to access the system video
-
card on those architectures for which the frame buffer devices
-
(/dev/fb*) are not applicable. Do not use /dev/console
-
for this purpose.
-
虚拟控制台是在系统视频监视器上全屏的显示终端。
-
虚拟控制台设备名为/dev/tty#,编号开始于/dev/tty1。
-
/dev/tty0是当前虚拟控制台。
-
/dev/tty0在那些帧缓冲设备(/dev/fb*)不适用的构架下可以被用来访问系统显卡。
-
而/dev/console并不用于此目的。
-
-
The console device, /dev/console, is the device to which system
-
messages should be sent, and on which logins should be permitted in
-
single-user mode. Starting with Linux 2.1.71, /dev/console is managed
-
by the kernel; for previous versions it should be a symbolic link to
-
either /dev/tty0, a specific virtual console such as /dev/tty1, or to
-
a serial port primary (tty*, not cu*) device, depending on the
-
configuration of the system.
-
控制台设备/dev/console是一个接受系统信息并在单用户模式下允许登录的设备。
-
从Linux 2.1.71开始,/dev/console由内核管理,
-
而以前的版本是一个到/dev/tty0、一个特定的虚拟控制台(如/dev/tty1)或者一个串口主(tty*,非cu*)设备动态链接,这些依赖系统配置。
-
-
-
Serial ports are RS-232 serial ports and any device which simulates
-
one, either in hardware (such as internal modems) or in software (such
-
as the ISDN driver.) Under Linux, each serial ports has two device
-
names, the primary or callin device and the alternate or callout one.
-
Each kind of device is indicated by a different letter. For any
-
letter X, the names of the devices are /dev/ttyX# and /dev/cux#,
-
respectively; for historical reasons, /dev/ttyS# and /dev/ttyC#
-
correspond to /dev/cua# and /dev/cub#. In the future, it should be
-
expected that multiple letters will be used; all letters will be upper
-
case for the "tty" device (e.g. /dev/ttyDP#) and lower case for the
-
"cu" device (e.g. /dev/cudp#).
-
串行端口是RS-232串口和任何类似的设备,无论是硬件的(如内部调制解调器)或者软件(如ISDN驱动)。
-
在Linux下,每个串口有两个设备名,主要的(callin设备)和备用的(callout设备),每类设备都通过不同的字母标识。对于任何字母X,设备名分别是/dev/ttyX# 和/dev/cux#;由于历史原因,/dev/ttyS#和/dev/ttyC#对应于/dev/cua#和/dev/cub#。未来,对于“tty”多字母的名字将会被使用,所有的字母都将是大写(如/dev/ttyDP#),对于"cu"设备则使用小写字母(如/dev/cudp#)。
-
-
The names /dev/ttyQ# and /dev/cuq# are reserved for local use.
-
名字(/dev/ttyQ#和/dev/cuq#)保留,用于本地使用。
-
-
The alternate devices provide for kernel-based exclusion and somewhat
-
different defaults than the primary devices. Their main purpose is to
-
allow the use of serial ports with programs with no inherent or broken
-
support for serial ports. Their use is deprecated, and they may be
-
removed from a future version of Linux.
-
备用设备提供基于内核的exclusion和某些与主要设备不同的默认配置。他们的主要目的是允许那些对于串口并非内部支持或是有一定问题的程序使用串口。他们的使用已经过时,他们可能会从未来的Linux版本中删除。
-
-
Arbitration of serial ports is provided by the use of lock files with
-
the names /var/lock/LCK..ttyX#. The contents of the lock file should
-
be the PID of the locking process as an ASCII number.
-
串口的仲裁是通过锁文件(/var/lock/LCK..ttyX#)来提供的。
-
锁文件的内容应该是锁定进程PID的ASCII码。
-
-
It is common practice to install links such as /dev/modem
-
which point to serial ports. In order to ensure proper locking in the
-
presence of these links, it is recommended that software chase
-
symlinks and lock all possible names; additionally, it is recommended
-
that a lock file be installed with the corresponding alternate
-
device. In order to avoid deadlocks, it is recommended that the locks
-
are acquired in the following order, and released in the reverse:
-
安装一个例如/dev/modem的链接来指向串口是常见的做法。
-
为了确保适当锁定在这些环节的存在,建议软件追踪符号并锁定所有可能的名字;
-
此外,建议为相应的备用设备安装一个锁文件。
-
为了避免死锁,建议按以下顺序获取锁,并按反向的顺序释放:
-
-
1. The symbolic link name, if any (/var/lock/LCK..modem)
-
2. The "tty" name (/var/lock/LCK..ttyS2)
-
3. The alternate device name (/var/lock/LCK..cua2)
-
1、符号链接名,如果有(/var/lock/LCK..modem)
-
2、“tty”名(/var/lock/LCK..ttyS2)
-
3、备用设备名(/var/lock/LCK..cua2)
-
-
In the case of nested symbolic links, the lock files should be
-
installed in the order the symlinks are resolved.
-
在符号链接嵌套的情况下,锁定文件应按照符号链接的顺序来安装以解决问题。
-
-
Under no circumstances should an application hold a lock while waiting
-
for another to be released. In addition, applications which attempt
-
to create lock files for the corresponding alternate device names
-
should take into account the possibility of being used on a non-serial
-
port TTY, for which no alternate device would exist.
-
在任何情况下,应用程序应该等待另一个程序释放锁后,持有这个锁。
-
此外,试图为相应的备用设备名创建锁文件的应用程序应考虑被用于非串口的TTY端口的可能性,此时没有备用设备存在。
-
-
Pseudoterminals (PTYs)
-
伪终端(PTYs)
-
-
Pseudoterminals, or PTYs, are used to create login sessions or provide
-
other capabilities requiring a TTY line discipline (including SLIP or
-
PPP capability) to arbitrary data-generation processes. Each PTY has
-
a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
-
/dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by
-
allowing each master side to be opened only once.
-
伪终端(或PTYs)用于创建登录会话或提供给其他需要tty线路规程(包括SLIP或PPP能力)能力以生成数据的进程。
-
每个PTY有一个主端(/dev/pty[p-za-e][0-9a-f])和一个从端(/dev/tty[p-za-e][0-9a-f])。
-
内核通过只允许每个主端仅允许打开一次来仲裁PTY的使用。
-
-
Once the master side has been opened, the corresponding slave device
-
can be used in the same manner as any TTY device. The master and
-
slave devices are connected by the kernel, generating the equivalent
-
of a bidirectional pipe with TTY capabilities.
-
一旦主端被打开,相应的从设备可以像任何TTY设备一样的方式被使用。
-
主从设备都和内核连接,产生相当于一个带TTY功能的双向管道。
-
-
Recent versions of the Linux kernels and GNU libc contain support for
-
the System V/Unix98 naming scheme for PTYs, which assigns a common
-
device, /dev/ptmx, to all the masters (opening it will automatically
-
give you a previously unassigned PTY) and a subdirectory, /dev/pts,
-
for the slaves; the slaves are named with decimal integers (/dev/pts/#
-
in our notation). This removes the problem of exhausting the
-
namespace and enables the kernel to automatically create the device
-
nodes for the slaves on demand using the "devpts" filesystem.
-
Linux内核的最近版本和GNU库包含了对于System V和Unix98对PTY命名方式的支持。
-
它分配一个共用的设备(/dev/ptmx)给所有的主端(打开它会自动给你一个以前未分配的PTY)和一个子目录(/dev/pts)用于从端;从端通过十进制整数(/dev/pts/#)命名。
-
这消除了命名空间枯竭的问题,并使内核通过“devpts”文件系统按需自动为从端动创建设备节点。
对于TTY系统的理解(图解):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
推荐阅读:《Linux C编程一站式学习》----第
34 章 终端、作业控制与守护进程---1. 终端
wiki百科关于终端的网页:Computer
terminal | System console | Linux
console
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以上是我参考了网上的资料后对tty的认识整理,参考资料如下:
linux
tty pty pts 概念 区别
终端 /dev/console
/dev/tty tty
终端tty、虚拟控制台、FrameBuffer的切换过程详解
LINUX下的tty,console与串口分析
linux下tty,控制台,虚拟终端,串口,console(控制台终端)详解
LINXU下的TTY、CONSOLE、串口
Linux下的console和terminal