--- /sbin/mkinitrd	2007-03-12 14:54:08.000000000 -0500
+++ ./mkinitrd	2007-04-25 04:44:48.000000000 -0500
@@ -23,6 +23,7 @@
 #       Bill Nottingham <notting@redhat.com>
 #       Guillaume Cottenceau <gc@mandrakesoft.com>
 #       Peter Jones <pjones@redhat.com>
+#       Thomas Swan <thomas.swan@gmail.com>
 
 export MALLOC_PERTURB_=204
 
@@ -48,6 +49,15 @@
 CONFMODS="$MODULES"
 MODULES=""
 
+CRYPTODEVICES=""
+CRYPTOMODS="DEFAULT"
+crypto=""
+crypto_omit=0
+crypto_reps=0
+
+CONFIG=/etc/mkinintrd.conf
+config=1
+
 compress=1
 allowmissing=""
 target=""
@@ -98,7 +108,9 @@
     $cmd "       [--force-ide-probe] [--force-scsi-probe | --omit-scsi-modules]"
     $cmd "       [--image-version] [--force-raid-probe | --omit-raid-modules]"
     $cmd "       [--with=<module>] [--force-lvm-probe | --omit-lvm-modules]"
-    $cmd "       [--builtin=<module>] [--omit-dmraid] [--net-dev=<interface>]"
+    $cmd "       [--builtin=<module>] [--net-dev=<interface>] [--config=<config>]"
+    $cmd "       [--nocrypto] [--crypto-module=<module>|DEFAULT|ALL] [--omit-dmraid] "
+    $cmd "       [--crypto-dev=<device>[@<key-device>,<key-device-fstype>][:<key-file>]"
     $cmd "       [--fstab=<fstab>] [--nocompress] <initrd-image> <kernel-version>"
     $cmd ""
     $cmd "       (ex: `basename $0` /boot/initrd-2.2.5-15.img 2.2.5-15)"
@@ -437,6 +449,100 @@
     addnetdev $netdev
 }
 
+findallcryptomods() {
+    local cryptomods=""
+    cryptomods="$cryptomods dm-crypt"
+    cryptomods="$cryptomods blkcipher"
+    for modName in `find /lib/modules/$1/kernel/crypto/ -type f | sed 's/.*\/\(.*\)\..*/\1/'` ; do
+        cryptomods="$cryptomods $modName"
+    done
+    echo $cryptomods
+}
+
+execconfig() {
+    if [ -e ${CONFIG} ] ; then
+        local OPTIONS
+        while read config ; do 
+            config=${config/##*/}
+            config=${config/#\{ ,    \}*//}
+            config=${config/%*\{ ,    \}//}
+            if [ -n ${config} ] ; then
+                OPTIONS="${OPTIONS} ${config}" 
+            fi
+        done < /etc/mkinitrd.conf
+        if [ -n "${OPTIONS}" ] ; then
+            OPTIONS="--noconfig ${OPTIONS} $*"
+            exec $progname ${OPTIONS}
+        fi
+    fi
+}
+
+emit_crypto() {
+    if [ -n "${crypto_reps}" ] ; then
+        let crypto_reps=${crypto_reps}+1
+    else    
+        crypto_reps=1
+    fi
+    if [ -n "$crypto" ] ; then
+        for i in $CRYPTODEVICES ; do 
+            # We want a complete predictable name for the encrypted device
+            # to use with device-mapper. ... Assume nothing!
+            crypto_device=${i%%@*}
+            crypto_device=${crypto_device%%:*}
+            crypto_mapper_name=${crypto_device##/dev/}
+            crypto_mapper_name=`echo ${crypto_mapper_name} | sed 's!/!_!g'`
+            crypto_key_file=""
+            crypto_key_device=""
+            crypto_key_tmp=""
+            if [ ${i##*:} != ${i} ] ; then
+                crypto_key_file=${i##*:}
+                crypto_key_tmp=${i%%:*}
+                crypto_key_tmp=${crypto_key_tmp##*@}
+            fi
+            if [ "${crypto_key_tmp}" != "${crypto_device}" ] ; then
+                crypto_key_device=${crypto_key_tmp%%,*}
+                crypto_key_device_fs=${crypto_key_tmp##*,}
+                crypto_key_file=${crypto_key_file##/}
+                if [ ${crypto_key_device} == ${crypto_key_tmp} ] ; then
+                    echo "Crypto: No fstype specified for external crypto key:"
+                    echo "   ${i}"
+                    exit 211
+                fi
+            fi
+
+            emit "echo Decrypting ${crypto_device} (Round ${crypto_reps})"
+            if [ -n "${crypto_key_device}" ] ; then
+                # Mount the filesystem with the key, and decrypt using the key
+                # on the mounted media.  
+                emit "mount -t ${crypto_key_device_fs} -o ro ${crypto_key_device} /crypto/mount"
+                emit "cryptsetup luksOpen ${crypto_device} ${crypto_mapper_name} -d /crypto/mount/${crypto_key_file}"
+                emit "umount /crypto/mount"
+                if [ $crypto_reps == 1 ] ; then
+                    vecho -n "Crypto: Decrypt ${crypto_device} using external keyfile ${crypto_key_file} "
+                    vecho  "located on ${crypto_key_device} mounted as an ${crypto_key_device_fs} filesystem "
+                fi
+            elif [ -n "${crypto_key_file}" ] ; then 
+                # Embed the key in the initrd image.  * Useful if /boot is a removable drive * 
+                emit "cryptsetup luksOpen ${crypto_device} ${crypto_mapper_name} -d /crypto/"`basename ${crypto_key_file}`
+                if [ ! -f "$MNTIMAGE/crypto/$(basename ${crypto_key_file})" ] ; then
+                    if ! inst ${crypto_key_file} "$MNTIMAGE/crypto/$(basename ${crypto_key_file})" ; then
+                        echo "Unable to import key file ${crypto_key_file}" 
+                        exit 1
+                    fi
+                fi
+                if [ $crypto_reps == 1 ] ; then
+                    vecho "Crypto: Decrypt ${crypto_device} using embedded keyfile imported from ${crypto_key_file}"
+                fi
+            else
+                emit "cryptsetup luksOpen ${crypto_device} ${crypto_mapper_name}"
+                if [ $crypto_reps == 1 ] ; then
+                    vecho "Crypto: Decrypt ${crypto_device} using passphrase decryption"
+                fi
+            fi
+        done
+    fi
+}
+
 handleraid() {
     local start=0
 
@@ -552,9 +658,33 @@
 }
 
 
+option_next=1
+for option in $@ ; do 
+    let option_next=$option_next+1
+    case $option in 
+    --noconfig*)
+        config=0
+        ;;
+    --config*)
+    	if [ "$option" != "${option##--config=}" ] ; then
+    		CONFIG=${option##--config=}
+    	else
+    		CONFIG=${!option_next}
+    	fi
+    	;;
+    esac
+done    
+unset option_next
+
+if [ "$config" == "1" ] ; then 
+    progname=$0
+    execconfig $@
+fi
+
 while [ $# -gt 0 ]; do
     case $1 in
         --fstab*)
+            preserve_options=$1 $2
             if [ "$1" != "${1##--fstab=}" ]; then
                 fstab=${1##--fstab=}
             else
@@ -725,6 +855,34 @@
                 shift
             fi
 	    ;;
+        --noconfig*)
+            config=0
+            ;;
+        --omit-crypt*)
+            crypto_omit=1
+            ;;
+        --crypto-module*)
+            crypto=1
+            if [ "$1" != "${1##--crypto-module=}" ]; then
+                modname="${1##--crypto-module=}"
+            else
+                modname="$2"
+                if [ -z "$2" ] ; then
+                    modname="DEFAULT"
+                fi
+            fi
+            CRYPTOMODS="$CRYPTOMODS $modname"
+            ;;
+        --crypto-dev*)
+            crypto=1
+            cryptodevice=""
+            if [ "$1" != "${1##--crypto-dev=}" ]; then
+                cryptodevice="${1##--crypto-dev=}"
+            else
+                cryptodevice="$2"
+            fi
+            CRYPTODEVICES="$CRYPTODEVICES $cryptodevice"
+            ;;
         --help)
             usage -n
             ;;
@@ -780,6 +938,26 @@
     exit 1
 fi
 
+if [ $crypto_omit == 1 ] ; then 
+    crypto=""
+fi
+
+if [ -n "$crypto" ] ; then
+    for modname in $CRYPTOMODS ; do 
+        case $modname in 
+        ALL)
+            PREMODS="$PREMODS "`findallcryptomods $kernel`
+            ;;
+        DEFAULT)
+            PREMODS="$PREMODS dm-crypt blkcipher aes cbc sha256 crypto_null"
+            ;;
+        *)
+            PREMODS="$PREMODS $modname"
+            ;;
+        esac
+    done
+fi
+
 vecho "Creating initramfs"
 modulefile=/etc/modprobe.conf
 
@@ -931,6 +1109,9 @@
         findmodule -dm-mirror
         findmodule -dm-zero
         findmodule -dm-snapshot
+        if [ -n "$crypto" ] ; then
+            findmodule -dm-crypt
+        fi
         
         RAIDS=$(/sbin/dmraid -s -craidname 2>/dev/null | grep -vi "no raid disks") 
     
@@ -1059,6 +1240,11 @@
 mkdir -p $MNTIMAGE/sysroot
 ln -s bin $MNTIMAGE/sbin
 
+if [ -n "$crypto" ] ; then
+    mkdir -p $MNTIMAGE/crypto
+    mkdir -p $MNTIMAGE/crypto/mount
+fi
+
 if [ -e /etc/fstab.sys ]; then
     inst /etc/fstab.sys "$MNTIMAGE/etc/fstab.sys"
 fi
@@ -1066,6 +1252,10 @@
 inst /sbin/insmod.static "$MNTIMAGE/bin/insmod"
 ln -s /sbin/nash $MNTIMAGE/sbin/modprobe
 
+if [ -n "$crypto" ] ; then
+    inst /sbin/cryptsetup "$MNTIMAGE/bin/cryptsetup"
+fi
+
 for MODULE in $MODULES; do
     if [ -x /usr/bin/strip ]; then
         /usr/bin/strip -g $verbose $MODULE -o $MNTIMAGE/lib/$(basename $MODULE)
@@ -1233,6 +1423,11 @@
 # things like RAID or LVM
 emit "mkblkdevs"
 
+# Chickens and eggs.  Because you can encrypt both LV's and the devices
+# containing containing LV's, we need try to try to decrypt twice or we
+# need to be far more clever.
+emit_crypto
+
 emitdms
 
 if [ -n "$raiddevices" ]; then
@@ -1249,6 +1444,14 @@
     emit "lvm vgchange -ay --ignorelockingfailure $vg_list"
 fi
 
+# Eggs and chickens.  Try decrypting just in case any LV's are encrypted.
+# We need to do to this before resuming on the off chance that swap has been
+# encrypted with a permanent key.  
+#
+# If the volume has already been decrypted, no harm has been done doing it 
+# twice.
+emit_crypto
+
 if [ -z "$noresume" -a -n "$swsuspdev" ]; then
     emit "resume $swsuspdev"
 fi
