4.4 构建基本的initramfs
在这一节,我们先建立一个initramfs的原型,用来验证内核配置以及这个initramfs原型。我们在/vita目录下创建一个initramfs目录,initramfs的内容保存在这个目录中。
如果没有在传递给内核的命令行参数中指定"rdinit",内核启动后,执行的initramfs中第一个程序是根目录下的init。那我们就从创建init程序开始,来创建我们的initramfs。
基本上所有的init程序都是采用shell脚本编写的,我们这里也不例外,当然你也可以采用其他语言(比如C)来编写。这里要注意的一点是,编写init脚本时,用来指明脚本使用的解释器的字符串"#!/bin/bash"一定要从第一行的左侧第一个字符开始,因为内核中的脚本加载器将根据脚本文件的前两个字符判断使用什么解释器。具体如下:
编写完这个脚本后,我们需要为其增加可执行属性,具体如下:
这个脚本首先使用echo输出"Hello Linux!",echo是shell内置的命令,不需要再额外安装其他程序。然后运行一个交互式shell,与用户进行交互。
shell提供两种运行模式:一种是非交互模式,另外一种是交互模式。在运行解释init脚本文件时,最后会转化为形如"/bin/bash/init",即将脚本文件init作为参数传给bash程序,这是典型的非交互方式,即bash的输入不是通过用户输入,而是保存在一个shell脚本文件中。
但是,我们需要通过shell与内核进行交互,因此,最后通过命令启动了一个新的shell,这个bash程序没有任何输入,自然就以交互模式运行,因为其需要从用户获得输入。这里使用exec的目的是后面的shell进程直接代替前面的shell进程,而不是复制出另外一个进程,也就是确保这个进程依然是pid为1的进程。
init是需要shell解释器来解释运行的,因此,除了init脚本文件外,initramfs中还需要bash程序。安装bash程序的命令如下:
我们需要检查bash依赖的动态库,命令如下:
bash依赖于libc、libdl以及libgcc_s.so.1,因此,我们需要在initramfs中安装这三个库,以及安装加载动态库的动态加载/链接器。安装命令如下:
我们还需要检查它们的依赖。
根据依赖关系可见,libdl依赖libc和动态链接器,libgcc只依赖libc,libc仅依赖动态链接器,而动态链接器不依赖其他任何库,因此,我们不再需要安装其他库到initramfs中。
至此,基本的initramfs已经准备完成,打包前,我们可以使用find命令最后再检查一遍initramfs中的内容:
最后我们将initramfs打包并压缩,保存在/vita/sysroot/boot目录下。根据内核要求,需要使用cpio压缩,并且压缩的格式为"newc",具体命令如下:
我们将bzImage和initrd.img复制到虚拟机:
然后更改虚拟机的GRUB的配置文件grub.cfg,告知GRUB加载initrd。
重启系统,进入vita系统,运行结果如图4-8所示。
图 4-8 运行到initramfs中的bash
由图4-8可见,initramfs中的init输出了"Hello Linux!"后,启动了一个交互式的shell。