This should be less and less necessary these days as most distributions offer command line tools to automatically create or update initrd or initramfs files. Still, once in a while you may need a level of control that those tools don't offer, so you need to manually unpack, modify and repack the initrd or initramfs file. It's not particularly complicated, but there are some steps that you need to get right.
Introduction
The purpose of initrd and initramfs (also known, generically, as "initial RAM disk") is similar: they contain a minimal root filesystem, along with some scripts. When the kernel boots, if it is instructed to use an initrd or initramfs (this is usually done with some boot loader configuration) it unpacks the file in RAM, chroot()s into it, and run some predefined scripts. Finally, the "real" root file system is mounted, the kernel switches to it and the normal init process can begin.
Why do we need an initial RAM disk in the first place? You're probably wondering this if you use to build your own kernel with the necessary modules for your hardware built-in. In that case, you almost never need an initial RAM disk.
But many distributions have to ship a binary kernel that should work on most, or even all, different combinations of hardware, storage, filesystems, etc. They can't obviously build all the possible modules into the kernel. So they ship a minimal, generic kernel, and use an initial RAM disk that contains most hardware modules and some logic to detect which modules need to be loaded to be able to continue to boot the system normally (ie from the hard drive).
This means that it's possible to boot the kernel, load some modules and run some tasks (from the RAM disk), and finally start the normal boot process (
As briefly mentioned, there are two types of initial RAM disk: initrd and initramfs. The main difference is that an initrd contain a raw filesystem image (eg ext2), while an initramfs contains a cpio archive (which, when expanded, produces a directory hierarchy). Note that there are quite a few other differences, not mentioned here. In both cases, the image file is compressed (typically with gzip) and the kernel expands and mount it.
All the recent Linux distribution that use an initial RAM disk use an initramfs image. initrd is being used less and less.
To check if the file you're interested in is an initrd or an initramfs, you can decompress it and feed it to file:
# gunzip -c /boot/initrd-2.4.19.img.gz | file - /dev/stdin: Linux rev 1.0 ext2 filesystem data
so that file is a real initrd. Here's what you'd see with an initramfs:
# gunzip -c /boot/initrd.img-2.6.24-19-generic | file - /dev/stdin: ASCII cpio archive (SVR4 with no CRC)
Note the "SVR4 with no CRC" format which will be useful later.
Modifying an initrd image
An initrd image is a compressed filesystem, so you just uncompress and mount it:
# mkdir temp # gunzip -c /boot/initrd-2.4.19.img.gz > initrd.img # mount -t ext2 -o loop initrd.img temp/ # ls -l temp total 36 drwxr-xr-x 2 root root 1024 May 30 2005 bin drwxr-xr-x 4 root root 5120 Jan 26 2005 dev drwxr-xr-x 2 root root 1024 May 30 2005 etc drwxr-xr-x 2 root root 1024 May 30 2005 gentoo drwxr-xr-x 2 root root 2048 May 30 2005 lib -rwxr-xr-x 1 root root 5730 May 30 2005 linuxrc drwx------ 2 root root 12288 May 30 2005 lost+found drwxr-xr-x 2 root root 1024 May 30 2005 mnt drwxr-xr-x 2 root root 1024 May 30 2005 proc drwxr-xr-x 3 root root 1024 Jan 26 2005 root drwxr-xr-x 2 root root 1024 May 30 2005 sbin drwxr-xr-x 2 root root 1024 May 30 2005 sys drwxr-xr-x 2 root root 1024 May 30 2005 tmp drwxr-xr-x 6 root root 1024 May 30 2005 usr drwxr-xr-x 2 root root 1024 May 30 2005 var
Now it can be modified. Keep in mind that the loop filesystem won't probably have a lot of free space (if at all), so think carefully if you want to add a lot of files. (btw, this is one of the limitations that led to the more recent initramfs.)
Ater you've modified what you want, you just need to unmount the image and recompress it:
# umount temp # gzip -9 -c initrd.img > /boot/initrd-2.4.19.img.gz-NEW
Modifying an initramfs image
As said, an initramfs image is a compressed cpio archive, although the file name may sometimes be deceiving; sometimes it still has "initrd" in its name, and also many times it does not end in .gz or other suffixes that indicate compression:
# file /boot/initrd.img-2.6.24-19-generic /boot/initrd.img-2.6.24-19-generic: gzip compressed data, from Unix, last modified: Wed May 26 11:55:59 2010, max compression
Now cpio is an ancient (and a bit weird) archive format. When de-archiving, it needs to read the archive from standard input (GNU cpio also has a
# mkdir temp # cd temp # gunzip -c /boot/initrd.img-2.6.24-19-generic | cpio -i 34208 blocks # ls -l total 36 drwxr-xr-x 2 root root 4096 2010-05-28 14:16 bin drwxr-xr-x 3 root root 4096 2010-05-28 14:16 conf drwxr-xr-x 6 root root 4096 2010-05-28 14:16 etc -rwxr-xr-x 1 root root 3355 2010-05-28 14:16 init drwxr-xr-x 5 root root 4096 2010-05-28 14:16 lib drwxr-xr-x 2 root root 4096 2010-05-28 14:16 modules drwxr-xr-x 2 root root 4096 2010-05-28 14:16 sbin drwxr-xr-x 12 root root 4096 2010-05-28 14:16 scripts drwxr-xr-x 3 root root 4096 2010-05-28 14:16 var
Now you can finally edit and change the contents at will (no space limitations, unlike initrd). When you're done, you have to recreate the compressed cpio archive. Again, cpio is a bit weird when archiving, because it wants to read the names of the files to archive on standard input (and writes the archive on standard output). So you can do as follows:
# pwd /root/temp # find . | cpio -H newc -o | gzip -9 > /boot/initrd.img-2.6.24-19-generic-NEW 34207 blocks
The only catch is that the
Note that the construct
find . | something
is generally considered unsafe and to be avoided in shell scripting, because files could have newlines and control characters in them that could deceive the consumer of those filenames. This is generally not the case for filenames contained in an initramfs image, so it is "safe enough" to use here.
Boot loader configuration
Regardless of whether you used an initrd or an initramfs, when the new image file is created you should edit your boot loader configuration file to instruct it to use the image you just created. This is an example with an initramfs and grub 1 (not 2):
title Ubuntu 8.04.1, kernel 2.6.24-19-generic root (hd0,0) kernel /boot/vmlinuz-2.6.24-19-generic root=/dev/sda1 ro quiet splash initrd /boot/initrd.img-2.6.24-19-generic-NEW
The "initrd" line now references the newly created initrd/initramfs file.
Thank you for the great tutorial i wonder if you might have a tutorial or be able to create one about how to modify the initramfs to connect to a nfs boot over a wpa wifi access point?
If not please point me towards the resources i need I've been trying for a month now.
I have never done that, it looks like you have to include wpa_supplicant in the initramfs, a quick google search turns up eg https://ubuntuforums.org/showthread.php?t=1853554
Thank you! An excellent article and very useful, saved my skin.
Thanks! It helped saving my debian testing raid 1 virtual machine.
Waldner,
nice article, but you stress something that is indeed incorrect: both 'newc' and 'crc' cpio formats are eqally valid.
Thanks for the information. It's just that all the initramfs that I could check were in that "newc" format so I just assumed it was safe to recreate them in the same format.
Thank you, very good article.
Hi,
Very good article. I ran into something though. If I try an add a command
like mdadm, then when the kernel runs initrd and it opens up the command
cannot be found. Any idea on this?
Well, the first thing that comes to mind is that the file isn't executable, or its location is not in the PATH in effect at that time. Also remember that the command needs to be able to find all the libraries it needs to run, and probably its configuration files (if any), so you have to copy these as well.