diff options
Diffstat (limited to 'source/a/mkinitrd/init')
-rwxr-xr-x | source/a/mkinitrd/init | 262 |
1 files changed, 172 insertions, 90 deletions
diff --git a/source/a/mkinitrd/init b/source/a/mkinitrd/init index 0559932e..a6f1091e 100755 --- a/source/a/mkinitrd/init +++ b/source/a/mkinitrd/init @@ -4,7 +4,7 @@ # This requires that your kernel supports initramfs!!! # # Copyright 2004 Slackware Linux, Inc., Concord, CA, USA -# Copyright 2007, 2008 Patrick J. Volkerding, Sebeka, MN, USA +# Copyright 2007, 2008, 2009, 2010 Patrick J. Volkerding, Sebeka, MN, USA # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -33,95 +33,131 @@ # # Config files used by this script: # -# /rootdev Contains the name of the root device, such as: /dev/hda1 +# /rootdev Contains the name of the root device, such as: /dev/hda1 # -# /rootfs Contains the root filesystem type, such as: xfs +# /rootfs Contains the root filesystem type, such as: xfs # # /initrd-name Contains the name of the initrd file. # +# /resumedev Contains the name of the device to resume from hibernation. +# +# /luksdev Contains colon separated list of luks encrypted devices to +# be unlocked. +# +# /lukskey Contains the path to a LUKS key-file for automatic unlock +# Format: LABEL=<partition_label>:/path/to/file +# UUID=<partition_uuid>:/path/to/file +# +# /wait-for-root Contains a number - the init script will wait this amount +# of seconds before creating device nodes. +# +# /keymap Contains the name for a custom keyboard map +# # Optional: -# /load_kernel_modules A script that uses insmod to load the desired -# modules. If this file is not present, all the modules -# in /lib/modules/`uname -r`/ will be loaded in the usual -# sorted order. If you need to load the modules in a -# certain order, or if the modules need extra options, -# then use a load_kernel_modules script. -# -# There's an example in here. To actually use it, you'll -# need to make it executable: -# -# chmod 755 load_kernel_modules - -INITRD=`cat /initrd-name` -ROOTDEV=`cat /rootdev` -ROOTFS=`cat /rootfs` -LUKSDEV=`cat /luksdev` -RESUMEDEV=`cat /resumedev` -WAIT=`cat /wait-for-root` -KEYMAP=`cat /keymap` +# +# /load_kernel_modules +# A script that uses insmod to load the desired +# modules. If this file is not present, all the modules +# in /lib/modules/$(uname -r)/ will be loaded in the usual +# sorted order. If you need to load the modules in a +# certain order, or if the modules need extra options, +# then use a load_kernel_modules script. +# +# There's an example in here. To actually use it, you'll +# need to make it executable: +# +# chmod 755 load_kernel_modules + +INITRD=$(cat /initrd-name) +ROOTDEV=$(cat /rootdev) +ROOTFS=$(cat /rootfs) +LUKSDEV=$(cat /luksdev) +LUKSKEY=$(cat /lukskey) +RESUMEDEV=$(cat /resumedev) +WAIT=$(cat /wait-for-root) +KEYMAP=$(cat /keymap) +INIT=/sbin/init + +PATH="/sbin:/bin:/usr/sbin:/usr/bin" # Mount /proc and /sys: mount -n proc /proc -t proc mount -n sysfs /sys -t sysfs +if grep devtmpfs /proc/filesystems 1>/dev/null 2>/dev/null ; then + DEVTMPFS=1 + mount -n devtmpfs /dev -t devtmpfs +fi + # Parse command line -for ARG in `cat /proc/cmdline`; do +for ARG in $(cat /proc/cmdline); do case $ARG in - rescue) - RESCUE=1 - ;; - root=/dev/*) - ROOTDEV=`echo $ARG | cut -f2 -d=` + 0|1|2|3|4|5|6|S|s|single) + RUNLEVEL=$ARG ;; - rootfs=*) - ROOTFS=`echo $ARG | cut -f2 -d=` + init=*) + INIT=$(echo $ARG | cut -f2 -d=) ;; luksdev=/dev/*) - LUKSDEV=`echo $ARG | cut -f2 -d=` + LUKSDEV=$(echo $ARG | cut -f2 -d=) ;; - waitforroot=*) - WAIT=`echo $ARG | cut -f2 -d=` + lukskey=*) + LUKSKEY=$(echo $ARG | cut -f2- -d=) ;; - root=LABEL=*) - ROOTDEV=`echo $ARG | cut -f2- -d=` + rescue) + RESCUE=1 ;; resume=*) - RESUMEDEV=`echo $ARG | cut -f2 -d=` + RESUMEDEV=$(echo $ARG | cut -f2 -d=) ;; - 0|1|2|3|4|5|6) - RUNLEVEL=$ARG + root=/dev/*) + ROOTDEV=$(echo $ARG | cut -f2 -d=) + ;; + root=LABEL=*) + ROOTDEV=$(echo $ARG | cut -f2- -d=) + ;; + root=UUID=*) + ROOTDEV=$(echo $ARG | cut -f2- -d=) + ;; + rootfs=*) + ROOTFS=$(echo $ARG | cut -f2 -d=) + ;; + waitforroot=*) + WAIT=$(echo $ARG | cut -f2 -d=) ;; esac done # Load kernel modules: -if [ ! -d /lib/modules/`uname -r` ]; then - echo "No kernel modules found for Linux `uname -r`." +if [ ! -d /lib/modules/$(uname -r) ]; then + echo "No kernel modules found for Linux $(uname -r)." elif [ -x ./load_kernel_modules ]; then # use load_kernel_modules script: echo "${INITRD}: Loading kernel modules from initrd image:" . ./load_kernel_modules else # load modules (if any) in order: - if ls /lib/modules/`uname -r`/*.*o 1> /dev/null 2> /dev/null ; then + if ls /lib/modules/$(uname -r)/*.*o 1> /dev/null 2> /dev/null ; then echo "${INITRD}: Loading kernel modules from initrd image:" - for module in /lib/modules/`uname -r`/*.*o ; do - insmod $module + for module in /lib/modules/$(uname -r)/*.*o ; do + /sbin/insmod $module done unset module fi fi -# Sometimes the devices needs extra time to be available. -# root on USB are good example of that. +# Sometimes the devices need extra time to be available. +# A root filesystem on USB is a good example of that. sleep $WAIT # If udevd is available, use it to generate block devices # else use mdev to read sysfs and generate the needed devices if [ -x /sbin/udevd -a -x /sbin/udevadm ]; then /sbin/udevd --daemon - /sbin/udevadm trigger --subsystem-match=block + /sbin/udevadm control --property=STARTUP=1 + /sbin/udevadm trigger --subsystem-match=block --action=add /sbin/udevadm settle --timeout=10 + /sbin/udevadm control --property=STARTUP= else - mdev -s + [ "$DEVTMPFS" != "1" ] && mdev -s fi # Load a custom keyboard mapping: @@ -136,62 +172,106 @@ if [ "$RESCUE" = "" ]; then /sbin/mdadm -E -s >/etc/mdadm.conf /sbin/mdadm -A -s fi - - # Find root device if a label was given: - if echo $ROOTDEV | grep -q "LABEL=" ; then - ROOTDEV=`findfs $ROOTDEV` - fi - # Make encrypted root partition available: - # The useable device will be under /dev/mapper/ - # Three scenarios for the commandline exist: - # 1- ROOTDEV is on a LUKS volume, and LUKSDEV is a real block device - # 2- ROOTDEV is on a LVM volume, and LUKSDEV is a real block device - # 3- ROOTDEV is on a LUKS volume, and LUKSDEV is on a LVM volume - # Case (3) will have to wait until we initialize the LVM. - # Test if ROOTDEV is "/dev/someting" or just "something" - the first means - # ROOTDEV is on a LVM volume (scenario 2); we don't need to rewrite ROOTDEV. - # The second means that ROOTDEV is on a LUKS volume (scenario 1). - CRYPTDEV="" + # Unlock any encrypted partitions necessary to access the + # root filesystem, such as encrypted LVM Physical volumes, disk + # partitions or mdadm arrays. + # Unavailable devices such as LVM Logical Volumes will need to be + # deferred until they become available after the vgscan. + if [ -x /sbin/cryptsetup ]; then - # If we find a LUKS device now, it is on a real block device: - if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then - CRYPTDEV=$(basename $ROOTDEV) - echo "Unlocking LUKS crypt volume '${CRYPTDEV}' on device '$LUKSDEV':" - /sbin/cryptsetup luksOpen ${LUKSDEV} $CRYPTDEV </dev/systty >/dev/systty 2>&1 - if [ "$CRYPTDEV" == "$ROOTDEV" ]; then # scenario 1 - ROOTDEV="/dev/mapper/${CRYPTDEV}" + + # Determine if we have to use a LUKS keyfile: + if [ ! -z "$LUKSKEY" ]; then + mkdir /mountkey + KEYPART=$(echo $LUKSKEY |cut -f1 -d:) + LUKSPATH="/mountkey$(echo $LUKSKEY |cut -f2 -d:)" + # Catch possible mount failure: + if blkid -t TYPE=vfat $KEYPART 1>/dev/null 2>&1 ; then + MOUNTOPTS="-t vfat -o shortname=mixed" + else + MOUNTOPTS="-t auto" + fi + mount $MOUNTOPTS $(findfs $KEYPART) /mountkey 2>/dev/null + # Check if we can actually use this file: + if [ ! -f $LUKSPATH ]; then + LUKSKEY="" + else + echo ">>> Using LUKS key file: '$LUKSKEY'" + LUKSKEY="-d $LUKSPATH" fi fi + + LUKSLIST_DEFERRED="" + LUKSLIST=$(echo $LUKSDEV | tr -s ':' ' ') + for LUKSDEV in $LUKSLIST ; do + if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then + if echo $ROOTDEV | grep -q "LABEL=" || echo $ROOTDEV | grep -q "UUID=" ; then + CRYPTDEV="luks$(basename $LUKSDEV)" + elif [ "x$ROOTDEV" = "x$(basename $ROOTDEV)" ]; then + CRYPTDEV="$ROOTDEV" + else + CRYPTDEV="luks$(basename $LUKSDEV)" + fi + echo "Unlocking LUKS encrypted device '${LUKSDEV}' as luks mapped device '$CRYPTDEV':" + /sbin/cryptsetup ${LUKSKEY} luksOpen ${LUKSDEV} ${CRYPTDEV} </dev/tty0 >/dev/tty0 2>&1 + if [ "$ROOTDEV" = "$LUKSDEV" -o "$ROOTDEV" = "$CRYPTDEV" ] ; then + ROOTDEV="/dev/mapper/$CRYPTDEV" + fi + else + LUKSLIST_DEFERRED="${LUKSLIST_DEFERRED} ${LUKSDEV}" + fi + done fi # Initialize LVM: - if [ -x /sbin/vgscan ]; then - /sbin/vgscan --mknodes --ignorelockingfailure - sleep 10 + if [ -x /sbin/vgchange ]; then /sbin/vgchange -ay --ignorelockingfailure fi - # Make encrypted root partition available (scenario 3): - # We have to handle cases here where the LUKS volume is created on a LV - if [ -x /sbin/cryptsetup ]; then - if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then - # Only act if we could not open the LUKS device before (i.e. is on a LV): - if [ "x$CRYPTDEV" == "x" ]; then - echo "Unlocking LUKS crypt volume '${ROOTDEV}' on device '$LUKSDEV':" - /sbin/cryptsetup luksOpen ${LUKSDEV} $ROOTDEV </dev/systty >/dev/systty 2>&1 - ROOTDEV="/dev/mapper/${ROOTDEV}" + # Unlock any LUKS encrypted devices that were deferred above but have now + # become available due to the vgscan (i.e. filesystems on LVM Logical Volumes) + + if [ -x /sbin/cryptsetup -a -n "${LUKSLIST_DEFERRED}" ]; then + for LUKSDEV in ${LUKSLIST_DEFERRED} ; do + if /sbin/cryptsetup isLuks ${LUKSDEV} 1>/dev/null 2>/dev/null ; then + if echo $ROOTDEV | grep -q "LABEL=" || echo $ROOTDEV | grep -q "UUID=" ; then + CRYPTDEV="luks$(basename $LUKSDEV)" + elif [ "x$ROOTDEV" = "x$(basename $ROOTDEV)" ]; then + CRYPTDEV="$ROOTDEV" + else + CRYPTDEV="luks$(basename $LUKSDEV)" + fi + echo "Unlocking LUKS encrypted device '${LUKSDEV}' as luks mapped device '$CRYPTDEV':" + /sbin/cryptsetup ${LUKSKEY} luksOpen ${LUKSDEV} ${CRYPTDEV} </dev/tty0 >/dev/tty0 2>&1 + if [ "$ROOTDEV" = "$LUKSDEV" -o "$ROOTDEV" = "$CRYPTDEV" ] ; then + ROOTDEV="/dev/mapper/$CRYPTDEV" + fi + else + echo "LUKS device '${LUKSDEV}' unavailable for unlocking!" fi - fi + done fi + # Find root device if a label or UUID was given: + if echo $ROOTDEV | grep -q "LABEL=" || \ + echo $ROOTDEV | grep -q "UUID=" ; then + ROOTDEV=$(findfs $ROOTDEV) + fi + + # Clean up after LUKS unlock using a keyfile: + if grep -q mountkey /proc/mounts 2>/dev/null ; then + umount -l /mountkey + rmdir /mountkey 2>/dev/null + fi + # Resume state from swap if [ "$RESUMEDEV" != "" ]; then if ls -l $RESUMEDEV | grep -q "^l" ; then - RESUMEDEV=`ls -l $RESUMEDEV | awk '{ print $NF }'` + RESUMEDEV=$(ls -l $RESUMEDEV | awk '{ print $NF }') fi echo "Trying to resume from $RESUMEDEV" - RESMAJMIN=`ls -l $RESUMEDEV | tr , : | awk '{ print $5$6 }'` + RESMAJMIN=$(ls -l $RESUMEDEV | tr , : | awk '{ print $5$6 }') echo $RESMAJMIN > /sys/power/resume fi @@ -206,6 +286,7 @@ if [ "$RESCUE" = "" ]; then /bin/sh fi else + echo echo "RESCUE mode" echo echo " You can try to fix or rescue your system now. If you want" @@ -219,12 +300,13 @@ else /bin/sh fi -if ps axc | grep -q udevd ; then - killall udevd +if pgrep udevd >/dev/null ; then + pkill udevd fi unset ERR -umount /proc -umount /sys +mount -o move /proc /mnt/proc +mount -o move /sys /mnt/sys +[ "$DEVTMPFS" = "1" ] && mount -o move /dev /mnt/dev echo "${INITRD}: exiting" -exec switch_root /mnt /sbin/init $RUNLEVEL +exec switch_root /mnt $INIT $RUNLEVEL |