为什么我的initrd只有一个目录,即“内核”?


28

我正在使用debian live-build在可启动系统上工作。在该过程结束时,我得到了用于引导实时系统的典型文件:squashfs文件,一些GRUB模块和配置文件以及initrd.img文件。

我可以使用这些文件启动,并通过以下方式将initrd传递给内核

initrd=/path/to/my/initrd.img

在引导加载程序命令行上。但是,当我尝试检查initrd图像的内容时,如下所示:

$file initrd.img
initrd.img: ASCII cpio archive (SVR4 with no CRC)
$mkdir initTree && cd initTree
$cpio -idv < ../initrd.img

我得到的文件树如下所示:

$tree --charset=ASCII
.
`-- kernel
    `-- x86
        `-- microcode
            `-- GenuineIntel.bin

实际的文件系统树在哪里,其中典型的/ bin,/ etc,/ sbin ...包含引导期间使用的实际文件?


1
为此,设计了“ lsinitramfs”命令。
Earlgrey

Answers:


31

给出的cpio块跳过方法无法可靠运行。那是因为我得到的initrd映像没有将两个存档串联在512字节边界上。

相反,请执行以下操作:

apt-get install binwalk
legolas [mc]# binwalk initrd.img 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ASCII cpio archive (SVR4 with no CRC), file name: "kernel", file name length: "0x00000007", file size: "0x00000000"
120           0x78            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86", file name length: "0x0000000B", file size: "0x00000000"
244           0xF4            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode", file name length: "0x00000015", file size: "0x00000000"
376           0x178           ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/GenuineIntel.bin", file name length: "0x00000026", file size: "0x00005000"
21004         0x520C          ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
21136         0x5290          gzip compressed data, from Unix, last modified: Sat Feb 28 09:46:24 2015

请为我使用不在512字节边界上的最后一个数字(21136):

legolas [mc]# dd if=initrd.img bs=21136 skip=1 | gunzip | cpio -tdv | head
drwxr-xr-x   1 root     root            0 Feb 28 09:46 .
drwxr-xr-x   1 root     root            0 Feb 28 09:46 bin
-rwxr-xr-x   1 root     root       554424 Dec 17  2011 bin/busybox
lrwxrwxrwx   1 root     root            7 Feb 28 09:46 bin/sh -> busybox
-rwxr-xr-x   1 root     root       111288 Sep 23  2011 bin/loadkeys
-rwxr-xr-x   1 root     root         2800 Aug 19  2013 bin/cat
-rwxr-xr-x   1 root     root          856 Aug 19  2013 bin/chroot
-rwxr-xr-x   1 root     root         5224 Aug 19  2013 bin/cpio
-rwxr-xr-x   1 root     root         3936 Aug 19  2013 bin/dd
-rwxr-xr-x   1 root     root          984 Aug 19  2013 bin/dmesg

确实,您的答案胜过我的。我从未想过对齐会是个问题。但是,我想知道,如果多图像文件中包含的第一张图像未使用512B内衬,cpio是否会提供一些更有趣的输出。
user986730 2015年

修改后如何使用相同的文件夹层次结构将其还原(重新打包为原始状态)?
EdiD '16

2
只是cd到您提取您的cpio归档文件,运行目录下find | cpio -H newc -o > /tmp/my_archive.cpio,然后用gzip它gzip /tmp/my_archive.cpio,最后,与它拼接与微图像,如果你有一个:cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img。如果没有微码映像,则可以像在引导加载程序中一样使用gzip压缩文件
user986730

在阅读此答案时,似乎只有在压缩的内容在文件中途超过一半时,这才有效。否则,应将块大小更改为1,并将skip设置为要跳过的字节数。有什么理由不总是这样做吗?
TamaMcGlinn

其次,要实际编写文件而不是仅列出其中一些文件,请将管道中的最终命令更改为cpio -i,而不是cpio -tdv | head
TamaMcGlinn

21

如果您知道自己initrd.img由未压缩的cpio归档文件和gz压缩的cpio归档文件组成,则可以使用以下命令将所有文件(来自两个归档文件)提取到当前工作目录中(在bash中进行测试):

(cpio -id; zcat | cpio -id) < /path/to/initrd.img

上述命令行传递的内容initrd.img作为标准输入到其中执行所述两个命令子外壳cpio -idzcat | cpio -id顺序。cpio -id一旦读取了属于第一个cpio归档文件的所有数据,第一个命令()将终止。然后将其余内容传递到zcat | cpio -id,以解压缩第二个存档并解压缩。


1
这似乎是迄今为止最干净的解决方案
velis

1
它工作
得很

神秘地,@ woolpool的好答案是用户发布过的唯一答案。那是风格。如果您在整个StackExchange整个职业生涯中仅发布一个答案,那么您很难做得比发布这样的答案更好。OP可以考虑将接受的答案更改为此。
18th

16

事实证明,由Debian的实时构建生成的initrd(令人惊讶的是,被内核接受)实际上是两个图像的串联:

  • CPIO存档,其中包含要在处理器上应用的微代码更新;
  • 一个gzip版本的cpio归档文件,其中实际上包含initrd文件树(带有/ etc / bin / sbin / dev ...预期的目录)。

直接从实时构建输出中提取原始的initrd.img后,我得到以下输出:

$cpio -idv ../initrd.img
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/GenuineIntel.bin
896 blocks

这意味着cpio提取在解析了每个512字节的896个块之后结束。但是原始的initrd.img比896 * 512 = 458752B = 448 KB大得​​多:

$ls -liah initrd.img
3933924 -r--r--r-- 1 root root 21M Oct 21 10:05 initrd.img

因此,我正在寻找的实际initrd映像会附加在第一个cpio归档文件(包含微代码更新的归档文件)之后,并且可以使用dd访问:

$dd if=initrd.img of=myActualInitrdImage.img.gz bs=512 skip=896

2

您可以使用unmkinitramfsinitramfs-tools> = 0.126,这是Debian 9(stretch)和Ubuntu 18.04(bionic)自包含的。


1

基于@woolpool答案中给出的想法,我编写了一个递归函数,该函数可用于任何cpio归档文件,而不必考虑串联数据的排列方式,并且不需要诸如binwalk之类的任何特殊工具。例如,我的mkinitramfs正在生成cpio; cpio; gzip文件。它的工作方式是提取串联的initrd文件的每个部分,将其余部分保存到一个tempfile中,然后使用“文件”程序来决定对下一部分进行处理。

uncpio(){
if [[ $(wc -c $1 | cut -d ' ' -f1) -eq 0 ]]; then
    return
fi

type=$(cat $1 | file -)
local tmpfile=$(date +%s.%N)
echo -e "\n$type"
if [[ $type =~ .*cpio.* ]]; then
    cat $1 | (cpio -id; cat >$tmpfile)
elif [[ $type =~ .*gzip.* ]]; then
    zcat $1 | (cpio -id; cat >$tmpfile)
else
    return
fi
uncpio $tmpfile 
rm $tmpfile
}

要使用的类型:uncpio initrdfilename


0

如果您需要经常执行此任务,则可能要创建一个类似于以下内容的小型bash函数(并将其添加到您的.bashrc中):

initramfs-extract() {
    local target=$1
    local offset=$(binwalk -y gzip $1 | awk '$3 ~ /gzip/ { print $1; exit }')
    shift
    dd if=$target bs=$offset skip=1 | zcat | cpio -id --no-absolute-filenames $@
}

该代码基于Marc的答案,但由于binwalk仅查找gzip文件,因此速度明显加快。您可以像这样调用它:

$ initramfs-extract /boot/initrd.img -v

您将需要binwalk安装才能使其正常运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.