Posts Tagged ‘init’

[译文]Upstart: Ubuntu 的基于事件的启动进程

March 8th, 2008

By Mark Sobell on February 08, 2008 (9:00:00 AM)
原文链接:http://www.linux.com/feature/125977
翻译时间:2008年3月7日
译者:王旭(gnawux at gmail.com)

译注:尽管译者是一位铁杆的Debian粉丝,但也注意 upstart 很久了,就译者本人观点,upstart 应该说是 Ubuntu 所做的众多工作中最为杰出的一个,它将可以极大地加快 Linux 系统启动的过程。尽管它不是惟一的下一代 init 程序,但它已经作为 Ubuntu 的缺省 init 进程工作了相当长的时间,这点将极大有助于程序的成熟;而且,upstart 使用了基于事件的模型,而不是简单的将各个 daemon 并行化,这个架构上的突破也是具有革命性的,下面我们来看这篇文章吧。

因为传统的System V 的 init daemon (Sysvinit)无法很好地处理现代硬件,如热插拔设备、USB硬盘或山村、网络文件系统等,Ubuntu 使用了Upstart init daemon。

本文抽取自最近出版的 A Practical Guide to Ubuntu Linux.

目前已经有多种 sysvinit 的替代产品了,这其中最为著名的一个就是 initng,它已经可以用于 Debian 了,并且在 Ubuntu 上也能工作。在同一位置上,Solaris 使用 SMF (Service Management Facility),而 Mac OS 则使用 launchd。而 Ubuntu 则更倾向于集这些软件的优点于一身。

Sysvinit daemon 是一个基于运行级别的初始化程序,它使用了运行级别(如单用户、多用户等)并通过从 /etc/rc?.d 目录到 /etc/init.d 目录的初始化脚本的链接来启动与终止系统服务。自从 Feisty 开始,Ubuntu 转向了 Upstart init daemon,并开始将Sysvinit 设置转换为 Upstart 的设置。本文探讨 Upstart 和残存的部分 Sysvinit 遗迹:/etc/rc?.d 和 /etc/init.d 目录以及运行级别的概念。

Upstart init daemon 是基于事件的,当系统中的什么情况发生变化时,它会运行某个特定的程序。这里被运行的程序多半是用来启动或终止服务的脚本。这个配置方式和systemv 在系统进入某个运行级别的时候运行init脚本的链接的概念实际上是非常类似的,只不过 upstart 更加灵活一些。Upstart 不仅能在运行级别改变的时候启动或终止服务,也能在接收到系统发生其他改变的信息的时候启动或终止服务。这些系统的改变被称为“事件”。例如,当 upstart 从 udev 接收到运行时文件系统加载、打印机安装或其他类似的设备添加或删除的信息,并采取相应的行动。Upstart 也可以在系统启动、关闭或某个任务状态改变的时候启动或关闭服务。

Upstart由五个包组成,(Ubuntu 中)它们都会被缺省安装:

  • upstart 提供Upstart init daemon 和 initctl 工具。

  • upstart-logd 提供 logd daemon 和 logd 服务的工作定义文件。

  • upstart-compat-sysv 提供了 rc 任务的工作定义文件,并提供了 reboot, runlevel, shutdown, telinit 等工具,以便与 sysvinit 相兼容。

  • startup-tasks 提供了系统启动任务的工作定义文件。

  • system-services 提供了 tty 服务的工作定义文件。

定义

有几个名词帮助我们理解 init 相关的东西。事件(event)是 init 可以得到的状态变更信息。几乎系统所有的内部或外部状态变更都可以触发一个事件。比如,引导程序会触发启动(startup)事件,系统进入运行级别2会触发运行级别2(runlevel 2)事件,而文件系统加载则会触发路径加载(path-mounted)事件,拔掉或安装一个热插拔或USB设备(如打印机)也会触发一个时间。用户还可以通过 initctl emit 命令来手动触发一个事件。

一个工作(job)是 init 可以理解的一系列指令。典型的指令包括一个程序(二进制文件或是脚本)和事件的名称。Upstart init daemon 会在事件触发的时候运行相应的程序。用户可以分别用 initctl start 和 stop 命令手动启动或终止一项工作。工作又可以分为任务和服务。

任务是运行、并在执行结束后返回到等待状态的工作。

服务是那些通常不会自己结束的工作。比如,logd daemon 和 gettys 就被实现为服务。init daemon 会监测每个服务的状态,如果服务出现问题会重启服务,在某些事件触发时或手工停止时会杀死服务。

/etc/event.d 目录下包含着一系列的工作定义文件(定义了 upstart init daemon 运行的工作的文件)。最初,这个目录由 Upstart 包来生成。在 Feisty 之后的 Ubuntu 中,被安装的服务会向这个目录中添加控制服务的文件,替代哪些安装到 /etc/rc?.d 和 /etc/init.d 目录的文件。

Upstart init daemon 的核心是一个状态机。它持续跟踪各个工作的状态,当有事件触发的时候,跟踪工作的状态改变。当 init 跟踪到一个工作的状态从一个转变到了另一个的时候,就可能会执行工作的命令或是终止工作。

System V 的 init daemon 通过改变运行级别来启动或停止服务。而使用 Upstart init daemon 的 Ubuntu 系统没有运行级别的概念。为了将基于运行级别的系统平滑移植到基于事件的系统,并为面向其他发布版的软件提供一定的兼容性,Ubuntu 使用 Upstart 模拟了运行级别。

在 /etc/event.d/rc? 文件中定义的 rc? 工作会运行 /etc/init.d/rc 脚本,这个脚本会运行链接到 /etc/rc?.d 目录中的 /etc/init.d 中的启动脚本,以模拟 SysVinit 的行为。当系统进入一个运行级别的时候,rc? 工作就会运行这些脚本。同时,Upstart 提供了 runlevel 和 telinit 工具以提供与 SysVinit 的兼容性。

使用 initctl (init control) 工具,具有 root 权限的管理员可以和 Upstart init daemon 通信。这个工具可以用来启动、停止或报告(report)一项工作。 比如,initctl list 命令会列出所有的工作和它们的状态:


$ sudo initctl list logd (stop) waitingrc-default (stop) waitingrc0 (stop) waiting ...tty5 (start) running, process 4720 tty6 (start) running, process 4727

要获得更详细的信息,可以参考 initctl 的 man page 或本节的例子。使用 initctl help 命令 (help 前没有横杠)可以列出 initctl 的命令列表。此外,也可以用 initctl list –help 来列出 list 命令的帮助信息,当然,将 list 换乘其它的 initctl 命令会得到该命令对应的信息。start, stop 和 status 工具是 initctl 的链接,会直接运行 initctl 的对应命令。

工作(Job)

/etc/event.d 目录下的每个文件都定义了一个工作,其中至少应该包含一个事件和一个命令。当事件被触发的时候,init 执行对应的命令。本节将介绍管理员自定义的工作和 Upstart 包中包含的工作。

下面的管理员自定义的工作使用 exec 关键字执行了一条 shell 命令。实际上,也可以用这个关键字执行一个 shell 脚本或一个二进制可执行文件。


$ cat /etc/event.d/mudat start on runlevel 2 exec echo "Entering multiuser mode on " $(date) > /tmp/mudat.out

这个文件定义了一个任务:当系统进入到多用户模式(运行级2)的时候执行 echo 命令。这个命令会向 /tmp/mudat.out 文件写出一条包含日期时间消息。shell 会运行 date 命令替换其中的内容。在任务结束后, mudat 任务会停止并进入等待状态。

在下一个的例子中,cat 命令展示了 /tmp/mudat.out 文件的内容和 initctl list 命令关于这个任务的输出(status 工具也可以得到同样的信息):


$ cat /tmp/mudat.out Entering multiuser mode on Tue Jul 10 17:34:39 PDT 2007 

$ sudo initctl list mudatmudat (stop) waiting

如果 exec 命令行中包含 shell 的特殊字符, init 会运行 /bin/sh(dash 的符号链接)并把命令行交给它来处理。否则,exec 会直接运行命令行。如果要执行多个 shell 命令,可以把他们放到脚本文件中并运行脚本,或是使用 script….end script (下面会介绍)。

Upstart initdaemon  只能监测哪些使用 exec 运行的工作(服务),无法监测使用 script…end script 运行的工作。换句话说,服务应该使用 exec 运行,而任务则可以使用任意的方法。

myjob 示例

用户也可以自己定义一个事件,并让一个工作被这个事件触发。如下的 myjob 工作定义文件定义了一个被 hithere 事件触发的工作:


$ cat /etc/event.d/myjob start on hithere script 	echo "Hi there, here I am!" > /tmp/myjob.out 	date >> /tmp/myjob.out 	end script

myjob 文件提供了另一种运行命令的方法:在 script 和 end script 关键字之间包含了两行命令。这两个关键字常常导致 init 去运行 /bin/sh。例中的命令将一条消息和日期输出到了 /tmp/myjob.out 文件。现在可以使用 initctl emit 命令触发这个工作。如下,init 展示了 myjobs 在我们的触发下所经历的各个状态:


$ sudo initctl emit hitherehithere myjob (start) waiting myjob (start) starting myjob (start) pre-start myjob (start) spawned, process 6064 myjob (start) post-start, (main) process 6064 myjob (start) running, process 6064 myjob (stop) running myjob (stop) stopping myjob (stop) killed myjob (stop) post-stop myjob (stop) waiting 

$ cat /tmp/myjob.out Hi there, here I am! Sat Jul 7 20:19:13 PDT 2007 

$ sudo initctl list myjob myjob (stop) waiting

在上面的例子里,cat 展示了 myjob 产生的输出,initctl 展示了工作的状态。同样也可以用 initctl start myjob(或直接用 start myjob)来运行它。initctl start 十个非常有用的命令,这样你就可以在没有事件的情况下启动一个工作。比如,你可以用 initctl start mudat 来直接运行前面例子中的 mudat 工作而不会触发 runlevel 2 事件。

指定带参数的事件

telinit 和 shutdown 工具发送带有参数的 runlevel 事件。比如,shutdown 发送 runlevel 0,telinit 2 会发送 runlevel 2 事件。你可以在工作定义中用如下格式匹配这些事件:

start | stop on event [arg]

其中 event 是一个事件,而 arg 是一个可选参数。要在系统进入 runlevel 2 的时候停止一个工作,可以指定 stop on runlevle 2,也可以指定 runlevel [235] 来匹配运行级 2, 3 和 5,或用 runlevel [!2] 来匹配 2 之外的运行级。

尽管 Upstart 会忽略掉多余的事件参数,但工作定义文件中的事件名称里的参数必须在事件中存在。比如,没有参数的 runlevel 可以匹配所有的 runlevel 事件,不论是否有参数,但 runlevel S arg2 将不会匹配任何事件,因为 runlevel 事件只会带有一个参数。

/etc/event.d 中的工作定义文件

随着 Ubuntu 从 SysVinit 向 Upstart 的迁移,更多地工作会在 /etc/event.d 文件中定义。本节介绍一些 Upstart 包放在这个目录中的工作定义文件。

/etc/event.d/rc2 工作定义文件定义了 rc2 任务,这和其他的 rc? 任务没什么区别。rc2 任务在系统进入到多用户模式的时候会被触发(事件名称是 runlevel 2);当系统进入到其它任意运行级的时候(runlevel [!2])会结束。脚本的第一个部分调用 runlevel 工具,它会让系统显示自己在运行级2 (当然,实际上已经没有运行级这个玩意儿了)并给两个变量赋值。接下来的工作由 exec 命令完成,它会使用参数 2 运行 /etc/init.d/rc 脚本。这个脚本使用相应的参数调用 /etc/rc?.d 目录中的那些链接。这里 rc2 任务会运行 /etc/rc2.d 下的符号链接对应的 init 脚本。


$ cat /etc/event.d/rc2 # rc2 - runlevel 2 compatibility # # This task runs the old sysv-rc runlevel 2 ("multi-user") scripts. It # is usually started by the telinit compatibility wrapper.

start on runlevel 2 

stop on runlevel [!2] 

console output script 	set $(runlevel --set 2 || true) 	if [ "$1" != "unknown" ]; then 		PREVLEVEL=$1 		RUNLEVEL=$2 		export PREVLEVEL RUNLEVEL 	fi 

	exec /etc/init.d/rc 2 end script
tty 服务

如下是一个在 tty1 上启动并监视 getty 进程的服务的工作定义文件:


$ cat /etc/event.d/tty1 # tty1 – getty# # This service maintains a getty on tty1 from the point when# the system is started until it is shut down again. 

start on runlevel 2 start on runlevel 3 start on runlevel 4 start on runlevel 5 

stop on runlevel 0 stop on runlevel 1 stop on runlevel 6 

respawn exec /sbin/getty 38400 tty1

这个服务由 runlevel 2 到 5 (多用户模式)来触发,启动 getty 进程,并在系统关闭、重启或进入单用户模式,即运行级 0,1 和 6 时触发来关闭该服务。respawn关键字告诉 init 在服务终止后重启服务,而 exec 命令是让 getty 进程以 38400 波特率运行在 tty1。如下,initctl 工具显示该服务处于启动状态,进程ID 4747,ps 命令显示该服务的进程:


$ sudo initctl list tty1 tty1 (start) running, process 4747 

$ ps -ef | grep 4747 root   4747   1 0 Jul02 tty1   00:00:00 /sbin/getty 38400 tty1

rc-default 任务和 inittab

在 SysVinit 中,/etc/inittab 文件通过 initdefault 项告诉 init 在系统启动的时候进入哪个运行级,而 Ubuntu 没有 inittab 文件,缺省的,Upstart init daemon (使用 rc-default 任务)引导系统进入多用户模式(缺省运行级为2)。如果希望系统启动进入其他运行级别,那么就创建一个 inittab 文件。如下会让系统缺省进入单用户模式 (runlevel S):


$ cat /etc/inittab :id:S:initdefault:

当系统进入到单用户(修复)模式,如果系统的root帐号没有被锁定,init 会在显示 root 提示符之前要求输入 root 密码。否则,它会不要求输入密码而直接显示 root 提示符。

注意:不要将系统设置启动到运行级别 0 或 6,这样系统将永远无法正常启动。要直接进入多用户模式(运行级 2),如果有 inittab 删除这个文件,或者用上述的例子,将里面的 S 替换成 2.


Upstart的未来

从 SysVinit 到 Upstart 的迁移涉及到了 Linux 系统的很多部分。要让这个转换尽量平滑并且引入尽量少的问题,Upstart 团队决定通过多个 release 来完成这个迁移。

Ubuntu 从 Feisty 开始使用 Upstart init daemon。在 Feisty 和 Gutsy+2 之间,Ubuntu 将完成 SysVinit 到更加干净、更加灵活的 Upstart 的迁移。随着越来越多的服务被放到 Upstart 的控制之下,/etc/event.d 目录下的内容将会替代 /etc/init.d 和 /etc/rc?.d 目录下的内容。运行级将不再作为 Ubuntu 正式支持的特征,虽然它们可能为了保持与第三方软件的兼容性而继续保留。最终 Upstart 将会替换掉 crond。

Linux忘记密码的处理方法

January 14th, 2006

这个问题总被问,回答过无数次了,贴在这里,这是终极方法,适用于一切可以重新启动系统、使用 LILO/GRUB,并且引导程序没有密码的情况。
如果你忘了普通用户的用户名密码,用 root 登录,然后运行 passwd username 即可修改
如果忘了 root 密码,启动到单用户模式,用 passwd 命令修改密码
如果单用户模式也需要密码,启动时用内核参数 init=/bin/sh 即可,出现提示符后,以 rw 方法重新 mount 根分区,编辑 /etc/passwd,去掉 root 密码即可,具体操作是
1.a 如果用 grub 引导的话,在引导菜单上要启动的选项处按’e',然后上下找到kernel那一行,再按 e,在后面加上 init=/bin/sh 这几个字,然后按回车,然后大概是按b,启动
1.b 如果用lilo,在 lilo 提示界面下,输入你启动的东东的 lable,再在后面加上参数,比如label是linux,那就输入 linux init=/bin/sh,然后回车
2. 看到 Shell 提示符之后,输入命令, mount -o remount,rw /,重新以可读写方式挂载根分区。
3 用 passwd 命令修改密码,也可以直接修改 /etc/passwd文件
4 用 mount -o ro,remount / 重新把根分区只读,这个必须做,否则就功亏一篑了
5 按计算机的 reset 键,重新启动系统。因为没有 init,所以 reboot, halt, shutdown 这些命令很可能不好用。
完毕。

半日惊魂—Linux 系统 Debug 小记

November 14th, 2005

原创文章,转载请保留出处 (bupt.org 或 gnawux.blogchina.com) 和作者 (王旭)
笔记本的 Debian Sid 系统于周末在无网络条件下出现故障,经过半天的排查、分析,
调整若干处,重启十数回,终于定位错误并修正,使系统恢复如初,特此记录
————-(目录)—————
1 万恶之源—背景概述
2 危机浮现—案发现场
2.1 现场一: 无线网卡无法启动了
2.2 现场二: CPUFreqd 启动失败
2.3 现场三: 硬件监视传感器失灵、快捷键停转
3 蛛丝马迹—错误排查
3.1 新安装的软家包没有问题
3.2 降级 udev 没有效果
3.3 新内核不是罪魁祸首
3.4 modconf 招来最大嫌疑
3.5 单用户模式找不到问题,濒临放弃
4 拨云见日—定位错误
4.1 udev 仍在风口浪尖
4.2 udev 拒绝认罪
4.3 真相只有一个
5 余音绕梁—疑虑尚存
5.1 为什么会这样
5.2 FHS 之疑
————————————
万恶之源—背景概述
===================
这是一台华硕 M2N 笔记本,Pentium M 处理器,Intel I845GMe 的芯片组/整合显卡,
以及 Intel Pro/Wireless 2100 (ipw2100) 802.11b 无线网卡,典型的迅驰配置,购
买一年以来,它的 40 G 硬盘上只装过一种操作系统—Debian GNU/Linux,而且只安
装过一次,稳定性、性能与功能都很不错,无可非议。
硬盘的分区是很讲究的老鸟的划分方式: /, /usr/, /var/, /home/ 分享硬盘,而恰恰
是这种细致的划分,让系统陷入了危机,如果上天重新给我一次机会,我一定不会分这
么多分区,不过这是后话了。
我的所有硬件,包括快捷按钮、无线网卡、屏幕切换、多媒体控制中心等,全部工作良
好,而根据电池的情况和计算机所执行的人物,我的 Dophin Pentium M CPU 的主频也
可以在 600MHz 到 1500MHz 之间浮动,一年之后的今天,电池也可以使用超过四个小
时,对我来说,这台爱机真是天衣无缝阿。
危机浮现—案发现场
===================
十一月十日,光光节前夜,在 IPW2100 进入官方内核的鼓舞下,我安装了 Debian 打
包的 2.6.14 内核,并且,证实该内核工作良好,系统完全正常,无须安装其他驱动和
补丁,这是我第一次在笔记本上使用这么省事的内核。
第二天 (11.11) 启动,系统仍然正常,无线网卡工作很好,我还用它传送了不少数
据,之后,升级了系统,安装了几个关于蓝牙软件包,准备有机会借个蓝牙适配器来调
教蓝牙玩玩。
晚上,回家之后,系统启动后突然发现出问题了……
现场一: 无线网卡无法启动了
————————–
第一个注意到的问题就是无线网卡加载失败了……这是不小的打击,刚才不是还好好的
么? 使用 modconf 加载 ipw2100 模块,仍然不起作用,究竟是怎么回事呢?
系统日志里没有说明这一点,重新启动之后注意到,居然是 firmware 无法加载? 我的
天阿,一年前他们就已经存在了阿? 况且刚刚换内核的时候也没有说过他们有不兼容的
情况阿,重新复制一次文件也毫无反应,究竟是什么原因呢,总不会是硬盘平白无故的
出问题了吧……
现场二: CPUFreqd 启动失败
————————-
第二个被注意到的问题是十分容易被发现的 cpufreqd 的问题,它作为处理器频率调整
工具十分重要,而且,它的启动脚本中,十分厚道的用红字显式出来—启动失败。
本来一次失败不容易被注意的,因为与 ipw2100 不同,cpufreqd 在我手动加载相应模
块之后便正常了,只是每次启动都需要手工加载一次,这点十分不正常!于是才引起了
我的极大注意。
现场三: 硬件监视传感器失灵、快捷键停转
————————————–
同时被观察到的还有硬件传感器 lm-sensors 的硬件温度采集失灵和笔记本的快捷键也
都一一停止了工作,这让我觉得十分懊恼,而他们和 cpufreqd 一样,稍后加载模块就
可以工作了,只是每次加载都无法保存,似乎 /etc/modules 根本就没人理。
蛛丝马迹—错误排查
===================
周五 (11.11) 当天晚上比较累了,于是就没有解决,问题一直拖到周日(11.13) 下午
才正式开始解决,这也就是所谓的“惊魂半日”,在劫后余生的今天,我回忆着把主要
的调试过程记录下来,重复一次显然不需要半天,不过当时的复杂考虑、犹豫、斗争等
夹杂着的情况下,用这么长时间还是挺正常的。
新安装的软家包没有问题
———————-
从出问题的先后顺序看,系统在出问题前后最大的变化莫过于更新了几个软件包、安装
了一些蓝牙相关的软件包,而其中恰好有一个是有关 firmware 的,它们就首当其冲的
成为了我的第一批刀下之鬼。
闲话少说,根据 /var/log/aptitude,直接删掉新安装软件包,使用 purge,让它随风
去,不留一点痕迹 (当是显然是没有现在这么轻松的心情了)。
重启系统……居然不管用! 无奈下只好考虑降级刚刚升级的软件包,可是它们看起来实
在是太无辜了,根本就不关系统和硬件什么事,于是,只好转移目光。
降级 udev 没有效果
——————
近来硬件相关的系统级软件包当中,udev 无疑是最具偶像气质的一个,因为彻底删除
了 hotplug,其出镜率一直居高不下,bug 多多也是此君最近表现枪眼的原因,自然
的,我对他投上怀疑的目光也是不无道理的。
迄今为止,我对系统调整仍然是软件包级别的,如果我就此深入调查一下的话,可能可
以节省至少两个小时的时间,不过,处理问题总要循序渐进的,以我的水平和对问题的
认识,不可能先验地直接去 Debug。
于是,我抱着侥幸心理,利用 /var/cache/apt/archives 目录下的藏品,把 udev 强
行降级,结果,根据上面的现象其实就已经注定这种尝试是不会有结果的,udev 包其
实根本就没有变动过的。
新内核不是罪魁祸首
——————
那么……会不会是新内核惹的祸呢? 这是我不愿意做的假设,我对这个官方内核包还是
很有信心的,可是事到如今,我也只好拿起怀疑一切的态度来了。
使用旧内核启动,问题不减当年,更换内核参数,仍然是问题如故……真是有些万念俱
灰的感觉阿,难道让我放弃么?!
modconf 招来最大嫌疑
——————–
想想这两天还动过些什么— modconf! 用它加载的模块在后来证明根本无效,包存在
/etc/modules 中的模块从来没有在启动过程中顺利启动的,这个东西已经把很多重复
的内容写到 /etc/modules 里面了,难道是它干的?
几乎一定是它了,去掉老的 /etc/modules,重新手动创建一个,只写我最需要的几个
模块,不再用 modconf 了,而是用 modprobe 一个一个来。
然后用 module-init-tools 的启动搅拌试一次,可以加载这几个模块,好了,重新启
动。
打击再一次降临,上面的修改,架空 modconf 根本没有取得效果,我仍然停留在原地,
甚至可能让情况更糟了。
单用户模式找不到问题,濒临放弃
——————————
使用单用户模式进入系统,问题丝毫没有变化,我开始把做过的大多数调整恢复,盼望
着新一次的系统更新可以还给我一个干净的系统。
不过,modules 刚才的问题还困扰着我,我仍然在观察着 /etc/rcS.d/ 的内容,
modules-init-tools 为什么会在那个时候不工作呢? 这个问题我似乎曾经在别的什么
地方遇到过啊……
拨云见日—定位错误
===================
这种时候放弃是一个选择,但我还有方法没有尝试,更多的蛛丝马迹仍然在不断地暴
露出来,我隐隐的感到—udev 还是有问题的。
udev 仍在风口浪尖
—————–
似乎有某个软件包宣称找不到设备,难道 udev 仍然不正常么? 来到 /dev/ 下面一
ls,吓了我一大跳—这么多文件,难道 udev 没有工作么?
大家知道,根据 hal (硬件抽象层) 提供的规则,udev 会在 /dev/ 下面创建一个
disk/ 目录,可是事实是,现在这个目录并不存在,可以得到结论:udev 根本就没工
作!
那么,启动过程中的 udev 到底发生了什么呢? dmesg 和 syslog 都没有给我答案,
我试试手动启动一下 udev,看看会怎么样。
/etc/init.d/udev start 运行的结果是,该程序已经在运行中了—那它在干什么?!
udev 拒绝认罪
————-
忽然我在又一次启动中注意到,udev 抱怨说它无法加载 tmpfs,所以无法启动。笑
话! /dev/shm 的 249MB 的 tmpfs 在那里乖乖的,你居然说挂不上! 作为愤青的我当
然不能接受,可是怎么才能知道这是为什么呢?
我把 /etc/udev/udev.conf 里面的日志记录级别从 “err” 调整到了 “info”,
冀望于它能够把更多信息写到 syslog 里面。不过,事实又一次证明了敌人的强大和
我的不成熟,把希望寄托到这里是徒劳的,syslog 里面连挂不上 tmpfs 都没写,那
只在系统启动时 post 出来的信息中存在……
局面似乎僵持在这里了
真相只有一个
————
不过,我还有杀手锏没有亮出来呢!
我注意到,udev 在 /etc/rcS.d/ 之中的位置是第三个,仅仅在 glibc 和
mountvirtualfs 之后,我们不妨手动启动一次系统,这样,谁犯的错误就是“秃子
头上的虱子”—明摆着的了。
grub 中设定内核参数 init=/bin/sh,这是绕过复杂登录过程的看家本领,如果密码
丢失或是什么其它特殊情况,这个手段是绕过 /sbin/init 的最好手段。不要说密码
了,任何守护进程都没有开过。
这时,系统启动后得到了 root 权限的 shell 提示符,我已经准备好解决问题了,
进入 /etc/rcS.d,一个一个的用 start 参数运行这些脚本,不多,只要三个就可以
发现问题的。
事实是,当运行到第二个的时候,也就是 mountvirtualfs,加载虚拟文件系统时,
问题已经产生,因为缺少 libpcre3.so,无法挂载!!!
这个错误其实刚才我已经注意到了,但它是 Perl 5 兼容政则表达式库,会那么关键
么? 我居然忽略了它! 是事实,正是它的缺席导致了 grep -E 运行出错,既无法挂载
虚拟文件系统,也会让 udev 出错,而它原本是在 /usr/lib/ 之下的,在 /usr/ 挂
载之前是不可能找到的。
解决问题很简单,复制一份到 / 分区里面的 /usr/lib/, 这个目录在 /usr 挂载之后
会被覆盖,但在挂载之前,它独自支撑起了这个系统。
重新起动……振奋人心的一刻终于来到了!问题解决,一切正常了!
余音绕梁—疑虑尚存
===================
为什么会这样
————
时至今日,我仍然不知道为什么会这样,是脚本的 grep 参数变化了,还是 grep 变
化了,还是 libpcre3 变化了才引发的半日惊魂? 这个问题从何而来的让我百思不得
其解,因为从软件包变化上,这个问题实在难以引人注意。
FHS 之疑
——–
可是根据 Linux 文件系统层次标准 (debian-policy 包中),/usr 不需要在系统启动
中始终存在,甚至应该可以位于 NFS 分区上的,为什么会这样呢? 究竟是哪里的问题
呢。
现在,经历劫后余生,我也希望大家要主义,如果没有特殊情况,/usr 和 / 还是放到
同一个分区之中吧,免生事端。
补充
====
目前(11.14 星期一,问题发生后的第一次更新系统),Debian 已经升级了 grep 软件包,
去掉了对 libpcre 的依赖,从而解决了这一问题。

Switch to our mobile site