#! /bin/bash

# mkinitrd - create the initramfs images
# usage: see below usage() or call with -h
#
# Copyright (C) 1999-2006 SuSE Linux Products GmbH, Nuernberg, Germany
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
# USA.

# This file is kept in the following CVS repository:
#
# $Source: /suse/yast2/cvsroot/mkinitrd/mkinitrd,v $
# $Revision: 1.374 $

usage() {
    cat<<EOF
	Create initial ramdisk images that contain all kernel modules
	needed in the early boot process, before the root file system
	becomes available. This usually includes SCSI and/or RAID
	modules, a file system module for the root file system, or
	a network interface driver module for dhcp.

        mkinitrd [options]

        options:
          -h               This Text.
          -k "kernel list" List of kernel images for which initrd files
                           are created. Defaults to all kernels found
			   in /boot.
          -i "initrd list" List of file names for the initrd; position
	  		   have match to "kernel list". Defaults to all
			   all kernels found in /boot.
          -m "module list" Modules to include in initrd. Defaults to the
                           INITRD_MODULES variable in /etc/sysconfig/kernel.
          -u "DomU module list" Modules to include in initrd. Defaults to
                           the DOMU_INITRD_MODULES variable in
                           /etc/sysconfig/kernel.
          -f "feature list" Features to be enabled when generating initrd.
                           Available features are:
                           iscsi, md, mpath, lvm, lvm2, evms
          -b boot_dir      Boot directory. Defaults to /boot.
          -d root_device   Root device. Defaults to the device from which
                           / is mounted. Overrides the rootdev enviroment
			   variable if set.
	  -s size          Add splash animation and bootscreen to initrd.
	  -t tmp_dir       Temporary directory. Defaults to /var/tmp.
	  -D interface     Run dhcp on the specified interface.
	  -I interface     Configure the specified interface statically.
	  -a acpi_dsdt     Attach compiled ACPI DSDT (Differentiated System
	  		   Description Table) to initrd. This replaces the
			   DSDT of the BIOS. Defaults to the ACPI_DSDT
			   variable in /etc/sysconfig/kernel.
          -e               Use static binaries where possible (currently unavailable)
          -P               Include modules for IDE devices on the PCI bus
	  -V script        Vendor specific script to run in linuxrc.
	  -M map           System.map file to use.
EOF
    exit
}

default_kernel_images() {
    local regex kernel_image kernel_version version_version initrd_image
    local qf='%{NAME}-%{VERSION}-%{RELEASE}\n'

    case "$(uname -m)" in
	s390|s390x)
	    regex='image'
	    ;;
	ppc|ppc64)
	    regex='vmlinux'
	    ;;
	*)  regex='vmlinuz'
	    ;;
    esac

    # user mode linux
    if grep -q UML /proc/cpuinfo; then
	    regex='linux'
    fi

    kernel_images=""
    initrd_images=""
    for kernel_image in $(ls /boot \
	    | sed -ne "\|^$regex\(-[0-9.]\+-[0-9]\+-[a-z0-9]\+$\)\?|p") ; do

	# Note that we cannot check the RPM database here -- this
	# script is itself called from within the binary kernel
	# packages, and rpm does not allow recursive calls.

	[ -L "/boot/$kernel_image" ] && continue
	kernel_version=$(/sbin/get_kernel_version \
			 /boot/$kernel_image 2> /dev/null)
	initrd_image=$(echo $kernel_image | sed -e "s|${regex}|initrd|")
	if [ "$kernel_image" != "$initrd_image" -a \
	     -n "$kernel_version" -a \
	     -d "/lib/modules/$kernel_version" ]; then
		kernel_images="$kernel_images /boot/$kernel_image"
		initrd_images="$initrd_images /boot/$initrd_image"
	fi
    done
}

# You can specify the root device via the environment variable rootdev (e.g.
# "rootdev=/dev/hda mkinitrd").

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# general configurable parameters

kernel_images=
initrd_images=
modules=
modules_set=
domu_modules=
domu_modules_set=
feature_list=
boot_dir=
splash=off
use_static_binaries=ignored
acpi_dsdt=
use_selinux=
sysmap=
journaldev=
build_day=@BUILD_DAY@
scan_pci_bus=

# architecture dependend changes:
case "$(uname -m)" in
    i?86|x86_64)
	splash="auto"
	;;
esac

while getopts :ef:hk:i:m:u:b:d:s:St:D:I:V:a:M:Pj: a ; do
    case $a in
	\:|\?)	case $OPTARG in
		k)  echo "-k requires kernel list parameter"
		    ;;
		i)  echo "-i requires initrd list parameter"
		    ;;
		m)  echo "-m requires module list parameter"
		    ;;
		u)  echo "-u requires module list parameter"
		    ;;
		f)  echo "-f requires feature list parameter"
		    ;;
		b)  echo "-b requires boot dir parameter"
		    ;;
		d)  echo "-d requires root device parameter"
		    ;;
		s)  echo "-s requires image size(s)"
		    ;;
		t)  echo "-t requires tmp dir parameter"
		    ;;
		D)  echo "-D requires dhcp interface parameter"
		    ;;
		I)  echo "-I requires network interface parameter"
		    ;;
		a)  echo "-a requires a DSDT parameter"
		    ;;
		V)  echo "-V requires an executable to run inside linuxrc"
		    ;;
		M)  echo "-M requires the System.map file"
		    ;;	
		j)  echo "-j requires the journal device"
		    ;;	
		*)  echo "Unknown option: -$OPTARG"
		    echo "Try mkinitrd -h"
		    ;;
	    esac
	    exit 1
	    ;;
	e)  use_static_binaries=ignored
	    ;;
	f)  feature_list=$OPTARG
	    ;;
	k)  kernel_images=$OPTARG
	    ;;
	i)  initrd_images=$OPTARG
	    ;;
	m)  modules=$OPTARG
	    modules_set=1
	    ;;
	u)  domu_modules=$OPTARG
	    domu_modules_set=1
	    ;;
	b)  boot_dir=$OPTARG
	    ;;
	d)  rootdev=$OPTARG
	    ;;
	s)  splash=$OPTARG
	    ;;
	t)  tmp_dir=$OPTARG
	    ;;
	D)  interface=$OPTARG
	    interface=${interface#/dev/}
	    use_dhcp=1
	    scan_pci_bus=
	    ;;
 	I)  interface=$OPTARG
 	    interface=${interface#/dev/}
 	    use_ipconfig=1
	    scan_pci_bus=
	    ;;
	a)  acpi_dsdt="$OPTARG"
	    ;;
	S)  use_selinux=1
	    ;;
	V)  vendor_init_script="$OPTARG"
	    ;;
	M)  sysmap="$OPTARG"
	    ;;
	P)  scan_pci_bus=1
	    ;;
	j)  journaldev="$OPTARG"
	    ;;
	h)  usage
	    ;;
    esac
done
shift $(( $OPTIND - 1 ))

mkinit_name="mkinitramfs"

if [ -n "$1" ]; then
    root_dir=${1%/}  # strip trailing slash
else
    root_dir=
fi

if [ -n "$boot_dir" ]; then
    boot_dir="${boot_dir#/}"
    boot_dir="/${boot_dir%/}"
else
    boot_dir="/boot"
fi
if [ ! -d "$boot_dir" ]; then
    echo "$boot_dir is not a directory" >&2
    exit 1
fi

if [ -n "$tmp_dir" ]; then
    tmp_dir="/${tmp_dir#/}"  # make sure it is an absolute path
else
    tmp_dir=/var/tmp
fi
if [ ! -d "$tmp_dir" ]; then
    echo "$tmp_dir is not a directory" >&2
    exit 1
fi

# Check if the -k and -i settings are valid.
if [ $(set -- $kernel_images ; echo $#) -ne \
     $(set -- $initrd_images ; echo $#) ]; then
    echo "You have to specify -k and -i, or none of both. The -k" \
         "and -i options must each contain the same number of items." >&2
    exit 1
fi

# Mount /usr, required for ldd and other tools to create the initrd tree
mounted_usr=
if [ ! -x /usr/bin/ldd ]; then
  mounted_usr=/usr
  if ! mount -n -v /usr ; then
    echo "/usr/bin/ldd not available and mount /usr failed." \
         "mkinitrd does not work without it." >&2
    exit 1
  fi
fi

# Mount /proc if not already done so
mounted_proc=
if [ ! -e /proc/mounts ]; then
  mounted_proc=/proc
  mount -n -t proc proc $mounted_proc
fi

# And /sys likewise
mounted_sys=
if [ ! -d /sys/devices ] ; then
    mounted_sys=/sys
    mount -n -t sysfs none /sys
fi

if [ -z "$kernel_images" -o -z "$initrd_images" ]; then
    default_kernel_images
fi

# The shell-bang line to use inside initrd.
# has to be bash due to $@ array usage
shebang=/bin/bash

initrd_insmod=/sbin/insmod
initrd_modprobe=/sbin/modprobe

# maximum initrd size
image_blocks=40960
image_inodes=2048

# handle splash screen
case "$splash" in
off)
    splashsizes= ;;
auto)
    unset ${!splash_size_*}
    modes=
    for file in $root_dir/{etc/lilo.conf,boot/grub/menu.lst,proc/cmdline}; do
	[ -e $file ] || continue
 	modes="$modes $(sed -e '/^[ \t]*#/d' $file \
			| sed -ne 's/^.*vga[ \t]*=[ \t]*\([^ \t]*\).*/\1/p' \
			| sed -ne '/^\([0-9]\+\|0[xX][0-9a-fA-F]\+\)$/p')"
    done

    for mode in $modes; do
	case $(($mode)) in  # $((...)) : Convert 0xFOO to decimal
	785|786) splash_size_640x480=1 ;;
	788|789) splash_size_800x600=1 ;;
	791|792) splash_size_1024x768=1 ;;
	794|795) splash_size_1280x1024=1 ;;
	*)       vgahex=$(printf 0x%04x "$(($mode))")
		 if [ -x /usr/sbin/hwinfo ] ; then
		     size=$(/usr/sbin/hwinfo --framebuffer | \
			 sed -ne 's/^.*Mode '$vgahex': \([^ ]\+\) .*$/\1/p' \
			 2>/dev/null)
		     eval splash_size_$size=1
		 fi ;;
        esac
    done
    # Get current modes from fb
    for fb in /sys/class/graphics/fb* ; do
	if [ -d $fb ] && [ -f $fb/virtual_size ] ; then
	    size=$(sed -ne 's/,/x/p' $fb/virtual_size)
	    eval splash_size_$size=1
	fi
    done
    splashsizes="$(for x in ${!splash_size_*}; do
			echo ${x#splash_size_}
		   done)"
    unset ${!splash_size_*}
    ;;
*)
    splashsizes=$splash ;;
esac

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# should be nothing to change below...

PATH=/sbin:/usr/sbin:$PATH

# Fixup old installations
unset CDPATH

work_dir=$(mktemp -qd $tmp_dir/${mkinit_name}.XXXXXX)
if [ $? -ne 0 ]; then
	echo "$0: Can't create temp dir, exiting." >&2
	exit 1
fi

umount_proc() {
    [ "$mounted_proc" ] && umount -n $mounted_proc
    mounted_proc=
    [ "$mounted_sys" ] && umount -n $mounted_sys
    mounted_sys=
    [ "$mounted_usr" ] && umount -v -n $mounted_usr
    mounted_usr=
}

cleanup() {
    rm -f $tmp_initrd $tmp_initrd.gz
    initrd_bins=()
}

cleanup_finish() {
    umount_proc
    [ -d "$work_dir" ] && rm -rf $work_dir
}

handle_terminate() {
    echo "(received signal)

Interrupted, cleaning up." >&2
    cleanup
    cleanup_finish
    exit 255
}

trap handle_terminate 1 2 3 15

error() {
    echo "$2" >&2
    cleanup
    cleanup_finish
    exit $1
}

oops() {
    exit_code=$1
    shift
    echo "$@" >&2
}

is_xen_kernel() {
    local kversion=$1
    local cfg

    for cfg in ${root_dir}/boot/config-$kversion $root_dir/lib/modules/$kversion/build/.config
    do
	test -r $cfg || continue
	grep -q "^CONFIG_XEN=y\$" $cfg
	return
    done
    test $kversion != "${kversion%-xen*}"
    return 
}

# Check if module $1 is listed in $modules.
has_module() {
    case " $modules " in
	*" $1 "*)   return 0 ;;
    esac
    return 1
}

# Check if any of the modules in $* are listed in $modules.
has_any_module() {
    local module
    for module in "$@"; do
	has_module "$module" && return 0
    done
}

# Add module $1 at the end of the module list.
add_module() {
    local module
    for module in "$@"; do
	has_module "$module" || modules="$modules $module"
    done
}

# Install a binary file
cp_bin() {
    cp -a "$@" \
    || exit_code=1

    # Remember the binaries installed. We need the list for checking
    # for dynamic libraries.
    while [ $# -gt 1 ]; do
	initrd_bins[${#initrd_bins[@]}]=$1
	shift
   done
   # file may print '^setuid ELF ...'
   # suid mount will fail if mkinitrd was called as user
   if [ -L "$1" ]; then
	: do nothing with symlinks
   elif [ -d "$1" -o -f "$1" ]; then
     find "$1" -type f -print0 | xargs -0 chmod 0755 
   fi
}

# Resolve dynamic library dependencies. Returns a list of symbolic links
# to shared objects and shared object files for the binaries in $*.
shared_object_files() {
    local LDD CHROOT initrd_libs lib_files lib_links lib link

    LDD=/usr/bin/ldd
    if [ ! -x $LDD ]; then
	error 2 "I need $LDD."
    fi

    initrd_libs=( $(
	for i in "$@" ; do $LDD "$i" ; done \
	| sed -ne 's:\t\(.* => \)\?\(/.*\) (0x[0-9a-f]*):\2:p'
    ) )

    # Evil hack: On some systems we have generic as well as optimized
    # libraries, but the optimized libraries may not work with all
    # kernel versions (e.g., the NPTL glibc libraries don't work with
    # a 2.4 kernel). Use the generic versions of the libraries in the
    # initrd (and guess the name).
    local n optimized
    for ((n=0; $n<${#initrd_libs[@]}; n++)); do
	lib=${initrd_libs[$n]}
	optimized="$(echo "$lib" | sed -e 's:.*/\([^/]\+/\)[^/]\+$:\1:')"
	lib=${lib/$optimized/}
	if [ "${optimized:0:3}" != "lib" -a -f "$lib" ]; then
	    #echo "[Using $lib instead of ${initrd_libs[$n]}]" >&2
	    initrd_libs[$n]="${lib/$optimized/}"
	fi
    done

    for lib in "${initrd_libs[@]}"; do
	case "$lib" in
	linux-gate*)
	    # This library is mapped into the process by the kernel
	    # for vsyscalls (i.e., syscalls that don't need a user/
	    # kernel address space transition) in 2.6 kernels.
	    continue ;;
	/*)
	    lib="${lib:1}" ;;
	*)
	    # Library could not be found.
	    oops 7 "Dynamic library $lib not found"
	    continue ;;
	esac

	while [ -L "/$lib" ]; do
	    echo $lib
	    link="$(readlink "/$lib")"
	    if [ x"${link:0:1}" == x"/" ]; then
	        lib=${link#/}
	    else
	        lib="${lib%/*}/$link"
	    fi
	done
	echo $lib
    done \
    | sort -u
}

# Resolve module dependencies and parameters. Returns a list of modules and
# their parameters.
resolve_modules() {
    local kernel_version=$1 module
    shift

    for module in "$@"; do
	local with_modprobe_conf
	module=${module%.o}  # strip trailing ".o" just in case.
	module=${module%.ko}  # strip trailing ".ko" just in case.
	if [ -e /etc/modprobe.conf ]; then
	    with_modprobe_conf="-C /etc/modprobe.conf"
	fi
	module_list=$(/sbin/modprobe $with_modprobe_conf \
	    --set-version $kernel_version --ignore-install \
	    --show-depends $module 2> /dev/null \
	    | sed -ne 's:.*insmod /\?::p' )
	if [ -z "$module_list" ]; then
	    oops 7 "Cannot determine dependencies of module $module." \
		"Is modules.dep up to date?"
	fi
	echo "$module_list"
    done \
    | awk ' # filter duplicates: we must not reorder modules here!
	NF == 0     { next }
	$1 in seen  { next }
		    { seen[$1]=1
		      # drop module parameters here: modprobe in the initrd
		      # will pick them up again.
		      print $1
		    }
    '
    rm -f $temp
}

# Test if file $1 is smaller than file $2 (kilobyte granularity)
smaller_file() {
    local size1=$(ls -l "$1" |awk '{print $5}')
    local size2=$(ls -l "$2" |awk '{print $5}')
    [ $size1 -lt $size2 ]
}

# Cat from stdin to linuxrc, removing leading whitespace up to pipe symbol.
# Note that here documents can only be indented with tabs, not with spaces.
cat_linuxrc() {
    sed 's/^[ \t]*|//' >> $linuxrc
    echo >> $linuxrc
}

# Attach ACPI DSDT if necessary.
attach_dsdt() {
    local initrd_image=$1
    local sdt_match

    if [ -z "$acpi_dsdt" ]; then
	if [ -f /etc/sysconfig/kernel ]; then
	    . /etc/sysconfig/kernel
	    acpi_dsdt="$ACPI_DSDT"
	fi
    fi
    if [ -z "$acpi_dsdt" ]; then
	return
    fi
    for sdt in "$acpi_dsdt";do
	# File must be named: DSDT.aml or SSDT[0-9]*.aml
	sdt_match=`expr match $(echo $sdt) ".*[SD]SDT[0-9]*\.aml"`
	if [ $sdt_match -lt 8 ];then
	    oops 2 "($sdt) [DS]SDT must be named: DSDT.aml or SSDT[0-9]*.aml"
	    return
	fi
	if [ ! -f "$sdt" ]; then
	    oops 2 "ACPI DSDT $sdt does not exist."
	    return
	fi
	if ! grep -q "[SD]SDT" "$sdt" ; then
	    oops 2 "File $sdt is not a valid ACPI DSDT. Ignoring."
	    return
	elif grep -qE 'DefinitionBlock' "$sdt" ; then
	    oops 2 "ACPI DSDT $sdt does not seem to be in binary form." \
		"Will not attach this to $initrd_image."
	    return
	fi

	cp "$sdt" $tmp_mnt

	echo -e "ACPI DSDT:\t$sdt"
    done
}

# Check for IDE module
check_ide_modules_pcimap() {
    local ide_modules

    pcimap_file=$1
    vendor_id=$2
    device_id=$3
	
    pci_vendor_id=$(printf "0x%08x" $(($2)))
    pci_device_id=$(printf "0x%08x" $(($3)))
    while read pcimap_module rest; do
	if [ "$pcimap_module" == "ata_piix" ]; then
	    # FIXME: add_module will have no effect in a sub-shell...
	    add_module "ahci"
	    ide_modules="$ide_modules ahci"
	fi
	ide_modules="$ide_modules $pcimap_module"
    done < <(grep "$pci_vendor_id $pci_device_id" $pcimap_file)

    echo "$ide_modules"
}

check_ide_modules_hwinfo() {
    local ide_modules
    local kernel_version

    kernel_version=$(basename ${modules_dir})

    pci_id_vendor=$1
    pci_id_device=$2
    pci_revision=$3
    pci_subid_vendor=$4
    pci_subid_device=$5

    while read hwinfo_module; do
	if [ "$hwinfo_module" == "ata_piix" ]; then
	    # Always add ahci prior to ata_piix
	    ide_modules="$ide_modules ahci $hwinfo_module"
	elif [ "$hwinfo_module" != "ahci" ]; then
	    # Skip ahci module from hwinfo output
	    ide_modules="$ide_modules $hwinfo_module"
	fi
    done < <(hwinfo --kernel-version $kernel_version \
	            --db "pci ${pci_id_vendor:+vendor=$pci_id_vendor} 
                         ${pci_id_device:+device=$pci_id_device} 
                         ${pci_subid_vendor:+subvendor=$pci_subid_vendor}  
                         ${pci_subid_device:+subdevice=$pci_subid_device} 
                         ${pci_revision:+revision=$pci_revision}")

    echo "$ide_modules"
}

# Check for IDE modules, new version
# We'll be asking hwinfo to return the proper module for us
check_ide_modules() {
    local modules_dir=$1 ide_modules

    # Check for PCI bus
    if [ ! -d /proc/bus/pci ]; then
        # Not found, no error
        return
    fi

    pcimap_file="${modules_dir}/modules.pcimap"

    if [ ! -f "$pcimap_file" ] ; then
	echo "No modules.pcimap file found" >&2
	return
    fi

    while read pci_id none class_id dev_id rev_id; do
	if [ "$class_id" == "0101:" ] ; then
	    ide_slots="$ide_slots $pci_id"
	fi
    done < <(/sbin/lspci -n)

    for pci_id in $ide_slots; do
	set -- $(/sbin/lspci -nm -s $pci_id)
	if [ -z "$4" ] ; then
	    continue;
	fi
	eval id=$4
	if [ -z "$5" ] ; then
	    continue;
	fi
	pci_id_vendor=$(printf "0x%x" $((0x$id)))
	eval id=$5
	pci_id_device=$(printf "0x%x" $((0x$id)))
	if [ -z "$6" ] ; then
	    continue;
	fi
	id=${6#-r}
	pci_revision=$(printf "0x%x" $((0x$id)))
	case "$7" in
	    -*)
		shift
		;;
	    *)
		;;
	esac
	if [ "$7" ] ; then
	    eval id=$7
	    pci_subid_vendor=$(printf "0x%x" $((0x$id)))
	fi
	if [ "$8" ] ; then
	    eval id=$8
	    pci_subid_device=$(printf "0x%x" $((0x$id)))
	fi
	: Slot ${pci_id}: $pci_id_vendor $pci_id_device $pci_subid_vendor $pci_subid_device
	if [ -x /usr/sbin/hwinfo ] ; then
	    ide_modules=$(check_ide_modules_hwinfo $pci_id_vendor $pci_id_device $pci_revision $pci_subid_vendor $pci_subid_device)
	fi
	if [ -z "$ide_modules" ]; then
	    ide_modules=$(check_ide_modules_pcimap $pcimap_file $pci_id_vendor $pci_id_device)
	fi

	    if [ "$ide_modules" ]; then
		for module in $ide_modules; do
		    # Only add ahci module if ata_piix is not loaded already
		    if [ "$module" == "ahci" ]; then
			has_module ata_piix || add_module $module
		    else
			add_module $module
		    fi
		done
		# All IDE modules are now loaded later
		# if grep -q ide-disk ${modules_dir}/modules.dep; then
		#     add_module ide-disk
		# fi
		# IDE-floppy is considered obsolete
		# if grep -q ide-floppy ${modules_dir}/modules.dep; then
		#     add_module ide-floppy
		# fi
		# if grep -q ide-cd ${modules_dir}/modules.dep; then
		#     add_module ide-cd
		# fi
		echo
	    fi
    done
}

# NOTE: The mkdevn, devmajor and block_driver functions are reused
#

# Convert a major:minor pair into a device number
mkdevn() {
    local major=$1 minor=$2 minorhi minorlo
    major=$(($major * 256))
    minorhi=$(($minor / 256))
    minorlo=$(($minor % 256))
    minor=$(($minorhi * 256 * 4096))
    echo $(( $minorlo + $major + $minor ))
}

# Extract the major part from a device number
devmajor() {
    local devn=$(($1 / 256))
    echo $(( $devn % 4096 ))
}

# Extract the minor part from a device number
devminor() {
    local devn=${1:-0}
    echo $(( $devn % 256 )) 
}

block_driver() {
    local devn block major driver
    case "$1" in
    /dev/*) devn=$(devnumber $1 2> /dev/null) ;;

    *:*)    # major:minor
	    set -- $(IFS=: ; echo $1)
	    devn=$(mkdevn $1 $2) ;;

    [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
	    # hex device number
	    devn=$((0x$1)) ;;
    esac

    [ -z "$devn" ] && return 1
    major=$(devmajor $devn)
    driver=$(sed -n "s/^[ ]*$major \(.*\)/\1/p;/Block/p" < /proc/devices | tail -1)
    case "$driver" in
	Block*)
	    return 1
	    ;;
	*)
	    echo $driver
	    return 0
	    ;;
    esac
}

# (We are using a devnumber binary inside the initrd.)
devnumber() {
    set -- $(ls -lL $1)
    mkdevn ${5%,} $6
}

# Calculate the netmask for a given prefix
calc_netmask() {
    local prefix=$1
    local netmask

    netmask=
    num=0
    while (( $prefix > 8 )) ; do
	if (( $num > 0 )) ; then
	    netmask="${netmask}.255"
	else
	    netmask="255"
	fi
	prefix=$(($prefix - 8))
	num=$(($num + 1))
    done
    if (( $prefix > 0 )) ; then
	mask=$(( 0xFF00 >> $prefix ))
    else
	mask=0
    fi
    netmask="${netmask}.$(( $mask & 0xFF ))"
    num=$(($num + 1))
    while (( $num < 4 )) ; do
	netmask="${netmask}.0"
	num=$(($num + 1))
    done
    echo $netmask
}

# Get the interface information for ipconfig
get_ip_config() {
    local iface
    local iplink
    local iproute

    iface=$1
    iplink=$(ip addr show dev $iface | grep "inet ")

    set -- $iplink
    if [ "$1" == "inet" ]; then
	shift

	ipaddr=${1%%/*}
	prefix=${1##*/}
	shift 
	if [ "$1" == "peer" ] ; then
	    shift
	    peeraddr=${1%%/*}
	fi
	netmask=$(calc_netmask $prefix)
	bcast=$3
    fi
    iproute=$(ip route list dev $iface | grep default)
    if [ $? -eq 0 ]; then
	set -- $iproute
	gwaddr=$3
    fi
    hostname=$(hostname)
    echo "$ipaddr:$peeraddr:$gwaddr:$netmask:$hostname:$iface:none"
}  

check_iscsi_root() {
    local devname=$1
    local sysfs_path

    sysfs_path=$(udevinfo -q path -n $rootdev 2> /dev/null)
    if [ -z "$sysfs_path" ] || [ ! -d /sys$sysfs_path ] ; then
	return;
    fi

    pushd /sys$sysfs_path > /dev/null
    if [ ! -d device ] ; then
	cd ..
    fi

    if [ ! -d device ] ; then
	# no device link; return
	popd > /dev/null
	return;
    fi

    cd -P device
    cd ../..

    if [ -d iscsi_session:session* ]; then
	cd -P iscsi_session:session*
	echo $(basename $PWD)
    fi
    popd > /dev/null
}

get_default_interface() {
    local ifname
    local inffile="/etc/install.inf"

    # Determine the default network interface
    if [ -f $inffile ] ; then
	# Get info from install.inf during installation
	BOOTPROTO=$(sed -ne 's/NetConfig: \(.*\)/\1/p' $inffile)
	ifname=$(sed -ne 's/Netdevice: \(.*\)/\1/p' $inffile)
    else
    for cfg in /etc/sysconfig/network/ifcfg-*; do
	if [ $(basename $cfg) = "ifcfg-lo" ] ; then
	    continue;
	fi
	eval $(grep STARTMODE $cfg)
	if [ "$STARTMODE" = "nfsroot" ]; then
	    cfgname=$(basename $cfg)
	    ifname=$(getcfg-interface ${cfg#*/ifcfg-})
	    eval $(grep BOOTPROTO $cfg)
	    break;
	fi
    done
    fi
    echo $ifname/$BOOTPROTO
}

###################################################################
#
# S/390 specific procedures
#
s390_check_lvm2() {
    local vgname
    local devname
    
    # Check whether the LVM is on zfcp or DASD
    vgname=$(lvdisplay -c $1 | cut -d : -f 2)

    if [ "$vgname" ]; then
	for devname in $(pvdisplay -c | grep $vgname | cut -d : -f 1); do
	    case "$devname" in
		*/dasd*)
		    s390_enable_dasd=1
		    ;;
		*/sd*)
		    s390_enable_zfcp=1
		    ;;
		*)
		    ;;
	    esac
	done
    fi
}

s390_check_evms() {
    local evms_cmd
    local evms_reg
    local evms_cont
    local evms_seg
    local evms_dsk

    if [ ! -x /sbin/evms ]; then
	return 1
    fi

    if [ -n "$1" ]; then
	evms_cmd="q:r,v=$1"

	while read a b c d; do
	    if [ "$a $b" = "Region Name:" ]; then
		evms_reg="$evms_reg $c"
	    fi
	done < <( echo "$evms_cmd" | /sbin/evms -s )
    fi

    for reg in $evms_reg; do
	evms_cmd="q:c,r=$reg"
	
	while read a b c d; do
	    if [ "$a $b" = "Container Name:" ]; then
		evms_cont="$evms_cont $c"
	    fi
	done < <(echo "$evms_cmd" | /sbin/evms -s )
    done
    
    for cont in $evms_cont; do
	evms_cmd="q:s,c=$cont"
	
	while read a b c d; do
	    if [ "$a $b" = "Segment Name:" ]; then
		evms_seg="$evms_seg $c"
	    fi
	done < <(echo "$evms_cmd" | /sbin/evms -s )
    done

    for seg in $evms_seg; do
	evms_cmd="q:d,s=$seg"
	while read a b c d; do
	    if [ "$a $b $c" = "Logical Disk Name:" ]; then
		evms_dsk="$evms_dsk $d"
	    fi
	done < <(echo "$evms_cmd" | /sbin/evms -s )
    done

    for dsk in $evms_dsk; do
	case $dsk in
	    dasd*)
		s390_enable_dasd=1;
		;;
	    sd*)
		s390_enable_zfcp=1
		;;
	esac
    done
}

s390_check_dasd() {
    local devn=$(devnumber $1)

    for dir in /sys/block/*/*; do
	if [ -d "$dir" ] && [ -f "$dir/dev" ]; then
	    IFS=":" read major minor < $dir/dev
	    if (($devn == $(mkdevn $major $minor) )); then
		path=$dir
		break;
	    fi
	fi
    done
    if [ "$path" ] && [ -d ${path}/../device ]; then
	if [ -r ${path}/../device/discipline ]; then
	    s390_enable_dasd=1
	fi
    fi
}

s390_check_zfcp() {
    local devn=$(devnumber $1)

    for dir in /sys/block/*/*; do
	if [ -d "$dir" ] && [ -f "$dir/dev" ]; then
	    IFS=":" read major minor < $dir/dev
	    if (($devn == $(mkdevn $major $minor) )); then
		path=$dir
		break;
	    fi
	fi
    done
    
    if [ "$path" ] && [ -d "$path/../device" ] && [ -e "$path/../device/scsi_level" ] ; then
	s390_enable_zfcp=1
    fi
}

# Detect all zfcp disks
# We need to activate all disks in the same order
# as found in the running system to get the same
# behaviour during booting.
s390_zfcp_sysfs() {
    local dev_dir
    local fcp_disk_hba
    local fcp_disk_wwpn
    local fcp_disk_lun

    if [ "$s390_enable_zfcp" ] ; then
	# Root is on SCSI, detect all SCSI devices
	for dev_dir in /sys/block/sd? /sys/block/sd?? /sys/block/sd??? /sys/block/sd???? ; do
	    if [ -d "$dev_dir" ] && [ -e "$dev_dir/device" ]; then
		pushd $dev_dir > /dev/null;
		cd $(readlink device);
		if [ -r ./hba_id ]; then
		    read fcp_disk_hba < ./hba_id
		    read fcp_disk_wwpn < ./wwpn
		    read fcp_disk_lun < ./fcp_lun
	    
		    s390_zfcp_disks="$s390_zfcp_disks $fcp_disk_hba:$fcp_disk_wwpn:$fcp_disk_lun"

		    for id in $s390_zfcp_hbas; do
			if [ "$id" == "$fcp_disk_hba" ]; then
			    fcp_disk_hba=
			fi
		    done
		    [ "$fcp_disk_hba" ] && s390_zfcp_hbas="$s390_zfcp_hbas $fcp_disk_hba"
		fi
		popd > /dev/null
	    fi
	done
	if [ "$s390_zfcp_hbas" ]; then
	    add_module sd_mod
	    add_module zfcp
	fi
    fi

}

s390_dasd_sysfs() {
    local type
    local discipline

    if [ "$s390_enable_dasd" ]; then
	# Root device is on a dasd device, enable all dasd disks
	for dir in /sys/block/dasd[a-z] /sys/block/dasd[a-z][a-z] /sys/block/dasd[a-z][a-z][a-z] ; do
	    if [ -d "$dir" ] && [ -d ${dir}/device ]; then
		pushd $dir > /dev/null
		cd $(readlink device)
		if [ -r ./discipline ]; then
		    read type < ./discipline
		    
		    case $type in
			ECKD)
			    add_module dasd_eckd_mod
			    discipline=0
			    ;;
			FBA)
			    add_module dasd_fba_mod
			    discipline=1
			    ;;
			DIAG)
			    add_module dasd_diag_mod
			    discipline=2
			    ;;
			*)
			    ;;
		    esac
		    s390_dasd_disks="$s390_dasd_disks $(basename $PWD):$discipline"
		fi
		popd > /dev/null
	    fi
	done

    fi
}

s390_dasd_proc() {
    local zipl_conf_with_dasd dasd_module

    if [ -f /etc/zipl.conf ] \
       && grep -q '^[[:space:]]*parameters[[:space:]]*=' \
	    /etc/zipl.conf; then
	    zipl_conf_with_dasd=1
    fi

    if modprobe -c \
       | grep -q '^[[:space:]]*options[[:space:]]\+dasd_mod' ; then
	dasd_module=1
    fi

    if grep -q -e "^dasd" /proc/modules \
       || [ -n "$zipl_conf_with_dasd" ] \
       || [ -n "$dasd_module" ] \
       || has_module dasd_mod ; then

	if [ ! "$zipl_conf_with_dasd" -a ! "$dasd_module" ]; then
	    error 1 "\
The dasd module is required, but no dasd configuration was found in
root_dir/etc/zipl.conf or root_dir/etc/modules.conf."
	fi

	if grep -q ECKD /proc/dasd/devices ; then
	    add_module dasd_eckd_mod
	fi

	if grep -q FBA  /proc/dasd/devices ; then
	    add_module dasd_fba_mod
	fi

	if grep -q DIAG /proc/dasd/devices ; then
	    add_module dasd_diag_mod
	fi
    else
	# /proc not mounted or somesuch. Enable all dasd modules
	add_module dasd_mod
	add_module dasd_eckd_mod
	add_module dasd_fba_mod
	add_module dasd_diag_mod
    fi
}

s390_get_ctc_ccwdevs()
{
    local interface=$1

    if [ ! -d /sys/class/net/$interface/device ] ; then
	error 1 "No device link for interface $interface"
    fi
    pushd /sys/class/net/$interface/device > /dev/null 2>&1
    cd -P cdev0
    cdev0=$(basename $PWD)
    popd > /dev/null 2>&1

    pushd /sys/class/net/$interface/device > /dev/null 2>&1
    cd -P cdev1
    cdev1=$(basename $PWD)
    popd > /dev/null 2>&1

    echo "$cdev0,$cdev1"
}

###################################################################
#
# Create the initrd image $2 for kernel $1 (both are absolute path names).
#
mkinitrd_kernel() {
    local kernel_image=$1 initrd_image=$2
    local kernel_version
    local need_raidstart
    local need_mdadm
    local need_dmraid
    local -a features
    local fs_modules drv_modules uld_modules xen_modules
    local i

    tmp_mnt=$work_dir/mnt
    tmp_mnt_small=${tmp_mnt}_small
    tmp_msg=$work_dir/msg$$
    vendor_script=$tmp_mnt/vendor_init.sh

    linuxrc=$tmp_mnt/init

    if [ ! -f "$kernel_image" ] ; then
	echo "No kernel image $kernel_image found" >&2
	return
    fi

    kernel_version=$(/sbin/get_kernel_version $kernel_image)
    modules_dep=$root_dir/lib/modules/$kernel_version/modules.dep

    #echo -e "Kernel version:\t$kernel_version"
    echo -e "Kernel image:\t$kernel_image"
    echo -e "Initrd image:\t$initrd_image"

    if [ ! -d "/lib/modules/$kernel_version/misc" -a \
	 ! -d "/lib/modules/$kernel_version/kernel" ]; then
	oops 2 "No modules found for kernel $kernel_version"
        return
    fi

    # Make sure to always include the module for the root filesystem
    # if the root filesystem is modularized.
    if ! has_module "$rootfstype" && \
       grep -qe "$rootfstype\.ko:" $modules_dep; then
	echo "Adding the root filesystem module ($rootfstype)"
	add_module $rootfstype
    fi

    # create an empty initrd
    if ! mkdir $tmp_mnt ; then
	error 1 "could not create temporary directory"
    fi

    # fill the initrd
    mkdir -p $tmp_mnt/{sbin,bin,etc,dev,proc,sys,root}

    mkdir -p -m 4777 $tmp_mnt/tmp

    # Create a dummy /etc/mtab for mount/umount
    echo -n > $tmp_mnt/etc/mtab

    mkdir -p $tmp_mnt${shebang%/*}
    cp_bin $shebang $tmp_mnt$shebang
    if [ $shebang != /bin/sh ]; then
	ln -s $shebang $tmp_mnt/bin/sh
    fi
    
    if ! cp_bin $initrd_insmod $tmp_mnt/sbin/insmod 2>/dev/null ; then
	error 5 "no insmod"
    fi

    # Add modprobe, modprobe.conf*, and a version of /bin/true: modprobe.conf
    # might use it.
    if ! cp_bin $initrd_modprobe $tmp_mnt/sbin/modprobe 2>/dev/null ; then
	error 5 "no modprobe"
    fi
    cp -r $root_dir/etc/modprobe.conf $root_dir/etc/modprobe.conf.local \
 	  $root_dir/etc/modprobe.d $tmp_mnt/etc
    cat > $tmp_mnt/bin/true <<-EOF
	#! /bin/sh
	:
	EOF
    chmod +x $tmp_mnt/bin/true
 
    # Enable user-selected features
    if [ "$feature_list" ] ; then
	for f in $feature_list ; do
	    case $f in
		iscsi)
		    add_module iscsi_tcp
		    ;;
		mpath)
		    add_module dm-multipath
		    ;;
		lvm2)
		    add_module dm-snapshot
		    add_module dm-crypt
		    add_module dm-zero
		    add_module dm-mirror
		    root_lvm2=1
		    root_dm=1
		    ;;
		lvm)
		    add_module lvm-mod
		    root_lvm=1
		    ;;
		evms)
		    add_module dm-mirror
		    add_module dm-snapshot
		    root_evms=1
		    root_dm=1
		    ;;
		md)
		    add_module raid0
		    add_module raid1
		    add_module raid5
		    add_module linear
		    need_mdadm=1
		    ;;
		dmraid)
		    need_dmraid=1
		    ;;
		*)
		    error 6 "invalid feature $f"
		    ;;
	    esac
	done
    fi

    if [ ! -z "$vendor_init_script" ] ; then
	features=(${features[@]} script\($vendor_script\))
	cp_bin $vendor_init_script $vendor_script
    fi

    if [ -n "$root_dmraid" -a -x /sbin/dmraid ] ; then
	need_dmraid=1
    fi

    if has_module dm-multipath && [ -x /sbin/multipath ] ; then
	add_module dm-round-robin
	add_module dm-emc
	root_mpath=1
	root_dm=1
    fi

    if has_module iscsi_tcp ; then
	features=(${features[@]} iscsi)
	add_module crc32c
	cp_bin /sbin/iscsid $tmp_mnt/sbin/iscsid
	cp_bin /sbin/iscsiadm $tmp_mnt/sbin/iscsiadm
	mkdir -p $tmp_mnt/etc/iscsi
	cat /etc/iscsi/initiatorname.iscsi > $tmp_mnt/etc/iscsi/initiatorname.iscsi
	mkdir -p $tmp_mnt/var/run
	mkdir -p $tmp_mnt/var/lock/iscsi
    fi

    if [ -n "$s390_dasd_disks" ]; then
	cp_bin /sbin/dasd_configure $tmp_mnt/sbin
	cp_bin /sbin/dasdview $tmp_mnt/sbin
    fi

    if [ -n "$s390_zfcp_disks" ]; then
	cp_bin /sbin/zfcp_host_configure $tmp_mnt/sbin
	cp_bin /sbin/zfcp_disk_configure $tmp_mnt/sbin
    fi

    features=(${features[@]} initramfs)

    # Programs /sbin
    for prog in killall5 blogd showconsole; do
	cp_bin /sbin/$prog $tmp_mnt/sbin
    done

    if test -x $tmp_mnt/sbin/blogd; then
	mkdir -p $tmp_mnt/var/log
    fi

    # Programs /bin
    for prog in sed sleep cat ln ls pidof mount umount date; do
	cp_bin /bin/$prog $tmp_mnt/bin
    done

    # Common utilities
    for bin in chmod mkdir mknod rm; do
	cp_bin /bin/$bin $tmp_mnt/bin
    done

    for file in /lib/mkinitrd/bin/* ; do
	if [ -x $file ] ; then
	    cp_bin $file $tmp_mnt/bin
	fi
    done

    # all dev nodes belong to root, but some may be
    # owned by a group other than root
    # getent passwd | sed '/^root:/s/^\([^:]\+\):[^:]*:\([^:]\+\):\([^:]\+\):.*/\1::\2:\3:::/p;d' > $tmp_mnt/etc/passwd
    echo 'root::0:0:::' > $tmp_mnt/etc/passwd
    echo 'nobody::65534:65533:::' >> $tmp_mnt/etc/passwd
    getent group | sed 's/^\([^:]\+\):[^:]*:\([^:]\+\):.*/\1::\2:/' > $tmp_mnt/etc/group
    (echo 'passwd: files';echo 'group: files') > $tmp_mnt/etc/nsswitch.conf

    cp_bin /sbin/udevd $tmp_mnt/sbin/
    cp_bin /sbin/udevtrigger $tmp_mnt/sbin/
    cp_bin /sbin/udevsettle $tmp_mnt/sbin/
    cp_bin /usr/bin/udevinfo $tmp_mnt/sbin/
    if [ -e /usr/sbin/resume ]; then
        cp_bin /usr/sbin/resume $tmp_mnt/sbin/
    fi

    mkdir -p $tmp_mnt/etc/udev/rules.d
    # Create our own udev.conf
    echo "udev_root=\"/dev\"" > $tmp_mnt/etc/udev/udev.conf
    echo "udev_rules=\"/etc/udev/rules.d\"" >> $tmp_mnt/etc/udev/udev.conf
    # copy needed rules
    for rule in 05-udev-early.rules 50-udev-default.rules 60-persistent-storage.rules 64-device-mapper.rules; do
	if [ -f /etc/udev/rules.d/$rule ]; then
	    cp /etc/udev/rules.d/$rule $tmp_mnt/etc/udev/rules.d
	fi
    done
    # copy helper scripts
    mkdir -p $tmp_mnt/lib/udev
    if [ -f /sbin/vol_id ] ; then
        ln -s ../../sbin/vol_id ${tmp_mnt}/lib/udev/vol_id
    fi
    for script in /lib/udev/* /sbin/*_id ; do
	if [ -f "$script" ] ; then
	    cp_bin $script ${tmp_mnt}${script}
	fi
    done
    rm -f $tmp_mnt/lib/udev/mount.sh
    echo '#!/bin/sh' > $tmp_mnt/lib/udev/mount.sh
    echo 'exit 0' >> $tmp_mnt/lib/udev/mount.sh

    # scsi_id config file
    cp /etc/scsi_id.config $tmp_mnt/etc/scsi_id.config

    # QLogic firmware
    mkdir -p $tmp_mnt/lib/firmware
    for fw in /lib/firmware/ql*.bin ; do
	if [ -f "$fw" ] ; then
	    cp -a $fw $tmp_mnt/lib/firmware
	fi
    done

    if [ -n "$root_lvm" ] ; then
	features=(${features[@]} lvm)
	mkdir -p $tmp_mnt/etc/lvmtab.d
	cp_bin /sbin/{vgscan,vgchange} $tmp_mnt/sbin
	cp_bin /sbin/dmsetup $tmp_mnt/sbin
    fi

    if [ -n "$root_mpath" ] ; then
	features=(${features[@]} dm/mpath)
	cp_bin /sbin/multipath $tmp_mnt/sbin
	cp_bin /sbin/kpartx $tmp_mnt/sbin
	cp_bin /sbin/dmsetup $tmp_mnt/sbin
	cp_bin /sbin/mpath_id $tmp_mnt/sbin
	cp_bin /sbin/kpartx_id $tmp_mnt/sbin
	for pp in /sbin/mpath_prio_* ; do
	    cp_bin $pp $tmp_mnt/sbin
	done
	if [ -f /etc/multipath.conf ] ; then
	    cp -a /etc/multipath.conf $tmp_mnt/etc
	fi
	cp /etc/udev/rules.d/71-multipath.rules $tmp_mnt/etc/udev/rules.d
	cp /etc/udev/rules.d/72-multipath-compat.rules $tmp_mnt/etc/udev/rules.d
    fi

    if [ -n "$root_lvm2" ] ; then
	features=(${features[@]} dm/lvm2)
	mkdir -p $tmp_mnt/etc/lvm
	mkdir -p $tmp_mnt/var/lock/lvm
	cp_bin /sbin/{vgscan,vgchange,lvm} $tmp_mnt/sbin
	cp_bin /sbin/dmsetup $tmp_mnt/sbin
	cp_bin /bin/{sed,mkdir,mknod,ls} $tmp_mnt/bin
	cp -a /etc/lvm/lvm.conf $tmp_mnt/etc/lvm
    fi

    if [ -n "$root_evms" ] ; then
	features=(${features[@]} dm/evms2)
	cp_bin /sbin/{evms_activate,dmsetup} $tmp_mnt/sbin
	cp_bin /bin/{sed,mkdir,mknod,rm} $tmp_mnt/bin
	cp_bin /usr/bin/expr $tmp_mnt/bin
	mkdir -p $tmp_mnt/mnt
	cp -a /etc/evms.conf $tmp_mnt/etc
	evms_lib=
	case "`LANG=C LC_ALL=C file -b $tmp_mnt/sbin/evms_activate | awk '/^ELF ..-bit/ { print $2 }'`" in
		32-bit) evms_lib="/lib/evms" ;;
		64-bit) evms_lib="/lib64/evms" ;;
	esac
	if [ "$evms_lib" ] ; then
	    mkdir -p ${tmp_mnt}${evms_lib}
	    SD=$(ls -A $evms_lib | tail -n 1)
	    (cd ${tmp_mnt}${evms_lib} && mkdir -p $SD)
	    cp_bin $evms_lib/$SD/* ${tmp_mnt}${evms_lib}/$SD
	    rm -f ${tmp_mnt}${evms_lib}/*/*{ext2,jfs,ogfs,reiser,swap,xfs}*so
	else
	    oops 7 "No EVMS modules found"
	fi
    fi

    if [ -n "$root_md" ] ; then
	need_mdadm=1
	if [ -f /etc/mdadm.conf ] ; then
	    cat /etc/mdadm.conf > $tmp_mnt/etc/mdadm.conf
	    md_mod_list="mdconf"
	else
	    echo "DEVICE partitions" > $tmp_mnt/etc/mdadm.conf
	    for md in $md_list ; do
		mdconf=$(eval echo \$md_conf_$md)
		md_mod=${mdconf#*level=}
		md_mod=${md_mod%% *}
		for mod in $md_mod_list ; do
		    if [ "$mod" == $"md_mod" ] ; then
			md_mod=
		    fi
		done
		if [ "$md_mod" ] ; then
		    if [ "$md_mod_list" ] ; then
			md_mod_list="$md_mod $md_mod_list"
		    else
			md_mod_list="$md_mod"
		    fi
		fi
		echo $mdconf >> $tmp_mnt/etc/mdadm.conf
	    done
	fi
	features=(${features[@]} md\($md_mod_list\))
    fi

    if [ -n "$need_mdadm" ] ; then
	features=(${features[@]} mdadm)
	cp_bin /sbin/mdadm $tmp_mnt/sbin
    fi

    if [ -n "$need_dmraid" ] ; then
	features=(${features[@]} dm/raid)
	cp_bin /sbin/dmraid $tmp_mnt/sbin
    fi

    if [ -n "$use_dhcp" ] ; then
	features=(${features[@]} dhcp\($interface\))
	cp_bin /sbin/dhcpcd $tmp_mnt/bin
	cp_bin /bin/kill $tmp_mnt/bin
	mkdir -p $tmp_mnt/var/lib/dhcpcd
	mkdir -p $tmp_mnt/var/run
    fi

    if [ -n "$use_ipconfig" ] ; then
	features=(${features[@]} static\($interface\))
	cp_bin $root_dir/lib/mkinitrd/bin/ipconfig.sh $tmp_mnt/bin/ipconfig
	cp_bin $root_dir/sbin/ip $tmp_mnt/sbin/ip
    fi
  
    if [ "$rootfstype" = "ext2" ] ; then
	features=(${features[@]} fsck.ext2)
	cp_bin /sbin/fsck $tmp_mnt/bin
	cp_bin /sbin/fsck.ext2 $tmp_mnt/bin
    fi

    if [ "$rootfstype" = "ext3" ] ; then
	features=(${features[@]} fsck.ext3)
	cp_bin /sbin/fsck $tmp_mnt/bin
	cp_bin /sbin/fsck.ext3 $tmp_mnt/bin
    fi

    if [ "$rootfstype" = "reiserfs" ] ; then
	features=(${features[@]} fsck.reiserfs)
	cp_bin /sbin/fsck $tmp_mnt/bin
	cp_bin /sbin/fsck.reiserfs $tmp_mnt/bin
    fi

    if [ "$rootfstype" = "jfs" ] ; then
	features=(${features[@]} fsck.jfs)
	cp_bin /sbin/fsck $tmp_mnt/bin
	cp_bin /sbin/fsck.jfs $tmp_mnt/bin
    fi

    if [ "$rootfstype" = "xfs" ] ; then
	features=(${features[@]} fsck.xfs)
	cp_bin /sbin/fsck $tmp_mnt/bin
	cp_bin /sbin/fsck.xfs $tmp_mnt/bin
    fi

    if [ -n "$debug_mkinit" ]; then
	features=(${features[@]} debug)
	cp_bin /bin/ls $tmp_mnt/bin
    fi

    # The devnumber builtin does not use /bin/ls
    if [ -z "$use_static_binaries" ] ; then
	cp_bin /bin/ls $tmp_mnt/bin
    fi

    echo -ne "Shared libs:\t"
    # Copy all required shared libraries and the symlinks that
    # refer to them.
    lib_files=$(shared_object_files "${initrd_bins[@]}")
    if [ -n "$lib_files" ]; then
	for lib in $lib_files; do
	    [ -L $root_dir/$lib ] || echo -n "$lib "
	    ( cd ${root_dir:-/} ; cp -dp --parents $lib $tmp_mnt )
	done
	lib_files=
	# no symlinks, most point into the running system
	for i in `LANG=C LC_ALL=C file -b $tmp_mnt/{,usr/}{lib*/udev/,{,s}bin}/* | awk '/^ELF ..-bit/ { print $2 }' | sort -u`
	do
		case "$i" in
			32-bit)
				mkdir -p $tmp_mnt/lib
				lib_files="$lib_files `echo $root_dir/lib/libnss_files* $root_dir/lib/libgcc_s.so*`"
				;;
			64-bit)
				mkdir -p $tmp_mnt/lib64
				lib_files="$lib_files `echo $root_dir/lib64/libnss_files* $root_dir/lib64/libgcc_s.so*`"
				;;
		esac
	done
	for lib in $lib_files ; do
	    if [ -f $lib ] ; then
		echo -n "${lib##$root_dir/} "
		cp -dp --parents $lib $tmp_mnt
	    fi
	done
	echo
    else
	echo "none"
    fi

    > $linuxrc
    chmod 755 $linuxrc

    # Note that the in-place documents must be indented with tabs, not spaces.
    cat_linuxrc <<-EOF
	|#! $shebang
	|
	|export PATH=/sbin:/usr/sbin:/bin:/usr/bin
	|
	|devpts=no
	|die() {
	|    umount /proc
	|    umount /sys
	|    umount /dev
	|    if test "\$devpts" = "yes"; then
	|	test -e /dev/pts      && umount -t devpts /dev/pts
	|	test -e /root/dev/pts && umount -t devpts /root/dev/pts
	|    fi
	|    exit \$1
	|}
	|
	|mount -t proc  proc  /proc
	|mount -t sysfs sysfs /sys
	|mount -t tmpfs -o mode=0755 udev /dev
	|
	|mknod -m 0666 /dev/tty     c 5 0
	|mknod -m 0600 /dev/console c 5 1
	|mknod -m 0666 /dev/ptmx    c 5 2
	|
	|exec < /dev/console > /dev/console 2>&1
	|
	|mknod -m 0666 /dev/null c 1 3
	|mknod -m 0600 /dev/kmsg c 1 11
	|mknod -m 0660 /dev/snapshot c 10 231
	|mknod -m 0666 /dev/random c 1 8
	|mknod -m 0644 /dev/urandom c 1 9
	|mkdir -m 0755 /dev/pts
	|mkdir -m 1777 /dev/shm
	|ln -s /proc/self/fd /dev/fd
	|ln -s fd/0 /dev/stdin
	|ln -s fd/1 /dev/stdout
	|ln -s fd/2 /dev/stderr
	|
	|tty_driver=
	|for o in \$(cat /proc/cmdline); do
	|    case "\$o" in
	|    console=*)
	|	o=\${o##console=}
	|	o=\${o%%,*}
	|	tty_driver="\${tty_driver:+\$tty_driver }\$o"
	|	;;
	|    esac
	|done
	|for o in \$tty_driver; do
	|    case "\$o" in
	|    tty0)  test -e /dev/tty1  || mknod -m 0660 /dev/tty1  c 4  1 ;;
	|    ttyS0) test -e /dev/ttyS0 || mknod -m 0660 /dev/ttyS0 c 4 64 ;;
	|    esac
	|done
	|tty_driver=\$(showconsole -n 2>/dev/null)
	|if test -n "\$tty_driver" ; then
	|    major=\${tty_driver%% *}
	|    minor=\${tty_driver##* }
	|    if test \$major -eq 4 -a \$minor -lt 64 ; then
	|	tty=/dev/tty\$minor
	|	test -e \$tty || mknod -m 0660 \$tty c 4 \$minor
	|    fi
	|    if test \$major -eq 4 -a \$minor -ge 64 ; then
	|	tty=/dev/ttyS\$((64-\$minor))
	|	test -e \$tty || mknod -m 0660 \$tty c 4 \$minor
	|    fi
	|    unset major minor tty
	|fi
	|unset tty_driver
	|
	|REDIRECT=\$(showconsole 2>/dev/null)
	|if test -n "\$REDIRECT" ; then
	|    > /dev/shm/initrd.msg
	|    ln -sf /dev/shm/initrd.msg /var/log/boot.msg
	|    mkdir -p /var/run
	|    mount -t devpts devpts /dev/pts
	|    devpts=yes
	|    /sbin/blogd \$REDIRECT
	|fi
	|
	|echo "" > /proc/sys/kernel/hotplug
	|
	|kernel_cmdline=(\$@)
	|
	|build_day=$build_day
	|case "\$build_day" in
	|	@*) ;;
	|	*)
	|		current_day="\$(LC_ALL=C date -u '+%Y%m%d')"
	|		if [ "\$current_day" -lt "\$build_day" ] ; then
	|			echo "your system time is not correct:"
	|			LC_ALL=C date -u
	|			echo "setting system time to:"
	|			LC_ALL=C date -us "\$build_day"
	|			sleep 3
	|			export SYSTEM_TIME_INCORRECT=\$current_day
	|		fi
	|	;;
	|esac
	|# Default timeout is 30 seconds
	|udev_timeout=30
	|
	|for o in \$(cat /proc/cmdline); do
	|    case \$o in
	|    linuxrc=trace)
	|	echo -n "cmdline: "
	|	for arg in \$@; do
	|	    echo -n "\$arg "
	|	done
	|	echo ""
	|	set -x
	|	debug_linuxrc=1
	|	;;
	|    noresume)
	|	resume_mode=off
	|	;;
	|    rw)
	|       read_write=1
	|       ;;
	|    ro)
	|       read_only=1
	|       ;;
	|    esac
	|done
	|
	|
	|for o in \$(cat /proc/cmdline); do
	|    case \$o in
	|    root=*)
	|	rootdev=\${o#root=}
	|	rootdev_cmdline=1
	|	;;
	|    rootfstype=*)
	|	rootfstype=\${o#rootfstype=}
	|	;;
	|    rootflags=*)
	|	rootflags=\${o#rootflags=}
	|	;;
	|    nfsroot=*)
	|	rootdev=\${o#nfsroot=}
	|	rootdev_cmdline=1
	|	;;
	|    resume=*)
	|	resumedev=\${o#resume=}
	|	;;
	|    journal=*)
	|	journaldev=\${o#journal=}
	|	;;
	|    mduuid=*)
	|	md_uuid=\${o#mduuid=}
	|	;;
	|    init=*)
	|	init=\${o#init=}
	|	;;
	|    udev_timeout=*)
	|	udev_timeout=\${o#udev_timeout=}
	|	;;
	|    rootflags=*)
	|	rootfsflags=\${o#rootflags=}
	|	;;
	|    esac
	|done
	|
	|if [ -z "\$rootdev" ]; then
	|    rootdev=$rootdev
	|fi
	|# lilo strips off the /dev/prefix from device names!
	|case \$rootdev in
	|	/dev/disk/by-name/*)
	|	    rootdevid=\${rootdev#/dev/disk/by-name/}
	|	    rootdevid=\${rootdevid%-part*}
	|	    ;;
	|	/dev/md*)
	|	    md_dev=\$rootdev
	|	    md_minor=\${rootdev#/dev/md}
	|	    ;;
	|	/dev/*)
	|	    ;;
	|	LABEL=*)
	|	    label=\${rootdev#LABEL=}
	|	    echo "ENV{ID_FS_USAGE}==\"filesystem|other\", ENV{ID_FS_LABEL_SAFE}==\"\$label\", SYMLINK+=\"root\"" > /etc/udev/rules.d/99-mkinitrd-label.rules
	|	    rootdev=/dev/root
	|	    ;;
	|	UUID=*)
	|	    uuid=\${rootdev#UUID=}
	|	    echo "ENV{ID_FS_USAGE}==\"filesystem|other\", ENV{ID_FS_UUID}==\"\$uuid\", SYMLINK+=\"root\"" > /etc/udev/rules.d/99-mkinitrd-uuid.rules
	|	    rootdev=/dev/root
	|	    ;;
	|	[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
	|	    maj=\$((0x0\$rootdev >> 8))
	|	    min=\$((0x0\$rootdev & 0xff))
	|	    echo "SUBSYSTEM==\"block\", SYSFS{dev}==\"\$maj:\$min\", SYMLINK+=\"root\"" > /etc/udev/rules.d/05-mkinitrd-lilo.rules
	|	    rootdev=/dev/root ;;
	|	[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
	|	    maj=\$((0x\$rootdev >> 8))
	|	    min=\$((0x\$rootdev & 0xff))
	|	    echo "SUBSYSTEM==\"block\", SYSFS{dev}==\"\$maj:\$min\", SYMLINK+=\"root\"" > /etc/udev/rules.d/05-mkinitrd-lilo.rules
	|	    rootdev=/dev/root ;;
	|	0x[0-9a-fA-F][0-9a-fA-F]*)
	|	    maj=\$((\$rootdev >> 8))
	|	    min=\$((\$rootdev & 0xff))
	|	    echo "SUBSYSTEM==\"block\", SYSFS{dev}==\"\$maj:\$min\", SYMLINK+=\"root\"" > /etc/udev/rules.d/05-mkinitrd-lilo.rules
	|	    rootdev=/dev/root ;;
	|	*:/*)
	|	    rootfstype="nfs"
	|	    ;;
	|	*)
	|	    rootdev=/dev/\$rootdev
	|	    ;;
	|esac
	|md_major=\$(sed -ne 's/\s*\([0-9]\+\)\s*md$/\1/p' /proc/devices)
	|if [ -n "\$md_major" -a "\$md_major" = "\$maj" ]; then
	|    md_minor="\$min"
	|    md_dev="/dev/md\$md_minor"
	|fi
	|
	|# Verify manual resume mode
	|if [ "\$resume_mode" != "off" -a -n "\$resumedev" ]; then
	|    if [ -x /sbin/resume -o -w /sys/power/resume ]; then
	|	echo "Trying manual resume from \$resumedev"
	|	resume_mode=1
	|    else
	|	resumedev=
	|    fi
	|fi
	|
	|# Check for debugging
	|if [ -n "\$debug_linuxrc" ]; then
	|    echo "udev_log=\"debug\"" >> /etc/udev/udev.conf
	|else
	|    echo "udev_log=\"error\"" >> /etc/udev/udev.conf
	|fi
	|
	|# Set default for the journal device
	|if [ -z "\$journaldev" ]; then
	|    journaldev=$journaldev
	|fi
	EOF

    # Transfer the the block_driver function into the initrd
    type mkdevn | sed -e '1d' >> $linuxrc
    echo >> $linuxrc
    type devmajor | sed -e '1d' >> $linuxrc
    echo >> $linuxrc
    type devminor | sed -e '1d' >> $linuxrc
    echo >> $linuxrc
    type block_driver | sed -e '1d' >> $linuxrc
    echo >> $linuxrc
    type devnumber | sed -e '1d' >> $linuxrc
    echo >> $linuxrc

    # Start udev
    cat_linuxrc <<-EOF
	|echo "Creating device nodes with udev"
	|/sbin/udevd --daemon
	|/sbin/udevtrigger
	|/sbin/udevsettle --timeout=\$udev_timeout
	EOF

    # Start blogd if not already done
    cat_linuxrc <<-'EOF'
	|if test -z "$REDIRECT" ; then
	|    REDIRECT=$(showconsole 2>/dev/null)
	|    if test -n "$REDIRECT" ; then
	|	> /dev/shm/initrd.msg
	|	ln -sf /dev/shm/initrd.msg /var/log/boot.msg
	|	mkdir -p /var/run
	|	/sbin/blogd $REDIRECT
	|    fi
	|fi
	EOF

    # FIXME: we should only load IDE modules if we need them for booting
    # Check for IDE modules
    if [ -n "$scan_pci_bus" ] ; then
	check_ide_modules $root_dir/lib/modules/$kernel_version
    fi

    resolved_modules="$(resolve_modules $kernel_version $modules)"

    # If a SCSI module is loaded, we will have a dependency on scsi_mod
    # for kernels which don't have this built in. In that case, assume
    # that the root file system is on a SCSI device, and also include
    # sd_mod.
    local have_scsi have_sd
    case "$resolved_modules" in
	*/scsi_mod.*)   have_scsi=1
			;;
	*/sd_mod.*)	have_sd=1
			;;
    esac
    if [ -n "$have_scsi" -a -z "$have_sd" ]; then
	modules="sd_mod $modules"
	# Re-evaluate module dependencies
	resolved_modules="$(resolve_modules $kernel_version $modules)"
    fi

    # The same reasoning goes for IDE modules
    local have_ide have_ide_disk
    case "$resolved_modules" in
	*/ide-core.*)   have_ide=1
			;;
	*/ide-disk.*)	have_ide_disk=1
			;;
    esac
    if [ -n "$have_ide" -a -z "$have_ide_disk" ]; then
	modules="ide-disk $modules"
	# Re-evaluate module dependencies
	resolved_modules="$(resolve_modules $kernel_version $modules)"
    fi

    if is_xen_kernel $kernel_version; then
	xenu_modules="$(resolve_modules $kernel_version $domu_modules)"
    fi

    # Copy all modules into the initrd
    for module in $resolved_modules $xenu_modules; do
	if [ ! -r $root_dir/$module ]; then
	    oops 9 "Module $module not found."
	    continue
	fi
	if ! ( cd ${root_dir:-/} ; cp -p --parents $module $tmp_mnt ) ; then
	    oops 6 "Failed to add module $module."
	    rm -rf $tmp_mnt
	    return
	fi
    done

    # Add modules which might be loaded via udev during booting
    uld_modules=
    for module in sd_mod osst st sr_mod sg ide-disk ide-scsi \
	          ide-cd ide-tape ide-floppy cdrom; do
	grep -qw $module $root_dir/lib/modules/$kernel_version/modules.dep \
	&& uld_modules="$uld_modules $module"
    done
    uld_modules="$(resolve_modules $kernel_version $uld_modules)"

    # Now copy the upper level driver modules
    for module in $uld_modules; do
	if [ ! -f $tmp_mnt/$module ]; then
	    if ! ( cd ${root_dir:-/} ; cp -p --parents $module $tmp_mnt ) ; then
		oops 6 "Failed to add module $module."
		rm -rf $tmp_mnt
		return
	    fi
	fi
    done

    # Filter modules into fs and non-fs (driver) modules.
    # We do this to avoid loading xfs when doing a resume: xfs had
    # (or still has) a bug that slows down resume a lot.
    # FIXME: get rid of this split crap again.
    for module in $resolved_modules; do
	if [ "$module" != "${module#*/kernel/fs/}" ]; then
	    fs_modules="$fs_modules $module"
	elif is_xen_kernel $kernel_version && [ "$module" != "${module#*/kernel/drivers/xen/*/xen}" ]; then
	    xen_modules="$xen_modules $module"
	else
	    drv_modules="$drv_modules $module"
	fi
    done
    #fs_modules="$(echo "$resolved_modules" | grep -e '/kernel/fs/')"
    #drv_modules="$(echo "$resolved_modules" | grep -v -e '/kernel/fs/')"

    echo -ne "Driver modules:\t"
    initrd_is_using_modules=

    if is_xen_kernel $kernel_version; then
	# NOTE: We use the same settings as the dom0 initrd, except
	# for the different module list. So we share fsck, dm, ... support.
	cat_linuxrc <<-EOF
	|caps="\$(</proc/xen/capabilities)"
	|if [ ! -f /proc/xen/capabilities -o "\$caps" != "\${caps%control_d*}" ]; then
	EOF
    fi

    for modpath in $drv_modules; do
	module=${modpath##*/}
	module=${module%.ko}
	echo -n "${module} "
	cat_linuxrc <<-EOF
	|params=
	|for p in \$(cat /proc/cmdline) ; do
	|  case \$p in
	|    $module.*)
	|      params="\$params \${p#$module.}"
	|      ;;
	|  esac
	|done
	EOF

	case $module in
	    dasd_mod)
		# kernel cmdline dasd parameter is placed into the environment.
		# This is tricky. The only reliably way to check whether the
		# dasd parameter is set is to indeed check for it within the
		# initrd environment itself. Unfortunately the dasd module
		# refuses to load when the dasd parameter is empty, so we
		# need introduce an intermediate parameter which might be
		# set to empty entirely so as not to confuse the dasd module.
		#
		# This checks whether the dasd parameter is present
		cat_linuxrc <<-EOF
		|# check for DASD parameter in /proc/cmdline
		|for p in \$(cat /proc/cmdline) ; do
		|  case \$p in
		|    dasd=*)
		|      params="\$params \$p"
		|      ;;
		|  esac
		|done
		EOF
		;;
	    ide?core)
		# This checks whether an ide= parameter is present
		cat_linuxrc <<-EOF
		|# check for IDE parameter in /proc/cmdline
		|for p in \$(cat /proc/cmdline) ; do
		|  case \$p in
		|    ide=*)
		|      ide_params="\$ide_params \$p"
		|      ;;
		|    hd?=*)
		|      ide_params="\$ide_params \$p"
		|      ;;
		|  esac
		|done
		|if [ -n "\$ide_params" ]; then
		|  params="\$params options=\"\$ide_params\""
		|fi
		EOF
		;;
	    scsi_mod)
		# We may have SCSI parameters on the kernel command line,
		# but because scsi_mod is a module, those would be ignored.
		# Hack around this by scanning /proc/cmdline in linuxrc.

		cat_linuxrc <<-EOF
		|# check for SCSI parameters in /proc/cmdline
		|devflags=0
		|for p in \$(cat /proc/cmdline) ; do
		|  case \$p in
		|    scsi_mod.*)
		|	params="\$params \${p#scsi_mod.}"
		|	;;
		|    scsi_reportlun2=1)
		|	echo "scsi_reportlun2 compat: Use scsi_mod.default_dev_flags=0x20000 instead"
		|	devflags=\$((131072+\$devflags))
		|	;;
		|    scsi_noreportlun=1)
		|	echo "scsi_noreportlun compat: Use scsi_mod.default_dev_flags=0x40000 instead"
		|	devflags=\$((262144+\$devflags))
		|	;;
		|    scsi_sparselun=1)
		|	echo "scsi_sparselun compat: Use scsi_mod.default_dev_flags=0x40 instead"
		|	devflags=\$((64+\$devflags))
		|	;;
		|    scsi_largelun=1)
		|	echo "scsi_largelun compat: Use scsi_mod.default_dev_flags=0x200 instead"
		|	devflags=\$((512+\$devflags))
		|	;;
		|    llun_blklst=*)
		|	echo "llun_blklst is not supported any more"
		|	echo "use scsi_mod.dev_flags=VENDOR:MODEL:0x240[,V:M:0x240[,...]]"
		|	;;
		|    max_ghost_devices=*)
		|	echo "max_ghost_devices is not needed any more"
		|	;;
		|    max_sparseluns=*)
		|	echo "max_sparseluns not supported any more"
		|	echo "use scsi_mod.max_luns or enable the new REPORT_LUNS scsi"
		|	echo "scanning methods; try scsi_mod.default_dev_flags=0x20000"
		|	;;
		|    max_luns=*|max_report_luns=*|inq_timeout=*|dev_flags=*|default_dev_flags=*)
		|	echo "scsi_mod compat: Please use prefix: scsi_mod.\$p"
		|	params="\$params \$p"
		|      ;;
		|  esac
		|done
		|if [ \$devflags != 0 ]; then 
		|    params="default_dev_flags=\$devflags \$params"
		|fi
		EOF
		;;
	esac
	cat_linuxrc <<-EOF
	|echo "Loading $module"
	|modprobe $module \$params
	EOF

	initrd_is_using_modules=1
    done

    if is_xen_kernel $kernel_version; then
	if [ "$xenu_modules" -o "$xen_modules" ]; then
	    cat_linuxrc <<-EOF
		|else
		EOF
	    echo -ne "\nXen domU modules:\t"

	    for modpath in $xenu_modules $xen_modules; do
		module=${modpath##*/}
		module=${module%.ko}
		echo -n "${module} "
		cat_linuxrc <<-EOF
		|params=
		|for p in \$(cat /proc/cmdline) ; do
		|  case \$p in
		|    $module.*)
		|      params="\$params \${p#$module.}"
		|      ;;
		|  esac
		|done
		|echo "Loading $module"
		|modprobe $module \$params
		EOF

		initrd_is_using_modules=1
	    done
	fi
	cat_linuxrc <<-EOF
	|fi
	EOF
    fi

    if [ -z "$initrd_is_using_modules" ]; then
	echo "none"
    else
	echo
    fi

    if [ -n "$s390_dasd_disks" ]; then
	# We only need to activate DASDs manually if it
	# is not done via the kernel command line
	echo -e -n "DASDs:\t\t"
	cat_linuxrc <<-EOF
	|if test -z "\$dasd_params"; then
	|    echo -n "Activating DASDs:"
	EOF
	s390_dasd_disk_num=0
	for disk in $s390_dasd_disks; do
	    set -- $(IFS=":"; echo $disk)
	    use_diag=0
	    case "$2" in
		0)
		    echo -n " $1(ECKD)"
		    ;;
		1)
		    echo -n " $1(FBA)"
		    ;;
		2)
		    echo -n " $1(DIAG)"
		    use_diag=1
		    ;;
	    esac
	    cat_linuxrc <<-EOF
	|    echo -n " $disk"
	|    /sbin/dasd_configure $1 1 $use_diag
	EOF
	    s390_dasd_disk_num=$(( $s390_dasd_disk_num + 1 ))
	done
	echo ""
	cat_linuxrc <<-EOF
	|    echo " : done"
	|fi
	EOF
    fi

    if [ -n "$s390_zfcp_disks" ]; then
	echo -e -n "zfcp HBAs:\t"
	for hba in $s390_zfcp_hbas; do
	    echo -n "$hba "
	    cat_linuxrc <<-EOF
	|echo "Activating zfcp host $hba"
	|/sbin/zfcp_host_configure $hba 1
	EOF
	done
	echo

	echo -e "zfcp disks:\t"
	s390_zfcp_disk_num=0
	for disk in $s390_zfcp_disks; do
	    s390_zfcp_disk_num=$(( $s390_zfcp_disk_num + 1 ))
	    set -- $(IFS=":"; echo $disk)
	    echo -e "\t\t$1:$2:$3"
	    cat_linuxrc <<-EOF
	|echo "Activating zfcp disk $1:$2:$3"
	|/sbin/zfcp_disk_configure $1 $2 $3 1
	EOF
	done
    fi

    case "$(uname -m)" in
	s390|s390x)
	    if [ -z "$s390_zfcp_disks" -a -z "$s390_dasd_disks" ]; then
		echo ""
		echo "WARNING: No boot devices found."
		echo "Make sure to add 'dasd=<dasd-range>' to" \
		     "the kernel command line"
	    fi
	    ;;
    esac

    if [ -n "$use_dhcp" ] ; then
	cat_linuxrc <<-'EOF'
	|case $rootdev in
	|/dev/nfs|*:/*|"")
	|   dhcp_mode=1 ;;
	|esac
	EOF
    fi

    if [ -n "$iscsi_root" ] ; then
	cat_linuxrc <<-EOF
	|for o in \$(cat /proc/cmdline); do
	|  case \$o in
	|    TargetAddress=*)
	|      iscsiserver="\${o#TargetAddress=}" ;;
	|    TargetName=*)
	|      iscsitarget="\${o#TargetName=}" ;;
	|    TargetPort=*)
	|      iscsiport="\${o#TargetPort=}" ;;
	|    InitiatorName=*)
	|      echo \$o > /etc/iscsi/initiatorname.iscsi ;;
	|  esac
	|done
	|# Always enable DHCP for iSCSI
	|dhcp_mode=1
	EOF
    fi

    if [ -n "$use_dhcp" ] ; then
	cat_linuxrc <<-EOF
	|# run dhcp
	|if [ -n "\$dhcp_mode" ]; then
	|  # ifconfig lo 127.0.0.1 netmask 255.0.0.0 broadcast 127.255.255.255 up
	|  # portmap
	|  echo "running dhcpcd on interface $interface"
	|  dhcpcd -R -Y -N -t 100000000 $interface
	|  [ -s /var/lib/dhcpcd/dhcpcd-$interface.info ] || {
	|    echo "no response from dhcp server."
	|    die 0
	|  }
	|  . /var/lib/dhcpcd/dhcpcd-$interface.info
	|  kill -9 \$(cat /var/run/dhcpcd-$interface.pid)
	|  if [ -n "\$DNS" ]; then
	|    oifs="\$IFS"
	|    IFS=","
	|    for ns in \$DNS ; do
	|      echo "nameserver \$ns" >> /etc/resolv.conf
	|    done
	|    IFS="\$oifs"
	|    if [ -n "\$DOMAIN" ]; then
	|	echo "search \$DOMAIN" >> /etc/resolv.conf
	|    fi
	|    echo 'hosts: dns' > /etc/nsswitch.conf
	|  fi
	|fi
	EOF
    fi

    if [ -n "$interface" ] ; then
	case $interface in
	    ctc*)
		ccwdevs=$(s390_get_ctc_ccwdevs $interface)
	cat_linuxrc <<-EOF
	|# configure $interface
	|if [ -d /sys/bus/ccwgroup/drivers/ctc ]; then
	|  echo "$ccwdevs" > /sys/bus/ccwgroup/drivers/ctc/group
	|  # Wait for the device to appear
	|  i=100
	|  while [ "\$i" -gt 0 ]; do
	|    [ -d /sys/bus/ccwgroup/devices/${ccwdevs%%,*} ] && break
	|    i=\$(( \$i - 1 ))
	|  done
	|  if [ "\$i" -le 0 ] ; then
	|    echo "Interface $interface could not be setup, exiting to /bin/sh"
	|    cd /
	|    PATH=$PATH PS1='$ ' /bin/sh -i
	|  else
	|    echo 1 > /sys/bus/ccwgroup/devices/${ccwdevs%%,*}/online
	|  fi
	|fi
	EOF
	;;
	esac
    fi

    if [ -n "$use_ipconfig" ]; then
	ipinterface=$(get_ip_config $interface)
	cat_linuxrc <<-EOF
	|# configure interface
	|for o in \$(cat /proc/cmdline); do
	|  case \$o in
	|    ip=*)
	|      ifspec=\${o#ip=};;
	|  esac
	|done
	|if [ -z "\$ifspec" ]; then
	|    # Fallback to configured interface
	|    ifspec=$ipinterface
	|fi
	|if [ -n "\$ifspec" ]; then
	|  /bin/ipconfig \$ifspec
	|fi
	EOF
    fi

    if [ -n "$iscsi_root" ] ; then
	iscsi_tgtname=$(cat /sys/class/iscsi_session/${iscsi_root}/targetname)
	iscsi_tgtaddr=$(cat /sys/class/iscsi_connection/connection${iscsi_root#session}:0/address)
	cat_linuxrc <<-EOF
	|iscsi_login_root_node()
	|{
	|    if [ -z "\$iscsitarget" ] ; then 
	|      iscsitarget=$iscsi_tgtname
	|    fi
	|
	|    if [ -z "\$iscsiserver" ] ; then 
	|      iscsiserver=$iscsi_tgtaddr
	|    fi
	|
	|
	|    echo -n "Discover targets on \$iscsiserver: "
	|    if /sbin/iscsiadm -m discovery -t st -p \$iscsiserver:\$iscsiport 2> /dev/null ; then
	|	echo "ok."
	|    else
	|	echo "failed."
	|	return 1
	|    fi
	|    echo -n "Logging into \$iscsitarget: "
	|    if /sbin/iscsiadm -m node -T \$iscsitarget -p \$iscsiserver:\$iscsiport -l ; then
	|	echo "ok."
	|    else
	|	echo "failed."
	|    fi
	|}
	|
	|echo "Starting iSCSI daemon"
	|/sbin/iscsid
	|
	|iscsi_login_root_node
	|
	EOF
    fi

    if [ "$rootfstype" = "nfs" ]; then
	cat_linuxrc <<-'EOF'
	|if [ -z "$rootdev_cmdline" ]; then
	|  case "$ROOTPATH" in
	|    "") ;;
	|    *:*)
	|	rootfstype="nfs"
	|	rootdev="$ROOTPATH" ;;
	|    *)
	|	if [ -n "$DHCPSIADDR" ]; then
	|	    rootdev="$DHCPSIADDR:$ROOTPATH"
	|	    rootfstype="nfs"
	|	elif [ -n "$DHCPSNAME" ]; then
	|	    rootdev="$DHCPSNAME:$ROOTPATH"
	|	    rootfstype="nfs"
	|	fi ;;
	|   esac
	|   if [ -z "$rootdev" ]; then
	|	echo "no local root= kernel option given and no root" \
	|	     "server set by the dhcp server."
	|	die 0
	|   fi
	|fi
	EOF
    fi

    if [ -n "$root_mpath" -o -n "$root_lvm2" -o -n "$root_evms" ]; then
	cat_linuxrc <<-'EOF'
	|echo -n "Waiting for /dev/mapper/control to appear: "
	|for i in 1 2 3 4 5; do
	|    [ -e /dev/mapper/control ] && break
	|    sleep 1
	|    echo -n "."
	|done
	|if [ -e /dev/mapper/control ]; then
	|    echo " ok"
	|else
	|    echo " failed"
	|fi
	EOF
    fi

    cat_linuxrc <<-'EOF'
	|
	|# Waiting for a device to appear
	|# device node will be created by udev
	|udev_check_for_device() {
	|    local root
	|    local retval=1
	|    local timeout=$udev_timeout
	|    root=$1
	|    if [ -n "$root" ]; then
	|	echo -n "Waiting for device $root to appear: "
	|	while [ $timeout -gt 0 ]; do
	|	    if [ -e $root ]; then
	|		echo " ok"
	|		retval=0
	|		break;
	|	    fi
	|	    sleep 1
	EOF

    if [ -n "$root_lvm2" ]; then
	cat_linuxrc <<-EOF
	|           /sbin/vgscan
	|           /sbin/vgchange -a y \$vg_root
	EOF
    fi

    cat_linuxrc <<-'EOF'
	|	    echo -n "."
	|	    timeout=$(( $timeout - 1 ))
	|	done
	|    fi
	|    return $retval;
	|}
	|
	|udev_discover_resume() {
	|    local resume devn major minor
	|    if [ ! -f /sys/power/resume ] ; then
	|	return
	|    fi
	|    if [ -z "$resumedev" ] ; then
	|	return
	|    fi
	|    # Waits for the resume device to appear
	|    if [ "$resume_mode" != "off" ]; then
	|	if [ -e $resumedev ] ; then
	|	    # Try major:minor number of the device node
	|	    devn=$(devnumber $resumedev)
	|	    major=$(devmajor $devn)
	|	    minor=$(devminor $devn)
	|       fi
	|       if [ -n "$major" -a -n "$minor" ]; then
	|	    if [ -x /sbin/resume ]; then
	|		echo "Invoking userspace resume from $resumedev"
	|		/sbin/resume $resumedev
	|	    fi
	|	    echo "Invoking in-kernel resume from $resumedev"
	|	    echo "$major:$minor" > /sys/power/resume
	|	else
	|	    echo "resume device $resumedev not found (ignoring)"
	|       fi
	|    fi
	|}
	|
	|udev_discover_root() {
	|    local root devn major minor
	|    case "$rootdev" in
	|	*:/*) root= ;;
	|	/dev/nfs) root= ;;
	|	/dev/*)	root=${rootdev#/dev/} ;;
	|    esac
	|    if [ -z "$root" ]; then
	|	return 0
	|    fi
	|    if udev_check_for_device $rootdev  ; then
	|	# Get major:minor number of the device node
	|	devn=$(devnumber $rootdev)
	|	major=$(devmajor $devn)
	|	minor=$(devminor $devn)
	|    fi
	|    if [ -n "$devn" ]; then
	|	return 0
	|    else
	|	return 1
	|    fi
	|}
	|
	|/sbin/udevsettle --timeout=$udev_timeout
	|
	EOF

    # Load fs modules _after_ resume
    echo -ne "Filesystem modules:\t"
    initrd_is_using_modules=
    for modpath in $fs_modules; do
	module=${modpath##*/}
	module=${module%.ko}
	echo -n "$module "
	cat_linuxrc <<-EOF
	|params=
	|for p in \$(cat /proc/cmdline) ; do
	|  case \$p in
	|    $module.*)
	|      params="\$params \${p#$module.}"
	|      ;;
	|  esac
	|done
	EOF

	cat_linuxrc <<-EOF
	|echo "Loading ${module#/lib/modules/$kernel_version/}"
	|modprobe $module \$params
	EOF
	initrd_is_using_modules=1
    done
    echo

    # And run depmod to ensure proper loading
    if [ "$sysmap" ] ; then
	map="$sysmap"
    else
	map=$root_dir/boot/System.map-$kernel_version
    fi
    if [ ! -f $map ]; then
	map=$root_dir/boot/System.map
    fi
    if [ ! -f $map ]; then
	oops 9 "Could not find map $map, please specify a correct file with -M."
	rm -rf $tmp_mnt
	return
    fi

    ( cd $tmp_mnt; /sbin/depmod -b $tmp_mnt -e -F $map $kernel_version )

    if [ -n "$root_mpath" ] ; then
	cat_linuxrc <<-EOF
	|# check for IDE parameter in /proc/cmdline
	|for o in \$(cat /proc/cmdline) ; do
	|  case \$o in
	|    multipath=*)
	|      mpath_status=\${o#multipath=};;
	|  esac
	|done
	|mpath_list=\$(sed -n '/multipath/p' /proc/modules)
	|if [ -z "\$mpath_list" ] ; then
	|  mpath_status=off
	|fi
	|if [ "\$mpath_status" != "off" ] ; then
	|  # Rescan for multipath
	|  echo -n "Setup multipath devices: "
	|  /sbin/multipath -v0
	|  /sbin/udevsettle --timeout=\$udev_timeout
	|  echo 'ok.'
	|fi
	EOF
    fi

    if [ -n "$need_raidstart" ]; then
	features=(${features[@]} raidstart)
	cat_linuxrc <<-EOF
	|echo "raidstart ..."
	|raidstart --all
	|echo "done..."
	EOF
    fi

    if [ -n "$need_mdadm" ]; then
	cat_linuxrc <<-EOF
	|
	|if [ -f /etc/mdadm.conf ] ; then
	|    mdarg="-Ac /etc/mdadm.conf"
	|    [ -z "\$md_dev" ] && md_dev="--scan"
	|else
	|    mdarg="-Ac partitions"
	|fi
	|
	|if [ -n "\$md_uuid" ] ; then
	|    mdarg="\$mdarg --uuid=\$md_uuid"
	|elif [ -n "\$md_minor" ] ; then
	|    mdarg="\$mdarg --super-minor=\$md_minor"
	|    md_dev="/dev/md\$md_minor"
	|fi
	|
	|if [ -z "\$md_uuid" -a -n "$md_uuid" ] ; then
	|    mdarg="\$mdarg --uuid=$md_uuid"
	|elif [ -z "\$md_minor" -a -n "$md_minor" ] ; then
	|    mdarg="\$mdarg --super-minor=$md_minor"
	|fi
	|
	|case \$resumedev in
	|    /dev/md*)
	|        echo 1 > /sys/module/md_mod/parameters/start_ro
	|        resumeminor="\${resumedev#/dev/md}"
	|        mdadm -Ac partitions -m \$resumeminor --auto=md \$resumedev
	|        ;;
	|esac
	|
	|if [ "\$md_dev" ] ; then
	|    /sbin/mdadm \$mdarg --auto=md \$md_dev
	|fi
	EOF
    fi

    cat_linuxrc <<-'EOF'
	|# Wait for udev to settle
	|/sbin/udevsettle --timeout=$udev_timeout
	|# Check for a resume device
	|udev_discover_resume
	EOF

    if [ -n "$need_mdadm" ]; then
	cat_linuxrc <<-EOF
	|if [ -n "\$resume_minor" ] ; then
	|    # Stop all arrays
	|    /sbin/mdadm --stop
	|    # Switch md back to read-write mode
	|    if [ -f /sys/module/md_mod/parameters/start_ro ]; then
	|        # maybe should switch all arrays to rw/ but not really necessary
	|        echo 0 > /sys/module/md_mod/parameters/start_ro
	|    fi
	|
	|    # And restart them again
	|    /sbin/mdadm \$mdarg --auto=md \$md_dev
	|    /sbin/udevsettle --timeout=\$udev_timeout
	|fi
	EOF
    fi

    if [ -n "$need_dmraid" ] ; then
	cat_linuxrc <<-EOF
	|/sbin/dmraid -a y -p
	|/sbin/udevsettle --timeout=\$udev_timeout
	EOF
    fi
	
    if [ -n "$root_lvm" ] ; then
	# Name of the volume containing the root filesystem
        local vg_root=${rootdev#/dev/}
        vg_root=${vg_root%%/*}

	cat_linuxrc <<-EOF
	|#need space for lvm data
	|mount -tramfs none /etc/lvmtab.d
	|vgscan
	|for o in \$(cat /proc/cmdline); do
	|  case \$o in
	|    root=/dev/*)
	|	set -- \$(IFS=/ ; echo \$o)
	|	vg_root=\$3
	|	;;
	|  esac
	|done
	|if [ -z "\$vg_root" ]; then
	|  vg_root=$vg_root
	|fi
	|
	|vgchange -a y \$vg_root
	|umount /etc/lvmtab.d
	EOF
    fi

    if [ -n "$root_lvm2" ] ; then
	cat_linuxrc <<-EOF
	|
	|for o in \$(cat /proc/cmdline); do
	|  case \$o in
	|    root=/dev/disk/by-*/*)
	|       vg_root=
	|       ;;
	|    root=/dev/mapper/*)
	|       set -- \$(IFS=- ; echo \$o)
	|       vg_root=\$2
	|       ;;
	|    root=/dev/*)
	|       set -- \$(IFS=/ ; echo \$o)
	|       vg_root=\$3
	|       ;;
	|  esac
	|done
	|if [ -z "\$vg_root" ]; then
	|  vg_root=$vg_root
	|fi
	|
	|vgchange -a y \$vg_root
	EOF
    fi

    if [ -n "$root_evms" ] ; then
	cat_linuxrc <<-EOF
	|fix_evms_root_node()
	|    {
	|    CURDEV=\$(devnumber \$2)
	|    OLDDEV=\$(devnumber \$1\$2)
	|    if [ ! -b \$1\$2 -o "\$CURDEV" -ne "\$OLDDEV" ]
	|    then
	|	mount -oremount,rw \$2 \$1
	|	rm -f \$1\$2
	|	mknod -m 0640 \$1\$2 b \$(devmajor \$CURDEV) \$(devminor \$CURDEV)
	|	mount -oremount,ro \$2 \$1
	|    fi
	|    }
	|
	|remove_evms_fstab()
	|    {
	|    for i in \$*
	|    do
	|	dmsetup remove "\$i"
	|    done
	|    }
	|
	|get_fstab_entries()
	|    {
	|    FSTLIST=\$(sed -n "\:^/dev/:p" <\$1 | sed -e "\:/media/:d" -e "s:/dev/::" -e "s:[   ].*::" -e "s:/:|:g")
	|    for i in \$FSTLIST
	|    do
	|	LINES=\$(dmsetup ls | sed -n "\:^\$i:p")
	|        [ -n "\$LINES" ] && RETLIST="\$RETLIST \$i"
	|    done
	|    echo \$RETLIST
	|    }
	|
	|create_evms_save_table()
	|    {
	|    TNAME=\$1
	|    shift
	|    COUNT=0
	|    rm -f /table_file
	|    for i in \$*
	|    do
	|	dd=\$(echo \$i | sed "s:|:/:g")
	|	echo \$(expr \$COUNT "*" 100) 100 linear /dev/\$dd 0 >> /table_file
	|	COUNT=\$(expr \$COUNT + 1)
	|    done
	|    dmsetup create \$TNAME </table_file
	|    rm -f /table_file
	|    }
	|
	|/sbin/evms_activate
	|mkdir -p /mnt
	|mount -oro \$rootdev /mnt
	|FSTAB_ITEMS=\$(get_fstab_entries /mnt/etc/fstab)
	|umount /mnt
	|dmsetup remove_all
	|create_evms_save_table wrzlbrnft \$FSTAB_ITEMS
	|/sbin/evms_activate
	|dmsetup remove wrzlbrnft
	|# set the right root device if user specified a lvm root
	|if [ "\$(block_driver "\$rootdev")" = device-mapper ]; then
	|    case \$rootdev in
	|    /dev/*)
	|	mkdir -p /mnt
	|	mount -oro \$rootdev /mnt
	|	fix_evms_root_node /mnt \$rootdev
	|	remove_evms_fstab \$FSTAB_ITEMS
	|	umount /mnt
	|	;;
	|    esac
	|fi
	EOF
    fi

    cat_linuxrc <<-'EOF'
	|# And now for the real thing
	|if ! udev_discover_root ; then
	|    echo "not found -- exiting to /bin/sh"
	|    cd /
	|    PATH=$PATH PS1='$ ' /bin/sh -i
	|fi
	EOF

    cat_linuxrc <<-'EOF'
	|if [ -z "$rootfstype" ]; then
	|    rootfstype=$(/lib/udev/vol_id -t $rootdev)
	|    [ $? -ne 0 ] && rootfstype=
	|    [ -n "$rootfstype" ] && [ "$rootfstype" = "unknown" ] && $rootfstype=
	|fi
	|
	|# check filesystem if possible
	|if [ -z "$rootfstype" ]; then
	|    echo "invalid root filesystem -- exiting to /bin/sh"
	|    cd /
	|    PATH=$PATH PS1='$ ' /bin/sh -i
	|elif [ -x /bin/fsck.${rootfstype} ]; then
	|    # fsck is unhappy without it
	|    echo "$rootdev / $rootfstype defaults 1 1" > /etc/fstab
	|    # Display progress bar if possible 
	|    fsckopts="-V -a"
	|    [ "`/sbin/showconsole`" = "/dev/tty1" ] && fsckopts="$fsckopts -C"
	|    # Check external journal for reiserfs
	|    [ "$rootfstype" = "reiserfs" -a -n "$journaldev" ] && fsckopts="-j $journaldev $fsckopts"
	|    fsck -t $rootfstype $fsckopts $rootdev
	|    # Return the fsck status
	|    ROOTFS_FSCK=$?
	|    export ROOTFS_FSCK
	|    ROOTFS_FSTYPE=$rootfstype
	|    export ROOTFS_FSTYPE
	|    if [ $ROOTFS_FSCK -gt 1 -a $ROOTFS_FSCK -lt 4 ]; then
	|        # reboot needed
	|        echo "fsck succeeded, but reboot is required."
	|        echo "Rebooting system."
	|        /bin/reboot -d -f
	|    elif [ $ROOTFS_FSCK -gt 3 ] ; then
	|        echo "fsck failed. Mounting root device read-only."
	|        read_write=
	|    else
	|        if [ "$read_only" ]; then
	|            echo "fsck succeeded. Mounting root device read-only."
	|            read_write=
	|        else
	|            echo "fsck succeeded. Mounting root device read-write."
	|            read_write=1
	|        fi
	|    fi
	|fi
	EOF

    cat_linuxrc <<-'EOF'
	|opt="-o ro"
	|[ -n "$read_write" ] && opt="-o rw"
	|[ "$rootfstype" = "nfs" ] && opt="${opt},nolock"
	|
	|# mount the actual root device below /root
	|echo "Mounting root $rootdev"
	|# check external journal
	|[ "$rootfstype" = "xfs" -a -n "$journaldev" ] && opt="${opt},logdev=$journaldev"
	|[ "$rootfstype" = "xfs" -a -n "$rootfsflags" ] && opt="${opt},$rootfsflags"
	|[ "$rootfstype" = "reiserfs" -a -n "$journaldev" ] && opt="${opt},jdev=$journaldev"
	|[ -n "$rootflags" ] && opt="${opt},$rootflags"
	|[ -n "$rootfstype" ] && opt="${opt} -t $rootfstype"
	|if [ -x /bin/nfsmount -a "$rootfstype" = "nfs" ]; then
	|    nfsmount $rootdev /root || die 1
	|else
	|    mount $opt $rootdev /root || die 1
	|fi
	|# Look for an init binary on the root filesystem
	|if [ -n "$init" ] ; then
	|    if [ ! -f "/root$init" ]; then
	|        init=
	|    fi
	|fi
	|
	|if [ -z "$init" ] ; then
	|    for i in /sbin/init /etc/init /bin/init /bin/sh ; do
	|        if [ ! -f "/root$i" ] ; then continue ; fi
	|        init="$i"
	|        break
	|    done
	|fi
	|
	|if [ -z "$init" ] ; then
	|    echo "No init found. Try passing init= option to the kernel."
	|    die 1
	|fi
	|
	|# Parse root mount options
	|if [ "$rootfstype" != "nfs" -a -f /root/etc/fstab ] ; then
	|    fsoptions=$(while read d m f o r; do if [ "$m" == "/" ] ; then echo $o; fi; done < /root/etc/fstab)
	|    set -- $(IFS=,; echo $fsoptions)
	|    fsoptions=
	|    while [ "$1" ] ; do
	|        case $1 in
	|        *quota) ;;
	|        defaults) ;;
	|        *)
	|            if [ "$fsoptions" ] ; then
	|                fsoptions="$fsoptions,$1"
	|            else
	|                fsoptions="$1"
	|            fi
	|            ;;
	|        esac
	|        shift
	|    done
	|    if [ "$fsoptions" ] ; then
	|        mount -o remount,$fsoptions $rootdev /root
	|    fi
	|fi
	|
	|# Create framebuffer devices
	|if [ -f /proc/fb ]; then
	|    while read fbnum fbtype; do
	|        if [ $(($fbnum < 32)) ] ; then
	|            [ -c /dev/fb$fbnum ] || mknod -m 0660 /dev/fb$fbnum c 29 $fbnum
	|        fi
	|    done < /proc/fb
	|fi
	|
	|blogd_pid=$(pidof blogd)
	|if test -n "$blogd_pid" ; then
	|    kill -IO "$blogd_pid"
	|fi
	|/bin/mount --move /dev /root/dev
	|
	|# Call vendor-specific init script
	|if [ -x /vendor_init.sh ] ; then
	|    /vendor_init.sh
	|fi
	|
	|# kill udevd, we will run the one from the real root
	|kill $(pidof udevd)
	|
	|# kill iscsid, will be restarted from the real root
	|iscsi_pid=$(pidof iscsid)
	|[ "$iscsi_pid" ] && kill -KILL $iscsi_pid
	|
	|if test -n "$blogd_pid" ; then
	|    kill -QUIT "$blogd_pid"
	|    sleep 1
	|    rm -f /var/log/boot.msg
	|    test "$devpts" = "no" || umount -t devpts /root/dev/pts
	|    devpts=no
	|fi
	|
	|# ready to leave
	|cd /root
	|umount /proc
	|umount /sys
	|
	|# Export root fs information
	|ROOTFS_BLKDEV="$rootdev"
	|export ROOTFS_BLKDEV
	|
	|exec /bin/run-init -c ./dev/console /root $init ${kernel_cmdline[@]}
	|echo could not exec run-init!
	|die 0
	EOF

    [ ${#features[@]} -gt 0 ] \
	&& echo -e "Including:\t${features[@]}"

    splash_bin=
    [ -x /sbin/splash.bin ] && splash_bin=/sbin/splash.bin
    [ -x /bin/splash ] && splash_bin=/bin/splash
    splash_image=
    if [ -n "$splashsizes" -a -n "$splash_bin" ]; then
	if [ -f /etc/sysconfig/bootsplash ]; then
	    . /etc/sysconfig/bootsplash
	fi

	themes_dir=
	if [ -d "$root_dir/etc/bootsplash/themes" ]; then
	    themes_dir="$root_dir/etc/bootsplash/themes"
	elif [ -d "$root_dir/usr/share/splash/themes" ]; then
	    themes_dir="$root_dir/usr/share/splash/themes"
	fi

	no_splash=
	case ${kernel_version##*-} in
	    kdump|um|xen*)
		no_splash=1
		;;
	esac

	if [ -n "$no_splash" ]; then
	    echo "No bootsplash for kernel flavor ${kernel_version##*-}"
	else
	    echo -ne "Bootsplash:\t"
	    if [ -n "$themes_dir" ] && \
		 [ -d "$themes_dir/$THEME" -o -L "$themes_dir/$THEME" ]; then
		for size in $splashsizes; do
		    bootsplash_picture="$themes_dir/$THEME/images/bootsplash-$size.jpg"
		    cfgname="$themes_dir/$THEME/config/bootsplash-$size.cfg"
		    if [ ! -r $cfgname ] ; then
			echo "disabled for resolution $size"
		    elif [ ! -r $bootsplash_picture ] ; then
			echo "no image for resolution $size"
		    else
			echo -n "${splash_image:+, }$THEME ($size)"
			splash_image="$splash_image $cfgname"
		    fi
		done
		echo
	    else
		echo "no theme selected"
	    fi
	fi
    fi

    # Include bootsplash image
    for image in $splash_image; do
	$splash_bin -s -f $image >> $tmp_mnt/bootsplash
    done

    attach_dsdt

    pushd . > /dev/null 2>&1
    cd $tmp_mnt
    find . ! -name "*~" | cpio -H newc --create | gzip -9 > $tmp_initrd.gz
    popd > /dev/null 2>&1
    if ! cp -f $tmp_initrd.gz $initrd_image ; then
	oops 8 "Failed to install initrd"
    fi
    rm -rf $tmp_mnt
}

###################################################################

# working directories
tmp_initrd=$work_dir/initrd
tmp_initrd_small=${tmp_initrd}_small

if [ -z "$rootdev" ] ; then
  # no rootdev specified, get current root from /etc/fstab
  while read fstab_device fstab_mountpoint fstab_type fstab_options dummy ; do
    if [ "$fstab_mountpoint" = "/" ]; then
      rootdev="$fstab_device"
      rootfstype="$fstab_type"
      rootfsopts="$fstab_options"
      break
    fi
  done < <( sed -e '/^[ 	]*#/d' < $root_dir/etc/fstab)
else
  # get type from /etc/fstab or /proc/mounts (actually not needed)
  x1=$(cat $root_dir/etc/fstab /proc/mounts 2>/dev/null \
       | grep -E "$rootdev[[:space:]]" | tail -n 1)
  rootfstype=$(echo $x1 | cut -f 3 -d " ")
fi

if [ -z "$rootdev" ] ; then
    if [ -z "$use_dhcp" ]; then
	error 1 "No '/' mountpoint specified in $root_dir/etc/fstab"
    else
	rootdev=
	rootfstype=nfs
    fi
fi

realrootdev="$rootdev"
case "$rootdev" in
    /dev/sd*)
	# Check for iSCSI
	sid=$(check_iscsi_root $rootdev)
	iscsi_root="$sid"
	;;
    LABEL=*|UUID=*)
	# get real root via fsck hack
	realrootdev=$(fsck -N "$rootdev" \
		      | sed -ne '2s/.* \/dev/\/dev/p' \
		      | sed -e 's/  *//g')
	if [ -z "$realrootdev" ] ; then
	    error 1 "Could not expand $rootdev to real device"
	fi
	realrootdev=$(/usr/bin/readlink -m $realrootdev)
	;;
    /dev/disk/*)
	realrootdev=$(/usr/bin/readlink -m $rootdev)
	# Check for iSCSI
	sid=$(check_iscsi_root $realrootdev)
	iscsi_root="$sid"
	;;
    *:*)
	rootdev=
	rootfstype=nfs
	;;
esac

# check for journal device
if [ "$rootfsopts" -a -z "$journaldev" ] ; then
    jdev=${rootfsopts#*,jdev=}
    if [ "$jdev" != "$rootfsopts" ] ; then
	journaldev=${jdev%%,*}
    fi
    logdev=${rootfsopts#*,logdev=}
    if [ "$logdev" != "$rootfsopts" ] ; then
	journaldev=${logdev%%,*}
    fi
fi

# check if the root device is an lvm device
#
# Caveat: currently the dmraid support requires some programs from
# the multipath-tools package (kpartx etc). So we always have
# to select both, multipath and dmraid, for full dmraid support.
root_lvm=
root_dm=
root_lvm2=
root_evms=
root_mpath=
root_md=
root_dmraid=
if [ -n "$realrootdev" -a -b "$root_dir/${realrootdev#/}" ] ; then
    rootdevn=$(devnumber $root_dir/${realrootdev#/})

    [ "$(block_driver "$root_dir/${realrootdev#/}")" = lvm ] \
	&& root_lvm=1
    [ "$(block_driver "$root_dir/${realrootdev#/}")" = device-mapper ] \
    	&& root_dm=1
    [ "$(block_driver "$root_dir/${realrootdev#/}")" = md ] \
    	&& root_md=1
    if [ "$root_dm" ] ; then
	major=$(devmajor $rootdevn)
	minor=$(devminor $rootdevn)
	# Check whether we are using EVMS
	if [ -x /sbin/evms ] ; then
	    region=$(echo "q:r" | evms -s | grep -B 2 "Minor: $minor" | sed -n 's@Region Name: \(.\)@\1@p')
	    if [ "$region" ] ; then
		volume=$(echo "q:v,r=$region" | evms -s | sed -n 's@Volume Name: \(.*\)@\1@p')
		if [ -e "$volume" ] ; then
		    root_evms=1
		    realrootdev=$volume
		fi
	    fi
	else
	    root_evms=
	fi
        # Check whether we are using LVM2
	if [ -z "$root_evms" ] && [ -x /sbin/lvs ] ; then
	    vg_root=$(lvs --noheadings -o vg_name,lv_kernel_major,lv_kernel_minor 2> /dev/null | sed -n "s/ *\(.*\) *$major *$minor/\1/p")
	    if [ "$vg_root" ] ; then
		root_lvm2=1
	    fi
	else
	    root_lvm2=
	fi
	if [ "$root_lvm2" ] ; then
	    # Check for LVM2 on top of md
	    md_list=
	    pv_list=$(vgs --noheadings --options devices /dev/${vg_root} 2> /dev/null | sed -n "s@ *\(/dev/.*\)([0-9]*) *@\1@p" | sort | uniq)
	    for dev in $pv_list ; do
		case $dev in
		    /dev/dm-*)
			root_dmraid=1
			root_mpath=1
			;;
		    *)
			mdconf=$(mdadm -Db $dev 2> /dev/null)
			if [ -n "$mdconf" ] ; then
			    md_dev=${dev##/dev/}
			    md_list="$md_dev $md_list"
			    eval md_conf_${md_dev}=\"$mdconf\"
			fi
			;;
		esac
	    done
	    unset md_dev
	    unset mdconf
	fi
	if [ -z "$root_lvm2" ] ; then
	    # Check for dmraid
	    dm_uuid=$(dmsetup info -c --noheadings -o uuid -j $major -m $minor)
	    case $dm_uuid in
		part*)
		    root_dmraid=1
		    root_mpath=1
		    ;;
	    esac
	fi
    fi
    if [ "$root_md" ] && [ -x /sbin/mdadm ] ; then
	minor=$(devminor $rootdevn)
	# get md configuration
	mdconf=$(mdadm -Db $rootdev 2> /dev/null | sed -n "s@/dev/md[0-9]*@/dev/md$minor@p")
	if [ -n "$mdconf" ] ; then
	    md_dev=${rootdev##/dev/}
	    md_list="$md_dev"
	    eval md_conf_${md_dev}=\"$mdconf\"
	fi
	unset minor
	unset md_dev
	unset mdconf
    else
	root_md=
    fi
fi

###################################################################

x="$rootdev"
[ "$rootfstype" = "nfs" ] && x="nfs-root"
[ "$iscsi_root" ] && x="$(cat /sys/class/iscsi_session/$iscsi_root/targetname)"
[ "$rootdev" != "$realrootdev" ] && x="$x ($realrootdev)"
echo -e "Root device:\t$x (mounted on ${root_dir:-/} as $rootfstype)"

if [ -z "$modules_set" ]; then
    # get INITRD_MODULES from system configuration
    . $root_dir/etc/sysconfig/kernel
    modules="$INITRD_MODULES"
fi

if [ -z "$domu_modules_set" ]; then
    # get DOMU_INITRD_MODULES from system configuration
    . $root_dir/etc/sysconfig/kernel
    domu_modules="$DOMU_INITRD_MODULES"
fi

###################################################################
# add modules required by features
if [ "$rootfstype" = "nfs" ] ; then
    add_module nfs
fi

if [ -n "$root_lvm" ] ; then
    add_module lvm-mod
fi

if [ -n "$root_dm" ] ; then
    add_module dm-mod
    add_module dm-snapshot
    domu_modules="$domu_modules dm-mod dm-snapshot"
fi

if [ -n "$md_list" ] ; then
    # load all md modules
    add_module raid0
    add_module raid1
    add_module raid5
    add_module linear
    if [ -f $root_dir/etc/mdadm.conf ] ; then
	# make sure we're overriding the default here
	md_list=
	root_md=1
    fi
fi

if [ -n "$root_dm" ] ; then
    # Add all dm modules
    dm_modules=$(dmsetup table | cut -f 4 -d ' ' | sort | uniq)
    for table in $dm_modules; do
	if [ "$table" ] && [ "$table" != "linear" ] && [ "$table" != "striped" ] ; then
	    add_module dm-$table
	fi
	# Check for multipathing
	if [ "$table" == "multipath" ] ; then
	    root_mpath=1
	    add_module dm-round-robin
	    add_module dm-emc
	fi
    done
fi

if [ -n "$iscsi_root" ] ; then
    add_module scsi_transport_iscsi
    add_module iscsi_tcp
    if [ -z "$interface" ] ; then
	ifspec=$(get_default_interface)
	interface=${ifspec%%/*}
	bootproto=${ifspec##*/}
	if [ "$bootproto" = "dhcp" ] ; then
	    use_dhcp=1
	else
	    use_ipconfig=1
	fi
    fi
    scan_pci_bus=
fi

if [ -n "$interface" ] ; then
    # Pull in network module
    if [ -d /sys/class/net/$interface/device ] ; then
	if [ -f /sys/class/net/$interface/device/modalias ] ; then
	    read drvlink  < /sys/class/net/$interface/device/modalias
	elif [ -f /sys/class/net/$interface/device/driver/module ] ; then
	    drvlink=$(cd /sys/class/net/$interface/device/driver; readlink module)
	else
	    drvlink=$(cd /sys/class/net/$interface/device; readlink driver)
	fi
	add_module ${drvlink##*/}
    fi
fi

if [ -n "$use_dhcp" ]; then
    # dhcpd reqires the af_packet module, we include it here
    # in case the root FS will be mounted via NFS
    add_module af_packet
fi

case "$(uname -m)" in
    s390|s390x)
	# Check if zfcp or dasd modules need to be added automatically:
	if [ -d /sys/block ]; then
	    # Always enable all devices, hotplug is completely garbled
	    s390_enable_dasd=1
	    s390_enable_zfcp=1
	    # if [ "$root_evms" ]; then
	    #     s390_check_evms $rootdev
	    # elif [ "$root_dm" ]; then
	    #     s390_check_lvm2 $rootdev
	    # else
	    #     s390_check_dasd $rootdev
	    #     s390_check_zfcp $rootdev
	    # fi
	    # Activate devices
	    s390_dasd_sysfs
	    s390_zfcp_sysfs
	else
	    echo ""
	    echo "WARNING: sysfs not mounted on /sys."
	    echo "Booting from zfcp will _not_ work."
	    s390_dasd_proc
	fi
    ;;
esac

###################################################################

exit_code=0

initrd_images=( $initrd_images )
kernel_images=( $kernel_images )

boot_modules="$modules"
echo -e "Module list:\t$boot_modules ($domu_modules)"
for ((i=0 ; $i<${#kernel_images[@]} ; i++)); do
    echo
    modules="$boot_modules"
    kernel_image=${kernel_images[$i]}
    [ ${kernel_image:0:1} != '/' ] \
    	&& kernel_image=$boot_dir/$kernel_image

    initrd_image=${initrd_images[$i]}
    [ ${initrd_image:0:1} != '/' ] \
    	&& initrd_image=$boot_dir/$initrd_image

    mkinitrd_kernel $kernel_image $initrd_image

    # If the current $kernel_image has a symlink without "-<version>" (e.g.
    # "vmlinuz") pointing to it, create an "initrd" symlink for the
    # corresponding $initrd_image.
    if [ $exit_code -eq 0 -a "$(readlink ${kernel_image%%-*})" = \
	 "${kernel_image#$boot_dir/}" ]; then
	rm -f $root_dir/$boot_dir/initrd
	ln -s "${initrd_image#$boot_dir/}" $root_dir/$boot_dir/initrd
    fi
    cleanup
done

cleanup_finish

if [ -e $root_dir/etc/sysconfig/bootloader ]; then
    . $root_dir/etc/sysconfig/bootloader
fi
case $LOADER_TYPE in
  lilo)
    echo "
Run lilo now to update the boot loader configuration."
    ;;
  elilo)
    if [ -x /sbin/elilo ]; then
      /sbin/elilo
    else
      echo "
You may now have to update the elilo boot loader configuration."
    fi
    ;;
  grub)
    ;;
  *)
    if [ -f "$root_dir/etc/zipl.conf" ]; then
	echo "
initrd updated, zipl needs to update the IPL record before IPL!"
    else
	echo "
You may now have to update your boot loader configuration."
    fi
    ;;
esac

exit $exit_code
