我正在使用 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
给出的 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
使用最后一个数字 (21136),它对我来说不在 512 字节边界上:
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
答案2
如果您知道您的initrd.img
文件由未压缩的 cpio 存档和 gz 压缩的 cpio 存档组成,则可以使用以下命令将所有文件(来自两个存档)提取到当前工作目录(在 bash 中测试):
(cpio -id; zcat | cpio -id) < /path/to/initrd.img
上面的命令行将 的内容initrd.img
作为标准输入传递到子 shell 中,该子 shell 依次执行这两个cpio -id
命令zcat | cpio -id
。第一个命令 ( cpio -id
) 在读取属于第一个 cpio 存档的所有数据后终止。然后剩余的内容被传递到zcat | cpio -id
,它会解压缩并解压第二个存档。
答案3
事实证明,Debian 的 live-build 生成的 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 提取在解析 896 个块(每个块 512 字节)后结束。但原始的 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
答案4
根据 @woolpool 的答案中给出的想法,我编写了一个递归函数,该函数适用于任何 cpio 存档,无论连接数据的排列如何,并且不需要任何特殊工具(例如 binwalk)。例如,我的 mkinitramfs 正在生成 cpio;cpio;gzip 文件。它的工作原理是提取串联的 initrd 文件的每个部分,将其余部分保存到临时文件中,然后使用“文件”程序决定如何处理下一部分。
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初始化文件名