Initrd and initramfs files are used together with a Linux kernel and a bootloader (such as GRUB and syslinux) to start up Linux in many different ways. Linux distributions provide prepackaged kernels and convenient tools for creating initramfs, but I like to build my own kernel and initramfs because it allows me to customize the boot process. For instance, one can choose to boot from the local disk or the network with the help of initramfs and some user-defined boot parameters. Here's a list of things that I'd like to achieve with my custom initramfs.
- Boot from a live CD
- Boot from a read-only filesystem image, compressed with SquashFS
- Copy the filesystem image to a RAM disk and run Linux entirely within memory
- Boot Linux from a USB flash drive or a Firewire disk
- Boot Linux from a local disk partition
- Boot Linux from a network drive
- Run a rescue shell without booting Linux
- Start a kdrive X-server and run gparted, partclone or partimage
In this post, I show how I normally create initrd / initramfs files. For this tutorial, the following Debian/Ubuntu packages are needed:
- busybox
provides small essential utilities for booting and rescue shell.
- cpio
is used to create the actual initramfs format.
- e2fsprogs, jfsutils, etc.
provides fsck to check Linux filesystems and replay any stale journal before booting
- lzma or xz-utils
compresses the initramfs
- pciutils
is used to detect PCI hardware
- unionfs-fuse
makes it possible to use read-only Linux systems, such as live CD and filesystem images
- unzip
is used to apply local settings when booting a live CD.
- v86d
is used to set the screen resolution for framebuffer screens
First, create a text file with a list of files to put in initramfs. The following is an example of such file:
bin/busybox
bin/dash
bin/mount
etc/filesystems
etc/fuse.conf
etc/group
etc/modprobe.d
lib/ld-linux.so.2
lib/i386-linux-gnu/libacl.so.1
lib/i386-linux-gnu/libattr.so.1
lib/i386-linux-gnu/libblkid.so.1
lib/i386-linux-gnu/libbz2.so.1.0
lib/i386-linux-gnu/libcom_err.so.2
lib/i386-linux-gnu/libc.so.6
lib/i386-linux-gnu/libdl.so.2
lib/i386-linux-gnu/libe2p.so.2
lib/i386-linux-gnu/libext2fs.so.2
lib/i386-linux-gnu/libfuse.so.2
lib/i386-linux-gnu/libkmod.so.2
lib/i386-linux-gnu/libmount.so.1
lib/i386-linux-gnu/libm.so.6
lib/i386-linux-gnu/libpci.so.3
lib/i386-linux-gnu/libpthread.so.0
lib/i386-linux-gnu/libresolv.so.2
lib/i386-linux-gnu/librt.so.1
lib/i386-linux-gnu/libselinux.so.1
lib/i386-linux-gnu/libsepol.so.1
lib/i386-linux-gnu/libuuid.so.1
lib/i386-linux-gnu/libx86.so.1
lib/i386-linux-gnu/libz.so.1
lib/modules/3.6.2-586mmx/kernel/drivers/ata
lib/modules/3.6.2-586mmx/kernel/drivers/block/loop.ko
lib/modules/3.6.2-586mmx/kernel/drivers/cdrom/cdrom.ko
lib/modules/3.6.2-586mmx/kernel/drivers/connector/cn.ko
lib/modules/3.6.2-586mmx/kernel/drivers/firewire/firewire-core.ko
lib/modules/3.6.2-586mmx/kernel/drivers/firewire/firewire-ohci.ko
lib/modules/3.6.2-586mmx/kernel/drivers/firewire/firewire-sbp2.ko
lib/modules/3.6.2-586mmx/kernel/drivers/i2c/algos/i2c-algo-bit.ko
lib/modules/3.6.2-586mmx/kernel/drivers/scsi/sd_mod.ko
lib/modules/3.6.2-586mmx/kernel/drivers/scsi/sr_mod.ko
lib/modules/3.6.2-586mmx/kernel/drivers/usb/host/ehci-hcd.ko
lib/modules/3.6.2-586mmx/kernel/drivers/usb/host/ohci-hcd.ko
lib/modules/3.6.2-586mmx/kernel/drivers/usb/host/uhci-hcd.ko
lib/modules/3.6.2-586mmx/kernel/drivers/usb/host/xhci-hcd.ko
lib/modules/3.6.2-586mmx/kernel/drivers/usb/storage/usb-storage.ko
lib/modules/3.6.2-586mmx/kernel/drivers/video
lib/modules/3.6.2-586mmx/kernel/fs/ext3/ext3.ko
lib/modules/3.6.2-586mmx/kernel/fs/ext4/ext4.ko
lib/modules/3.6.2-586mmx/kernel/fs/fat/fat.ko
lib/modules/3.6.2-586mmx/kernel/fs/fat/vfat.ko
lib/modules/3.6.2-586mmx/kernel/fs/fuse/fuse.ko
lib/modules/3.6.2-586mmx/kernel/fs/isofs/isofs.ko
lib/modules/3.6.2-586mmx/kernel/fs/jbd2/jbd2.ko
lib/modules/3.6.2-586mmx/kernel/fs/jbd/jbd.ko
lib/modules/3.6.2-586mmx/kernel/fs/jfs/jfs.ko
lib/modules/3.6.2-586mmx/kernel/fs/nls/nls_cp437.ko
lib/modules/3.6.2-586mmx/kernel/fs/nls/nls_iso8859-1.ko
lib/modules/3.6.2-586mmx/kernel/fs/nls/nls_utf8.ko
lib/modules/3.6.2-586mmx/kernel/fs/reiserfs/reiserfs.ko
lib/modules/3.6.2-586mmx/kernel/fs/squashfs/squashfs.ko
lib/modules/3.6.2-586mmx/kernel/fs/xfs/xfs.ko
lib/modules/3.6.2-586mmx/kernel/lib/crc16.ko
lib/modules/3.6.2-586mmx/kernel/lib/crc-t10dif.ko
lib/modules/3.6.2-586mmx/modules.alias
lib/modules/3.6.2-586mmx/modules.dep
lib/modules/3.6.2-586mmx/modules.dep.bin
sbin/blkid
sbin/e2fsck
sbin/jfs_fsck
sbin/modprobe
sbin/v86d
usr/bin/lspci
usr/bin/unionfs-fuse
usr/bin/unzip
Then, create an empty directory, for example, /tmp/initrd and copy the files listed in the above-mentioned text file (called rd354.txt) to the new directory.
mkdir /tmp/initrd
cd /
tar cvhf - -T rd354.txt | (cd /tmp/initrd; tar xf -)
Then, create the necessary directory structure under /tmp/initrd:
cd /tmp/initrd
mkdir -p dev media mnt proc root sys tmp
Since I chose to use busybox, I need to create symbolic links to busybox in /bin. Busybox provides incomplete functionality for modprobe, mount, sh and unzip, so I removed their symbolic links.
cd /tmp/initrd/bin
for f in $(./busybox --list); do [ -e $f ] || ln -s busybox $f ; done
rm modprobe unzip
Then, create essential device nodes in /tmp/initrd/dev:
cd /tmp/initrd/dev
MAKEDEV std fb0 fd0 sda sdb scd
mknod console c 5 1
mknod fuse c 10 229
chmod 666 fuse
Now, create an init script. The contents of this init script is crucial for customization of the boot process. For an example of init script, please read this post. The example script is capable of booting a live CD and running Linux from memory disk in addition to booting Linux from hard drives and USB flash. Just put the init script at the top level of initrd tree and the etc subfolder, and make it executable.
chmod 777 /tmp/initrd/init
chmod 777 /tmp/initrd/etc/init
Then, use cpio and lzma to create an initramfs file. This assumes that the kernel was compiled with CONFIG_RD_LZMA option enabled.
cd /tmp/initrd
find . | cpio -H newc -o | lzma -c > ../initram.lzm
A file named initram.lzm will be created. If you want to create an old-style initrd file instead, use the mkcramfs command. This assumes your kernel has built-in cramfs support (CONFIG_CRAMFS):
mkcramfs /tmp/initrd /boot/initrd.bin
Copy the kernel and the initramfs file to your boot directory. Finally, edit your bootloader's configuration file. The following is the contents of a sample syslinux.cfg:
LABEL debian
KERNEL 314.lnx
INITRD /initrd/initram.lzm
APPEND root=/dev/sda7
LABEL sid
KERNEL 314.lnx
INITRD /initrd/initram.lzm
APPEND boot=usb label=SID edd=off vmode=800x600
LABEL bfile
KERNEL 314.lnx
INITRD /initrd/initram.lzm
APPEND boot=loop root=/dev/sda1
LABEL ram
KERNEL 314.lnx
INITRD /initrd/initram.lzm
APPEND boot=ram ramdisk_size=524288 root=/dev/sda1