#!/bin/bash

# mkinitrd
#
# Written by Erik Troan <ewt@redhat.com>
#
# Contributors:
#	Elliot Lee <sopwith@cuc.edu>
#	Miguel de Icaza <miguel@nuclecu.unam.mx>
#	Christian 'Dr. Disk' Hechelmann <drdisk@ds9.au.s.shuttle.de>
#	Michael K. Johnson <johnsonm@redhat.com>
#	Pierre Habraken <Pierre.Habraken@ujf-grenoble.fr>
#	Jakub Jelinek <jakub@redhat.com>
#	Carlo Arenas Belon (carenas@chasqui.lared.net.pe>
#	Keith Owens <kaos@ocs.com.au>
#	Bernhard Rosenkraenzer <bero@redhat.com>
#	Matt Wilson <msw@redhat.com>
#       Trond Eivind Glomsrød <teg@redhat.com>
#       Jeremy Katz <katzj@redhat.com>
#       Preston Brown <pbrown@redhat.com>
#	Bill Nottingham <notting@redhat.com>
#       Guillaume Cottenceau <gc@mandrakesoft.com>
#	Pixel <pixel@mandrakesoft.com>
#	Luca Berra <bluca@vodka.it>

PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
export PATH

VERSION=4.1.12mdk

compress=1
allowmissing=""
target=""
kernel=""
force=""
verbose=""
MODULES=""
img_vers=""
builtins=""
pivot=1
initrdfs="ext2"
modulefile=/etc/modules.conf
tmpdir=
rc=0
kernel25=""

DEFAULT_DSDT_FILE="/boot/dsdt.aml"
dsdt_file=""

IMAGESIZE=100
NB_INODES=100
fstab="/etc/fstab"
IGNOREMODS="$IGNOREMODS ppa imm ide-scsi $initrdfs"

[ -f /etc/udev/udev.conf -a -x /sbin/udevstart ] && USE_UDEV=yes

[ -f /etc/sysconfig/mkinitrd ] && source /etc/sysconfig/mkinitrd

usage () {
    echo "usage: `basename $0` [--version] [-v] [-f] [--preload <module>]" >&2
    echo "       [--with=<module>] [--omit-scsi-modules] [--omit-raid-modules]" >&2
    echo "       [--image-version] [--fstab=<fstab>] [--nocompress]" >&2
    echo "       [--builtin=<module>] [--nopivot] [--noudev] [--allow-missing]" >&2
    echo "       [--tmpdir=<tmpdir>] [--initrdfs=<fs>]" >&2
    echo "       [--dsdt[=<dsdt.aml>]] [--lvm-version=<1|2>] [--force-usb]" >&2
    echo "       <initrd-image> <kernel-version>" >&2
    echo "" >&2
    echo "       (ex: `basename $0` /boot/initrd-$(uname -r).img $(uname -r))" >&2
    exit 1
}

check_kernel_25() {
	local -i major minor

	major=$(expr "$1" : '\([^.]\+\)\..*')
	minor=$(expr "$1" : '[^.]\+\.\([^.]\+\)\..*')

	if [ $major -ge 3 -o $major -eq 2 -a $minor -ge 5 ]; then
		kernel25=yes
		modulefile=/etc/modprobe.conf
		modulemap="s@pdc-ultra@sata_promise@;s@usb-uhci@uhci-hcd@;s@usb-ohci@ohci-hcd@;s@^uhci\$@uhci-hcd@"
		IGNORE="$IGNORE ataraid"
	else
		USE_UDEV=
	fi
}

moduledep() {
    if [ ! -f "/lib/modules/$kernel/modules.dep" ]; then
	echo "No dep file found for kernel $kernel" >&2
	exit 1
    fi

    [ -n "$verbose" ] && echo "Looking for deps of module $1"
    deps=$(awk 'BEGIN { searched=ARGV[2]; ARGV[2]=""; rc=1 } \
	function modname(filename) { match(filename, /\/([^\/]+)\.k?o/, ret); return ret[1] } \
	function show() { if (orig == searched) { print dep; orig=""; rc=0; exit } } \
	/^\/lib/ { show(); \
	    orig=modname($1); dep=""; \
	    for (i=2; i<=NF; i++) { dep=sprintf("%s %s", dep, modname($i)) } } \
	/^[[:space:]]/ { dep=sprintf("%s %s", dep, modname($1));  } \
	END      { show(); exit(rc) }' /lib/modules/$kernel/modules.dep $1)
    [ -n "$verbose" -a -n "$deps" ] && echo -e "\t$deps"
}

findmodule() {
    skiperrors=""

    if [ $1 == "--skiperrors" ]; then
	skiperrors=--skiperrors
	shift
    fi

    local modName=$1

    if [ -n "$modulemap" ]; then
	local modMap=`echo $modName | sed -e $modulemap`
	if [ "${modMap}" != "${modName}" ]; then
		[ -n "$verbose" ] && echo "replacing $modName with $modMap"
		modName=$modMap
	fi
    fi

    # only need to add each module once
    if echo $MODULES | grep -q "/$modName\.k\?o" 2>/dev/null ; then
	return
    fi


    if [ "$modName" = "off" -o "$modName" = "null" ]; then
	return
    fi

    if [ "$modName" != "${modName#-}" ]; then
	skiperrors=--skiperrors
	modName=${modName#-}
    fi

    if echo $builtins | egrep -q '(^| )'$modName'( |$)' ; then
	[ -n "$verbose" ] && echo "module $modName assumed to be built in"
	return
    fi

    for i in $IGNOREMODS; do
 	[ "$i" = "$modName" ] && return
    done

    moduledep $modName
    for i in $deps; do
	findmodule $i
    done

    for modExt in o.gz o ko.gz ko ; do
	fmPath=`(cd /lib/modules/$kernel; find . -type f -name $modName.$modExt | grep -v "^./build")`
	[ -n "$fmPath" ] && break
    done

    if [ -z "$fmPath" ]; then
	if [ -n "$skiperrors" ]; then
	    return 1
	fi


	if [ -n "$allowmissing" ]; then
	    echo "WARNING: No module $modName found for kernel $kernel, continuing anyway" >&2
	    return
	fi
     
	echo "No module $modName found for kernel $kernel, aborting." >&2
	exit 1
    fi

    zfmPath=${fmPath%.gz}
    # only need to add each module once
    if ! echo $MODULES | grep -q "$zfmPath" 2>/dev/null ; then
	MODULES="$MODULES $zfmPath"
    fi
}

is_good_fs() {
    local parttype= tmpname=
    local dir=$1
    [[ -d $dir ]] || return 1
    [[ -w $dir ]] || return 1
    [[ $dir == */ ]] && dir=${dir%/}
    parttype=$(awk "{if (\$2 == \""$dir"\") print \$3 }" /proc/mounts)

    while tmpname=${dir%/*} && [[ -z $parttype ]];do
	[[ -z $tmpname ]] && tmpname=/
	parttype=$(awk "{if (\$2 == \""$tmpname"\") print \$3 }" /proc/mounts)
	dir=$tmpname
    done

    case $parttype in
	nfs|tmpfs) return 1;;
	*) return 0;
    esac
}

inst() {
    if [ "$#" != "2" ];then
        echo "usage: inst <file> <destination>"
        return
    fi 
    [ -n "$verbose" ] && echo "$1 -> $2"
    cp -aL $1 $2
    for i in `ldd $1 | awk '$2 == "=>" {print $3}'`; do
	j=${i##*/}
	[ -e $MNTIMAGE/lib/$j ] || cp -aL $i $MNTIMAGE/lib/$j
    done
}


mddev() {
    local -i major
    local dev md
    major=$((0x$(stat -L -c '%t' $1)))
    if [ $major = 9 ]; then
	raiddevices="$raiddevices $1"
	md=${1##*/}
	md=md${md#md} # /dev/md/0 and /dev/md0 become md0
	mddevs=$(awk '/^'$md'[[:space:]]*:/ {for (i=5;i<=NF;i++) {sub("\\[[0-9]*\\]","",$i); print "/dev/" $i } }' /proc/mdstat)
	for dev in $mddevs; do
	    mddev $dev
	done
    else
	nonraiddevices="$nonraiddevices $1"
    fi
}

scsidriver() {
    local -i major minor count i
    local foo bus j drv
    major=$((0x$(stat -L -c '%t' $1)))
    foo=`awk -v major=$major '
	BEGIN { i=0 }
	$1 == major && $2 == "sd" { print i; exit }
	$2 == "sd" { i++ }
	' /proc/devices`
    if [ -n "$foo" ]; then
	minor=$((0x$(stat -L -c '%T' $1)))
	count=$((foo * 16 + $minor / 16))

	bus=`awk -v count=$count '
	    BEGIN { i=0 }
	    /^Host:/ { h=$2; sub("^scsi","",h) }
	    /Type:[[:space:]]*Direct-Access/ {
		    if (i++==count) { print h; exit }
	    }
	    ' /proc/scsi/scsi`
	for i in `seq 0 $bus`; do
	    for j in /proc/scsi/*/$i; do
		if [ -f $j ]; then
		    j=${j%/$i}
		    drv="$drv ${j##*/}"
		else
		    # Fallback to old method if we haven't found the driver.
		    # This happens for example for SATA drivers that aren't populating
		    # /proc/scsi. FL [Thu Sep  2 10:30:42 2004]
		    grep -E '^[[:space:]]*(alias|probeall|install)[[:space:]]+scsi_hostadapter' $modulefile | \
		   	 sed 's/^.*scsi_hostadapter//;s/\/sbin\/modprobe//g;s/;//g;s/\/bin\/true//;s/||//'
		    return
		fi
	    done
	done
	# filter some drivers
	case $drv in
	*IT8212*)	echo "it821x"	;;
	*it8212*)	echo "it821x"	;;
	*iteraid*)	echo "it821x"	;;
	*)		echo $drv	;;
	esac
    fi
}

usbdriver() {
    local driver
    local usbdrivers=$(grep -E '^[[:space:]]*(alias|probeall|install)[[:space:]]+usb-interface' $modulefile | sed 's/^.*usb-interface//;s/\/sbin\/modprobe//g;s/;//g;s/\/bin\/true//;s/||//')
    if [ -n "$usbdrivers" ]; then
	for driver in $usbdrivers; do
	    findmodule $driver
	done
    fi
}

ieee1394driver() {
    local driver
    local ieee1394drivers=$(grep -E '^[[:space:]]*(alias|probeall|install)[[:space:]]+ieee1394-controller' $modulefile | sed 's/^.*ieee1394-controller//;s/\/sbin\/modprobe//g;s/;//g;s/\/bin\/true//;s/||//')
    if [ -n "$ieee1394drivers" ]; then
	for driver in $ieee1394drivers; do
	    findmodule $driver
	done
    fi
}

while [ $# -gt 0 ]; do
    case $1 in
	--fstab*)
	    if echo $1 | grep -q '=' ; then
	    	fstab=`echo $1 | sed 's/^--fstab=//'`
	    else
		fstab=$2
		shift
	    fi		    
	    ;;

	--tmpdir*)
	    if echo $1 | grep '=' >/dev/null ; then
	    	tmpdir=`echo $1 | sed 's/^--tmpdir=//'`
	    else
		tmpdir=$2
		shift
	    fi		    
	    ;;

	--with-usb)
	    withusb=yes
	    ;;

	--force-usb)
	    forceusb=yes
	    ;;

	--with*)
	    if echo $1 | grep -q '=' ; then
	    	modname=`echo $1 | sed 's/^--with=//'`
	    else
		modname=$2
		shift
	    fi		    

	    basicmodules="$basicmodules $modname"
	    ;;

	--builtin*)
	    if echo $1 | grep -q '=' ; then
	    	modname=`echo $1 | sed 's/^--builtin=//'`
	    else
		modname=$2
		shift
	    fi		    
	    builtins="$builtins $modname"
	    ;;

	--initrdfs*)
	    if echo $1 | grep -q '=' ; then
	    	initrdfs=`echo $1 | sed 's/^--initrdfs=//'`
	    else
		initrdfs=$2
		shift
	    fi		    
	    case $initrdfs in
		romfs|cramfs) readonly=1;;
		ext2|ext3|minix|initramfs) ;;
		*) echo "Unsupported initrd fs ($initrdfs)." 1>&2 ; exit 1 ;;
		esac
	    ;;
	    
	--version)
	    echo "mkinitrd: version $VERSION"
	    exit 0
	    ;;

	-v)
	    verbose=-v
	    ;;

	--nocompress)
	    compress=""
	    ;;

	--nopivot)
	    pivot=""
	    ;;

	--ifneeded)
	    # legacy
	    ;;

	-f)
	    force=1
	    ;;
	--preload*)
	    if echo $1 | grep -q '=' ; then
	    	modname=`echo $1 | sed 's/^--preload=//'`
	    else
		modname=$2
		shift
	    fi		    
	    PREMODS="$PREMODS $modname"
	    ;;
	--omit-scsi-modules)
	    noscsi=1;
	    ;;
	--omit-raid-modules)
	    noraid=1;
	    ;;
	--lvm-version*)
	    if echo $1 | grep -q '=' ; then
	    	lvmver=`echo $1 | sed 's/^--lvm-version=//'`
	    else
		lvmver=$2
		shift
	    fi		    
	    ;;
	--image-version)
	    img_vers=yes
	    ;;
	--noudev)
	    USE_UDEV=
	    ;;
	--allow-missing)
	    allowmissing=yes
	    ;;
	--dsdt*)
	    if echo $1 | grep '=' >/dev/null ; then
	    	dsdt_file=`echo $1 | sed 's/^--dsdt=//'`
	    else
		dsdt_file=$DEFAULT_DSDT_FILE
	    fi		    
	    ;;
	*)
	    if [ -z "$target" ]; then
		target=$1
	    elif [ -z "$kernel" ]; then
		kernel=$1
	    else
		usage
	    fi
	    ;;
    esac

    shift
done

if [ -z "$target" -o -z "$kernel" ]; then
    usage
fi

check_kernel_25 "$kernel"

if [ -n "$img_vers" ]; then
    target="$target-$kernel"
fi

if [ -z "$force" -a -f $target ]; then
    echo "$target already exists." >&2
    exit 1
fi

if [ ! -d /lib/modules/$kernel ]; then
    echo "/lib/modules/$kernel is not a directory." >&2
    exit 1
fi

if [ $UID != 0 ]; then
    echo "mkinitrd must be run as root"
    exit 1
fi

if [ ! -f /proc/version ]; then
    mount -t proc /proc /proc
    if [ ! -f /proc/version ]; then
	echo "/proc filesystem must be available"
	exit 1
    fi
fi

# check for modular initrdfs
findmodule -$initrdfs
if [ -n "$MODULES" ]; then
    echo "you must use a built-in filesystem for the initrd"
    echo "use the --initrdfs option to change to a different filesystem than $initrdfs"
    exit 1
fi

for n in $PREMODS; do
	findmodule $n
done

if [ -n "$forceusb" ]; then
    if [ -n "$kernel25" ]; then
        DRIVERLIST=(uhci-hcd ehci-hcd ohci-hcd)
    else
        DRIVERLIST=(scsi_mod uhci usb-uhci ehci-hcd usb-ohci)
    fi
    for driver in ${DRIVERLIST[*]}; do
	findmodule $driver
    done
    findmodule usbhid
    findmodule usb-storage
    findmodule sd_mod
fi

kbddrivers="$(awk '
		BEGIN {IGNORECASE=1}
		/Name=.*keyboard/ {k=1;next}
		/Name=/ {k=0;next}
		/Phys=isa/ {ph="ps2";next}
		/Phys=usb/ {ph="usb";next}
		/Phys=/ {ph="UNKNOWN";next}
		/Handlers=.*kbd/ && k == 1 {print ph}
	' /proc/bus/input/devices)"
if [ -n "${kbddrivers##*ps2*}" -a -z "${kbddrivers##*usb*}" ]; then
    usbdriver
    findmodule -usbhid
fi

# check to see if we need to set up a loopback filesystem
rootdev=$(awk '/^[ \t]*[^#]/ { if ($2 == "/") { print $1; }}' $fstab)
fstabrootdev=$rootdev
if [ ${rootdev#LABEL=} != $rootdev ]; then
    rootdev=${rootdev#LABEL=}
    if [ $(e2label /dev/root) = ${rootdev} ]; then
	rootdev=/dev/root
    fi
    echo "rootdev=${rootdev}"
fi
fullloopfile=$(awk '$2 == "/" && $4 ~ "loop" { print $1 }' /etc/fstab)
if [ -n "$fullloopfile" ]; then
    dir=$fullloopfile
    while [ -n "$dir" -a -z "$line" ]; do
        dir=$(dirname $dir)
	line=$(awk -v dir=$dir '$2 == dir { print $0 }' /etc/fstab)	
    done
    if [ -z "$line" -o "$dir" = "/" ]; then
	echo "bad fstab, loopback file doesn't belong to any device"
	exit 1
    fi

    loopDev=$(echo $line | awk '{ print $1 }')
    loopFs=$(echo $line | awk '{print $3 }')
    loopFile=$(echo $fullloopfile | sed "s|$dir||")
    # to check if loopdev needs some set-up
    rootdev=${loopDev}

    basicmodules="$basicmodules -loop"
    if [ "$loopFs" = "vfat" -o "$loopFs" = "msdos" ]; then
	basicmodules="$basicmodules -fat"
    fi
    basicmodules="$basicmodules -${loopFs}"
fi

# check if the root fs is on a logical volume or md device
root_major=$((0x$(stat -L -c '%t' $rootdev)))
[ -f /sbin/lvm1-vgdisplay ] && lvmprefix="lvm1-"
dm_major=`awk '$2 == "device-mapper" {print $1}' /proc/devices`
if [ "$root_major" = "$dm_major" ]; then
# trick to support making initrd for kernel that has a different version of lvm
# unless forced by --lvmver
    case x$lvmver in
	x1) findmodule -lvm-mod;;
	x2) findmodule -dm-mod;;
	x)  if ! findmodule -dm-mod && findmodule -lvm-mod; then
		lvmver=1
	    else
		lvmver=2
	    fi;;
    esac
    # root is on an LVM2 LV
    root_lvm=1
    rootvg=`/sbin/lvm2 lvdisplay $fstabrootdev | /bin/awk '/VG Name/ { print $NF }'`
    pvs=$(/sbin/lvm2 vgdisplay -v ${rootvg} | /bin/awk '/PV Name/ { print $NF }')
elif [ $root_major = 58 ]; then
    case x$lvmver in
	x1) findmodule -lvm-mod;;
	x2) findmodule -dm-mod;;
	x)  if ! findmodule -lvm-mod && findmodule -dm-mod; then
		lvmver=2
	    else
		lvmver=1
	    fi;;
    esac
    # root is on an LVM LV
    root_lvm=1
    rootvg=`/sbin/${lvmprefix}lvdisplay $fstabrootdev | /bin/awk '/VG Name/ { print $NF }'`
    pvs=$(/sbin/${lvmprefix}vgdisplay -v ${rootvg} | /bin/awk '/PV Name/ { print $(NF-1) }')
fi

# let's see if some pv or the root device is a raid device
if [ -n "$pvs" ]; then
    for dev in $pvs; do
	mddev $dev
    done
else
    mddev $rootdev
fi

if [ -n "$raiddevices" -a -z "$noraid" ]; then
    for md in $raiddevices; do
	md=${md##*/}
	md=md${md#md} # /dev/md/0 and /dev/md0 become md0
	level=$(awk '/^'$md'[[:space:]]*:/ { print $4 }' /proc/mdstat)
	case $level in
	    linear|multipath|raid[0156])
		findmodule $level
		;;
	    *)
		echo "raid level $level (in /proc/mdstat) not recognized" >&2
		;;
	esac
    done
fi

# now see if some device is on a scsi bus, and load appropriate modules
if [ -z "$noscsi" ]; then
    for sddev in $nonraiddevices; do
	scsidriver=$(scsidriver $sddev)
	if [ -n "$scsidriver" ]; then
	    scsimodules="$scsimodules $scsidriver"
	else
	    nonscsidevices="$nonscsidevices $sddev"
	fi
    done
fi

if [ -n "$scsimodules" ]; then
    for n in $scsimodules; do
	[ $n = usb-storage ] && usbdriver
	[ $n = sbp2 ] && ieee1394driver
	findmodule $n
    done
    findmodule sd_mod
fi

for idedev in $nonscsidevices; do
    major=$((0x$(stat -L -c '%t' $idedev)))
    is_ide=`awk -v major=$major '$1 == major && $2 ~ /^ide[0-9]/ {print $2}' /proc/devices`
    if [ -n "$is_ide" ]; then
	idedevices="$idedevices $idedev"
    else
	nonidedevices="$nonidedevices $idedev"
    fi
done

if [ -n "$idedevices" ]; then
    # are we using modular ide?
    if [ -f $modulefile ]; then
	idemodules=$(grep -E '^[[:space:]]*(alias|probeall|install)[[:space:]]+ide-controller[0-9]*[[:space:]]' $modulefile | sed 's/^.*ide-controller[0-9]*//;s/\/sbin\/modprobe//g;s/;//g;s/\/bin\/true//;s/||//')
    fi

    for idemodule in $idemodules; do
	findmodule $idemodule
    done

    # Debian patch
    findmodule -ide-mod
    findmodule -ide-probe-mod

    # official way
    findmodule -ide-core
    findmodule -ide-disk

fi

for otherdev in $nonidedevices; do
    major=$((0x$(stat -L -c '%t' $otherdev)))
    driver=`awk -v major=$major '
    	/Block devices:/ {block=1}
	block == 0 {next}
	$1 == major && $2 ~ /^ida/ {print "cpqarray";exit}
	$1 == major && $2 ~ /^dac960/ {print "DAC960";exit}
	$1 == major && $2 ~ /^ad/ {print "acsi";exit}
	$1 == major && $2 ~ /^sx8/ {print "sx8";exit}
	$1 == major && $2 ~ /^ataraid/ {print "-FAIL";exit}
	$1 == major {gsub("[0-9]*$","",$2); print "-" $2}
	' /proc/devices`

    findmodule $driver
    if echo $MODULES | grep -q "/$driver\.k\?o" 2>/dev/null ; then
	: #ok
    else
	# we look into scsi_hostadapter even if it is not a scsi driver
	for i in `grep -E '^[[:space:]]*(alias|probeall|install)[[:space:]]+scsi_hostadapter' $modulefile | \
	    sed 's/^.*scsi_hostadapter//;s/\/sbin\/modprobe//g;s/;//g;s/\/bin\/true//;s/||//'`; do
	    findmodule $i
	done
    fi
done

rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' $fstab)
rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' $fstab)

# in case the root filesystem is modular
findmodule -${rootfs}

for n in $basicmodules; do 
    findmodule $n
done

if [ -n "$verbose" ]; then
    echo "Using modules: $MODULES"
fi


[[ -n $tmpdir ]] && { is_good_fs $tmpdir || tmpdir= ;} #command-line
[[ -z $tmpdir && -n $TMPDIR ]] && { is_good_fs $TMPDIR || tmpdir= && tmpdir=$TMPDIR ;} #environement
if [[ -z $tmpdir ]];then
    if is_good_fs /tmp;then
	tmpdir=/tmp
    elif is_good_fs /var/tmp;then
	tmpdir=/var/tmp
    elif is_good_fs /root/tmp;then
	tmpdir=/root/tmp
    else
	echo "Cannot find a suitable tmp directory" >&2
	exit 1
    fi
fi
[[ -n $verbose ]] && echo "Using $tmpdir as temporary directory."

MNTIMAGE=`mktemp -d ${tmpdir}/initrd.XXXXXX`
IMAGE=`mktemp ${tmpdir}/initrd.img.XXXXXX`
MNTPOINT=`mktemp -d ${tmpdir}/initrd.mnt.XXXXXX`
if [ "$initrdfs" = "initramfs" ]; then
    RCFILE=$MNTIMAGE/init
else
    RCFILE=$MNTIMAGE/linuxrc
fi
# cleanup on exit, hangup, interrupt, quit, termination
trap 'rm -rf $MNTIMAGE $MNTPOINT $IMAGE' 0 1 2 3 15

if [ -z "$MNTIMAGE" -o -z "$IMAGE" -o -z "$MNTPOINT" ]; then
    echo "Error creating temporaries.  Try again" >&2
    exit 1
fi

mkdir -p $MNTIMAGE/lib
mkdir -p $MNTIMAGE/bin
mkdir -p $MNTIMAGE/etc
mkdir -p $MNTIMAGE/dev
mkdir -p $MNTIMAGE/proc
mkdir -p $MNTIMAGE/sys
mkdir -p $MNTIMAGE/sysroot
ln -s bin $MNTIMAGE/sbin

# We don't need this directory, so let's save space
rm -rf $MNTPOINT/lost+found

inst /sbin/nash "$MNTIMAGE/bin/nash"
if [[ -z "$kernel25" ]]; then
    if [[ -f /sbin/insmod-DIET ]]; then
	inst /sbin/insmod-DIET "$MNTIMAGE/bin/insmod"
    elif [[ -f /sbin/insmod.static ]]; then
	inst /sbin/insmod.static "$MNTIMAGE/bin/insmod"
    fi
fi
ln -s ../bin/nash $MNTIMAGE/sbin/modprobe

for MODULE in $MODULES; do
    f="/lib/modules/$kernel/$MODULE"
    if [ -e $f ]; then
	cp $verbose -a $f $MNTIMAGE/lib
    else
	gunzip -c $verbose $f.gz > $MNTIMAGE/lib/`basename $MODULE`
    fi
    [ -x /usr/bin/strip ] && /usr/bin/strip -g $verbose $MNTIMAGE/lib/`basename $MODULE`
done

# mknod'ing the devices instead of copying them works both with and
# without devfs...
mknod $MNTIMAGE/dev/console c 5 1
mknod $MNTIMAGE/dev/null c 1 3
for i in 1 2 3 4; do
    mknod $MNTIMAGE/dev/tty$i c 4 $i
done
mkdir $MNTIMAGE/dev/pts
mkdir $MNTIMAGE/dev/shm

echo "#!/bin/nash" > $RCFILE
echo "" >> $RCFILE

for MODULE in $MODULES; do
    text=""
    module=${MODULE##*/}
    module_s=${module%.o}
    module_s=${module_s%.ko}

    options=$(sed -n -e "s/^options[[:space:]]\+${module_s}[[:space:]]\+//p" $modulefile 2>/dev/null)

    if [ -n "$verbose" ]; then
	if [ -n "$options" ]; then
	    text=" with options $options"
	fi
        echo "Loading module $module$text"
    fi
    echo "echo \"Loading $module module\"" >> $RCFILE
    echo "insmod /lib/$module $options" >> $RCFILE

    # Hack - we need a delay after loading usb-storage and sbp2 to give things
    #        time to settle down before we start looking a block devices
    if [ "$module_s" = "usb-storage" ] || [ "$module_s" = "sbp2" ]; then
	echo "sleep 5" >> $RCFILE
    fi
done

echo "echo Mounting /proc filesystem" >> $RCFILE
echo "mount -t proc /proc /proc" >> $RCFILE
if [ -n "$kernel25" ];then
    echo "echo Mounting sysfs" >> $RCFILE
    echo "mount -t sysfs none /sys" >> $RCFILE
fi

echo "echo Creating device files" >> $RCFILE
[ -n "$readonly" -o -n "$USE_UDEV" ] && echo "mountdev size=5M,mode=0755" >> $RCFILE
if [ -n "$USE_UDEV" ]; then
    [ -x /sbin/udev-klibc ] && _klibc=-klibc
    inst /sbin/udev$_klibc $MNTIMAGE/sbin/udev
    inst /sbin/udevstart$_klibc $MNTIMAGE/sbin/udevstart
    mkdir -p $MNTIMAGE/etc/udev/rules.d
    cp /etc/udev/udev.conf $MNTIMAGE/etc/udev/udev.conf
    ln -s /sbin/nash $MNTIMAGE/sbin/hotplug
    echo "echo starting udev" >> $RCFILE
    echo "udevstart" >> $RCFILE
    echo "echo -n /sbin/hotplug > /proc/sys/kernel/hotplug" >> $RCFILE
else
    echo "mkdevices /dev" >> $RCFILE
    if [ -z "$readonly" ]; then
	_partitions=`cat /proc/partitions | wc -l`
	NB_INODES=$[NB_INODES + $_partitions * 3 ]
    fi
fi

if [ -n "$raiddevices" ]; then
    echo "echo Activating md devices" >> $RCFILE
    [ -x /sbin/mdadm ] && echo "DEVICE partitions" > $MNTIMAGE/etc/mdadm.conf
    for dev in $raiddevices; do
	md=${dev##*/}
	md=${md#md} # /dev/md/0 and /dev/md0 become 0
	echo "mknod /dev/md${md} b 9 ${md}" >> $RCFILE
	echo "mknod /dev/md/${md} b 9 ${md}" >> $RCFILE
	if [ -x /sbin/mdadm ]; then
	    /sbin/mdadm -D -b $dev | grep '^ARRAY' >> $MNTIMAGE/etc/mdadm.conf
    	fi
    done
    if [ -x /sbin/mdassemble ]; then
	cp $verbose -aL /sbin/mdassemble $MNTIMAGE/sbin
	echo "mdassemble" >> $RCFILE
    elif [ -x /sbin/mdadm ]; then
	inst /sbin/mdadm $MNTIMAGE/sbin
	echo "mdadm -A -s" >> $RCFILE
    else
	echo "raidautorun /dev/md${md}" >> $RCFILE
    fi
fi

if [ -n "$loopDev" ]; then
    loopDev_major=$((0x$(stat -L -c '%t' $loopDev)))
    loopDev_minor=$((0x$(stat -L -c '%T' $loopDev)))
    mkdir -p $MNTIMAGE/loopfs

    echo "echo Mounting device containing loopback root filesystem" >> $RCFILE
    echo "mknod $loopDev b $loopDev_major $loopDev_minor"
    echo "mount -t $loopFs $loopDev /loopfs" >> $RCFILE
    echo "echo Setting up loopback device on $loopFile" >> $RCFILE
    echo "mknod /dev/loop7 b 7 7"
    echo "losetup /dev/loop7 /loopfs$loopFile" >> $RCFILE
    rootdev=/dev/loop7
elif [ -n "$root_lvm" ]; then
    if [ "$lvmver" = "2" ]; then
	if [ -x /sbin/lvm2-static ]; then
	    cp $verbose -aL /sbin/lvm2-static $MNTIMAGE/sbin/vgscan
	else 
	    inst /sbin/lvm2 $MNTIMAGE/sbin/vgscan
	fi
	ln -s vgscan $MNTIMAGE/sbin/vgchange
	ln -s vgscan $MNTIMAGE/sbin/vgmknodes
	mkdir -p $MNTIMAGE/etc/lvm/{archive,backup}
	mkdir -p $MNTIMAGE/var/lock/lvm

	echo "devices {" >> $MNTIMAGE/etc/lvm/lvm.conf
	echo " dir = \"/dev\"" >> $MNTIMAGE/etc/lvm/lvm.conf
	grep "^[[:space:]]*\(scan\|filter\|types\)" /etc/lvm/lvm.conf >> $MNTIMAGE/etc/lvm/lvm.conf
	echo " write_cache_state = 0" >> $MNTIMAGE/etc/lvm/lvm.conf
	echo "}" >> $MNTIMAGE/etc/lvm/lvm.conf

	echo "echo Making device-mapper control node" >> $RCFILE
	echo "mkdmnod" >> $RCFILE
	echo "echo Scanning logical volumes" >> $RCFILE
	echo "vgscan -P --ignorelockingfailure" >> $RCFILE
	echo "echo Activating logical volumes" >> $RCFILE
	echo "vgchange -P -ay --ignorelockingfailure" >> $RCFILE
	echo "echo Making device nodes" >> $RCFILE
	echo "vgmknodes" >> $RCFILE
    else
	if [ -x /sbin/${lvmprefix}vgwrapper ]; then
	    cp $verbose -aL /sbin/${lvmprefix}vgwrapper $MNTIMAGE/sbin/vgscan
	    ln -s vgscan $MNTIMAGE/sbin/vgchange
	else 
	    inst /sbin/${lvmprefix}vgchange $MNTIMAGE/sbin/vgchange
	    inst /sbin/${lvmprefix}vgscan $MNTIMAGE/sbin/vgscan
	fi

	echo "mknod /dev/lvm b 109 0" >> $RCFILE
	echo "mount -t tmpfs /etc /etc" >> $RCFILE
	echo "echo Scanning logical volumes" >> $RCFILE
	echo "vgscan" >> $RCFILE
	echo "echo Activating logical volumes" >> $RCFILE
	echo "vgchange -ay" >> $RCFILE
	echo "umount /etc" >> $RCFILE
    fi
    rootdev=$fstabrootdev
else
    echo "echo Creating root device" >> $RCFILE
    echo "mkrootdev /dev/root" >> $RCFILE
    rootdev=/dev/root
fi


if [ -n "$pivot" ]; then
    [ "$rootopts" != "defaults" ] && rootopts_msg="with flags $rootopts"
    echo "echo Mounting root filesystem $rootopts_msg" >> $RCFILE
    echo "mount -o $rootopts --ro -t $rootfs $rootdev /sysroot" >> $RCFILE

    if [ -n "$kernel25" -a "$initrdfs" = "initramfs" ]; then
	echo "echo Remounting devfs/udev at correct place if necessary" >> $RCFILE
	[ -n "$USE_UDEV" ] && _flag=-f
	echo "remountdev ${_flag} /sysroot/dev" >> $RCFILE
	echo "echo Running init" >> $RCFILE
	echo "switchroot /sysroot" >> $RCFILE
    else	
	echo "echo 0x0100 > /proc/sys/kernel/real-root-dev" >> $RCFILE
	echo "pivot_root /sysroot /sysroot/initrd" >> $RCFILE
	[ -n "$kernel25" ] && echo "umount /initrd/sys" >> $RCFILE
	echo "umount /initrd/proc" >> $RCFILE
    fi
else
    [ -n "$readonly" ] && echo "umount /dev" >> $RCFILE
    [ -n "$kernel25" ] && echo "umount /sys" >> $RCFILE
    echo "umount /proc" >> $RCFILE
fi
    echo "echo Initrd finished" >> $RCFILE

chmod +x $RCFILE

if [ -n "$verbose" ]; then
    echo "Contents of RCFILE:"
    cat $RCFILE 2> /dev/null
fi

case $initrdfs in
    ext2|ext3|minix)
	for i in `/bin/find $MNTIMAGE -printf '%k\n'`; do
	    IMAGESIZE=$[IMAGESIZE + $i]
	    NB_INODES=$[NB_INODES + 1]
	done
	IMAGESIZE=$[IMAGESIZE + NB_INODES / 10]  # 10 inodes needs 1k

	dd if=/dev/zero of=$IMAGE bs=1k count=$IMAGESIZE 2> /dev/null

	if [ -n "$verbose" ]; then
	    echo "Creating filesystem with size ${IMAGESIZE}KB and $NB_INODES inodes"
	fi
	case $initrdfs in
	    ext2|ext3)
		mkfs.$initrdfs -q -m 0 -F -N $NB_INODES -s 1 $IMAGE
		tune2fs -i0 $IMAGE
	    ;;
	    minix)
		mkfs.minix $IMAGE
	    ;;
	esac

	mkdir -p $MNTPOINT
	mount -t $initrdfs $IMAGE $MNTPOINT -o loop || {
	    echo "Can't get a loopback device" >&2
	    exit 1
	}

	# We don't need this directory, so let's save space
	rm -rf $MNTPOINT/lost+found

	(cd $MNTIMAGE; tar cf - .) | (cd $MNTPOINT; tar xf -) || exit 1

	umount $MNTPOINT
	;;
    cramfs)
	mkfs.cramfs "$MNTIMAGE" "$IMAGE"
	compress=""
	;;
    romfs)
	genromfs -d "$MNTIMAGE" -f "$IMAGE"
	;;
    initramfs)
	(cd $MNTIMAGE; find . | cpio --quiet -c -o) > $IMAGE || exit 1
	;;
esac

if [ -n "$compress" ]; then
    gzip -9 < $IMAGE > $target || exit 1
else
    cp -a $IMAGE $target || exit 1
fi

if [[ -n "$dsdt_file" && -f "$dsdt_file" ]]; then
    echo -n "INITRDDSDT123DSDT123" >> $target
    cat "$dsdt_file" >> $target
fi

exit $rc
