Changchun Master Li

在寿终正寝路上的 SysVinit

2017-06-07

We don’t execute people just because they are old, and worship people just because they are new.

随着 systemd 出现, sysvinit 开始淡出主流的发行版. 但 sysvinit 极为简单, 使用 sysvinit 只需要一点 bash 基础和一些基本的文件操作, 不需要学习额外的知识. sysvinit 小而美但功能简单, 仍然是一个不错的选择.

BootLoader

init 进程是 stage3 启动到 stage4 的关键所在
从内核源码中可以看到, 在加载结束后, 内核会尝试启动 /sbin/init . 这是系统的第一个进程.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# file: init/main.c

static int __ref kernel_init(void *unused)
{
int ret;

kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
mark_readonly();
system_state = SYSTEM_RUNNING;
numa_default_policy();

flush_delayed_fput();

rcu_end_inkernel_boot();

if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}

/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;

panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
}

所以我们可以通过修改源码更改系统默认的 init 进程.
另一个更加简单方便的办法是传递一个 kernel parameter. 如果 BootLoader 是 lilo, 那么加入下面一行即可改变启动进程. (grub 也有类似选项)

1
2
# /etc/lilo.conf, 注意 python 不能为软链接
append="init=/usr/lib/python"

更多的 kernel parameters 在 referrence

runlevel

我们都知道, UNIX 有很多 runlevel. 其中有三种为保留预定义的运行模式:

  • 0 - 关机
  • 1 - 单用户模式
  • 6 - 重启

runlevel 5 大多是 X Window System.
其他的模式各个系统都有所不同, 默认运行模式也不一样, Gentoo 在 runlevel 3, Debian 在 runlevel 2, 可以在 /etc/inittab 中找到.

runlevel 是在 inittab 中实现的

1
2
3
4
5
6
7
8
# file: /etc/inittab
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6

所有的启动脚本都位于 /etc/init.d/ , 在某个 runlevel * 运行服务只不过是在 /etc/rc*.d/ 中增加这个服务的符号链接.

除此之外, sysv-rc-conf 也是一个不错的工具, 它能支持鼠标操作.
或是

1
update-rc.d DAEMON enable|disable

service

那么增加一个 service 就非常简单了, Debian 系统中有个模板 /etc/init.d/skeleton, 多数情况只需要改几个 bash 变量就可以用了.

记得最后加上执行权限

1
chmod +x /etc/init.d/DAEMON

referrence

SysVinit历史简介
lilo设置
内核参数
debian wiki: RunLevel
debian wiki: Daemon
debian wiki: sysvinit讨论页

Tags: Linux
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章