I’m using debian live-build to work on a bootable system. By the end of the process i get the typical files used to boot a live system: a squashfs file, some GRUB modules and config files, and an initrd.img file.
I can boot just fine using those files, passing the initrd to the kernel via
initrd=/path/to/my/initrd.img
on the bootloader command line. But when I try to examine the contents of my initrd image, like so:
$file initrd.img initrd.img: ASCII cpio archive (SVR4 with no CRC) $mkdir initTree && cd initTree $cpio -idv < ../initrd.img
the file tree i get looks like this:
$tree --charset=ASCII
.
`-- kernel
`-- x86
`-- microcode
`-- GenuineIntel.bin
Where is the actual filesystem tree, with the typical /bin , /etc, /sbin … containing the actual files used during boot?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
The cpio block skip method given doesn’t work reliably. That’s because the initrd images I was getting myself didn’t have both archives concatenated on a 512 byte boundary.
Instead, do this:
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
Use the last number (21136) which is not on a 512 byte boundary for me:
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
Method 2
If you know your initrd.img consists of an uncompressed cpio archive followed by a gz-compressed cpio archive, you can use the following to extract all files (from both archives) into your current working directory (tested in bash):
(cpio -id; zcat | cpio -id) < /path/to/initrd.img
The above command-line passes the contents of initrd.img as standard input into a subshell which executes the two commands cpio -id and zcat | cpio -id sequentially. The first command (cpio -id) terminates once it has read all the data belonging to the first cpio archive. The remaining content is then passed to zcat | cpio -id, which decompresses and unpacks the second archive.
Method 3
It turns out the initrd generated by Debian’s live-build (and to my surprise, accepted by the kernel) is actually the concatenation of two images:
- a CPIO archive containing microcode updates to be applied on the processor;
- a gzip-ed cpio archive, which actually contains the initrd file tree (with the /etc /bin /sbin /dev … directories that were expected).
Upon extracting the original initrd.img, straight out of the live-build output, I got this output:
$cpio -idv ../initrd.img kernel kernel/x86 kernel/x86/microcode kernel/x86/microcode/GenuineIntel.bin 896 blocks
Which means that the cpio extraction ended after parsing 896 blocks of 512 Bytes each. But the original initrd.img was way bigger than 896*512 = 458752B = 448 KB :
$ls -liah initrd.img 3933924 -r--r--r-- 1 root root 21M Oct 21 10:05 initrd.img
So the actual initrd image I was looking for was appended right after the first cpio archive (the one containing the microcode updates) and could be accessed using dd:
$dd if=initrd.img of=myActualInitrdImage.img.gz bs=512 skip=896
Method 4
You can use unmkinitramfs from initramfs-tools >= 0.126, which is included since Debian 9 (stretch) and Ubuntu 18.04 (bionic).
On arch you can use lsinitcpio.
Method 5
Based on the idea given in @woolpool’s answer I wrote a recursive function that will work for any cpio archive regardless of the arrangement of the concatenated data and doesn’t require any special tools like binwalk. For example my mkinitramfs was producing a cpio;cpio;gzip file. It works by extracting each part of the concatenated initrd file, saving the rest into a tempfile and then using the “file” program to decide what to do with the next part.
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
}
To use type: uncpio initrdfilename
Method 6
If you need to perform this task often, you may want to create a small bash function like the following (and maybe add it to your .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 [email protected]
}
The code is based on Marc’s answer, but it’s significantly faster since binwalk will only look for gzip files.
You can invoke it, like this:
$ initramfs-extract /boot/initrd.img -v
You will need binwalk installed to make it work.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0