Creating an Initramfs
From CBLFS
Revision as of 17:05, 29 October 2009 by Michael.six (talk | contribs) (I wrote this script myself compiled from various information I found by googling)
Contents
Introduction to Creating an Initramfs
The mkinitramfs script creates a gzip compressed cpio archive using busybox and a simple shell init script, which can be used in place of an initrd to do such things as load kernel modules before the system boots, in order to access functionality that is not compiled into the kernel, and therefore must be loaded, such as usb disks, scsi disks, etc. This is different than loading modules automatically at boot time, because those are loaded after the root disk is mounted, fsck'd etc, and typically an initrd contains modules which are loaded into the kernel before anything else, to fascilitate mounting the root fs. IE kernel doesn't have reiserfs support compiled in, but your root fs is formatted reiserfs
Project Homepage: Unknown
Dependencies
Required
The init script created for the initramfs will drop to the shell in busybox if there is an error, while only a few things are actually needed for the init to function, while compiling busybox you might want to keep in mind that it may need additional functionality to be able to work properly if the initramfs drops to the shell. Also this assumes that busybox is compiled statically linked, if that is not the case, additional libraries will be required to be added to the initramfs-tree. To test this run 'file /bin/busybox'. If file reports it as dynamically linked, running 'ldd /bin/busybox' should help you determine what libraries may be needed.
Creating the mkinitramfs script
cat > /usr/sbin/mkinitramfs << "END" #!/bin/bash # This is a bash script to create a busybox # based gzipped cpio archive to be used as # an initrd INITRAMFS_USE_KERNEL="$(uname -r)" INITRAMFS_OUTPUT="/boot/initramfs.igz" until [ -z "${1}" ]; do case ${1} in -c) rm -rf /boot/initramfs-tree ;; -k) INITRAMFS_USE_KERNEL="${2}" shift ;; -m) INITRAMFS_USE_MODULES="${2}" shift ;; -v|--verbose) INITRAMFS_USE_VERBOSE="true" ;; -m) INITRAMFS_USE_MODULES="${2}" shift ;; -o) INITRAMFS_OUTPUT="${2}" shift ;; esac shift done ermsg(){ cat << EOF [ERROR] $@ EOF } killme(){ ermsg "$@" ermsg "Exiting ..." exit 1 } vrbmsg(){ if [ "${INITRAMFS_USE_VERBOSE}" = 'true' ]; then cat << EOF $@ EOF fi } if [ ! -x /bin/busybox ]; then killme "The initramfs needs busybox ..." fi if [ ! -x /usr/bin/cpio ]; then killme "The initramfs needs cpio ..." fi if [ ! -x /bin/gzip ]; then killme "The initramfs needs gzip ..." fi rm -f /tmp/mkinitramfs.modules rm -f /tmp/mkinitramfs.moddeps get_moddeps(){ if [ -f /lib/modules/${INITRAMFS_USE_KERNEL}/modules.dep ]; then grep "${1}": /lib/modules/${INITRAMFS_USE_KERNEL}/modules.dep \ | sed -e "s|${1}:||" else cat << EOF get_moddeps failure EOF fi } fnd_module(){ fnd_mod_outpt="$(find /lib/modules/${INITRAMFS_USE_KERNEL} -name ${1}.ko)" if [ -z "${fnd_mod_oupt}" ]; then fnd_mod_outpt="$(find /lib/modules/${INITRAMFS_USE_KERNEL} -name ${1}.ko.gz)" fi echo ${fnd_mod_outpt} | sed -e "s|/lib/modules/${INITRAMFS_USE_KERNEL}/||" } if [ ! -d /boot/initramfs-tree ]; then mkdir /boot/initramfs-tree && mkdir /boot/initramfs-tree/{etc,bin,sbin,lib} && mkdir /boot/initramfs-tree/{proc,root,mnt,sys} mkdir /boot/initramfs-tree/lib/modules \ || killme "Problem making the initramfs-tree ..." ln -s . /boot/initramfs-tree/usr fi if [ -f /etc/sysconfig/initramfs.modules ]; then cat /etc/sysconfig/initramfs.modules | while read line; do if [ -n "${line}" -a "$(head -c1 <<<${line})" != "#" ]; then if [ -n "$(fnd_module ${line})" ]; then fnd_module ${line} >> /tmp/mkinitramfs.modules else ermsg "Couldn't find module ${line}" fi fi done fi if [ -n "${INITRAMFS_USE_MODULES}" ]; then for ITEM in $(echo ${INITRAMFS_USE_MODULES//,/ }); do if [ -n "$(fnd_module ${ITEM})" ]; then fnd_module ${ITEM} >> /tmp/mkinitramfs.modules else ermsg "Couldn't find module ${ITEM}" fi done unset ITEM fi touch /tmp/mkinitramfs.moddeps if [ -f /tmp/mkinitramfs.modules ]; then cat /tmp/mkinitramfs.modules | while read IMOD; do vrbmsg "generating module dependencies for ${IMOD}" && if [ "$(get_moddeps ${IMOD})" != "get_moddeps failure" ]; then if [ -n "$(get_moddeps ${IMOD})" ]; then for ITEM in $(get_moddeps ${IMOD}); do if [ -z "$(grep ${IMOD} /tmp/mkinitramfs.moddeps)" ]; then echo "${ITEM}" >> /tmp/mkinitramfs.moddeps fi done unset ITEM fi fi if [ -z "$(grep ${IMOD} /tmp/mkinitramfs.moddeps)" ]; then echo "${IMOD}" >> /tmp/mkinitramfs.moddeps fi done fi unset IMOD if [ -f /tmp/mkinitramfs.moddeps ]; then cat /tmp/mkinitramfs.moddeps | while read line; do case ${line} in *.ko.gz) gzip -dc /lib/modules/${INITRAMFS_USE_KERNEL}/${line} \ > /boot/initramfs-tree/lib/modules/$(basename ${line} .ko.gz).ko echo "$(basename ${line} .ko.gz)" >> /boot/initramfs-tree/etc/modules ;; *.ko) cat /lib/modules/${MKINITRAMFS_USE_KERNEL}/${line} \ > /boot/initramfs-tree/lib/modules/$(basename ${line}) echo "$(basename ${line} .ko)" >> /boot/initramfs-tree/etc/modules ;; esac done fi # Now for the init cat << "EOT" >/boot/initramfs-tree/init #!/bin/busybox sh # Mount things which are needed by this script /bin/busybox mount -t proc proc /proc /bin/busybox mount -t sysfs sysfs /sys # Disable kernel messages from popping up on # the screen /bin/busybox echo 0 > /proc/sys/kernel/printk # Clear the screen /bin/busybox clear /bin/busybox cat << EOF This system is uses Community Beyond Linux From Scratch <http://cblfs.cross-lfs.org/> EOF # Create the symlinks to busybox /bin/busybox --install -s # Create device nodes /bin/busybox mknod /dev/null c 1 3 /bin/busybox mknod /dev/tty c 5 0 # Check for modules if [ -f /etc/modules ]; then /bin/busybox depmod /lib/modules /bin/busybox cat /etc/modules | while read line; do if [ -n "${line}" ]; then /bin/busybox modprobe ${line/.ko/} fi done fi # Sleep for devices to connect, like USB /bin/busybox sleep 5 /bin/busybox mdev -s # Function for parsing command line options with # '=' in them. Ex. get_opt("init=/sbin/init") # would return "/sbin/init" get_opt() { echo "$@" | /bin/busybox cut -d "=" -f 2 } # Defaults init="/sbin/init" root="/dev/hda1" runlevel="3" for i in $(cat /proc/cmdline); do case ${i} in root\=*) root=$(get_opt ${i}) ;; init\=*) init=$(get_opt ${i}) ;; runlevel\=*) runlevel=$(get_opt ${i}) ;; esac done # Mount the root device mount -o ro "${root}" /root # Below is an example for loading a disk image from # a linux partition if [ -f /root/lfs-root.img ]; then BNROOT=$(/bin/busybox basename "${root}") umount root mkdir -p /mnt/"${BNROOT}" && mount "${root}" /mnt/"${BNROOT}" && mount -o loop /mnt/"${BNROOT}"/lfs-root.img /root && # Make sure that we don't lose access to the partition # containing the disk image mkdir -p /root/mnt/"${BNROOT}" && mount /mnt/"${BNROOT}" /root/mnt/"${BNROOT}" unset BNROOT fi # Check if the $init exists, and is executable if [[ -x "/root/${init}" ]]; then # Unmount all other mounts so that the ram used by # the initramfs can be cleared after switch_root umount /sys /proc # Switch to the new root and execute the init at # the specified runlevel exec switch_root /root "${init}" "${runlevel}" fi # This will only be run if the exec above failed echo "Failed 'exec switch_root /root \"${init}\" \"${runlevel}\"'" exec sh EOT chmod 0755 /boot/initramfs-tree/init cat /bin/busybox > /boot/initramfs-tree/bin/busybox chmod 0755 /boot/initramfs-tree/bin/busybox if [ ! -d "$(dirname ${INITRAMFS_OUTPUT})" ]; then killme "Cannot create ${INITRAMFS_OUTPUT}" fi ( cd /boot/initramfs-tree && find . | cpio -H newc -o | gzip -9c > ${INITRAMFS_OUTPUT} || exit 1 ) || exit 1 rm -f /tmp/mkinitramfs.modules rm -f /tmp/mkinitramfs.moddeps unset INITRAMFS_OUTPUT INITRAMFS_USE_KERNEL INITRAMFS_USE_MODULES INITRAMFS_USE_KERNEL END chmod 0755 /usr/sbin/mkinitramfs