这两天在制作云镜像时,之前的centos6.8旧版本镜像存在一个问题,基于virsh console命令登录虚机,会出现输入输出数据杂糅的问题,导致无法登录。
1 问题复现
# virsh console 1
输入的用户名密码要么输不全,要么会混到下次的输入行中。
2 问题分析
要想解决此问题,首先要了解一下可以连接linux的设备的类型。
- 串口终端:与计算机的串行端口相连接的终端设备,通常将串口相连接的设备都是字符设备,串口最大的用途是连接终端,一次常被称为串口终端,这些设备对应的文件位置在
/dev/ttySn
,设备号通常为ttyS0
、ttyS1
等。 - 伪终端:伪终端是成对的逻辑终端,一个master终端和一个salve终端,其中slave对应
/dev/pts/
下的一个文件,而master则在内存中标识为一个文件描述符。伪终端由终端模拟器提供,终端模拟器是运行在用户态的一个应用程序。/dev/ptmx
是用于创建master和slave的文件,当一个进程打开它时,获得了一个master的文件描述符,同时在/dev/pts
下创建一个slave设备文件。master端是更接近用户显示器、键盘的一端,slave端是在虚拟终端上运行的CLI(Command Line Interface,命令行接口)程序。Linux的伪终端驱动程序,会把“master端(如键盘)写入的数据”转发给slave端供程序输入,把“程序写入slave端的数据”转发给master端供(显示器驱动等)读取。
ssh和telnet则是使用伪终端实现的,虚拟终端的个数不受限制。 - 虚拟终端:控制台终端通常指与计算直接相连的终端,可以理解为物理终端,例如vmware打开虚机的操作终端界面,按
alt+[F1~F6]
更换控制台终端,默认情况下可以切换tty1~tty6。/dev/console
对应了当前的焦点终端,例如当前使用的是tty3,那么/dev/console/
则指/dev/tty3
。
除此之外,还有控制终端tty,控制终端通常是对于前台进程而言的一个概念,每一个前台进程有对应的控制终端,那么/dev/tty
就是该进程的设备文件,可以通过ps -ax
查看进程与哪个控制终端相连。对于当前登录的shell进程而言,/dev/tty
就是shell进程使用的终端,或者直接使用tty
命令查看其具体属于的终端设备。
virsh console
命令是属于串口终端一类,串口终端进程在启动之前会检查grub引导参数,并对相关的配置文件进行读取。
在centos6.8的镜像的/etc/grub.conf
的kernel行配置的最后为console=tty0 console=ttyS0,115200n8
,其含义是将kernel的启动log输入到tty0和ttyS0,且配置靠后者的优先级更高,即ttyS0作为主要console。
而在/etc/init/serial.conf
有一段说明:
# How this works:
#
# On boot, a udev helper examines /dev/console. If a serial console is the
# primary console (last console on the commandline in grub), the event
# 'fedora.serial-console-available <port name> <speed>' is emitted, which
# triggers this script. It waits for the runlevel to finish, ensures
# the proper port is in /etc/securetty, and starts the getty.
#
# If your serial console is not the primary console, or you want a getty
# on serial even if it's not the console, create your own event e.g.
# /etc/init/ttyS0.conf with content:
# # ttyS0 - agetty
# #
# # This service maintains a agetty on ttyS0.
意思是串口终端如果优先级较高的console配置在grub的commandline中,则会执行此脚本。此脚本中的命令为:
start on fedora.serial-console-available DEV=* and stopped rc RUNLEVEL=[2345]
stop on runlevel [S016]
instance $DEV
respawn
pre-start exec /sbin/securetty $DEV
exec /sbin/agetty /dev/$DEV $SPEED vt100-nav
post-stop exec /sbin/initctl emit --no-wait fedora.serial-console-available DEV=$DEV SPEED=$SPEED
usage 'DEV=ttySX SPEED=Y - where X is console id and Y is baud rate'
而在该镜像中的/etc/init/
下还存在一个ttyS0.conf
脚本文件,该脚本文件是在运行串口终端程序之前执行,其命令为:
start on stopped rc RUNLEVEL=[2345]
stop on starting runlevel [016]
respawn
instance /dev/ttyS0
exec /sbin/agetty /dev/ttyS0 115200 vt100-nav
我猜是这两个脚本执行重复了,然后我采用了如下的解决方法进行验证。
3 问题解决
- 删除
/etc/grub.conf
commandline行的console=ttyS0,115200n8
,或者将其置于console=tty
之前,这样/etc/init/serial.conf
不会得到执行; - 删除
/etc/init/ttyS0.conf
文件,只执行/etc/init/serial.conf
文件。
这两种方法均可以解决此问题,后来为了证明不是其他地方出现的问题,又在centos官网下载了6.8版本的镜像进行对比测试,测试结果无差异。