摘要:
学习如何关闭、重启Linux系统,提示用户们系统正在关闭,切换到一个更加严格或者宽松的运行级别。你可以利用本文来备考LPI 101考试,或者仅仅是学习如何关闭、重启和改变运行级。
概览:
在本文,你将学习(1)关闭或重启你的Linux系统,(2)警告用户系统正在关闭,(3)切换到单用户模式或者更高或更低的优先级。具体是:
- 设置默认运行级
- 切换运行级
- 单用户模式
- 从命令行关闭或者重启系统
- 提示用户主要的系统事件,包括切换到其他运行级
- 正确地终止进程
除非另外说明,本文中的例子使用Fedora8(2.6.26内核)系统。upstart的例子使用Fedora13(2.6.34内核)或者Ubuntu10.10(2.6.35内核)。systemd例子使用Fedora17(3.4.4内核)。如果读者使用其他系统,测试结果可能与本文不同。
本文帮助读者备考LPI的101.3目标,本目标的权重是3.
预备知识
为了最大程度从本文受益,读者应该具有Linux的基本知识和一个可以使用的Linux系统来试验本文提到的命令。
运行级
级别 | 作用 |
---|---|
0 | 关闭(停止)系统 |
1 | 单用户模式,通常用s或者S表示 |
6 | 重启系统 |
除了基本的运行级,不同发行版定义的运行级不同,一种常用的方式如表2。
级别 | 作用 |
---|---|
2 | 多用户模式;没有网络功能 |
3 | 多用户模式;有网络功能 |
5 | 多用户模式;有网络功能;有X Window图形环境 |
Slackware 发行版使用运行级4而不是5来运行X Window系统。Debian以及继承者如Ubuntu只使用一个运行级表示多用户模式,通常是2.具体一定要请参考发行版的文档。
默认运行级
当一个Linux系统启动时,默认运行级时通过/etc/inittab文件里的id: 项指定的。下表显示了像Fedora8或者OpenSUSE11.2这样的系统的典型情况,它们都是使用运行级5表示X Window系统。
[root@pinguino ~]# grep "^id:" /etc/inittab id:5:initdefault: |
如果你想让系统启动时进入不同的运行级,请编辑这个值,比如设置默认运行级为3.
改变运行级
有很多方式可以改变运行级。为了永久性改变默认运行级,需要修改/etc/inittab文件。
如果你仅仅是在一次启动时进入不同的运行级,你可以按照下面的来做。假设你刚刚安装了一个新内核,并且需要在启动X Window系统前利用新内核编译一些模块,此时,你需要启动系统进入运行级3来完成。在启动时编辑GRUB命令行或者在LILO增加参数可以做到这些。使用一个数字来指定需要的运行级(本例中是3)。这里,我们用GRUB为例。假设你的/boot/menu.lst文件包含如下内容:
title Fedora (2.6.26.8-57.fc8) root (hd0,5) kernel /boot/vmlinuz-2.6.26.8-57.fc8 ro root=LABEL=FEDORA8 rhgb quiet initrd /boot/initrd-2.6.26.8-57.fc8.img |

移动光标到该行的最后,输入一个空格,然后输入一个数字3,如果愿意的话你可以删除quiet,或者根据需要徐改其他参数。如下图所示:

最后,按下回车键保存修改,然后按下b来启动系统。
注意: 使用LILO或者GRUB2的步骤和GRUB是不同的。但是基本原理是相同的,都是修改内核启动参数。
一旦在运行级3下完成了你的工作,你可能想进入到运行级5. 幸运地是,做到这些不需要重启系统。你可以使用telinit命令来切换运行级。使用runlevel命令来显示前一个运行级和当前运行级。如果第一个输出的第一个字母是N,表示系统启动后运行级没有改变过。下表显示了验证和改变运行级。
[root@pinguino ~]# runlevel N 3 [root@pinguino ~]# telinit 5 |
在输入telinit 5 之后,将会看到一些消息一闪而过,然后图形界面的登陆窗口会出现。打开一个终端窗口,验证运行级已经改变。如下图:
[root@pinguino ~]# runlevel 3 5 |
如果你使用ls命令来显示telinit的详细情况,可以发现它其实是init命令的一个符号链接。如下图:
[root@pinguino ~]# ls -l $(which telinit) lrwxrwxrwx 1 root root 4 2008-04-01 07:50 /sbin/telinit -> init |
init程序知道它本身是通过init还是telinit调用的,由此来判断如何工作。由于init是在启动时作为PID 1来运行的,即使你通过init而不是telinit来调用它,它也就足够聪明地知道这些(知道这是改变运行级而不是初始化启动)。所以,你也可以使用init 5而不是telinit 5来切换到运行级5.
单用户模式
与个人计算机操作系统如DOS或者Windows不同,Linux根本上就是一个多用户系统。但是,有时侯比如修复主文件系统或者数据库或者安装新硬件,多用户就遇到了问题。运行级1或者叫单用户模式此时就派上了用场。不同发行版的实际实现各不相同,但是你通常可以在启动后进入一个带shell的最小系统。通常没有网络功能也没有(或者很少)守护进程运行。在有些系统中,你必须输入密码进入,而其他系统则可以直接以root用户进入shell。单用户模式可以拯救系统,也可以破坏系统,所以在使用root用户时始终要小心。一旦完成修复工作,立即重启进入正常的多用户模式。
与切换到多用户运行级一样,你可以可以通过telinit 1进入单用户模式。由于s 或者 S 同样代表运行级1,所以也可使用telinit s代替telinit 1。
干净地关闭系统
当你使用telinit 或者init 来停止多用户活动来切换到单用户模式时,将会导致其他用户的工作和进程不正常的终止。关闭或者重启系统的最好方式是使用shutdown命令。这个命令首先向所有已经登陆的用户发送警告消息并且阻止以后的登陆,然后告诉init去切换运行级。然后init进程会向所有运行的进程发送SIGTERM信号,这些进程收到信号后应该保存数据或者自己合适的结束。5秒以后(也可以指定其他秒数),init会向仍未结束的进程发送SIGKILL信号来强制终止这些进程。
默认情况下,shutdown切换到运行级1(单用户模式)。你可以指定-h来停止系统,或者-r来重新启动。一个标准的消息会附加到你指定的消息后发送。也可以指定shutdown运行时间(hh:mm格式表示绝对时间,n分钟表示相对时间)。如果想立即关闭系统,使用now参数,这与+0作用相同。
如果已经发出来一个延时的shutdown命令,但是时间尚未到期,此时可以通过Ctrl-C来取消shutdown,也可以通过shutdown -c命令来取消上一次关机。下表是实例。
[root@pinguino ~]# shutdown 5 File system recovery needed Broadcast message from root (pts/1) (Tue Jan 4 08:05:24 2011): File system recovery needed The system is going DOWN to maintenance mode in 5 minutes! ^C Shutdown cancelled. [root@pinguino ~]# shutdown -r 10 Reloading updated kernel& [1] 18784 [root@pinguino ~]# Broadcast message from root (pts/1) (Tue Jan 4 08:05:53 2011): Reloading updated kernel The system is going DOWN for reboot in 10 minutes! [root@pinguino ~]# fg shutdown -r 10 Reloading updated kernel ^C Shutdown cancelled. [root@pinguino ~]# shutdown -h 23:59& [1] 18788 [root@pinguino ~]# shutdown -c Shutdown cancelled. [1]+ Done shutdown -h 23:59 |
你可能已经注意到了,例子中没有警告消息发出。shutdown执行前时间15分钟才会发送警告消息,如下所示,下表也同时显示了通过-t参数来设置init发送SIGTERM和SIGKILL两个信号之间的时间间隔为60秒(默认是5秒)。
[root@pinguino ~]# date;shutdown -t60 17 Time to do backups& Tue Jan 4 08:12:55 EST 2011 [1] 18825 [root@pinguino ~]# date Tue Jan 4 08:14:13 EST 2011 [root@pinguino ~]# Broadcast message from root (pts/1) (Tue Jan 4 08:14:55 2011): Time to do backups The system is going DOWN to maintenance mode in 15 minutes! |
如果你取消了一次关机,应该使用wall命令来向所有用户发送消息通知大家系统将不会关闭。
像我们前面说过的,也可以使用telinit或者init来关闭或者重启系统。但是这样就不会向用户发送警告消息,并且会立即执行,当然SIGTER和SIGKILL之间的时间间隔仍然存在。关于telinit,init和shutdown的其他参数请参考相关的手册页。
停止、重启和关机
你应该知道更多的与关闭和重启有关的命令。
- halt命令停止当前系统。
- poweroff命令是halt命令的符号链接,它先停止系统然后尝试去关闭电源。
- reboot命令是halt命令的另一个符号链接,它停止系统然后重新启动。
运行级不是0或者6的情况下运行上述任何一个命令,都会导致相应的shutdown命令被执行。
这些命令的其他参数和详细信息请参考手册页。
/etc/inittab文件
现在,你可能在想在一些系统上为什么按下Atrl-Alt-Delete会导致重启呢,或者这些运行级别如何配置呢。还记得/etc/inittab里的id段吗?此文件里还有很多其他的段,在rc1.d,rc5.d等目录里还有很多初始化脚本,这里的数字表示运行级别。下表显示了Fedora 8的inittab文件:
# # inittab This file describes how the INIT process should set up # the system in a certain run-level. # # Author: Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org> # Modified for RHS Linux by Marc Ewing and Donnie Barnes # # Default runlevel. The runlevels used by RHS are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not have networking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:5:initdefault: # System initialization. si::sysinit:/etc/rc.d/rc.sysinit l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # When our UPS tells us power has failed, assume we have a few minutes # of power left. Schedule a shutdown for 2 minutes from now. # This does, of course, assume you have powerd installed and your # UPS connected and working correctly. pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down" # If power was restored before the shutdown kicked in, cancel it. pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled" # Run gettys in standard runlevels 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 # Run xdm in runlevel 5 x:5:respawn:/etc/X11/prefdm -nodaemon |
以#开头的行表示注释。其他行有很多字段,格式如下:
id:runlevels:action:process
-
id
- 唯一标识,有一到四个字符组成。老版本最多有2个字符,所以通常我们看到只有2个字符。 runlevels
- 执行此动作对应的运行级,如果没有运行级指定,那么表示对应所有的运行级。 action
- 描述执行的动作。 process
- 指定动作发生时执行的程序。
常用的动作如下表:
Action | Purpose |
---|---|
respawn | 无论何时终止,重新启动进程。通常用于getty进程,该进程用来监视用户登陆。 |
wait | 在指定的运行级进入时启动该进程,init进程继续之前等待其终止。(即串行执行一次) |
once | 指定的运行级进入时,执行一次。 |
initdefault | 指定默认运行级 |
ctrlaltdel | 当init收到SIGINT信号时执行相应的进程。例如,当有人按CTRL-ALT-DELETE时。 |
下表单独显示了ctrlaltdel动作,现在你明白为什么按下CTRL-ALT-DELETE会重新启动系统了吧。
# Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now |
初始化脚本
你可能已经注意到如下的行。
l5:5:wait:/etc/rc.d/rc 5 |
在这个例子中,进入运行级5后,init会运行/etc/rc.d/rc脚本,并且指定参数5. init会一直等待这个命令完成才能去做其他的事情。
init使用这些脚本来启动系统,改变运行级,或者关闭系统。这些脚本位于/etc/init.d目录下或者/etc/rc.d目录下。在rcn(n表示运行级).d目录下存在一系列上述脚本文件的符号链接,用来控制进入该运行级需要启动或者离开该运行级需要停止的脚本。这些符号链接以K或者S开头,然后是两位数字,然后是服务的名字,如下表所示:
[root@pinguino ~]# find /etc -path "*rc[0-9]*.d/???au*" /etc/rc.d/rc2.d/S27auditd /etc/rc.d/rc2.d/K72autofs /etc/rc.d/rc4.d/S27auditd /etc/rc.d/rc4.d/S28autofs /etc/rc.d/rc5.d/S27auditd /etc/rc.d/rc5.d/S28autofs /etc/rc.d/rc0.d/K72autofs /etc/rc.d/rc0.d/K73auditd /etc/rc.d/rc6.d/K72autofs /etc/rc.d/rc6.d/K73auditd /etc/rc.d/rc1.d/K72autofs /etc/rc.d/rc1.d/K73auditd /etc/rc.d/rc3.d/S27auditd /etc/rc.d/rc3.d/S28autofs [root@pinguino ~]# cd /etc/rc.d/rc5.d [root@pinguino rc5.d]# ls -l ???a* lrwxrwxrwx 1 root root 16 2008-04-07 11:29 S27auditd -> ../init.d/auditd lrwxrwxrwx 1 root root 16 2008-04-01 07:51 S28autofs -> ../init.d/autofs lrwxrwxrwx 1 root root 15 2008-04-01 14:03 S44acpid -> ../init.d/acpid lrwxrwxrwx 1 root root 13 2008-04-01 07:50 S95atd -> ../init.d/atd lrwxrwxrwx 1 root root 22 2008-04-01 07:54 S96avahi-daemon -> ../init.d/avahi-daemon lrwxrwxrwx 1 root root 17 2008-11-17 13:40 S99anacron -> ../init.d/anacron |
这里你会看到audi和autofs服务在所有的运行级里都有Knn链接,在3和5运行级里有Snn链接。S表示该服务在进入运行级时启动,K表示服务应该停止。nn表示启动或者停止的优先级。例如audit会先于autofs启动(S27<S28),晚于autofs停止(K72<K73)。
更多信息参考手册。
超越Init
我们已经看到了,传统的启动Linux系统的方法基于Unix System V init进程。它导致加载初始化内存盘(initrd),然后把控制权交给init程序,该程序通常是sysvinit包的一部分。init是第一个系统运行的程序,该进程的PID为1. 它运行一系列预先定义顺序的脚本文件来启动系统。如果有些东西不能按照期望可用,init进程通常会一直等待直到其可用。这种方式在系统启动前所有事情都就绪时能够很好的工作。然而,现在的系统通常有热插拔设备,网络文件系统,启动时不可用的网络接口,这些给传统的init带来了挑战。当然,长时间地等待一个尚未准备好的硬件是不令人满意的。
下面的章节将会描述System V init的两种替代品: upstart和systemd。
upstart
一种叫做upstart的新的初始化程序在2006年的Ubuntu6.10中被引入。Fedora9到14,RHEL6以及其衍生发行版使用upstart。尽管传统的init仍然存在,尽管upstart的功能尚未完全实现,upstart在ubuntu和其他系统上已经取代了init(为了兼容,两者的程序名都叫init)。
与传统的静态init初始化脚本不同,upstart系统是事件驱动的。硬件变化,任务启动与停止,系统中的任何一个进程都可以出发事件。事件被用来触发任务或服务,统称为工作。例如,连接一个USB硬盘可能会导致udev服务发送一个block-device-added事件,该事件将导致一个定义好的任务来检查/etc/fstab并且挂载设备。再比如,Apache服务器仅仅会在网络和文件系统资源可用时才能启动。
upstart初始化程序替换了/sbin/init。upstart的工作定义在/etc/init目录以及子目录下。upstart目前能够处理/etc/inittab和System V init脚本。在最新的Fedora系统里,/etc/inittab文件可能只包含id一个项(指定默认运行级)。目前的Ubuntu系统默认没有/etc/inittab文件,当然你可以手动建立一个来指定默认运行级。
upstart有一个initctl命令来和init(upstart的init,传统的system v init已经被替换)进程交互。可以用来启动停止工作,查看工作列表,获取工作状态,发出事件,重启init进程等等。下表显示了如何通过initctl命令来获取工作列表。
[ian@echidna ~]$ initctl list rc stop/waiting tty (/dev/tty3) start/running, process 1486 tty (/dev/tty2) start/running, process 1484 tty (/dev/tty6) start/running, process 1492 tty (/dev/tty5) start/running, process 1490 tty (/dev/tty4) start/running, process 1488 plymouth-shutdown stop/waiting control-alt-delete stop/waiting system-setup-keyboard start/running, process 1000 readahead-collector stop/waiting vpnc-cleanup stop/waiting quit-plymouth stop/waiting rcS stop/waiting prefdm start/running, process 1479 init-system-dbus stop/waiting ck-log-system-restart stop/waiting readahead stop/waiting ck-log-system-start stop/waiting start-ttys stop/waiting readahead-disable-services stop/waiting ck-log-system-stop stop/waiting rcS-sulogin stop/waiting serial stop/waiting |
关于upstart的更多信息,请参考手册。
systemd
另一个叫做systemd的初始化系统也出现了。systemd由Lennart Poettering在2010年初开发。他在一片博客里描述了其原理和设计。Fedora15,openSUSE 12.1和Mandriva 2011以及其他系统采用了systemd。
很多守护进程使用sockets通信。为了达到系统启动高速度和并行性,systemd在启动时就创建了这些sockets,但是仅仅当服务通过sockets被请求时才启动相应的任务。这样,服务可以在第一次被请求时启动,而没有必要在系统启动时启动。如果服务需要其他未准备好的东西将会阻塞,这样仅仅是需要等待其他进程的服务才会去等待。
systemd扩展了这种服务等待的思想,它使用了autofs去定义挂载点,这样一个文件系统的挂载点虽然可用,但是实际的挂载动作可能被延迟到有进程第一次打开该文件系统上的文件或者使用文件时。
这些思想不仅延迟了服务的启动,而且减少了服务间依赖的检查,因为服务的接口在服务本身启动很早之前就可用了。
与upstart一样,systemd能够处理/etc/inittab里的内容。它还能处理/etc/fstab来控制文件系统挂载。原生的systemd初始化来源于units概念,units可以分组成control groups或者叫cgroups。
- 服务units是守护程序,可以被启动,停止,重启,重新加载。
- Sokket units封装了文件系统或者Internet上的一个socket。
- 设备units封装了Linux设备树上的一个设备。
- 挂载units封装了文件系统的一个挂载点。
- 自动挂载units封装了文件系统的一个自动挂载点。
- 目标units包括了其他units,提供了一个多个units的单一控制单元。
- 快照units引用其他的units,被用来保存和回滚所有服务和units的状态,例如在系统suspend时。
Units使用的配置文件以Unit类型为后缀。例如,cups.service, rpcbind.socket 或者 getty.target。配置文件的位置可以通过pkg-config查看。下表显示了Fedora17上配置文件的位置。systemd还会检查/usr/local/lib/systemd/system和/usr/lib/sysystemd/system作为配置信息。
[ian@attic4 ~]$ pkg-config systemd --variable=systemdsystemconfdir /etc/systemd/system |
systemctl命令用来和systemd守护进程交互,包括启动,停止units或者查看他们的状态。下表显示了使用systemctl 来查看units状态。
[ian@attic4 ~]$ systemctl --no-pager UNIT LOAD ACTIVE SUB JOB DESCRIPTION proc-sys...misc.automount loaded active running Arbitrary Executable File sys-devi...et-eth0.device loaded active plugged RTL8111/8168B PCI Express sys-devi...da-sda1.device loaded active plugged WDC_WD6401AALS-00L3B2 sys-devi...a-sda10.device loaded active plugged WDC_WD6401AALS-00L3B2 sys-devi...a-sda11.device loaded active plugged WDC_WD6401AALS-00L3B2 sys-devi...a-sda12.device loaded active plugged WDC_WD6401AALS-00L3B2 sys-devi...da-sda2.device loaded active plugged WDC_WD6401AALS-00L3B2 ... systemd-...ssions.service loaded active exited Permit User Sessions systemd-...-setup.service loaded active exited Setup Virtual Console tcsd.service loaded failed failed LSB: Init script for TCSD udev-settle.service loaded active exited udev Wait for Complete Dev udev-trigger.service loaded active exited udev Coldplug all Devices udev.service loaded active running udev Kernel Device Manager udisks2.service loaded active running Storage Daemon upower.service loaded active running Daemon for power managemen avahi-daemon.socket loaded active listening Avahi mDNS/DNS-SD Stack Ac cups.socket loaded active running CUPS Printing Service Sock ... syslog.target loaded active active Syslog systemd-...ted-ntp.target loaded active active Network Time Protocol systemd-...ead-done.timer loaded active elapsed Stop Read-Ahead Data Colle systemd-...es-clean.timer loaded active waiting Daily Cleanup of Temporary LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type. JOB = Pending job for the unit. 132 units listed. Pass --all to see inactive units, too. |
更多systemd的信息,请参考其网站。