initrd的全名是 init ramdisk,是一个启动时存在于内存的文件系统。
kernal 到 initrd的流程
在GRUB加载kernel时,kernel会先在内存中制造一个rootfs当做临时的空间供系统使用,接下来,kernel便会将initrd当做是一个系统,将其mount到rootfs上启动。
引入initrd的目的是为了把kernel的启动分成两个阶段:在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的方式放在initrd中,这样就在启动过程中可以从initrd所mount的根文件系统中装载需要的模块。这样的一个好处就是在保持kernel不变的情况下,通过修改initrd中的内容就可以灵活的支持不同的硬件。在启动完成的最后阶段,根文件系统可以重新mount到其他设备上。
initrd文件结构
initrd文件在/boot目录中很容易找到,可以通过以下命令将期解压
## 将文件移至对应目录cp initrd.img-xxxx-generic ~/initrd/initrd.img.gz## 老版本gunzip initrd.img.gz
cpio -idmv < ../initrd.img## 新版本lsinitramfs /boot/initrd.img-xxx-generic (可以通过些命令查询其文件)
binwalk -y gzip initrd.img.gz (定位压缩文件的开始偏移量)## 6938624 即是通过binwalk定位出来的值
dd if=initrd.img.gz bs=6938624 skip=1 | zcat | cpio -id --no-absolute-filenames -v## 使用ls查看目录
bin conf etc init lib lib64 run sbin scripts usr var
经解压发现initrd就是最简单的一个文件系统,唯一不同的是存在一个init脚本。
export PATH=/sbin:/usr/sbin:/bin:/usr/bin
[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid sysfs /sys
mount -t proc -o nodev,noexec,nosuid proc /proc
在init文件中要执行的第一件事情,就是创建几个重要的目录。其中/sys,/proc作为kernel使用的主要目录,init必须将其挂载。
-
/proc 这目录其实是加载kernel后,在内存里面建立的一个虚拟目录,主要提供系统运行的实时信息
-
/proc/PID 这目录表示,系统一进程运行时信息
-
/proc/paritions 表示系统检测到的硬盘分区情况,其使用major和mintor 两字段来标识唯一
-
/sys/block
-
/sys/bus
在收集完设备信息后,就要开始玩设备文件了
mount -t devtmpfs -o nosuid,mode=0755 udev /dev
mkdir /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true
- /dev 是以tmpfs的文件系统存放的devfs系统架构的文件
- tmpfs 内存中的文件系统
- devfs 将所有的设备信息以文件的方式存储
- udev 补充devfs的问题,udev 会自动从/sys目录找到所需要的硬盘信息装置。
- /dev/pts 主机虚拟终端,当ssh连接进来后,就出来一文件
在initrd建立好相关的文件系统配置后,就要开始转移到实体操作系统
- 建立默认使用的设备文件
- 加载moule
- 建立系统使用目录 并 /proc, /sys /dev 转移过去
initrd最后工作就是要通过init脚本文件,将所有一切交给存在硬盘中的实体操作系统。
exec run-init ${drop_caps} ${rootmnt} ${init} "$@" ${recovery:+--startup-event=recovery} <${rootmnt}/dev/console >${rootmnt}/dev/console 2>&1
重新调用/sbin/init来开始后续的正常启动流程.当然也可以 内核启动参数 init={所要执行的程序}来替换
init启动流程
说白init进程就是内核自动启动第一个用户级程序,所以其进程编号始终为1。
1. 以initdefault值判断系统以那level运行
0 - 停机(千万不能把initdefault 设置为0 )
1 - 单用户模式
2 - 多用户,没有 NFS
3 - 完全多用户模式(标准的运行级)
4 - 没有用到
5 - X11 (xwindow)
6 - 重新启动 (千万不要把initdefault 设置为6 )
2. 执行/etc/rc.d/rc.sysinit
其过程相当很杂,大部份和系统环境相关
3. 执行/etc/rc.d/rcX.d
X 表示其运行级别,我们以3为例
- 里面有好多文件都以"S" 或 “K” 开头,"S" 为可会执行的脚本,“K”是死的。
- “SK”后面跟着数字,即脚本执行的顺序
- 通过改名字就可以调整服务
- 其中S99local连接到/etc/rc.d/rc.local专门给用户使用
4. 通过登录程序进入shell
initab的最后阶段扫运行minttyt程序,让用户输入密码登录,进行shell