西西河

主题:【原创】如何解开Ubuntu的initrd.img和Gentoo的initramfs -- wsxx

共:💬13 🌺37 新:
分页树展主题 · 全看
  • 家园 【原创】如何解开Ubuntu的initrd.img和Gentoo的initramfs

    你为什么要这么干?因为想DIY自己的Linux的启动过程。

    对于我来说,我最近的目的是把Gentoo安装到移动硬盘上,让电脑直接从移动硬盘启动。做成这样的一个Linux之后,我可以拿着硬盘到不同的机器上使用,甚至在不支持USB启动的老机器上使用(当然它得有USB接口)。

    如何在移动硬盘上安装我的Gentoo,参见

    链接出处

    在内核启动之后的几秒钟之内,USB设备可能尚未被系统确认,Linux可能会提示找不到根。我们需要修改启动过程,让内核sleep几秒钟之后再继续引导,就需要修改initrd(Ubuntu是initrd.img-xxxx,Gentoo是initramfs-genkernel-xxxxx)文件中的一个叫做init的脚本(script),在其中适当的地方插入一个sleep 5让它暂停5秒钟。

    要编辑init这个文件,需要把压缩的initrd解开,找到其中的init进行修改,然后再把修改好的文件连同一起解开的宋有文件再打包成initrd,更换掉原来的initrd或者使用新的文件名,在启动菜单中增加新的指向。后者是保险的方法,免得万一没搞好,原来的又没了。

    现在的问题是initrd文件如何解开。

    我看了不少网上的文章,介绍的基本上都是针对Linux 2.4之前的方法,那时的打包方法是把所有文件做成镜像文件,再用gzip压缩。打开那种initrd文件的过程就是先gunzip,把解压的文件挂载到一个目录中,就可以对目录中的任何文件进行阅读和修改了。

    但是,我开始学Linux的时候已经是2.6版推出之后了。使用上面的方法完全无法解开initrd文件,第一步gunzip可以,后面的挂载就怎么弄都是错的,修改其中的文件也就无从谈起。

    这种情况持续了可能有一个月,每天翻来覆去mount -o loop -t filetype都不行,在网上查来查去也还是这个办法。

    昨天,在google的搜索结果的第三页之后随便按了一个很不起眼的链接,看到一篇文章竟然有解决办法。原来2.6版开始,不再用镜像的方法制作initrd了,据分析说是为了简化制作步骤。新的制作方法采用cpio的方式制作。

    接下来,我将把Ubuntu和Gentoo的解压发放介绍一下,两者还有不同,这又花了我很长时间才搞个半懂。

    (待续)

    关键词(Tags): #Ubuntu#Gentoo#initrd#cpio元宝推荐:闲看蚂蚁上树,铁手,
    • 家园 好文,做个极好
    • 家园 【后记】我们应该养成好习惯

      在解压的过程中,我碰到问题的时候,花了很多时间在试验各种命令的选项和参数上了,又花了很多时间去查文献,虽然这些都是值得的,但是回想起来不是很科学的方法,效率很低。

      碰到这种情况,首先应该从大局出发,摸清它是什么类型的文件,知道了对手的情况才好下手解压。具体来说,要知道initramfs这个文件是什么类型的文件,不应该上去就解压,除非你已经确定知道它的类型,应该使用file这个命令先做一下火力侦察:

      file initramfs.gz

      系统报告:

      initramfs.gz: gzip compressed data, from Unix, max compression

      这是一个gzip压缩文件,用gzip/gunzip解压。

      而后

      file initramfs

      系统报告:

      initramfs: ASCII cpio archive (SVR4 with no CRC)

      原来这是cpio文档,我们很快就会找到解压的办法,就是用cpio去解压,而不是把它当作镜像文件去解。

      也许这是事后诸葛亮了,但愿以后碰到问题不会这么费劲。

      (完)

      关键词(Tags): #cpio#file
    • 家园 (续二)解压Gentoo中的initramfs的方法

      解压Gentoo的initramfs方法,与遵循常规方法的Ubuntun略有不同。

      我们先来看看问题在哪里:

      cp /boot/initramfs-genkernel-x86-2.6.17-gentoo-r4 /initramfs.gz # 复制到当前家目录,简化文件名

      gunzip initramfs.gz # gunzip解压

      mkdir initrd #建立一个新目录

      cd initrd #进入新目录

      cpio -i -d < ../initramfs #解开上层目录中的initramfs

      也可以这样:cat ../initramfs |cpio -id

      可是结果是显示5 blocks,也就是说解压出来的内容一共才有5K大小!这显然是有问题的,原始的initramfs.gz有2M多,gunzip解压之后有4M多,可是怎么可能cpio解压之后只有5K呢?Ubuntu解压出来之后有12M多呢。

      这个问题不解决,修改init是没有用的。曾经修改之后再打包压缩回去,剩下不到1K的内容。如果拿它去启动,不知道会是什么样子。

      被这个问题困扰的人不多也不少,在网上遇到问题求问的不少,有些人似乎找到了答案,但是也不是最终正确的。例如有人觉察到cpio打开initramfs之后遇到TRAILER解包就结束了,所以来了个我称作的“二次解包法”:

      cat ../initramfs |(cpio -id;cpio -id)

      这样可以解出343 blocks。我第一次以为这样算是可以了,后来才明白 1个block其实只有1K,343K是比5K大了不少,但是距离成千上万K的预期值还相去甚远。

      继续在网上翻,在几乎绝望的状态之下,很偶然地点击了google搜索结果第n页的一个不起眼的链接,里面竟然有正解!

      外链出处

      对于Linux比较熟练的人看了上面的链接就知道自己做了,我是琢磨了一番才搞明白的。新手们可能还需要解释一番,我回头再写一个详细一点的解释和示例。

      (待续)

      • 家园 (续三)解压Gentoo中的initramfs的详细方法

        外链出处这篇文章中说到,Gentoo的initramfs文件中有TRAILER的问题,cpio碰到这些东西就停止了解压。该作者写了一个小小的脚本,用来修理TRAILER:

        #!/bin/bash

        awk '

        BEGIN{RS="07070"}

        {

        if(/TRAILER\!\!\!/){y=""}else{y=RT}

        if(RT!=""){x=x gensub(/^.*TRAILER\!\!\!.*$/,"",1) y}else{x=x $0}

        }

        END{print x}' $1

        这个脚本的正则表达式使用得出神入化,我们恐怕一时难以搞明白,先这么使用着吧,等有空再回来琢磨。

        我们使用的时候,可以把以上内容保存为一个文本文件,按照作者的方法,命名为fixcpio,保存在家目录中。要让这个脚本可以被执行,还必须给它加上可执行的属性:

        chmod +x fixcpio

        然后就可以用它来做为解包过程中的一环:

        cat initramfs.gz | gunzip | ./fixcpio >initramfs-fixed # 解压后送到fixcpio处理一下再保存起来

        cd initrd #进入工作目录

        cpio -id <../initramfs-fixed # 解压上层目录的文件到本目录中

        initramfs-fixed就是修理过的cpio格式的文件,最后一步就和普通的cpio解包过程相同了。

        总结一下,可以把两步合并成一步,如果已经进入工作目录,只要这样就可以了:

        cat ../initramfs.gz | gunzip | ../fixcpio |cpio -id

        同理,修改init之后,再打包回去,只要这样一步就可以了:

        find .|cpio -oH newc|gzip -9> ../myinitramfs.gz

        重新打包当然就没有修理一说了。在上层家目录里将会得到myinitramfs.gz,这是可以用来启动的文件了。

        简化的方法也是用于Ubuntu。

        (完)

      • 家园 静心学习,花,呵呵,一花双宝,好爽!
    • 家园 (续一)解压Ubuntu的initrd.img的方法

      Ubuntu的initrd.img可以在/boot中找到,通常文件名后面还跟有很长的一串版本号。

      为了保险起见,不直接操作原文件,而是把它复制到自己的家目(home)录中。如果你是用root帐号登录的,家目录就在/root中,如果是用wsxx登录的,家目录一般就在/home/wsxx中,通常登录之后自动就到了家目中。我们把initrd.img复制但家目中进行解压:

      cp /boot/initrd.img-2.6.15-ubuntu-r6 ./initrd.img.gz

      上面这个命令把/boot区中的文件复制到当前目录,并更名为initrd.img.gz。一方面改成短文件名好一点好操作,另一方面加上gz的后缀更清楚表明它原本就是一个gzip压缩出来的文件。

      然后解压:

      gunzip initrd.img.gz

      也可以:

      gzip -d initrd.img.gz

      两者结果是相同的,都是在当前目录得到一个解压后的initrd.img,原来的initrd.img.gz被删除掉了(这也许是linux整洁的优点)。

      现在这个更大的initrd.img要用cpio解开,成为一系列目录和文件。为了不与当前目录中现有的文件搞混,我们有必要新建一个目录,把initrd.img解压到新目录中去。将来把里面的文件修改好之后,还要把所有的目录文件再打包起来:

      mkdir initrd #建立目录

      cd initrd #进入目录

      cpio -i -d < ../initrd.img #解开上层目录中的initrd.img

      因为已经进入到initrd中,../initrd.img表示上层目录中的initrd.img。

      现在就可以看到initrd中各目录中有很多新的目录和文件了。在这里我们可以窥视到ubuntu是如何装配起来的。可以对其中的内容进行修改了。

      修改文本文件没有什么好多说的了。

      修改之后,就是压缩回去,用它来启动,检验是否可以正常启动,是否达到预期的修改目的。先用cpio打包:

      find . | cpio -o -H newc > ../myinitrd.img #打包当前目录中的所有目录和文件,到上层目录中的myinitrd.img

      cd .. #回到上层目录

      gzip -9 myinitrd.img #gzip的最高级压缩

      得到的myinitrd.img.gz就是新的Ubuntu启动文件了。

      做到这里,要有必要停下来看看一看,比较一下重新压缩之后的文件,是否和原来的initrd.img.gz差不多大小?都应该是4M多的文件。如果文件大小相差太多,可能就有问题。我用Ubuntu文件解压后在压缩回来,用不同的文件名,最后比较,大小完全一致,心里就踏实了。

      再用Gentoo的initramfs文件进行同样方法的操作,2M多的文件解压再压缩回来,只剩下不到1K了,自己也不相信这是对的。

      (待续)

      关键词(Tags): #Ubuntu
    • 家园 很有兴趣,花催下文
    • 家园 这种情况持续了可能有一个月!!!

      搞不懂老兄一年到头怎么花那么多时间净琢磨这些东西啊??12万分的佩服!!!

    • 家园 支持diy,送花一朵
分页树展主题 · 全看


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河