2.9 Linux tty终端

Linux在内核启动完成以后,需要启动用户态的各种应用服务,让linux可以提供给用户使用。通常用户程序的执行过程如图所示。

1

其执行顺序是/sbin/init ——–>/sbin/mingetty ——–>/bin/login ——–>/bin/sh。Init程序的执行在前面的文章里已经描述过,本篇重点讲述tty、login、shell的工作原理和运行过程。

1、tty

1.1、基本概念

tty,用过linux操作系统的人一定听过它的大名,但是也许你从未弄清tty,因为相关的概念是很抽象和容易弄混淆的。

tty一词源于Teletypes,意思是电传打印机。在远古的小型中型大型计算机时代,小型机主机的显卡显示器和键盘就是控制台,这是人控制主机的第一人机接口;同时小型机还需要提供多个终端给多个人接入主机,终端有字符哑终端和图形终端两种,字符哑终端就是tty。

回到现在的pc时代,个人计算机只有控制台,没有终端。linux为了实现tty设备,在控制台上通过getty软件虚拟了六个字符哑终端(也叫控制台终端tty1-tty6,数量可以在/etc/inittab里自己调)和一个图型终端(X-Window), 在虚拟图形终端中又可以通过软件(如rxvt)再虚拟无限多个虚拟字符哑终端(pts/0….),网络连接telnet、ssh等创建的也都是虚拟字符哑终端。当然,linux也有自己的实际tty设备,串口终端就是实际的tty设备。

综上描述,linux中现有的tty终端有以下类型:

1.1.1、控制台虚拟字符终端/dev/ttyN

2

Linux在控制台上模拟了6个tty字符终端,对应/dev/tty1和/dev/tty6,可以使用“alt + fn”(fn=f1 – f6)组合键来进行切换。
/dev/tty0是一个特殊的设备,指向这六个终端中目前在使用的那一个。

3

其实tty驱动一共注册了63个控制台虚拟字符终端,可以在/dev/目录中看到tty1 – tty63,但是init程序只创建了6个对应的用户态程序。

4

1.1.2、其他虚拟字符终端/dev/pty/

也叫伪终端(/dev/pty/),在网络连接和图形终端中虚拟字符终端,需要成对的虚拟逻辑终端设备(即master和slave设备)。

形式有两种,一种是/dev/ptyp3和/dev/ttyp3形式(ptypN是master,ttypN是slave),另一种是/dev/ptm3和/dev/pts/3形式(ptm N是master,pts/N是slave,也有一对多的形式,即只有一个/dev/ptm对应多个/dev/pts/N)。
其设计的思想是,应用程序在使用虚拟字符终端时和使用实际字符终端方法是一致的,slave设备提供虚拟字符终端对应用程序接口,master设备关注实际不同方式通道的接口。

比如,我们通过ssh登陆的shell,就是一种网络连接虚拟字符终端:

5

1.1.3、串口字符终端/dev/ttySN

串口字符终端的形式是/dev/ttyS0 – ttySn。

在linux系统中,串口是一种实际的字符终端,不再是虚拟的字符终端。串口驱动是标准的tty驱动。

可以通过SOL串口登陆到系统上,查看串口终端的情况:

6

1.1.4、当前字符终端/dev/tty

/dev/tty表示当前使用的字符终端,在所有上述的虚拟和实际终端中,使用/dev/tty都会映射到当前的终端中。

7

“tty”命令,就是显示当前字符终端的名字。
注意,/dev/tty不同于/dev/tty0,/dev/tty0是目前使用的控制台虚拟字符终端。

1.1.、控制台/dev/console

所谓控制台/dev/console,也是一个或多个字符终端,在使用角度上说,就是所有的printk内核信息都会向此终端打印。

上述的虚拟终端和实际终端都可以充当控制台,只要你通过register_console()函数(linuxsrc/kernel/printk.c)将终端注册成控制台。如果你注册了多个终端成为控制台,那么内核信息会打印到多个终端上,原理可以参考其中的printk()函数的实现。
通常linux系统默认的控制台是/dev/tty0。

1.2、tty内核实现

1.2.1、tty驱动

tty驱动就是字符终端设备的驱动,虚拟字符终端、串口字符终端、控制台字符终端都需要实现自己的tty驱动。Linux tty驱动模型就是对tty设备使用的包装,所有的tty设备提供统一标准的接口。Tty驱动的层次如下图:

8

可以看到整个tty内核由3部分组成:tty核心、tty线路规程、tty驱动。最上层是tty核心,标准的tty处理代码,对所有tty设备是一样的;tty线路规程,负责原始数据的格式化,处理一些协议转换,不同的协议有不同的线路规程,可以通过tty_register_ldisc()函数注册自己的线路规程;tty驱动负责和硬件的实际交互数据,tty核心也可以不经过tty线路规则直接和tty驱动交互。

可以通过/proc文件,查看注册的tty驱动:

9

在sys文件下也有自己的目录:

10

tty驱动,主要是tty_register_driver()和tty_register_device()函数。其实现在linuxsrc/drivers/char/tty_io.c中:

11
12

可以看到tty驱动就是在标准字符驱动基础上进行了一层封装。一个标准的字符设备标准open、close、read、write函数调用下来,最早是tty核心的函数,往下是tty线路规程函数、再往下才是用户实现的和硬件交互的函数。

13

1.2.2、uart串口驱动

所谓的uart串口驱动是在tty的基础上进行了更进一步的封装,整个驱动就变成了四层:tty核心 -> tty线路规程-> tty驱动-> uart驱动。
Uart驱动中的关键函数是uart_register_driver()和uart_add_one_port()。uart_register_driver负责将一套标准的uart函数注册成tty驱动,uart_add_one_port函数想标准驱动注册自己的串口交互函数。其实现在linuxsrc/drivers/serial/serial _core.c中:

14
15

1.2.3、控制台console和printk函数

所谓控制台console,就是供printk函数将内核信息打印到其上面的字符终端。在printk函数的实现当中我们可以看到其实现,在linuxsrc/kernel/printk.c中:

printk调用关系是:printk() –> vprintk() –> emit_log_char ()、release_console_sem () 。emit_log_char函数将内核打印信息打印进内核缓存log_buf,供dmesg和klogd使用;release_console_sem函数负责将内核打印信息打印到控制台console上。

release_console_sem调用关系是:release_console_sem () –> call_console_drivers () –> _call_console_drivers () –> __call_console_drivers () 。

16

可以使用register_console()函数注册console:

17

1.2.4、标准输入输出设备的内核初始化

在linux kernel初始化过程中,有一段很有意思的输入输出设备初始化代码。在start_kernel –> rest_init –> init进程中,在linuxsrc/init/main.c中:

18

关于修改文件描述符的操作,用户态还有函数:

       int dup(int fildes);
       int dup2(int fildes, int fildes2);

2、linux用户程序启动流程

2.1、tty用户程序

从前面可以看到,tty驱动在注册驱动的同时创建了设备文件/dev/ttyN,而初始化和使用这些tty设备的用户态程序有mingetty、agetty。

在/sbin/init的配置文件/etc/inittab文件中,可以看到对mingetty、agetty的使用。一般串口终端ttySn使用agetty,ttyN控制台虚拟终端使用mingetty。

19

2.1.1、mingetty

mingetty由一个独立的软件包mingetty-1.08.tar.gz提供。/sbin/init调用mingetty以后,mingetty的功能非常简单,主要有以下功能:

  • 1、打开命令选项指定的tty设备,使用dup2函数将打开的tty设备指定为当前进程的标准输入、输出、错误输出设备(fd 0/1/2);
  • 2、等待用户输入用户名;
  • 3、使用execl()函数调用 “/bin/login”,并将相应的选项传递给login程序。

20

2.1.2、agetty

agetty由软件包util-linux-ng-2.18.tar.gz提供,agetty相比较mingetty功能更为强大,可以完全兼容mingetty。为什么还要使用mingetty?因为mingetty比较小巧,资源占用最小。

初始化时Agetty比mingetty多干一件事时,就是根据输入参数,配置tty设备的各种参数。这是mingetty没有的功能。

2.2、login

mingetty、agetty最后一件事就是调用login程序,login程序的作用就是校验用户名和密码,合法的用户名和密码才能登入系统,并赋给相应的权限。

2.2.1、shadow

login程序由shadow-4.0.15.tar.bz2软件包提供。Shadow软件包提供了一整套的用户管理工具:chage, chfn, chgpasswd, chpasswd, chsh, expiry, faillog, gpasswd, groupadd,groupdel, groupmod, grpck, grpconv, grpunconv, lastlog, login, logoutd, newgrp, newusers,nologin, passwd, pwck, pwconv, pwunconv, sg(→newgrp), su, useradd, userdel, usermod。

常见的有:登入登出系统(login、logoutd),增加用户组groupadd,增加用户useradd,修改用户密码passwd。下面详细的描述用户管理相关的一些配置文件格式。

2.2.1.1、/etc/group

用户组配置文件,使用groupadd命令添加用户组时,配置会添加到该文件。

21

The format of the /etc/group file is as follows:

“groupname:!:GID:member,member,...”

Where:

groupname
   The name of the group

!  The field that normally holds the password, but that is now relocated to the /etc/gshadow file.

GID
   The numerical group ID number

member
   List of group members
2.2.1.2、/etc/passwd

用户配置文件,使用useradd命令添加用户组时,配置会添加到该文件。在使用shadow时,实际的密码会保存到/etc/shadow文件当中。

22

A non-shadowed /etc/passwd file has the following format:

“username:passwd:UID:GID:full_name:directory:shell”

Where:

username
   The user (login) name

passwd
   The encoded password

UID
   Numerical user ID

GID
   Numerical default group ID

full_name
   The user's full name - Actually this field is called the GECOS(General Electric Comprehensive Operating System) field and canstore information other than just the full name.  The Shadow commands and manual pages refer to this field as the comment field.

directory
   User's home directory (Full pathname)

shell
   User's login shell (Full Pathname)
2.2.1.3、/etc/shadow

用户密码的实际存储文件。

23

The /etc/shadow file contains the following information:

“username:passwd:last:may:must:warn:expire:disable:reserved”

Where:

username
   The User Name

passwd
   The Encoded password
last
   Days since Jan 1, 1970 that password was last changed

may
   Days before password may be changed

must
   Days after which password must be changed

warn
   Days before password is to expire that user is warned

expire
   Days after password expires that account is disabled

disable
   Days since Jan 1, 1970 that account is disabled

reserved
   A reserved field

2.2.2、pam

pam全称是Pluggable Authentication Modules,中文叫“可插入认证模块”。其主要的用途是对linux权限认证的需求抽象出了一套模型架构,它是以一组so库形式存在。用户有认证方面的需求之需要配置好配置文件,调用pam库的相关接口函数即可。

24

Shadow是一套加密算法,pam是一套认证机制。Pam是可以用来对shadow提供的服务进行加强,在ssh、ftp等其他服务中都可以看到对pam的使用。

如果需要在shadow应用中打开pam的支持,需要在编译时在/configure配置时加入“–with-libpam”。确认当前使用的服务是否使用pam支持,可以用ldd查看文件是否依赖pam动态库。

25

2.2.3、调用shell

在login程序的最后,调用/etc/passwd文件中配置的用户对应的shell文件。可以在login.c中看到其实现:

26

2.3、shell

Linux系统提供多种不同的Shell以供选择。常用的有Bourne Shell(简称sh)、C-Shelll(简称csh)、Korn Shell(简称ksh)和Bourne Again Shell (简称bash)。Bourne Again Shell (即bash)是自由软件基金会(GNU)开发的一个Shell,它是Linux系统中一个默认的Shell。Bash不但与Bourne Shell兼容,还继承了C Shell、Korn Shell等优点。

2.3.1、登陆shell

登陆shell即login shell,在shell的调用名前加 “-”或者是使用—login参数的shell,就是登陆shell。

bash作为登陆shell启动时执行的startup文件如下:

* /etc/profile                                                                      
* ~/.bash_profile,~/.bash_login or ~/.profile, first existing readable file is read

2.3.2、非登陆shell

使用不带参数直接启动的shell就是非登陆shell。

bash作为非登陆shell启动时读取~/.bashrc。

注意,作为登陆shell时bash并不读取~/.bashrc,但是在文件~/.bash_profile中通常都有如下语句来读取~/.bashrc:if [ –f ~/.bashrc ]; then . ~/.bashrc; fi

2.3.3、非交互shell

Shell还分两种工作模式:交互式和非交互式,执行脚本时,shell就工作在非交互式模式下。

在非交互模式下,bash读取的 startup文件由环境变量BASH_ENV来决定。“$BASH_ENV”会被执行调用。

2.3.4、环境变量

环境变量,或者称为全局变量,存在与所有的shell 中,在你登陆系统的时候就已经有了相应的系统定义的环境变量了。Linux 的环境变量具有继承性,即子shell 会继承父shell 的环境变量。

本地变量,当前shell 中的变量,很显然本地变量中肯定包含环境变量。Linux 的本地变量的非环境变量不具备继承性。
有几个相关的命令:

env 和printenv
这两个命令用于打印所有的环境变量;

set
用于显示与设置当前本地 变量。单独一个set 就显示了当前环境的所有的变量,它肯定包括环境变量和一些非环境变量;

unset
用于清除变量。不管这个变量是环境变量还是本地变量,它都可以清除;

export
用于把变量变成当前shell 和其子shell 的环境变量,存活期是当前的shell 及其子shell ,因此重新登陆以后,它所设定的环境变量就消失了。如何将环境变量永久化?修改上面介绍的那几个环境变量的配置文件;

source
当直接执行一个脚本的时候,其实是在一个子shell 环境运行的,即开启了一个子shell 来执行这个脚本,脚本执行完后该子shell 自动退出。有没有办法在当前shell 中执行一个脚本呢?使用source 命令就可以让脚本在当前shell 中执行。

3、参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值