Modifying initramfs

BACKGROUND

Booting Linux involves various components at several different stages.  The following summary was taken from here.

First is BIOS.  After loading date, time, and important peripherals from CMOS, then the storage devices are probed.  When the first hard disk and its geometry are recognized, the system control passes from BIOS to the boot loader.

The Master Boot Record (first 512 bytes) on the disk is where you will find the boot loader.  The commands executed by the boot loader determine the rest of the boot process.  Control is passed to the actual operating system, like the Linux kernel.

The kernel and an initial RAM-based file system is loaded into memory.  The initramfs contains a small executable called init that handles the mounting of the real root file system.

The init program handles mounting the proper root file system.  If it is successful, initramfs is cleaned and the init program on the root file system is executed.

The init process handles the actual booting of the system through different levels.  I don’t want to summarize the following information because every bit of it is important for the purpose of the document (again, taken directly from here):

initramfs

 

initramfs is a small cpio archive that the kernel can load to a RAM disk. It provides a minimal Linux environment that enables the execution of programs before the actual root file system is mounted. This minimal Linux environment is loaded into memory by BIOS routines and does not have specific hardware requirements other than sufficient memory. initramfs must always provide an executable named init that should execute the actual init program on the root file system for the boot process to proceed.

 

Before the actual root file system can be mounted and the actual operating system can be started, the kernel needs the corresponding drivers to access the device on which the root file system is located. These drivers may include special drivers for certain kinds of hard drives or even network drivers to access a network file system. The needed modules for the root file system may be loaded by init on initramfs. After the modules are loaded, udev provides the initramfs with the needed devices. initramfs is available during the entire boot process. This makes it possible to handle all device events generated during boot.

Problem

So, my issue was trying to get a system image onto a system using Clonezilla.  This is fairly straight-forward as long as you don’t have any devices present that the Clonezilla’s Linux kernel isn’t prepared to recognize.  Otherwise, during boot, you will be dropped to a shell in the initramfs itself.  The system I was attempting to restore had a QLogic card which Clonezilla wasn’t prepared to handle.

Solution

Add the required firmware to the initramfs so it’s available for the module to load.

Process

Since Initramfs is essentially a concatenation of gzipped cpio archives which are extracted into a ramdisk and used as an early userspace by the Linux kernel, the only thing we need to do is to concatenate another file onto the archive.

The Q&A presented here opened my eyes to how easy this can be done.  This quote specifically cleared up any confusion I had:

Debian Installer’s initrd.gz is in fact a single gzipped cpio archive containing all the files the installer needs at boot time. By simply appending another gzipped cpio archive – containing the firmware files we are missing – we get the show on the road!

This means, all I had to do was:

    1. Extract the Clonezilla ISO
      mount -t iso9660 -o loop ./clonezilla-live.iso myiso
      # copy contents from read-only directory to a writable one
      cp -a myiso myiso_write
      cd myiso_write
    2. Concatenate my firmware onto the initramfs contained within the ISO
      echo '/lib/firmware/ql2500_fw.bin' | cpio -H newc -o | gzip >> live/initrd.img
    3. Repackage the ISO
      genisoimage -A 'My Clonezilla Installer' -f -r -hide-rr-moved -hide-joliet-trans-tbl \
           -J -l -allow-limited-size -b syslinux/isolinux.bin -c syslinux/boot.cat -no-emul-boot \
           -boot-load-size 4 -boot-info-table -eltorito-alt-boot -efi-boot boot/grub/efiboot.img \
           -no-emul-boot ./ > ../clonezilla-live-PJA.iso
    4. Boot from ISO
    5. Restore system

I had the easy task of just adding another file to the cpio archive.  If you need to modify existing files or structure or just unpack it in full for some other reason, you’ll need to consult this link – Modifying the Clonezilla initrd.

The file initrd.img from the Clonezilla live is not a ext2 file system, it’s cpio format. Therefore you can not mount it, instead you have to do something like this:

The initrd.img maybe in gzip format, or in xz format. You can use command “file initrd.img” to know the foramt.

(1) mkdir ~/tmp/initrd; cd ~/tmp/initrd

(2) for gzip format, run: zcat initrd.img | cpio -idm
    for xz format, run: xzcat initrd.img | cpio -idm

Then you can edit the files in ~/tmp/initrd. After that, you can use the following command to pack it as new initrd.img:

(3) cd ~/tmp/initrd

(4) For gzip format, run: find . | cpio --quiet -o -H newc | gzip -9 > ../initrd.img
    For xz format, run: find . | cpio --quiet -o -H newc | xz -c -9 --check=crc32 >  ../initrd.img

Then the new one is in ~/tmp/initrd.img