Creating an Initramfs

From CBLFS
Revision as of 18:05, 29 October 2009 by Michael.six (talk | contribs) (I wrote this script myself compiled from various information I found by googling)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

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

Caution.png

Note

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