制作initrd(5):解剖Ubuntu安装盘

from:http://blog.csdn.net/lixiangminghate/article/details/50719379

ubuntu定期更新他们的iso,iso引导系统后会有Try/Install Ubuntu两个选项。特别是选择了livecd,仅仅一张盘子就能运行一个图形化的linux,总觉得挺神奇的。在好奇心的推动下我打算拆开iso分析它是怎样引导到系统的。

    按常识,完整引导linux系统需要bootloader/kernel/(initrd)/fs这4个组件紧密配合(要不就叫启动4要素吧),光盘引导linux也一定是遵循这个过程,因此下文也按这个顺序展开。第一步当然得挂载iso,很可惜iso是只读的,因此要做修改还得把内容拷出来并修改权限。(注意,后面的命令都是用root帐户运行的)

  1. root@ubuntu:~# rsync /media/Ubuntu\ 14.10\ amd64/ -a ~/Desktop/iso/  
  2. root@ubuntu:~# chmod -R 744 ~/Desktop/iso/  

    嗯,这里安装盘已经被分尸了,后面就可以一块块拿出来看看改改。首先看下bootloader的入口点,网上查了一把安装盘以isolinux.bin作为bootloader,位于isolinux/isolinux.bin。一般bootloader会读取用户配置文件从中取出引导参数。isolinux读取的配置文件位于同层目录isolinux/isolinux.cfg:

  1. path   
  2. include menu.cfg  
  3. default vesamenu.c32  
  4. prompt 0  
  5. timeout 50  
  6. ui gfxboot bootlogo  

打开后并没有见到/proc/cmdline中常见的kernel=xxx initrd=xxx之类的内容,不过仔细一看居然有include menu.cfg语句(具体参考islinux语法),想想就知道肯定是去包含其他配置文件。经过对include语句层层跟进,最终在isolinux/txt.cfg这个文件中找到熟悉的kernel引导项:

  1. default live  
  2. label live  
  3.   menu label ^Try Ubuntu without installing  
  4.   kernel /casper/vmlinuz  
  5.   append  file=/cdrom/preseed/ubuntu.seed boot=casper initrd=/casper/initrd.lz quiet splash --  
  6. label live-install  
  7.   menu label ^Install Ubuntu  
  8.   kernel /casper/vmlinuz  
  9.   append  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity initrd=/casper/initrd.lz quiet splash --  

默认引导项是live。kernel文件位于casper/vmlinuz,initrd文件位于casper/initrd.lz同时,isolinux还向kernel提供了一个重要的参数boot=casper,初次看到这个参数,我以为这是告诉bootloader要从casper文件夹下寻找kernel和initrd文件,后来发现,并非如此,后面马上会提到。

    既然bootloader都指定kernel的位置了,那我们就跟进到casper文件夹下

  1. root@ubuntu:/media/Ubuntu 14.10 amd64# cd casper/  
  2. root@ubuntu:/media/Ubuntu 14.10 amd64/casper# ls  
  3. filesystem.manifest         filesystem.size      initrd.lz  
  4. filesystem.manifest-remove  filesystem.squashfs  vmlinuz.efi  
  5. root@ubuntu:/media/Ubuntu 14.10 amd64/casper#   

    看文件名的输出基本能猜到启动4要素中剩下的3个要素就在这几个文件里了。另外,看文件大小也知道光盘的核心数据在这个文件夹中。假设,bootloader已经把执行权交给kernel,就是casper/vmlinuz了(这个流程过于复杂我就略过了)。vmlinuz的最后会搜索根文件系统,由根文件系统检测系统配置并通过udevadm加载相应的modules,为进一步加载真实的fs做准备。可惜,这里的initrd双击打开什么都看不到,那就这么停止分析了么?当然不会,都分尸了,总的好好利用一下尸体吧~先分析一下initrd.lz的文件性质

  1. root@ubuntu:~/Desktop/iso/casper# file initrd.lz   
  2. initrd.lz: LZMA compressed data, streamed  

    嗯,lzma压缩,好的,解压

  1. root@ubuntu:~/Desktop/iso/casper# mv initrd.lz initrd.lzma  
  2. root@ubuntu:~/Desktop/iso/casper# lzma -d initrd.lzma   
  3. root@ubuntu:~/Desktop/iso/casper# ls|grep initrd  
  4. initrd  
  5. root@ubuntu:~/Desktop/iso/casper# file initrd   
  6. initrd: ASCII cpio archive (SVR4 with no CRC)  
  7. root@ubuntu:~/Desktop/iso/casper#   

    嗯,真调皮还经过cpio归档,再分解就能看到initrd的目录结构,这个结构和前面文章<制作initrd(N)>基本相同,毕竟这个initrd是mkinitramfs做出来的么:

  1. root@ubuntu:~/Desktop/iso/casper# cpio -idmv < initrd  
  2. root@ubuntu:~/Desktop/iso/casper# ls  
  3. bin                  sbin       
  4. conf                 lib     scripts  
  5. etc                  lib64   usr  
  6. init                 run     var  

    好的,请打开init脚本,这是kernel加载initrd后执行的第一个进程,里面先挂载虚拟的文件系统然后设置了一堆变量:

  1. #!/bin/sh  
  2.   
  3. [ -d /dev ] || mkdir -m 0755 /dev  
  4. [ -d /root ] || mkdir -m 0700 /root  
  5. [ -d /sys ] || mkdir /sys  
  6. [ -d /proc ] || mkdir /proc  
  7. [ -d /tmp ] || mkdir /tmp  
  8. mkdir -p /var/lock  
  9. mount -t sysfs -o nodev,noexec,nosuid sysfs /sys  
  10. mount -t proc -o nodev,noexec,nosuid proc /proc  
  11. # Some things don't work properly without /etc/mtab.  
  12. ln -sf /proc/mounts /etc/mtab  
  13.   
  14. grep -q '\<quiet\>' /proc/cmdline || echo "Loading, please wait..."  
  15.   
  16. # Note that this only becomes /dev on the real filesystem if udev's scripts  
  17. # are used; which they will be, but it's worth pointing out  
  18. if ! mount -t devtmpfs -o mode=0755 udev /dev; then  
  19.     echo "W: devtmpfs not available, falling back to tmpfs for /dev"  
  20.     mount -t tmpfs -o mode=0755 udev /dev  
  21.     [ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1  
  22.     [ -e /dev/null ] || mknod /dev/null c 1 3  
  23. fi  
  24. mkdir /dev/pts  
  25. mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true  
  26. mount -t tmpfs -o "noexec,nosuid,size=10%,mode=0755" tmpfs /run  
  27. mkdir /run/initramfs  

 

  1. export init=/sbin/init  
  2. export quiet=n  
  3. export readonly=y  
  4. export rootmnt=/root  
  5. ...  
  6. for x in $(cat /proc/cmdline); do  
  7.     case $x in  
  8.         ...  
  9.         boot=*)  
  10.         BOOT=${x#boot=}  
  11.         ;;  
  12.         ...  
  13.     esac  
  14. done  

    重要的来了,init脚本分析/proc/cmdline并以此设置参数,前面引导kernel时提到isolinux会向kernel传递参数boot=casper,目的就是设置BOOT变量,再来看下这个变量做了啥?

    

  1. export BOOT  
  2.   
  3. # Don't do log messages here to avoid confusing graphical boots  
  4. run_scripts /scripts/init-top  
  5.   
  6. maybe_break modules  
  7. "$quiet" != "y" ] && log_begin_msg "Loading essential drivers"  
  8. load_modules  
  9. "$quiet" != "y" ] && log_end_msg  
  10.   
  11. [ -n "${netconsole}" ] && modprobe netconsole netconsole="${netconsole}"  
  12.   
  13. maybe_break premount  
  14. "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"  
  15. run_scripts /scripts/init-premount  
  16. "$quiet" != "y" ] && log_end_msg  
  17.   
  18. maybe_break mount  
  19. log_begin_msg "Mounting root file system"  
  20. . /scripts/${BOOT}    #关键的一行  
  21. parse_numeric ${ROOT}  
  22. maybe_break mountroot  
  23. mountroot    #挂载fs函数  
  24. log_end_msg  

    加载modules后,init根据BOOT的值,include几个文件,对于光盘启动就是casper/initrd/scripts/casper这个shell脚本,这个脚本提供了mountroot挂载fs函数的实现

  1. root@ubuntu:~/Desktop/iso/casper/scripts# file casper  
  2. casper: POSIX shell script, ASCII text executable  

    一下摘取了casper脚本的部分代码,具体分析日后再说!

  1. mountroot() {  
  2.     exec 6>&1  
  3.     exec 7>&2  
  4.     exec > casper.log  
  5.     exec 2>&1  
  6.     tail -f casper.log >&7 &  
  7.     tailpid="$!"  
  8.   
  9.     parse_cmdline  
  10.   
  11.     [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/casper-premount"  
  12.     run_scripts /scripts/casper-premount  
  13.     [ "$quiet" != "y" ] && log_end_msg  


   经过initrd的一番折腾,最终是要去挂载fs了。和initrd一样,fs是个压缩过的镜像,镜像名casper/filesystem.squashfs。为了解剖这个镜像需要换把剔肉刀:squashfs-tools

  1. root@ubuntu:~/Desktop/iso/casper# apt-get install squashfs-tools  

    解压是个漫长的过程,特别是在虚拟机中可以看一个视频净化一下心灵:

  1. root@ubuntu:~/Desktop/iso/casper# unsquashfs filesystem.squashfs   
  2. Parallel unsquashfs: Using 1 processor  
  3. 174753 inodes (185772 blocks) to write  

   解压后多了一个squashfs-root的目录,ls看一下里面就是运行livecd时用到的文件系统。

  1. root@ubuntu:~/Desktop/iso/casper/squashfs-root# ls  
  2. bin   dev  home        lib    media  opt   root  sbin  sys  usr  
  3. boot  etc  initrd.img  lib64  mnt    proc  run   srv   tmp  
  4. root@ubuntu:~/Desktop/iso/casper/squashfs-root  


   好,这篇解剖报告到此为止,剧透一下后两篇的安排,制作initrd(6)应该是定制fs 制作initrd(7)是分析initrd中casper脚本的内容

  

posted @   愤怒的企鹅  阅读(275)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示