ARM linux源码分析之init进程创建和执行过程

其 中,S:代表启动相应的进程,K:代表杀死相应的进程。nn:是00至99的两位数字,不过在有些系统中是000至999三位数字。 在不同目录中的链接应采用同一数字。例如,如果某个服务在rc3.d中启动时名为S45.myscript,那么如果希望它在rc2.d中启动,应当使用 链接名S45.myscript。script_name:相应脚本的文件名,根据所在操作系统的不同,它们可能位于下列目录中:/usr/sbin/init.d、/etc/rc.d、/etc/init.d。当 init进程调用相应的运行级别脚本时,杀进程按照从高到低的K序号进行,即K23.myscript -> K12.named;而启动进程按照从低到高的序号进行。综上所述:init执行的基本流程如下:1.解析/etc/inittab:执行sysinit命令指定的进程,以前通常是/etc/init.d/rcS,在新版本的init程序中则通常是/etc/rc.d/rc.sysinit脚本。

2.执行/etc/rc.d/rc.sysinit:这是由init执行的第一个脚本,此步进行的工作包括配置网络、配置内核参数、挂载root文件系统、检查文件系统、设置系统时钟、配置机器、开启交换空间等。

3.执行/etc/rc.d/rcX.d/[K…][S…]:根据定义的initdefault运行级别,执行对应wait命令指定的程序,这会运行对应目录下的各个程序,并等待它们运行完。在rcX.d目录下,首先终止K开头的服务(用来关闭一个服务),然后启动S开头的服务(用来启动一个服务)。对每一个运行级别来说,在/etc/rc.d子目录中都有一个对应的下级目录。这些运行级别的下级子目录的命名方法为rcX.d, 其中X就是代表运行级别的数字。在各个运行级别的子目录中,都建立有到/etc/rc.d/init.d子目录中命令脚本程序的符号链接,链接的名称在K与S后有一个数字,表示执行顺序,数字小的先执行,例如K01tog-pegasus、S00microcode_ctl。对以K开头的脚本执行时系统会传递stop参数,而S开头的脚本系统会传递start参数。

4.执行/etc/rc.d/rc.local:Redhat中运行模式2,3,5都把/etc/rc.d/rc.local作为初始化脚本中的最后一个文件,所以用户可以自己在这个文件中添加一些需要在其他初始化工作之后,登陆之前执行的命令。5.执行getty程序:为每个联机终端使用fork()创建一个子进程,并在子进程中运行getty程序,init进程则调用wait(),进入等待子进程结束状态。getty程序设置终端类型、属性、速度和线路规程等。对于字符界面的运行级别(如级别2和3),它会打开并初始化一个tty端口,显示提示信息。通常,若/etc/issue文本文件存在,则getty会首先显示其中的文本信息,然后显示登录提示信息(例如“plinux login:” ),出现字符登录界面,并等待用户键入用户名和口令。可以在inittab文件中配置使用哪一种getty程序(在“id:runlevels:action:process”的process部分指定,并可以传递相应的getty参数),如agetty, getty, mgetty, uugetty, mingetty,fbgetty等。getty程序只能由超级用户执行。注意如果第1步中的inittab文件指定的默认运行级别是图形用户界面形式(如级别5),则init程序会转向去执行/etc/X11/prefdm脚本,它会执行/usr/sbin/gdm,启动图形登录界面。GDM管理的不只是X的启动,还有登录,注销,挂起等一系列操作。启动登录界面(图形或字符界面),并输入完用户名后,getty会调用login程序。

6.执行login程序:getty调用exec()执行login程序,以核对输入的用户名和口令。由于调用了exec(而不是fork),login的执行环境会覆盖getty的执行环境。login进程会读取/etc/passwd,以用户名和口令。login根据用户输入的用户名,从口令文件passwd中取得对应用户的登录项,然后调用getpass()以显示”password:”提示信息,读取用户键入的密码,然后使用加密算法对键入的密码进行加密处理,并与口令文件中该用户项中pw_passwd字段作比较。如果用户几次键入的密码均无效,则login程序会以出错码1退出执行,表示此次登录过程失败。此时父进程(进程init)的wait()会返回该退出进程的pid,因此会根据记录下来的信息再次创建一个子进程,并在该子进程中针对该终端设备再次执行getty程序,重复上述过程。如果用户键入的密码正确,则login就会把当前工作目录(Currend Work Directory)修改成口令文件中指定的起始工作目录。并把对该终端设备的访问权限修改成用户读/写和组写,设置进程的组ID。然后利用所得到的信息初始化环境变量信息,例如起始目录(HOME=)、使用的shell程序(SHELL=)、用户名(USER=和LOGNAME=)和系统执行程序的默认路径序列(PATH=)。接着显示/etc/motd文件(message-of-the-day)中的文本信息,并检查并显示该用户是否有邮件的信息。最后login程序改变成登录用户的用户ID,并执行口令文件中该用户项中指定的shell程序,如/bin/bash或/bin/csh等。有关login程序的一些执行选项和特殊访问限制的说明,可参见Linux系统中的在线手册页(man -8 login)。

7.执行shell程序或x-windows:如果用户名和口令正确,login调用exec执行shell命令行解释程序(当然,也可以执行X-windows的图形界面,如果用户设置了的话)。登录shell会首先从/etc/profile文件以及$HOME/.bash_profile文件(或.bashrc文件,若存在的话)读取命令并执行。因此用户可以把每次登录时都要执行的命令放在.bash_profile文件中。如果在进入shell时设置了ENV环境变量(或者在.bash_profile文件中设置了该变量),则shell还会从$ENV指定的文件中读去命令并执行。因此我们也可以把每次运行shell都要执行的命令放在ENV变量指定的文件中。设置ENV环境变量的方法是把下列语句放在你起始目录的.bash_profile文件中: ENV=$HOME/.anyfilename; export ENV。运行shell时,原来的getty进程最终被替换成了bash进程,对应的getty,login,bash这三个程序也就具有相同的进程ID。在成功登录到Linux系统后,你会发现(使用”top”或”ps –ax”命令)自己终端原来的getty进程已经找不到了。因为getty进程执行了login程序,被替换成了login进程,并且最后被替换成你的登录shell进程。对于图形用户界面,login程序最后会被替换成图形界面进程(如gnome-session程序)。

8.Linux运行时:init进程会负责收取孤儿进程。如果某个进程创建子进程之后,在子进程终止之前终止,则子进程成为孤儿进程。在Linux中所有的进程必须属于单棵进程树,所以孤立进程必须被收取。一旦进程成为孤儿,它会立即成为init进程的子进程。这是为了保持进程树的完整性。

9.用户注销:当某个终端或虚拟控制台上的用户注销之后,该终端上的所有进程都会被终止(killed),包括bash。然后,init进程就会调用fork为该终端或虚拟控制台重新创建一个getty进程,以便能够让其他用户登录。这是为什么呢?你应该发现,当用户登录时,“getty”用的是“exec”而不是“fork”系统调用来执行“login”,这样,“login”在执行的时候会覆盖“getty”的执行环境(同理,用户注册成功后,“login”的执行环境也会被shell占用)。所以,如果想再次使用同一终端,必须再启动一个“getty”。对于图形界面,用户注销后会回到图形登录界面。

10.系统关闭:init负责杀死所有其它的进程,卸载所有的文件系统并停止处理器的工作,以及任何其它被配置成要做的工作。

看着它或是汹涌或是平静,然而一直相随,不离不弃。

ARM linux源码分析之init进程创建和执行过程

相关文章:

你感兴趣的文章:

标签云: