在上一片博文中,我们知道操作系统的启动流程为:
所以启动Linux时有两种启动办法:
- 加载bios 的硬件信息-> 读取MBR –>执行Grub ->加载kernel–> 加载驱动–> init –> 执行bash
- 加载bios 的硬件信息-> 读取MBR –>执行Grub ->加载kernel–> 加载驱动–> init –> /sbin/init -> 取得run-level信息 -> /etc/rc.d/rc.sysinit -> services –> /etc/rc.d/rc.local –> mingetty –> login
为了从简单入手,我们从手动启动init开始。
1. 获取系统的initrd.img
在上一片博文中,我们已经知道如何解压img文件,此处不在阐述。但是需要说明的是,如果我们需要启动自己的驱动文件,需要更改/boot/grub/grub.conf
文件,添加自己的grub启动项。
1 | title MicroLinux-Core754 //名称 |
现在我们讲讲如何制作自己的img文件。
首先,我们需要写一个脚本init
作为启动项,使得内核用该文件系统启动后能够直接获得一个Bash
1 | !/bin/bash |
为了启动我们的init
文件,我们还需要bin
和lib64
文件,其中bin
文件夹存放可执行文件,lib64
存放应用程序所依赖的动态库。由于bash
等这些命令需要依赖/lib64
等目录下的一些动态链接的共享库,所以需要将依赖的库拷贝到小系统对应的目录下,用ldd
命令查询应用程序及其依赖的动态库。完成之后,执行:
1 | find . | cpio -H newc -o | gzip > /boot/microlinux.img |
将根文件系统打包成microlinux.img
放到/boot
目录下。启动时系统会自动执行microlinux.img
中的init
(配置好grub后)
此时我们重启系统,并在grub引导程序选择我们自己的启动程序后,就可以进入bash(虽然啥都没有)
2. 挂载原有系统
如果想挂载原系统,需要加载一些驱动程序,比如ext4
文件系统的驱动、scsi
设备的相关驱动等。这些驱动程序
在系统的/lib/modules
里,我们需要将一些必要的驱动拷到我们的小系统里,并需要modinfo
和lsmod
命令
编写init
文件为
1 | !/bin/bash |
这样,系统在启动时会先加载init中所写的一些ko文件,再挂载系统磁盘,然后挂载原有系统。
3. 完成拥有管理设备能力(udev)
udevd是管理、监控主机设备的服务程序,有了udevd后可以自动加载所需的驱动模块,避免了手动挂载的麻烦。udev依赖于sysfs系统文件,udevd的规则文件在/lib/udev/
目录下,配置文件在/etc/udev/
目录下,同时还需要/etc/nsswitch.conf
配置的名称服务交换,其依赖的库为/lib
目录下以libnss
开头的文件,将上述文件拷贝到我们的目录下,然后使用/sbin/start_udev
命令可以启动udevd
服务
启动后,udev会自动在/dev
目录下创建设备节点,普通linux环境/dev目录是tmpfs虚拟磁盘文件系统,设备节点可隶属于不同的用户和组(由/etc/group
、/etc/passwd
指派uid
、gid
)。
这样我们的init
文件可写为:
1 | !/bin/bash |
我们看看现在小系统里都有什么
其中/root
为创建的用户目录,/proc
和/sys
为系统目录,/dev
为设备目录,/var
存放变量,以上目录在小系统的img文件中均为空文件夹,lib64
存放共享库文件,lib
文件存放kernel的modules驱动目录和udevd的规则文件.
4.完成拥有login登录能力(多窗口)
login有一套复杂的机制,我们不妨先实现能在bash中手动执行login创建多窗口。
login的依赖很复杂,它有一套完整的认证体系,如/etc/pam.d
的配置和/lib64/security
的依赖(这个共享库还会依赖别的共享库,需要注意)login
还涉及用户组管理/bin/chgrp
、/bin/chown
、/bin/chmod
等,保存用户名的文件/etc/passwd
、/etc/group
,用户密码文件为/etc/shadow
等等
我们可以用strace
命令去追踪login
执行时所调用的文件,并将他们拷贝到我们的小系统里,这些文件在/etc
,/lib
,/lib64
中都有分布。
那怎么知道我们可以使用多窗口登入了呢,使用udevd管理设备后,我们可以在打开小系统后发现里面有一堆tty文件,意味着我们可以同时使用多个终端,但是我们发现使用ctrl+alt+Fn组合键并不能打开新的终端,这是因为快捷键驱动我们还没挂起,但是没关系,我们可以将login重定向到另一个终端,在bash中执行
1 | login > /dev/tty2 2>/dev/tty2 < /dev/tty2 & |
就可以在后台执行一个login,并重定向到tty2,现在在使用ctrl+alt+F2就可以打开tty2终端。我们使用ps命令查看进程,就可以发现一些运行的命令是在tty2下运行的。
5. 使用/sbin/init管理的小系统原型
在以往的环节中,我们都是手动启动设备管理,手动登入和执行bash,但是如果我们退出这个bash,系统就会死掉,所以我们需要一个可以保护系统bash和控制启动流程的程序,sbin/init
就很好的帮我们解决了这些烦恼。
执行/sbin/init后,执行顺序如下:
/sbin/init
的过程大致分为三块:第一块是udevd加载驱动模块、文件系统检查和根切换,相关配置在/etc/rc.sysinit
中;第二块是启动各项服务,相关配置在/etc/rc.d/
目录下;第三块是登录部分,需要调用/sbin/mingetty
和/bin/login
等命令。将上述所涉及的命令及文件拷贝到小系统对应的目录下,并对配置进行修改。
我们需要把与init启动相关的文件拷到小系统里
1 | /etc/init/rcS.conf 加载rc.sysinit脚本,完成系统初始化任务 |
配置好/sbin/init
后,我们可以在init脚本中直接调用sbin/init
,便可完成系统的启动