%general-entities; ]> $Date$ About initramfs The only purpose of an initramfs is to mount the root filesystem. The initramfs is a complete set of directories that you would find on a normal root filesystem. It is bundled into a single cpio archive and compressed with one of several compression algorithms. At boot time, the boot loader loads the kernel and the initramfs image into memory and starts the kernel. The kernel checks for the presence of the initramfs and, if found, mounts it as / and runs /init. The init program is typically a shell script. Note that the boot process takes longer, possibly significantly longer, if an initramfs is used. For most distributions, kernel modules are the biggest reason to have an initramfs. In a general distribution, there are many unknowns such as file system types and disk layouts. In a way, this is the opposite of LFS where the system capabilities and layout are known and a custom kernel is normally built. In this situation, an initramfs is rarely needed. There are only four primary reasons to have an initramfs in the LFS environment: loading the rootfs from a network, loading it from an LVM logical volume, having an encrypted rootfs where a password is required, or for the convenience of specifying the rootfs as a LABEL or UUID. Anything else usually means that the kernel was not configured properly. Building an initramfs If you do decide to build an initramfs, the following scripts will provide a basis to do it. The scripts will allow specifying a rootfs via partition UUID or partition LABEL or a rootfs on an LVM logical volume. They do not support an encrypted root file system or mounting the rootfs over a network card. For a more complete capability see the LFS Hints or dracut. To install these scripts, run the following commands as the root user: cat > /sbin/mkinitramfs << "EOF" #!/bin/bash # This file based in part on the mkinitramfs script for the LFS LiveCD # written by Alexander E. Patrakov and Jeremy Huntwork. copy() { local file if [ "$2" = "lib" ]; then file=$(PATH=/lib:/usr/lib type -p $1) else file=$(type -p $1) fi if [ -n "$file" ] ; then cp $file $WDIR/$2 else echo "Missing required file: $1 for directory $2" rm -rf $WDIR exit 1 fi } if [ -z $1 ] ; then INITRAMFS_FILE=initrd.img-no-kmods else KERNEL_VERSION=$1 INITRAMFS_FILE=initrd.img-$KERNEL_VERSION fi if [ -n "$KERNEL_VERSION" ] && [ ! -d "/lib/modules/$1" ] ; then echo "No modules directory named $1" exit 1 fi printf "Creating $INITRAMFS_FILE... " binfiles="sh cat cp dd killall ls mkdir mknod mount " binfiles="$binfiles umount sed sleep ln rm uname" binfiles="$binfiles readlink basename" # Systemd installs udevadm in /bin. Other udev implementations have it in /sbin if [ -x /bin/udevadm ] ; then binfiles="$binfiles udevadm"; fi sbinfiles="modprobe blkid switch_root" #Optional files and locations for f in mdadm mdmon udevd udevadm; do if [ -x /sbin/$f ] ; then sbinfiles="$sbinfiles $f"; fi done # Add lvm if present (cannot be done with the others because it # also needs dmsetup if [ -x /sbin/lvm ] ; then sbinfiles="$sbinfiles lvm dmsetup"; fi unsorted=$(mktemp /tmp/unsorted.XXXXXXXXXX) DATADIR=/usr/share/mkinitramfs INITIN=init.in # Create a temporary working directory WDIR=$(mktemp -d /tmp/initrd-work.XXXXXXXXXX) # Create base directory structure mkdir -p $WDIR/{bin,dev,lib/firmware,run,sbin,sys,proc,usr} mkdir -p $WDIR/etc/{modprobe.d,udev/rules.d} touch $WDIR/etc/modprobe.d/modprobe.conf ln -s lib $WDIR/lib64 ln -s ../bin $WDIR/usr/bin # Create necessary device nodes mknod -m 640 $WDIR/dev/console c 5 1 mknod -m 664 $WDIR/dev/null c 1 3 # Install the udev configuration files if [ -f /etc/udev/udev.conf ]; then cp /etc/udev/udev.conf $WDIR/etc/udev/udev.conf fi for file in $(find /etc/udev/rules.d/ -type f) ; do cp $file $WDIR/etc/udev/rules.d done # Install any firmware present cp -a /lib/firmware $WDIR/lib # Copy the RAID configuration file if present if [ -f /etc/mdadm.conf ] ; then cp /etc/mdadm.conf $WDIR/etc fi # Install the init file install -m0755 $DATADIR/$INITIN $WDIR/init if [ -n "$KERNEL_VERSION" ] ; then if [ -x /bin/kmod ] ; then binfiles="$binfiles kmod" else binfiles="$binfiles lsmod" sbinfiles="$sbinfiles insmod" fi fi # Install basic binaries for f in $binfiles ; do if [ -e /bin/$f ]; then d="/bin"; else d="/usr/bin"; fi ldd $d/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted copy $d/$f bin done for f in $sbinfiles ; do ldd /sbin/$f | sed "s/\t//" | cut -d " " -f1 >> $unsorted copy $f sbin done # Add udevd libraries if not in /sbin if [ -x /lib/udev/udevd ] ; then ldd /lib/udev/udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted elif [ -x /lib/systemd/systemd-udevd ] ; then ldd /lib/systemd/systemd-udevd | sed "s/\t//" | cut -d " " -f1 >> $unsorted fi # Add module symlinks if appropriate if [ -n "$KERNEL_VERSION" ] && [ -x /bin/kmod ] ; then ln -s kmod $WDIR/bin/lsmod ln -s kmod $WDIR/bin/insmod fi # Add lvm symlinks if appropriate # Also copy the lvm.conf file if [ -x /sbin/lvm ] ; then ln -s lvm $WDIR/sbin/lvchange ln -s lvm $WDIR/sbin/lvrename ln -s lvm $WDIR/sbin/lvextend ln -s lvm $WDIR/sbin/lvcreate ln -s lvm $WDIR/sbin/lvdisplay ln -s lvm $WDIR/sbin/lvscan ln -s lvm $WDIR/sbin/pvchange ln -s lvm $WDIR/sbin/pvck ln -s lvm $WDIR/sbin/pvcreate ln -s lvm $WDIR/sbin/pvdisplay ln -s lvm $WDIR/sbin/pvscan ln -s lvm $WDIR/sbin/vgchange ln -s lvm $WDIR/sbin/vgcreate ln -s lvm $WDIR/sbin/vgscan ln -s lvm $WDIR/sbin/vgrename ln -s lvm $WDIR/sbin/vgck # Conf file(s) cp -a /etc/lvm $WDIR/etc fi # Install libraries sort $unsorted | uniq | while read library ; do # linux-vdso and linux-gate are pseudo libraries and do not correspond to a file # libsystemd-shared is in /lib/systemd, so it is not found by copy, and # it is copied below anyway if [[ "$library" == linux-vdso.so.1 ]] || [[ "$library" == linux-gate.so.1 ]] || [[ "$library" == libsystemd-shared* ]]; then continue fi copy $library lib done if [ -d /lib/udev ]; then cp -a /lib/udev $WDIR/lib fi if [ -d /lib/systemd ]; then cp -a /lib/systemd $WDIR/lib fi if [ -d /lib/elogind ]; then cp -a /lib/elogind $WDIR/lib fi # Install the kernel modules if requested if [ -n "$KERNEL_VERSION" ]; then find \ /lib/modules/$KERNEL_VERSION/kernel/{crypto,fs,lib} \ /lib/modules/$KERNEL_VERSION/kernel/drivers/{block,ata,md,firewire} \ /lib/modules/$KERNEL_VERSION/kernel/drivers/{scsi,message,pcmcia,virtio} \ /lib/modules/$KERNEL_VERSION/kernel/drivers/usb/{host,storage} \ -type f 2> /dev/null | cpio --make-directories -p --quiet $WDIR cp /lib/modules/$KERNEL_VERSION/modules.{builtin,order} \ $WDIR/lib/modules/$KERNEL_VERSION depmod -b $WDIR $KERNEL_VERSION fi ( cd $WDIR ; find . | cpio -o -H newc --quiet | gzip -9 ) > $INITRAMFS_FILE # Prepare early loading of microcode if available if ls /lib/firmware/intel-ucode/* >/dev/null 2>&1 || ls /lib/firmware/amd-ucode/* >/dev/null 2>&1; then # first empty WDIR to reuse it rm -r $WDIR/* DSTDIR=$WDIR/kernel/x86/microcode mkdir -p $DSTDIR if [ -d /lib/firmware/amd-ucode ]; then cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin fi if [ -d /lib/firmware/intel-ucode ]; then cat /lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin fi ( cd $WDIR; find . | cpio -o -H newc --quiet ) > microcode.img cat microcode.img $INITRAMFS_FILE > tmpfile mv tmpfile $INITRAMFS_FILE rm microcode.img fi # Remove the temporary directories and files rm -rf $WDIR $unsorted printf "done.\n" EOF chmod 0755 /sbin/mkinitramfs mkdir -p /usr/share/mkinitramfs && cat > /usr/share/mkinitramfs/init.in << "EOF" #!/bin/sh PATH=/bin:/usr/bin:/sbin:/usr/sbin export PATH problem() { printf "Encountered a problem!\n\nDropping you to a shell.\n\n" sh } no_device() { printf "The device %s, which is supposed to contain the\n" $1 printf "root file system, does not exist.\n" printf "Please fix this problem and exit this shell.\n\n" } no_mount() { printf "Could not mount device %s\n" $1 printf "Sleeping forever. Please reboot and fix the kernel command line.\n\n" printf "Maybe the device is formatted with an unsupported file system?\n\n" printf "Or maybe filesystem type autodetection went wrong, in which case\n" printf "you should add the rootfstype=... parameter to the kernel command line.\n\n" printf "Available partitions:\n" } do_mount_root() { mkdir /.root [ -n "$rootflags" ] && rootflags="$rootflags," rootflags="$rootflags$ro" case "$root" in /dev/* ) device=$root ;; UUID=* ) eval $root; device="/dev/disk/by-uuid/$UUID" ;; PARTUUID=*) eval $root; device="/dev/disk/by-partuuid/$PARTUUID" ;; LABEL=* ) eval $root; device="/dev/disk/by-label/$LABEL" ;; "" ) echo "No root device specified." ; problem ;; esac while [ ! -b "$device" ] ; do no_device $device problem done if ! mount -n -t "$rootfstype" -o "$rootflags" "$device" /.root ; then no_mount $device cat /proc/partitions while true ; do sleep 10000 ; done else echo "Successfully mounted device $root" fi } do_try_resume() { case "$resume" in UUID=* ) eval $resume; resume="/dev/disk/by-uuid/$UUID" ;; LABEL=*) eval $resume; resume="/dev/disk/by-label/$LABEL" ;; esac if $noresume || ! [ -b "$resume" ]; then return; fi ls -lH "$resume" | ( read x x x x maj min x echo -n ${maj%,}:$min > /sys/power/resume ) } init=/sbin/init root= rootdelay= rootfstype=auto ro="ro" rootflags= device= resume= noresume=false mount -n -t devtmpfs devtmpfs /dev mount -n -t proc proc /proc mount -n -t sysfs sysfs /sys mount -n -t tmpfs tmpfs /run read -r cmdline < /proc/cmdline for param in $cmdline ; do case $param in init=* ) init=${param#init=} ;; root=* ) root=${param#root=} ;; rootdelay=* ) rootdelay=${param#rootdelay=} ;; rootfstype=*) rootfstype=${param#rootfstype=} ;; rootflags=* ) rootflags=${param#rootflags=} ;; resume=* ) resume=${param#resume=} ;; noresume ) noresume=true ;; ro ) ro="ro" ;; rw ) ro="rw" ;; esac done # udevd location depends on version if [ -x /sbin/udevd ]; then UDEVD=/sbin/udevd elif [ -x /lib/udev/udevd ]; then UDEVD=/lib/udev/udevd elif [ -x /lib/systemd/systemd-udevd ]; then UDEVD=/lib/systemd/systemd-udevd else echo "Cannot find udevd nor systemd-udevd" problem fi ${UDEVD} --daemon --resolve-names=never udevadm trigger udevadm settle if [ -f /etc/mdadm.conf ] ; then mdadm -As ; fi if [ -x /sbin/vgchange ] ; then /sbin/vgchange -a y > /dev/null ; fi if [ -n "$rootdelay" ] ; then sleep "$rootdelay" ; fi do_try_resume # This function will not return if resuming from disk do_mount_root killall -w ${UDEVD##*/} exec switch_root /.root "$init" "$@" EOF Using an initramfs Required Runtime Dependency Other Runtime Dependencies and/or must be installed before generating the initramfs, if the system partition uses them. User Notes: To build an initramfs, run the following as the root user: mkinitramfs [KERNEL VERSION] The optional argument is the directory where the appropriate kernel modules are located. This must be a subdirectory of /lib/modules. If no modules are specified, then the initramfs is named initrd.img-no-kmods. If a kernel version is specified, the initrd is named initrd.img-$KERNEL_VERSION and is only appropriate for the specific kernel specified. The output file will be placed in the current directory. If early loading of microcode is needed (see ), you can install the appropriate blob or container in /lib/firmware. It will be automatically added to the initrd when running mkinitramfs. After generating the initrd, copy it to the /boot directory. Now edit /boot/grub/grub.cfg and add a new menuentry. Below are several examples. # Generic initramfs and root fs identified by UUID menuentry "LFS Dev (LFS-7.0-Feb14) initrd, Linux 3.0.4" { linux /vmlinuz-3.0.4-lfs-20120214 root=UUID=54b934a9-302d-415e-ac11-4988408eb0a8 ro initrd /initrd.img-no-kmods } # Generic initramfs and root fs on LVM partition menuentry "LFS Dev (LFS-7.0-Feb18) initrd lvm, Linux 3.0.4" { linux /vmlinuz-3.0.4-lfs-20120218 root=/dev/mapper/myroot ro initrd /initrd.img-no-kmods } # Specific initramfs and root fs identified by LABEL menuentry "LFS Dev (LFS-7.1-Feb20) initrd label, Linux 3.2.6" { linux /vmlinuz-3.2.6-lfs71-120220 root=LABEL=lfs71 ro initrd /initrd.img-3.2.6-lfs71-120220 } Finally, reboot the system and select the desired system.