3. Creating an initramfs

This section describes how to create an initramfs from scratch. We assume we are working in a dedicated directory:

mkdir /tmp/initrd
cd /tmp/initrd

3.1. get binary dependency

for dynamically linked programs:

LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /sbin/lvm

for statically linked programs:

LANG=C readelf -e /usr/lib/klibc/bin/run-init | grep 'interpreter:'

3.2. directories

mkdir -p bin sbin dev etc etc/udev/rules.d lib lib/udev/rules.d \
  lib/modules/3.10.1 root usr/share

3.3. klibc

We mainly use busybox for our initrd, but instead of using pivot_root and chroot to run the init file on the new root filesystem, we use run-init from the klibc project:

cp /usr/lib/klibc/bin/run-init bin

It needs the klibc interpreter:

cp /lib/klibc-HD4lPOAFFcrZF9wKjmJlHFIQD-4.so lib

3.4. files

for p in /bin/busybox /bin/ksh /bin/disp /usr/bin/loadkeys /bin/bc
do
  cp $p bin
done

for p in /sbin/lvm /sbin/udevd /sbin/udevadm
do
  cp $p sbin
done

3.5. keymaps

rsync -a /usr/share/keymaps usr/share

3.6. libs

for l in libc.so.6 ld-linux.so.2 libdl.so.2 libm.so.6 \
         libdevmapper.so.1.02 libreadline.so.5 librt.so.1 libncurses.so.5 \
         libncursesw.so.5 libpthread.so.0 libnss_files.so.2
do
  cp /lib/$l lib
done

3.7. links

busybox:

cd bin
./busybox --list | while read p; do ln -s busybox $p; done
rm modprobe
cd ../sbin
ln -s ../bin/busybox modprobe
cd ..

lvm:

cd sbin
./lvm help 2>&1 | grep '^  [^ ]' | sed 1,2d | grep -v '^  help ' | \
  awk '{ print $1 }' | while read p; do ln -s lvm $p; done
cd ..

3.8. modules

selective copy:

for m in fs/ext4/ext4.ko lib/crc16.ko fs/jbd2/jbd2.ko \
         fs/mbcache.ko drivers/scsi/sg.ko drivers/scsi/sr_mod.ko \
         drivers/scsi/sd_mod.ko drivers/cdrom/cdrom.ko drivers/ata/ata_piix.ko \
         drivers/ata/libata.ko drivers/scsi/scsi_mod.ko md/dm-mod.ko
do
  cp /lib/modules/3.10.1/kernel/$m lib/modules/3.10.1
done

global copy:

rsync -a /lib/modules/3.10.1 lib/modules

depmod:

cd lib/modules/3.10.1
depmod -b $(pwd)/../../.. 3.10.1
cd ../../..

3.9. udev rules

rsync -a /lib/udev lib

3.10. id and gid

cp /etc/passwd /etc/group /etc/nsswitch.conf etc

3.11. profile

echo export EDITOR=vi > etc/profile

3.12. init

#!/bin/ksh

shell_escape ()
{
  export PATH=/bin:/sbin

  [ -d /dev ]  || mkdir -m 0755 /dev
  [ -d /root ] || mkdir --mode=0700 /root
  [ -d /sys ]  || mkdir /sys
  [ -d /proc ] || mkdir /proc
  [ -d /tmp ]  || mkdir /tmp

  mountpoint -q /sys || mount -t sysfs none /sys -onodev,noexec,nosuid
  mountpoint -q /proc || mount -t proc none /proc -onodev,noexec,nosuid
  [ -d /dev/pts ] || mkdir /dev/pts

  [ -e /dev/console ] || mknod /dev/console c 5 1
  [ -e /dev/null ] || mknod /dev/null c 1 3

  /sbin/udevd --daemon
  udevadm trigger
  udevadm settle

  for mod in dm_mod ext4 iso9660
  do
    modprobe -q $mod
  done
}

print '

                      __          __   _             
                      \ \        / /  | |            
                       \ \  /\  / /_ _| | _____  ___ 
                        \ \/  \/ / _` | |/ / _ \/ __|
                         \  /\  / (_| |   <  __/\__ \
                          \/  \/ \__,_|_|\_\___||___/

                        A GNU/Linux operating system.



'

print '
 ##############################################################################
 #                                                                            #
 #                     Starting initramfs boot scripts                        #
 #                                                                            #
 ##############################################################################
'

export PATH=/bin:/sbin

[ -d /dev ]  || mkdir -m 0755 /dev
[ -d /root ] || mkdir --mode=0700 /root
[ -d /sys ]  || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ]  || mkdir /tmp

disp "Mounting /sys" \
  mount -t sysfs none /sys -onodev,noexec,nosuid
disp "Mounting /proc" \
  mount -t proc none /proc -onodev,noexec,nosuid
mkdir /dev/pts

[ -e /dev/console ] || mknod /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3

disp "Starting udev"
/sbin/udevd --daemon
rc=$?
udevadm trigger
udevadm settle
disp $rc

for mod in dm_mod ext4 iso9660
do
  disp "Loading $mod" modprobe -q $mod
done

for x in $(</proc/cmdline)
do
  case $x in
    lang=*)
      lang=${x#lang=}
      disp "Setting $lang keyboard layout" loadkeys $lang
    ;;
    root=*)
      root=${x#root=}
    ;;
  esac
done

disp "Stopping udevd"
for f in /proc/*/exe
do
  l=$(readlink $f)
  if [ "$l" == /sbin/udevd ]
  then
    pid=$(print $f | cut -d'/' -f3)
    kill $pid
    rc=$?
    break
  fi
done
disp $rc

case $root in
  /dev/*/*)
    vg=$(print $root | cut -d'/' -f3)
    if vgdisplay | grep "VG Name" | awk '{ print $NF }' | grep -qw $vg
    then
      disp "Activate $vg" vgchange -a y $vg
      disp "Mounting $root" mount $root /root
    else
      print ""
      print "error: vg $vg not found, exiting to shell."
      . /etc/profile
      shell_escape
      exec /bin/ksh
    fi
  ;;
esac

if [ -n "$root" ]
then
  disp "Unmounting /sys" umount /sys
  disp "Unmounting /proc" umount /proc
  print ""
  exec run-init /root /sbin/init
else
  print ""
  . /etc/profile
  shell_escape
  exec /bin/ksh
fi
chmod 755 init

3.13. create the compressed image

find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/initrd-3.10.1

3.14. test the new initramfs

qemu -kernel /boot/vmlinuz-3.10.1 -initrd /boot/initrd-3.10.1 \
  -append "root=/dev/rootvg/sys quiet" -hda /dev/sda -snapshot