initrd&init进程

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建立好相关的文件系统配置后,就要开始转移到实体操作系统

  1. 建立默认使用的设备文件
  2. 加载moule
  3. 建立系统使用目录 并 /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为例

  1.  里面有好多文件都以"S" 或 “K” 开头,"S" 为可会执行的脚本,“K”是死的。
  2. “SK”后面跟着数字,即脚本执行的顺序
  3. 通过改名字就可以调整服务
  4. 其中S99local连接到/etc/rc.d/rc.local专门给用户使用

4. 通过登录程序进入shell

     initab的最后阶段扫运行minttyt程序,让用户输入密码登录,进行shell

主要参考

新型的initrd的解压方法

《Linux操作系统之奥秘》

猜你喜欢

转载自blog.csdn.net/y3over/article/details/53689885