#!/bin/sh # Copyright 2004 Slackware Linux, Inc., Concord, CA, USA # Copyright 2004 Patrick J. Volkerding, Concord, CA, USA # Copyright 2007, 2008, 2009 Patrick J. Volkerding, Sebeka, MN, USA # All rights reserved. # # Redistribution and use of this script, with or without modification, is # permitted provided that the following conditions are met: # # 1. Redistributions of this script must retain the above copyright # notice, this list of conditions and the following disclaimer. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Modified by Robby Workman 26 November 2007 # to add support for mkinitrd.conf - No additional license terms added # Modified by Alan Hicks 27 November 2007 to enable # passing arguments to kernel modules - No additional license terms added # volkerdi - feel free to remove these :) # Modified by Eric Hameleers 3 April 2008 # to add support custom keymaps - No additional license terms added # Modified by Patrick Volkerding 17 Dec 2008 # Added support to bail out if kernel modules are requested for a kernel # version that is not installed (thanks to Eric Hameleers), be more # verbose about showing modules added to the initrd (thanks to # Ellington Santos), and if "mount" returns /dev/root as the root device, # use readlink to resolve the device pointed to by the /dev/root # symlink, changed modprobe to use --ignore-install to avoid catching # custom "install" lines and causing /sbin/modprobe to be copied to the # initrd (thanks to Ken Milmore). # Of course, license terms remain unchanged. MKINITRD_VERSION=1.3.4 print_usage() { cat << EOF Usage: mkinitrd [OPTION] mkinitrd creates an initial ramdisk (actually an initramfs cpio+gzip archive) used to load kernel modules that are needed to mount the root filesystem, or other modules that might be needed before the root filesystem is available. Other binaries may be added to the initrd, and the script is easy to modify. Be creative. :-) -F Use the contents of /etc/mkinitrd.conf (optional) If this is used in conjunction with any other options passed on the command line, the command-line options will override the config file options. See mkinitrd.conf(5) for details. -c Clear the existing initrd tree first -f Filesystem to use for root partition (must be used with -r) --help Display this message -h Device to resume from hibernation. Needs to be the name of the swap partition holding the hibernation image. -k Kernel version to use -l Custom keymap to load. Like, 'nl' or 'de-latin1-nodeadkeys' -m A colon (:) delimited list of kernel modules to load. Additional options may be added to use when loading the kernel modules (but in this case the entire list must be wrapped with double quotes). Any dependencies of requested modules will also be added to the initrd. -o Output image (default /boot/initrd.gz) -r Root partition device (must be used with -f) -s Initrd source tree (default /boot/initrd-tree/) -w Time to wait until all disks are detected -C Use cryptsetup to unlock the underlying device of an encrypted root filesystem (must be used with '-r' parameter). Two scenarios are possible. (1) root filesystem was created on the encrypted disk/LVM partition, example: -C /dev/sda2 -r cryptroot where /dev/sda2 is the encrypted partition and the actual root device name in /etc/fstab is: /dev/mapper/cryptroot (2) the encrypted partition contains a LVM volume which holds the root filesystem, example: -C /dev/sda2 -r /dev/vg/root where /dev/sda2 is the encrypted partition and the actual root device name in /etc/fstab is: /dev/vg/root -L Add support for LVM partitions -R Add support for RAID partitions -V Display version number A simple example: Build an initrd for a reiserfs root partition: mkinitrd -c -m reiserfs Another example: Build an initrd image using Linux 2.6.29.3-smp kernel modules for a system with an ext3 root partition on /dev/hdb3: mkinitrd -c -k 2.6.29.3-smp -m mbcache:jbd:ext3 -f ext3 -r /dev/hdb3 Note that if you are already logged in with /dev/hdb3 as your / partition, and it is running ext3, this command works just the same: mkinitrd -c -m ext3 If run without options, mkinitrd will rebuild an initrd image using the contents of the $SOURCE_TREE directory, or, if that directory does not exist it will be created and populated, and then mkinitrd will exit. EOF } create_new_source_tree() { mkdir -p $SOURCE_TREE # Make sure a kernel module directory exists: mkdir -p $SOURCE_TREE/lib/modules/${KERNEL_VERSION} # Add the initrd-tree skeleton: ( cd $SOURCE_TREE ; tar xzf /usr/share/mkinitrd/initrd-tree.tar.gz ) # Make sure we have any block devices that might be needed: SLOPPY_DEV_LIST=$(cat /proc/partitions) for device in $SLOPPY_DEV_LIST ; do if [ ! -r $SOURCE_TREE/dev/$device ]; then if [ -b /dev/$device ]; then if [ -L /dev/$device ]; then cp -a --parents $(readlink -e /dev/$device) $SOURCE_TREE fi cp -a --parents /dev/$device $SOURCE_TREE fi fi done } clear_source_tree() { if [ -d "$SOURCE_TREE" ]; then rm -rf $SOURCE_TREE fi } build_initrd_image() { # Make sure we have any block devices that might be needed: SLOPPY_DEV_LIST=$(cat /proc/partitions) for device in $SLOPPY_DEV_LIST ; do if [ ! -r $SOURCE_TREE/dev/$device ]; then if [ -b /dev/$device ]; then if [ -L /dev/$device ]; then cp -a --parents $(readlink -e /dev/$device) $SOURCE_TREE fi cp -a --parents /dev/$device $SOURCE_TREE fi fi done # Wrap the initrd as an initramfs image and move it into place: ( cd $SOURCE_TREE rm -f $OUTPUT_IMAGE find . | cpio -o -H newc | gzip -9c > $OUTPUT_IMAGE ) } badconf_file() { # This won't really help with what's *wrong* with the file, # but it will at least give them a clue that there's a problem echo "/etc/mkinitrd.conf is bad or does not exist." echo "If the file does not exist, do not pass -F to mkinitrd." exit 1 } # If --help is given, print_usage and exit: if echo $* | grep -wq '\--help' ; then print_usage exit 0 fi # If -V given, print version and exit: if echo $* | grep -wq '\-V' ; then echo "mkinitrd version $MKINITRD_VERSION" exit 0 fi # Default values if these aren't previously set. # Might be set from config file or by -s and -o options too. SOURCE_TREE=${SOURCE_TREE:-/boot/initrd-tree} OUTPUT_IMAGE=${OUTPUT_IMAGE:-/boot/initrd.gz} KERNEL_VERSION=${KERNEL_VERSION:-"$(uname -r)"} # Default actions without options: if [ -z "$1" ]; then # If the output tree doesn't exist, create it and then exit: if [ ! -d $SOURCE_TREE ]; then echo "Nothing found at location $SOURCE_TREE, so we will create an" echo -n "initrd directory structure there... " create_new_source_tree echo "done." echo echo "Now cd to $SOURCE_TREE and install some modules in your" echo "module directory (lib/modules/${KERNEL_VERSION}). Then see init" echo "for more information (there are a few other files to edit)." echo "Finally, run mkinitrd again once the initrd-tree is ready," echo "and $OUTPUT_IMAGE will be created from it." echo exit 0 else # If the source tree does exist, the default is to build the initrd # image from it and then exit: build_initrd_image echo "$OUTPUT_IMAGE created." echo "Be sure to run lilo again if you use it." exit 0 fi fi # default no-option actions # Parse for the use config file option first or else the other command # line options can not override /etc/mkinitrd.conf. for opt in "$@"; do if [ $opt = "-F" ]; then if [ -e /etc/mkinitrd.conf ]; then . /etc/mkinitrd.conf || badconf_file else badconf_file fi fi done # Parse options: while [ ! -z "$1" ]; do case $1 in -c) CLEAR_TREE=1 shift ;; -f) ROOTFS="$2" shift 2 ;; -h) RESUMEDEV="$2" shift 2 ;; -k) KERNEL_VERSION="$2" shift 2 ;; -l) KEYMAP="$2" shift 2 ;; -m) MODULE_LIST="$2" shift 2 ;; -o) OUTPUT_IMAGE="$2" if [ ! "$(echo $OUTPUT_IMAGE | cut -b1)" = "/" ]; then OUTPUT_IMAGE=$(pwd)/$OUTPUT_IMAGE fi shift 2 ;; -r) ROOTDEV="$2" shift 2 ;; -s) SOURCE_TREE="$2" shift 2 ;; -w) WAIT="$2" shift 2 ;; -C) CRYPT=1 LUKSDEV="$2" shift 2 ;; -L) LVM=1 shift ;; -R) RAID=1 shift ;; *) # unknown, prevent infinite loop shift ;; esac done # If kernel modules are needed but the kernel version is absent, exit now: if [ ! -d /lib/modules/$KERNEL_VERSION ]; then echo "ERROR: No /lib/modules/$KERNEL_VERSION kernel modules tree found for kernel \"$KERNEL_VERSION\"" exit 1 fi # If clearing source tree was requested, do that first if [ "$CLEAR_TREE" = "1" ]; then clear_source_tree fi # If there's no $SOURCE_TREE, make one now: if [ ! -d "$SOURCE_TREE" ]; then create_new_source_tree fi # If $ROOTDEV and $ROOTFS are not set, assume we want the # values for the currently mounted / # (unless we find that values are already set in the initrd-tree): if [ -z "$ROOTDEV" -a -z "$(cat $SOURCE_TREE/rootdev 2> /dev/null)" ]; then ROOTDEV=$(mount | grep ' on / ' | cut -f 1 -d ' ') if [ "$ROOTDEV" = "/dev/root" ]; then # find real root device ROOTDEV="/dev/$(readlink /dev/root)" fi fi if [ -z "$ROOTFS" -a -z "$(cat $SOURCE_TREE/rootfs 2> /dev/null)" ]; then ROOTFS=$(mount | grep ' on / ' | cut -f 5 -d ' ') fi # If needed, write them in the initrd-tree: if [ ! -z "$ROOTDEV" ]; then echo $ROOTDEV > $SOURCE_TREE/rootdev fi if [ ! -z "$ROOTFS" ]; then echo $ROOTFS > $SOURCE_TREE/rootfs fi # If $WAIT is not set, assume we need only one second # to have all devices done # (unless we find that value is already set in the initrd-tree): if [ -z "$WAIT" -a -z "$(cat $SOURCE_TREE/wait-for-root)" ]; then WAIT=1 fi if [ ! -z "$WAIT" ]; then echo $WAIT > $SOURCE_TREE/wait-for-root fi # Useful to know which initrd is running: INITRD_NAME=$(basename $OUTPUT_IMAGE) echo $INITRD_NAME > $SOURCE_TREE/initrd-name # Fill /resumedev with the swap partition holding the hibernation image if [ ! -z "$RESUMEDEV" ]; then echo $RESUMEDEV > $SOURCE_TREE/resumedev fi # Add custom keymap support if one was given if [ ! -z "$KEYMAP" ]; then echo $KEYMAP > $SOURCE_TREE/keymap cp /usr/share/mkinitrd/keymaps.tar.gz $SOURCE_TREE/etc/ fi # If LUKSDEV was set in the config file, then we need to set CRYPT=1 if [ ! -z "$LUKSDEV" ]; then CRYPT=1 fi # Include RAID support in initrd if [ ! -z "$RAID" ]; then if [ -r /sbin/mdadm ]; then mkdir -p $SOURCE_TREE/sbin cp /sbin/mdadm $SOURCE_TREE/sbin/mdadm chmod 755 $SOURCE_TREE/sbin/mdadm else echo "ERROR: mdadm binary is missing, RAID support not installed" fi fi # Include LVM support in initrd if [ ! -z "$LVM" ]; then if [ -f /sbin/lvm.static ]; then mkdir -p $SOURCE_TREE/sbin cp /sbin/lvm.static $SOURCE_TREE/sbin/lvm.static cp /sbin/dmsetup.static $SOURCE_TREE/sbin/dmsetup.static ( cd $SOURCE_TREE/sbin ln -s lvm.static vgchange 2>/dev/null ln -s lvm.static vgscan 2>/dev/null ) if [ -z "${MODULE_LIST}" ] ; then MODULE_LIST="dm-mod" elif ! echo ${MODULE_LIST} | grep -q dm-mod ; then MODULE_LIST="$MODULE_LIST:dm-mod" fi else echo "LVM static binary is missing, LVM support isn't installed" fi fi # Include cryptsetup (LUKS) support in initrd if [ ! -z "$CRYPT" ]; then if [ -e /sbin/cryptsetup.static ]; then mkdir -p $SOURCE_TREE/sbin cp /sbin/cryptsetup.static $SOURCE_TREE/sbin/cryptsetup.static ( cd $SOURCE_TREE/sbin ln -s cryptsetup.static cryptsetup 2>/dev/null ) cat << EOF > $SOURCE_TREE/sbin/udevadm #!/bin/sh sleep 3 EOF chmod 0755 $SOURCE_TREE/sbin/udevadm if [ -z "${MODULE_LIST}" ] ; then MODULE_LIST="dm-mod" elif ! echo ${MODULE_LIST} | grep -q dm-mod ; then MODULE_LIST="$MODULE_LIST:dm-mod" fi # Write the underlying luks device to the initrd-tree: echo $LUKSDEV > $SOURCE_TREE/luksdev else echo "Cryptsetup static binary is missing, CRYPT support isn't installed" fi fi # Make module directory: if [ ! -d $SOURCE_TREE/lib/modules/$KERNEL_VERSION ]; then mkdir -p $SOURCE_TREE/lib/modules/$KERNEL_VERSION fi # If a module list was given, copy the modules into place: if [ ! -z "$MODULE_LIST" ]; then if grep -q "#insmod /lib/modules/2.6.18.8-smp/reiserfs.ko" $SOURCE_TREE/load_kernel_modules ; then rm -f $SOURCE_TREE/load_kernel_modules touch $SOURCE_TREE/load_kernel_modules chmod 755 $SOURCE_TREE/load_kernel_modules echo "# This is a script used to load the kernel modules." >> $SOURCE_TREE/load_kernel_modules echo "# To use it, chmod it 755, and then add the insmod" >> $SOURCE_TREE/load_kernel_modules echo "# lines needed to load your modules, like this:" >> $SOURCE_TREE/load_kernel_modules echo >> $SOURCE_TREE/load_kernel_modules fi # Count number of modules # This INDEX number gives us an easy way to find individual # modules and their arguments, as well as tells us how many # times to run through the list if ! echo $MODULE_LIST | grep ':' > /dev/null ; then # only 1 module specified INDEX=1 else INDEX=1 while [ ! "$(echo "$MODULE_LIST" | cut -f $INDEX -d ':' )" = "" ]; do INDEX=$(expr $INDEX + 1) done INDEX=$(expr $INDEX - 1) # Don't include the null value fi # Wrap everything in a while loop i=0 while [ $i -ne $INDEX ]; do i=$(( $i + 1 )) # FULL_MOD is the module plus any arguments (if any) # MODULE is the module name # ARGS is any optional arguments to be passed to the kernel FULL_MOD="$(echo "$MODULE_LIST" | cut -d ':' -f $i)" MODULE="$(echo "$FULL_MOD" | cut -d ' ' -f 1 )" # Test for arguments if echo "$FULL_MOD" | grep ' ' > /dev/null; then ARGS=" $(echo "$FULL_MOD" | cut -d ' ' -f 2- )" else unset ARGS fi # Get MODULE deps and prepare insmod lines /sbin/modprobe --set-version $KERNEL_VERSION --show-depends --ignore-install $MODULE 2> /dev/null \ | grep "^insmod " | cut -f 2 -d ' ' | while read SRCMOD; do if ! grep -q "$SRCMOD" $SOURCE_TREE/load_kernel_modules 2>/dev/null ; then LINE="$(echo "insmod -v $SRCMOD" | sed -e "s/$KERNEL_VERSION/\$(uname -r)/")" # Test to see if arguments should be passed # Over-ride the previously defined LINE variable if so if [ "$(basename $SRCMOD .ko)" = "$MODULE" ]; then # SRCMOD and MODULE are same, ARGS can be passed LINE="$LINE$ARGS" fi fi if ! grep -qx "$LINE" $SOURCE_TREE/load_kernel_modules ; then echo "$LINE" >> $SOURCE_TREE/load_kernel_modules fi if cp -a --parents $SRCMOD $SOURCE_TREE 2> /dev/null; then echo "OK: $SRCMOD added." else echo "WARNING: Could not find module \"$SRCMOD\"" fi done done fi # And finally, build the initrd: build_initrd_image