Linux操作性的运行级别、引导目标、关闭和重新引导

概述

在本文中,主要学习关闭或重新引导 Linux 系统相关知识,具体内容包括:

  • 设置默认运行级别或引导目标
  • 更改运行级别或引导目标
  • 更改为单用户模式
  • 从命令行关闭或重新引导系统
  • 向用户提醒主要的系统事件,包括切换到另一个运行级别或引导目标
  • 正确终止进程

除非另行说明,本文中的示例使用的是 Slackware 13.37 系统和 2.6.37 内核。upstart 示例使用了 Ubuntu 14.04 LTS 和 3.16.0 内核。systemd 示例使用了 Fedora 22 和 4.0.4 内核。您在其他系统上的结果可能有所不同。

运行 Linux

大多数时候,Linux 系统都作为多用户系统而运行,通常用作服务器,在多个不同用户 id 下运行着许多不同进程。有时,它有一个图形用户界面并主要为单一用户服务,而其他时候它是一个为许多用户服务的无头服务器。当您需要执行某些系统维护时, 您不希望所有这些用户都尝试完成操作,所以您需要能够使用单用户模式运行该系统,而不是许多用户。您还需要干净地切换到此模式,向登录用户提供合适的警 告。此外,您还需要尽快恢复常规操作。本文将展示如何做到这些。

关于本系列

本教程系列可以帮助您学习 Linux 系统管理任务。您还可以使用这些教程中的资料来对 Linux Professional Institute 的 LPIC-1:Linux 服务器专业认证考试 进行应考准备。

 

 

 

前提条件

要从本系列文章中获得最大收获,您应该拥有 Linux 的基本知识和一个正常工作的 Linux 系统,以便实践本文中涵盖的命令。有时程序的不同版本会得到不同的输出格式,所以您的结果可能并不总是与这里给出的清单和图完全相同。具体地讲,新的 upstart 和 systemd 系统改变了传统 System V init 进程的用户熟悉的许多方面(参阅了解详细信息)。本文首先讨论传统的 System V init 进程和它的运行级别。然后,我们将讨论更新的初始化进程 upstart 和 systemd。

System V 运行级别

传统的 System V 运行级别 定义哪些任务可在 Linux 系统的当前状态(或运行级别)下完成。传统 Linux 系统支持 3 种基本运行级别,以及一种或多种针对正常操作的运行级别。基本运行级别如 表 1所示。

表 1. Linux 基本运行级别

级别 用途
0 关闭(或停止)系统
1 单用户模式,通常使用别名 sS
6 重新引导系统

除了基本级别之外,运行级别的用法在不同发行版中会有所不同。常见的用法集合如 表 2所示。

表 2. 其他常见 Linux 运行级别

级别 用途
2 无网络连接的多用户模式
3 带网络连接的多用户模式
5 带网络连接和 X 视窗系统的多用户模式

Slackware 发行版为运行 X 视窗系统的完整系统使用运行级别 4,而不是 5。Debian 及其衍生版本(比如 Ubuntu)对任何多用户模式都会使用单一运行级别,通常为运行级别 2。请务必参阅您的发行版的文档。

System V 默认运行级别

当 Linux 系统启动时,从 in /etc/inittab 中的 id: 条目确定默认运行级别。清单 1演示了来自一个 Slackware 系统的文件 /etc/inittab 的一部分,该系统被设置为在非图形多用户模式下运行。

清单 1. /etc/inittab 中的默认运行级别

# These are the default runlevels in Slackware: 
 #   0 = halt 
 #   1 = single user mode 
 #   2 = unused (but configured the same as runlevel 3) 
 #   3 = multiuser mode (default Slackware runlevel) 
 #   4 = X11 with KDM/GDM/XDM (session managers) 
 #   5 = unused (but configured the same as runlevel 3) 
 #   6 = reboot 

 # Default runlevel. (Do not set to 0 or 6) 
 id:3:initdefault:

如果您希望系统在一种不同的运行级别(假设运行级别 4)上启动,可以编辑此值。

更改运行级别

可通过多种方式更改运行级别。要执行永久更改,可以编辑 /etc/inittab 并更改您在上面看到的默认级别。

如果仅需要为一次引导在不同的运行级别上启动系统,此目的也可以实现。例如,假设您刚安装了一个新内核,需要在使用新内核引导系统后,但在启动 X 视窗系统之前构建一些内核模块。您可能希望在运行级别 3 中启动系统来完成此任务。可在引导时编辑内核行(GRUB 或 GRUB 2),或者在选定的系统名称后添加一个参数 (LILO) 来实现此目的。使用一位数来指定想要的运行级别(在本例中为 3)。我们将使用一个 GRUB 示例演示该过程。假设您的 /boot/grub/menu.lst 文件包含 清单 2中所示的代码段来引导 CentOS。我们已使用反斜杠 () 字符将长内核行分解,以便获得美观的版面。

清单 2. 引导 CentOS 8 的典型的 GRUB 代码段

title CentOS (2.6.32-504.23.4.el6.x86_64) 
   root (hd0,10) 
   kernel /boot/vmlinuz-2.6.32-504.23.4.el6.x86_64 ro  
        root=UUID=2f60a3b4-ef6c-4d4c-9ef4-50d7f75124a2 rd_NO_LUKS  
        rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16  
        crashkernel=128M  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet

要在运行级别 3 中启动此系统,可等到引导条目显示后,选择此条目并输入 ‘ e ’ 来编辑它。取决于您的 GRUB 选项,您可能需要按一个键来显示引导条目,另外输入 ‘ p ’ 和一个密码来解锁编辑。我们的 CentOS 6 系统上的 GRUB 屏幕类似于 图 1。

图 1. 在 GRUB 中选择一个引导选项

centos-grub-menu

在本示例中,您现在应看到显示了 root、kernel 和 initrd 行。将光标移到以 “kernel” 开头的行并按 ‘ e ’ 编辑该行。我们的 CentOS 6 系统上的 GRUB 屏幕现在类似于 图 2。

图 2. 选择内核条目进行编辑

centos引导编辑

centos引导编辑

最后,将光标移到行末,添加一个空格和数字 ‘ 3 ’。如果愿意的话,可以删除 ‘ quiet ’,或者根据需要修改其他任何参数。我们的 CentOS 6 系统上的 GRUB 屏幕现在类似于 图 3。

图 3. 将启动运行级别设置为 3

centos引导内核

centos引导内核

最后,按 Enter 保存更改,然后键入 ‘ b ’ 引导系统。

备注:

  1. 使用 LILO 或 GRUB 2 完成此任务的步骤与 GRUB 不同,但编辑内核启动方式的基本原理是相同的。甚至其他系统或发行版上的 GRUB 屏幕可能看起来与这里显示的也有很大区别。通常会有提示可以帮助您。
  2. 在使用 upstart 或 systemd 的系统上,运行级别是模拟的,某些地方的运作方式可能与您期望的并不完全一样。如果尝试使用 telinit 更改运行级别,这种情形尤为明显。

在运行级别 3 下完成设置工作后,您可能希望切换到运行级别 5。在传统的 System V init 系统上,不需要重新引导系统。可以使用 telinit 命令切换到另一个运行级别。可使用 runlevel 命令显示前一个和当前运行级别。如果第一个输出字符是 ‘ N ’,那么运行级别自系统引导以来从未更改。清单 3演示了如何验证和更改运行级别。

清单 3. 验证和更改运行级别

[root@attic4-cent ~]# runlevel
 N 3 
 [root@attic4-cent ~]# telinit 5

输入 telinit 5 后,您会看到多条消息一闪而过,您的显示屏幕将切换到配置的图形登录屏幕。打开一个终端窗口并确认运行级别已更改,如 清单 4所示。

清单 4. 确认新运行级别

[ian@attic4-cent ~]$ runlevel
 3 5

如果使用 ls 命令显示使用 System V init 的系统(比如 Slackware 37)上的 telinit 命令的长清单,您会看到它实际上是 init 命令的符号链接。我们在 清单 5中演示了这一点。如果您的系统使用 upstart 或 systemd,可能不会出现这种情况。

清单 5. telinit – System V 风格系统上的 init 的符号链接

root@attic4:~# # Slackware 37 
 root@attic4:~# ls -l $(which telinit) 
 lrwxrwxrwx 1 root root 4 Aug 28  2011 /sbin/telinit -> init*

init 可执行程序知道它被调用为 init 还是 telinit , 并采取相应的行为。因为 init 在引导时被作为 PID 1 运行,所以它能够很聪明地知道您随后会使用 init 而不是 telinit 调用它。如果您这么做了,它会假设您希望它的行为与您调用 telinit 时一样。例如,您可使用 init 5 代替 telinit 5 来切换到运行级别 5。

单用户模式

与个人计算机操作系统(比如 DOS 或 Windows)相比,Linux 天生就是一个多用户系统。但是,这在许多时候可能带来问题,比如在您需要恢复某个主要文件系统或数据库,或者安装和测试某个新硬件时。运行级别 1 或 单用户模式 是这些情形的解决办法。实际实现可能因版本不同而不同,但您通常会从一个仅包含最精简的系统的 shell 中开始。该 shell 中通常没有网络连接,没有(或仅有很少的)守护进程在运行。在一些系统上,您必须通过登录来验证身份,但在其他系统上,可以以根用户身份直接进入 shell 提示符。单用户模式可能是您的救星,但它也可能会毁坏您的系统,所以以根用户权限运行时始终要小心。在完成后,立即重新引导到正常的多用户模式。

与切换到常规多用户运行级别一样,也可以使用 telinit 1 切换到单用户模式。正如 表 1中提到的,‘ s ’ 和 ‘ S ’ 是运行级别 1 的别名,所以您可以使用 telinit s 代替。

干净地关闭

尽管可以使用 telinitinit 停止多用户活动并切换到单用户模式,但这可能很冒失,会导致用户丢失工作和进程被异常终止。关闭或重新引导系统的首选方法是使用 shutdown 命令,该命令首先向所有登录用户发送一条警告消息,并阻止任何进一步登录。然后,它会告诉 init 切换运行级别。 init 进程随后向所有运行的进程发送一个 SIGTERM 信号,为它们提供机会来保存数据或适当地终止。5 秒或指定的另一个延迟时间过后, init 会发送一个 SIGKILL 信号来强制结束所有剩余的进程。

默认情况下, shutdown 会切换到运行级别 1(单用户模式)。您可以指定 -h 选项来停止系统,或者指定 -r 选项来重新引导。除了您指定的任何消息之外,还会发出一条标准消息。时间可指定为 hh:mm 格式的绝对时间,或者 n 格式的相对时间,其中 n 是距离关闭时间剩余的分钟数。对于立即关闭,可使用 now ,这等效于 +0

如果您发出了延迟关闭命令且时间未过期,而且该命令在前台运行,可以按 Ctrl-c 取消关闭,或者发出带 -c 选项的 shutdown 来取消未完成的关闭。清单 6给出了使用 shutdown 的一些例子,以及取消该命令的方式。

清单 6. 关闭示例

[root@attic4-cent ~]# shutdown 5 File system recovery needed

 Broadcast message from ian@attic4-cent 
   (/dev/pts/1) at 18:11 ... 

 The system is going down for maintenance in 5 minutes! 
 File system recovery needed 
 ^Cshutdown: Shutdown cancelled 
 [root@attic4-cent ~]# shutdown -r 10 Reloading updated kernel&
 [1] 5667 
 [root@attic4-cent ~]# 
 Broadcast message from ian@attic4-cent 
   (/dev/pts/1) at 18:11 ... 

 The system is going down for reboot in 10 minutes! 
 Reloading updated kernel 
 fg
 shutdown -r 10 Reloading updated kernel 
 ^Cshutdown: Shutdown cancelled 
 [root@attic4-cent ~]# shutdown -h 23:59&
 [1] 5669 
 [root@attic4-cent ~]# 
 Broadcast message from ian@attic4-cent 
   (/dev/pts/1) at 18:11 ... 

 The system is going down for halt in 348 minutes! 

 [root@attic4-cent ~]# shutdown -c
 shutdown: Shutdown cancelled 
 [1]+  Done                    shutdown -h 23:59

在上一个示例中可以注意到,我们的广播消息是在 18:11 发出的,但我们要求在 23:59(约 5.5 小时后)关闭。在传统 System V 的关闭实现中,如果关闭时间在 15 分钟以后,则不会发送警告消息。系统会等到离计划的关闭时间只有 15 分钟时,才会发送该消息。清单 7给出了 Slackware 37 上的一个 System V 示例,还展示了如何使用 -t 选项将 SIGTERM 与 SIGKILL 信号之间的默认延迟从 5 秒增加到 60 秒。

清单 7. 另一个关闭示例

root@attic4:~# date;shutdown -t60 17 Time to do backups&
 Tue Jul 14 18:27:08 EDT 2015 
 [1] 2240 
 root@attic4:~# 
 Broadcast message from root (tty1) (Tue Jul 14 18:29:08 2015): 

 Time to do backups 
 The system is going DOWN to maintenance mode in 15 minutes! 
  

使用 wall 通知用户

如果想取消关闭,应使用 wall 命令向所有用户发送一条警告,提醒他们系统 不会 关闭的事实。 wall 命令在命令行上获取一条警告或从一个文件发送一条消息。发送多行消息的一种快速方法是使用 echo -e 并将输出传输到 wall 。我们在 清单 8中演示了这一点。

清单 8. 使用 wall 警告用户

[root@atticf22 ~]# wall Scheduled outage at 23:59 has been canceled
                                                                               
 Broadcast message from ian@atticf22 (pts/1) (Tue Jul 14 21:07:05 2015):        
                                                                               
 Scheduled outage at 23:59 has been canceled 
                                                                               
 [root@atticf22 ~]# echo -e "We are experiencing system problemsOutage rescheduled to 02:30" | wall
                                                                               
 Broadcast message from ian@atticf22 (pts/1) (Tue Jul 14 21:07:36 2015):        
                                                                               
 We are experiencing system problems                                            
 Outage rescheduled to 02:30

我们之前说过,也可以使用 telinit (或 init )关闭或重新引导系统。与 telinit 的其他用法一样,不会向用户发送警告,该命令会立即生效,但 SIGTERM 与 SIGKILL 信号之间仍存在延迟。有关 telinitinitshutdown 的更多选项,请参阅合适的手册页。

如果不想由于突然关闭系统而烦扰用户,则需要使用 wall 以及您能自由使用的其他所有方式通知他们。

停止、重新引导和关机

您应该知道更多与关闭和重新引导相关的命令。

  • halt 命令停止系统。
  • poweroff 命令是 halt 命令的符号链接,它停止系统,然后提示关机。
  • reboot 命令是 halt 命令的另一个符号链接,它停止系统,然后重新引导它。

如果在系统不在运行级别 0 或 6 下时调用任何这些命令,则会调用相应的 shutdown 命令。

对于您可用于这些命令的其他选项,以及它们的操作的更详细信息,请参阅手册页。

System V /etc/inittab

现在,您可能想知道为什么在一些系统上按 Ctrl-Alt-Delete 会导致重新引导,或者所有这些运行级别设置是如何配置的。还记得我们之前在 /etc/inittab 中看到的 id 字段吗? /etc/inittab 中有一些其他的字段,以及 rc1.d 或 rc5.d 等目录中的一组 init 脚本,其中的数字表示该目录中的脚本适合的运行级别。清单 9给出了来自我们的 Slackware 37 系统的完整 inittab。

清单 9. 来自 Slackware 37 的完整 inittab

# 
 # inittab 	 This file describes how the INIT process should set up 
 # 		 the system in a certain run-level. 
 # 
 # Version: 	 @(#)inittab 		 2.04 	 17/05/93 	 MvS 
 #                                       2.10    02/10/95        PV 
 #                                       3.00    02/06/1999      PV 
 #                                       4.00    04/10/2002      PV 
 #                                      13.37    2011-03-25      PJV 
 # 
 # Author: 	 Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org> 
 # Modified by: 	 Patrick J. Volkerding, <volkerdi@slackware.com> 
 # 

 # These are the default runlevels in Slackware: 
 #   0 = halt 
 #   1 = single user mode 
 #   2 = unused (but configured the same as runlevel 3) 
 #   3 = multiuser mode (default Slackware runlevel) 
 #   4 = X11 with KDM/GDM/XDM (session managers) 
 #   5 = unused (but configured the same as runlevel 3) 
 #   6 = reboot 

 # Default runlevel. (Do not set to 0 or 6) 
 id:3:initdefault: 

 # System initialization (runs when system boots). 
 si:S:sysinit:/etc/rc.d/rc.S 

 # Script to run when going single user (runlevel 1). 
 su:1S:wait:/etc/rc.d/rc.K 

 # Script to run when going multi user. 
 rc:2345:wait:/etc/rc.d/rc.M 

 # What to do at the "Three Finger Salute". 
 ca::ctrlaltdel:/sbin/shutdown -t5 -r now 

 # Runlevel 0 halts the system. 
 l0:0:wait:/etc/rc.d/rc.0 

 # Runlevel 6 reboots the system. 
 l6:6:wait:/etc/rc.d/rc.6 

 # What to do when power fails. 
 pf::powerfail:/sbin/genpowerfail start 

 # If power is back, cancel the running shutdown. 
 pg::powerokwait:/sbin/genpowerfail stop 

 # These are the standard console login getties in multiuser mode: 
 c1:12345:respawn:/sbin/agetty 38400 tty1 linux 
 c2:12345:respawn:/sbin/agetty 38400 tty2 linux 
 c3:12345:respawn:/sbin/agetty 38400 tty3 linux 
 c4:12345:respawn:/sbin/agetty 38400 tty4 linux 
 c5:12345:respawn:/sbin/agetty 38400 tty5 linux 
 c6:12345:respawn:/sbin/agetty 38400 tty6 linux 

 # Local serial lines: 
 #s1:12345:respawn:/sbin/agetty -L ttyS0 9600 vt100 
 #s2:12345:respawn:/sbin/agetty -L ttyS1 9600 vt100 

 # Dialup lines: 
 #d1:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS0 vt100 
 #d2:12345:respawn:/sbin/agetty -mt60 38400,19200,9600,2400,1200 ttyS1 vt100 

 # Runlevel 4 also starts /etc/rc.d/rc.4 to run a display manager for X. 
 # Display managers are preferred in this order:  gdm, kdm, xdm 
 x1:4:respawn:/etc/rc.d/rc.4 

 # End of /etc/inittab

与平常一样,以 # 开头的行是注释。其他行有多个具有以下格式的字段:

id:runlevels:action:process

id
是一个唯一标识符,使用 1 到 4 个字符表示。旧版本将此限制到 2 个字符,所以您可能看到仅使用了 2 个字符。
runlevels
列出应对其执行此 id 的操作的运行级别。如果未列出运行级别,则对所有运行级别执行该操作。
action
描述应执行多个可能的操作中的哪一个。
process
指定在执行此行上的操作时,应运行哪个进程(如果有)。

可在 /etc/inittab 中指定的一些常见操作如 表 3所示。请参阅 inittab 的手册页了解其他可能性。

表 3. 一些常见的 inittab 操作

操作 用途
respawn 在进程终止时重新启动它。通常用于 getty 进程,该进程监视登录情况。
wait 在进入指定的运行级别时启动该进程一次,并等待它终止后再继续运行 init。
once 在进入指定的运行级别时启动该进程一次。
initdefault 指定在系统引导后要进入的运行级别。
ctrlaltdel 在 init 收到 SIGINT 信号时执行关联的进程,例如当系统控制台上的某个用户按 CTRL-ALT-DEL 时。

清单 10给出了来自 清单 9的 Ctrl-Alt-Delete 条目。现在您已知道为什么按 Ctrl-Alt-Delete 会导致系统重新引导。

清单 10. 捕获 Ctrl-Alt-Delete

# What to do at the "Three Finger Salute". 
 ca::ctrlaltdel:/sbin/shutdown -t5 -r now

System V 初始化脚本

您可能已注意到 清单 9中的几行代码,比如:

# Script to run when going multi user. 
 rc:2345:wait:/etc/rc.d/rc.M

在此示例中, init 将在进入运行级别 2、3、4 或 5 时运行 /etc/rc.d/M 脚本(或命令)。 init 将等待此命令完成后再执行其他任何操作。

init 在启动系统、更改运行级别或关闭时使用的脚本通常存储在 /etc/init.d 或 /etc/rc.d 目录中。rc n .d 目录(每个运行级别 n 一个目录)中的一系列符号链接,通常控制在进入一个运行级别时启动一段脚本或在离开该运行级别时停止该脚本。这些链接以 K 或 S 开头,后跟一个两位数,然后是服务的名称。来自旧式系统的一些示例如 清单 11所示。

清单 11. Init 脚本

[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

在这里可以看到, auditautofs 服务在所有运行级别中都有 K nn 条目,在运行级别 3 和 5 中拥有 S nn 条目。S 表示服务在进入该运行级别时启动,而 K 条目表示它应停止。链接名称的 nn 部分表示应启动或停止该服务的优先顺序。在此示例中, auditautofs 之前启动,并在以后停止。因为 K 和 S 链接通常链接到相同的脚本,所以该脚本可通过检查用于调用它的链接名称,获知它应该进入还是离开某个级别。

但是,Slackware 使用了一种稍微不同的方法,如 清单 12所示。请注意,/etc/rc[0-9].d 目录都是空的。进入某个特定的运行级别是通过一段脚本进行控制的,比如进入多用户模式的脚本 /etc/rc.d/rc.M,在进入运行级别 2、3、4 或 5 时会使用该脚本。

清单 12. Slackware 37 Init 脚本

root@attic4:~# find /etc/rc[0-9].*
 /etc/rc0.d 
 /etc/rc1.d 
 /etc/rc2.d 
 /etc/rc3.d 
 /etc/rc4.d 
 /etc/rc5.d 
 /etc/rc6.d 
 root@attic4:~# ls /etc/rc.*/???a*
 /etc/rc.d/rc.acpid*  /etc/rc.d/rc.atalk 
 /etc/rc.d/rc.alsa*   /etc/rc.d/rc.autofs

比较 /etc/rc.d/rc.autofs 脚本与上一个示例中指向 /etc/init.d/autofs 的 /etc/rc.d/rc2.d/K72autofs 和 /etc/rc.d/rc4.d/S28autofs 符号链接。

请参阅 initinittab 手册页了解更多信息。

除 Init 之外

我们已在这里看到,引导 Linux 系统的传统方法基于 UNIX System V init 进程。该方法涉及到加载一个初始 RAM 磁盘 (initrd),然后将控制权转交给一个名为 init 的程序,该程序通常安装在 sysvinit 包中。 init 进程是系统中的第一个进程,具有 PID(进程 ID)1。它按预定义的顺序运行一系列脚本来启动系统。如果某个期望的资源不可用,init 进程通常会等待它可用。尽管这对于在系统启动时所有资源都已知且已连接的系统足够了,但现代系统拥有热插拔设备、网络文件系统,甚至可能拥有在启动时不可 用的网络接口,这些系统会带来新的挑战。当然,人们不希望等待长时间或相对较长时间不可用的硬件。

在本文的后续章节中,我们会介绍 System V init 的两种替代方案: upstartsystemd

如果您不确定您拥有何种系统初始化脚本,请记住系统上启动的第一个进程具有进程 ID (PID) 1。查找哪个进程使用 PID1 来运行。如果它名为 “init”,则找到哪个包提供了它。清单 13展示了如何在一些系统上完成此任务。

清单 13. 查找提供 init 的包

[ian@atticf22 lpic-1]$ # Fedora 22
 [ian@atticf22 lpic-1]$ ps -p 1 -o comm=
 systemd 
 [ian@atticf22 lpic-1]$ # Ah! It's systemd

 ian@attic4:~$ # Slackware 37
 ian@attic4:~$ ps -p 1 -o comm=
 init 
 ian@attic4:~$ grep  sbin/init /var/log/packages/*
 /var/log/packages/sysvinit-2.86-x86_64-6:sbin/init.new 
 /var/log/packages/sysvinit-2.86-x86_64-6:sbin/initscript.sample 
 /var/log/packages/sysvinit-functions-8.53-x86_64-2:sbin/initlog 
 ian@attic4:~$ # System V style init

 ian@attic-u14:~$ # Ubuntu 14
 ian@attic-u14:~$ ps -p 1 -o comm=
 init 
 ian@attic-u14:~$ dpkg -S `which init`
 upstart: /sbin/init 
 ian@attic-u14:~$ # Upstart

 ian@yoga-u15:~$ # Ubuntu 15.04 
 ian@yoga-u15:~$ ps -p 1 -o comm= 
 systemd 
 ian@yoga-u15:~$ # Ubuntu has switched from upstart to systemd 

 [ian@attic4-cent ~]$ # CentOS6 
 [ian@attic4-cent ~]$ ps -p 1 -o comm=
 init 
 [ian@attic4-cent ~]$ rpm -q --whatprovides `which init`
 upstart-0.6.5-13.el6_5.3.x86_64 
 [ian@attic4-cent ~]$ # Another upstart system

对于 upstart 和 systemd,仍然存在 System V Init 的痕迹,具体地讲,可在 /etc/fstab 和 /etc/inittab 框架中看到此痕迹。无法直接支持运行级别的概念。 telinit 等 System V 命令受到支持,但它们的功能在内部对应于 upstart 作业或 systemd 单元的激活和停用。无需说,这种映射有时可能差强人意,所以如果您引导进入运行级别 3,然后使用 telinit 切换到运行级别 5,您的系统的运行情况不一定与您重新引导后完全相同。“SysVinit 与 Systemd 对应关系备忘单”(参见)可帮助您将 System V init 中的概念和命令映射到 systemd。

Upstart

新初始化进程 upstart 是在 2006 年的 Ubuntu 6.10 ("Edgy Eft") 中首次引入的。Fedora 9 到 14 和 Red Hat Enterprise Linux (RHEL) 6 都使用了 upstart,从这些版本衍生出的发行版也是如此。upstart 现在已在 Ubuntu 及其他版本中替代了 init 进程,但仍保留着 init 的痕迹,而且 upstart 的完善功能仍需要一段时间才能实现。

与早期系统中使用的静态 init 脚本集相比,upstart 系统由 事件 驱动。事件可能由硬件更改,启动或停止任务,或者系统上的其他任何进程触发。事件用于触发 任务服务 (统称为 作业 )。所以举例而言,连接 USB 驱动器可能导致 udev 服务发送一个 block-device-added 事件,该事件会导致一个定义的任务检查 /etc/fstab 并在适当时挂载该驱动器。作为另一个示例,Apache Web 服务器只能在网络和所需的文件系统资源均可用时启动。

upstart 初始化程序取代了 /sbin/init。Upstart 作业是在 /etc/init 目录及其子目录中定义的。upstart 系统目前将处理 /etc/inittab 和 System V init 脚本。在最新的 Fedora 版本等系统中,/etc/inittab 可能仅包含 initdefault 操作的 id 条目。最新的 Ubuntu 系统默认没有 /etc/inittab,但如果您想指定默认运行级别,可以创建一个。

Upstart 还有一个 initctl 命令来允许与 upstart init 守护进程交互。这允许您启动或停止作业,列出作业,获取作业的状态,发出事件,重新启动 init 进程等。清单 14展示了如何使用 initctl 获取 Fedora 13 系统上的 unstart 作业列表。

清单 14. 使用 initctl 与 upstart init 守护进程交互

ian@attic-u14:~/data/lpic-1$ # Ubuntu 14
 ian@attic-u14:~/data/lpic-1$ initctl list
 gnome-keyring-gpg stop/waiting 
 indicator-application start/running, process 1935 
 unicast-local-avahi stop/waiting 
 update-notifier-crash stop/waiting 
 update-notifier-hp-firmware stop/waiting 
 xsession-init stop/waiting 
 dbus start/running, process 1734 
 update-notifier-cds stop/waiting 
 gnome-keyring-ssh stop/waiting 
 gnome-session (Unity) start/running, process 1802 
 ssh-agent stop/waiting 
 unity7 stop/waiting 
 unity-voice-service stop/waiting 
 upstart-dbus-session-bridge start/running, process 1837 
 indicator-messages start/running, process 1884 
 logrotate stop/waiting 
 indicator-bluetooth start/running, process 1885 
 unity-panel-service start/running, process 1835 
 hud start/running, process 1798 
 im-config start/running 
 unity-gtk-module stop/waiting 
 session-migration stop/waiting 
 upstart-dbus-system-bridge start/running, process 1789 
 at-spi2-registryd start/running, process 1801 
 indicator-power start/running, process 1889 
 update-notifier-release stop/waiting 
 indicator-datetime start/running, process 1891 
 unity-settings-daemon start/running, process 1794 
 indicator-sound start/running, process 1894 
 upstart-file-bridge start/running, process 1790 
 gnome-keyring stop/waiting 
 window-stack-bridge start/running, process 1754 
 indicator-printers start/running, process 1902 
 re-exec stop/waiting 
 upstart-event-bridge start/running, process 1745 
 unity-panel-service-lockscreen stop/waiting 
 indicator-session start/running, process 1918

要进一步了解 upstart,请参阅。

Systemd

另一个名为 systemd 的新初始化系统正在兴起。Systemd 是 Lennart Poettering 于 2010 年初开发的。他在一篇博客文章中描述了该系统的基本原理和设计(参见)。早期采用者包括 Fedora 15、openSUSE 12.1 和 Mandriva 2011 等。在 15.04 版中,Ubuntu 从 upstart 切换到 systemd。

许多守护进程使用套接字进行通信。为了在系统启动过程中提高速度和增强并行性,systemd 在启动时创建这些套接字,但仅在套接字上收到对服务的连接请求时才启动关联的任务。这样,服务只能在首次需要时启动,没必要在系统初始化时启动。需要其他 某个工具的服务会在该工具可用前受阻塞,所以只有等待其他某个进程的服务会在该进程启动期间受阻。

作为等待服务的想法的延伸,systemd 使用 autofs 来定义挂载点,所以文件系统具有挂载点,但实际挂载可能延迟到某个进程尝试打开文件系统上的一个文件或使用它。

这些想法不仅会将服务的启动延迟到需要时,还会减少服务之间的依赖性检查,因为在需要提供服务本身之前,服务的接口早已准备就绪。

像 upstart 一样,systemd 可处理来自 /etc/inittab 的现有初始化脚本。它还可以处理 /etc/fstab 来控制文件系统挂载。原生的 systemd 初始化以 单元 概念为中心,单元可分组到 控制组cgroups 中。在多种单元类型中,您可能找到:

  • 服务单元是可以启动、停止、重新启动、重新加载的守护进程。
  • 套接字单元将套接字封装在文件系统或互联网中。
  • 设备单元将设备封装在 Linux 设备树中。
  • 挂载单元将挂载点封装在文件系统分层结构中。
  • 自动挂载单元将自动挂载点封装在文件系统分层结构中。
  • 目标单元将其他单元分组到一起,为其他多个单元提供单一的控制单元。
  • 快照单元引用其他单元,可用于保存和回滚 init 系统的所有服务和单元的状态(例如在挂起期间)。

单元使用一个配置文件来配置,其中该配置文件包含单元类型作为后缀。例如,cups.service、rpcbind.socket 或 getty.target。系统配置文件的位置(例如 /etc/systemd/system)可使用 pkg-config 命令确定,如 清单 14所示,其中展示了 Fedora 17 系统上的位置。Systemd 还检查 /usr/local/lib/systemd/system 和 /usr/lib/systemd/system 来获取配置信息。

清单 15. 查找 systemd 系统配置目录

[ian@atticf22 ~]$ pkg-config systemd --variable=systemdsystemconfdir
 /etc/systemd/system

systemctl 命令允许您查询和控制 systemd 守护进程,包括启动和停止单元或列出它们的状态。清单 16演示了如何使用 systemctl 显示我的 Fedora 22 系统上一些 systemd 单元的状态。

清单 16. 来自 systemctl 的部分输出

[ian@atticf22 ~]$ systemctl --no-pager
  UNIT                          LOAD   ACTIVE SUB       DESCRIPTION 
  proc-sys-fs-binfmt_misc.automount loaded active running   Arbitrary Executable File Form 
  sys-devices-pci0000:00-0000:00:02.0-0000:01:00.1-sound-card1.device loaded active plugged   
 GF119 HDMI Audio Controller 
  sys-devices-pci0000:00-0000:00:06.0-0000:03:00.0-net-enp3s0.device loaded active plugged   
 RTL8111/8168/8411 PCI Express 
  sys-devices-pci0000:00-0000:00:11.0-ata1-host0-target0:0:0-0:0:0:0-block-sda-sda1.device 
 loaded active plugged   WDC_WD6401AALS-00L3B2 /grubfil 
 ... 
  sys-devices-pci0000:00-0000:00:11.0-ata1-host0-target0:0:0-0:0:0:0-block-sda-sda9.device 
 loaded active plugged   WDC_WD6401AALS-00L3B2 9 
  sys-devices-pci0000:00-0000:00:11.0-ata1-host0-target0:0:0-0:0:0:0-block-sda.device 
 loaded active plugged   WDC_WD6401AALS-00L3B2 
 ... 
  sys-devices-pci0000:00-0000:00:12.2-usb1-1x2d6-1x2d6:1.2-sound-card2.device loaded 
 active plugged   Webcam C310 
  sys-devices-pci0000:00-0000:00:14.1-ata6-host5-target5:0:0-5:0:0:0-block-sr0.device loaded 
 active plugged   Optiarc_DVD_RW_AD-7240S 
 ... 
  sys-module-configfs.device    loaded active plugged   /sys/module/configfs 
  sys-module-fuse.device        loaded active plugged   /sys/module/fuse 
 ... 
  sys-subsystem-net-devices-enp3s0.device loaded active plugged   RTL8111/8168/8411 PCI Express 
  sys-subsystem-net-devices-virbr0.device loaded active plugged   /sys/subsystem/net/devices/vir 
  sys-subsystem-net-devices-virbr0x2dnic.device loaded active plugged   /sys/subsystem/net/devices/vir 
  -.mount                       loaded active mounted   / 
 ... 
  cups.path                     loaded active waiting   CUPS Scheduler 
  systemd-ask-password-plymouth.path loaded active waiting   Forward Password Requests to P 
  systemd-ask-password-wall.path loaded active waiting   Forward Password Requests to W 
  session-1.scope               loaded active abandoned Session 1 of user ian 
  session-2.scope               loaded active running   Session 2 of user ian 
  session-c1.scope              loaded active running   Session c1 of user gdm 
 ... 
  crond.service                 loaded active running   Command Scheduler 
  cups.service                  loaded active running   CUPS Scheduler 
  dbus.service                  loaded active running   D-Bus System Message Bus 
  dracut-shutdown.service       loaded active exited    Restore /run/initramfs on shut 
  fedora-import-state.service   loaded active exited    Import network configuration f 
  fedora-readonly.service       loaded active exited    Configure read-only root suppo 
 ... 
● mcelog.service                loaded failed failed    Machine Check Exception Loggin 
  NetworkManager.service        loaded active running   Network Manager 
  nfs-config.service            loaded active exited    Preprocess NFS configuration 
  packagekit.service            loaded active running   PackageKit Daemon 
 ... 
  cups.socket                   loaded active running   CUPS Scheduler 
  dbus.socket                   loaded active running   D-Bus System Message Bus Socke 
  dm-event.socket               loaded active listening Device-mapper event daemon FIF 
 ... 
  sockets.target                loaded active active    Sockets 
  sound.target                  loaded active active    Sound Card 
  swap.target                   loaded active active    Swap 
  sysinit.target                loaded active active    System Initialization 
  timers.target                 loaded active active    Timers 
  dnf-makecache.timer           loaded active waiting   dnf makecache timer 
  systemd-tmpfiles-clean.timer  loaded active waiting   Daily Cleanup of Temporary Dir 

 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. 

 164 loaded units listed. Pass --all to see loaded but inactive units, too. 
 To show all installed unit files use 'systemctl list-unit-files'.

单元名称的最后一部分(比如 device、path、target)是单元类型。

systemctl 命令允许您查询和控制系统单元。我们在 清单 17中给出了一些示例,在这些示例中,我们首先查询 SSH 服务器守护进程 (sshd.service),然后停止它并再次检查状态。最后再次启动它。

清单 17. 一些 systemctl 操作

[root@atticf22 ~]# # Fedora 22
 [[root@atticf22 ~]# systemctl status sshd.service
● sshd.service - OpenSSH server daemon 
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled) 
   Active: active (running) since Wed 2015-07-15 10:24:03 EDT; 5h 42min ago 
     Docs: man:sshd(8) 
           man:sshd_config(5) 
 Main PID: 765 (sshd) 
   CGroup: /system.slice/sshd.service 
           └─ 765 /usr/sbin/sshd -D 

 Jul 15 10:24:03 atticf20 systemd[1]: Started OpenSSH server daemon. 
 Jul 15 10:24:03 atticf20 systemd[1]: Starting OpenSSH server daemon... 
 Jul 15 10:24:03 atticf20 sshd[765]: Server listening on 0.0.0.0 port 22. 
 Jul 15 10:24:03 atticf20 sshd[765]: Server listening on :: port 22. 
 [root@atticf22 ~]# systemctl stop sshd.service
 [root@atticf22 ~]# systemctl status sshd.service
● sshd.service - OpenSSH server daemon 
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled) 
   Active: inactive (dead) since Wed 2015-07-15 16:06:28 EDT; 3s ago 
     Docs: man:sshd(8) 
           man:sshd_config(5) 
  Process: 765 ExecStart=/usr/sbin/sshd -D $OPTIONS (code=exited, status=0/SUCCESS) 
 Main PID: 765 (code=exited, status=0/SUCCESS) 

 Jul 15 10:24:03 atticf20 systemd[1]: Started OpenSSH server daemon. 
 Jul 15 10:24:03 atticf20 systemd[1]: Starting OpenSSH server daemon... 
 Jul 15 10:24:03 atticf20 sshd[765]: Server listening on 0.0.0.0 port 22. 
 Jul 15 10:24:03 atticf20 sshd[765]: Server listening on :: port 22. 
 Jul 15 16:06:28 atticf22 systemd[1]: Stopping OpenSSH server daemon... 
 Jul 15 16:06:28 atticf22 systemd[1]: Stopped OpenSSH server daemon. 
 [root@atticf22 ~]# systemctl start sshd.service

要了解 systemd 的更多信息,请参见。

对 Linux 运行级别、关闭和重新引导的介绍到此就结束了。

 

 

 

 

如果引用本站的原创文章,请注明原文链接:,本站保留追究责任的权利!

发表评论