二十、switch_root 命令
除了基于init ramfs的系统(如第四节的mini linux),通常init ramfs都是为安装最终的根文件系统做准备工作,它的最后一步需要安装最终的根文件系统,然后切换到新根文件系统上去。以往的基于ramdisk 的initrd 使用pivot_root命令切换到新的根文件系统,然后卸载ramdisk。但是init ramfs是rootfs,而rootfs既不能pivot_root,也不能umount。为了从init ramfs中切换到新根文件系统,需要作如下处理:
(1)删除rootfs的全部内容,释放空间
find -xdev / -exec rm '{}' ';'
(2)安装新的根文件系统,并切换
cd /newmount; mount --move . /; chroot .
(3)把stdin/stdout/stderr 附加到新的/dev/console,然后执行新文件系统的init程序
上述步骤比较麻烦,而且要解决一个重要的问题:第一步删除rootfs的所有内容也删除了所有的命令,那么后续如何再使用这些命令完成其他步骤?busybox的解决方案是,提供了switch_root命令,完成全部的处理过程,使用起来非常方便。
switch_root命令的格式是:
switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
其中NEW_ROOT是实际的根文件系统的挂载目录,执行switch_root命令前需要挂载到系统中;NEW_INIT是实际根文件系统的init程序的路径,一般是/sbin/init;-c /dev/console是可选参数,用于重定向实际的根文件系统的设备文件,一般情况我们不会使用;而ARGUMENTS_TO_INIT则是传递给实际的根文件系统的init程序的参数,也是可选的。
需要特别注意的是:switch_root命令必须由PID=1的进程调用,也就是必须由init ramfs的init程序直接调用,不能由init派生的其他进程调用,否则会出错,提示:
switch_root: not rootfs
也是同样的原因,init脚本调用switch_root命令必须用exec命令调用,否则也会出错,提示:
switch_root: not rootfs
二十一、实践:用init ramfs安装CLFS根文件系统
现在实践一下switch_root命令,用它切换一个CLFS的根文件系统硬盘分区。我的CLFS安装在/dev/sda8硬盘分区,我们就以此为例说明。
我们还是在以前的image目录中构建
(1)改写init脚本
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
mount /dev/sda8 /mnt (注意:为了简单,我们直接把CLFS分区写死在init脚本中了)
exec switch_root /mnt /sbin/init
(2)生成新的initrd
按上一节“精通init ramfs构建step by step (五):initrd”描述的cpio命令生成新的initrd。
(3)把新的initrd拷贝到CLFS分区的/boot目录下,改名为clfs-initrd
(4)在GRUB的menu.lst配置文件中增加一个启动项
#test for init ramfs of CLFS
title test for init ramfs of CLFS (on /dev/sda8)
root (hd0,7)
kernel /boot/clfskernel-2.6.17.13 (注意:并没有向内核传递root参数信息)
initrd /boot/clfs-initrd
全部做完后,重启机器,选择 test for init ramfs of CLFS 启动项,机器顺利进入了CLFS系统,我们构建的init ramfs用switch_root命令完成了CLFS实际根文件系统的安装和切换。