RSS Git Download  Clone
Raw Blame History
#!/bin/bash
################################################################################
#	Mknfsinitrd		Creates an initial ramdisk image for NFS boot
#				T.Barnaby,	BEAM Ltd,	14/2/04
#				Some functions taken from /sbin/mkinitrd
################################################################################
#
modulesPreload="nfs e1000e igb fscache"
busyboxProgs="[ ash awk basename bunzip2 bzcat cat chgrp chmod\
        chown chroot chvt clear cmp cp cut date dd deallocvt\
        df dirname dmesg du echo egrep env expr false fgrep\
        find free grep gunzip gzip halt head hexdump hostid hostname\
        id ifconfig init insmod install ipaddr kill killall klogd\
        linuxrc ln logger ls lsmod mkdir mknod mkswap mktemp\
        modprobe more mount mv openvt pidof ping pivot_root poweroff\
        ps pwd readlink reboot reset rm rmdir rmmod route sed\
        sh sleep sort strings swapoff swapon sync syslogd tail\
        tar tee test time touch tr true tty udhcpc umount uname uniq\
        unzip uptime usleep vi wc wget which whoami xargs yes\
        zcat stat switch_root"

baseDir=""
kernelVersion=""
modules=""
verbose="-v"
target=""
builtins=""

##############################################################################
#	Script files
##############################################################################
#

fileInit(){
cat <<"EOF"
#!/bin/sh
################################################################################
#	Init.rc		Diskless NFS boot init script
#			T.Barnaby,	BEAM Ltd,	16/2/05
################################################################################
#

modules="mii pps_core e1000e i2c-core i2c-algo-bit dca igb sunrpc auth_rpcgss nfs_acl fscache lockd nfs"

echo "BEAM Diskless boot starting ..."

#mount -n -o remount,rw /
mount -n -t proc /proc /proc
mount -n -t sysfs none /sys
mount -n -t tmpfs /dev/shm /tmp

#/bin/sh

echo "Loading modules"
for m in $modules; do
	insmod /lib/$m.ko
done

#/bin/sh

echo "Seting up network interface"
while true; do
	if udhcpc -s /dhcpConfig -f -n -q -i eth0; then break; fi
	if udhcpc -s /dhcpConfig -f -n -q -i eth1; then break; fi
done
. /tmp/dhcpInfo

if [ -n "$dhcp_hostname" ]; then
	hostname $dhcp_hostname
fi

#/bin/sh

echo "Mounting root filesystem"
mount -n -t rpc_pipefs sunrpc /var/lib/nfs/rpc_pipefs
mount -n -r -t nfs  -o async,nolock $dhcp_rootpath /sysroot

#/bin/sh

echo "Switching to new root"
echo 0x100 > /proc/sys/kernel/real-root-dev
umount /var/lib/nfs/rpc_pipefs
umount /sys
umount /proc
umount /tmp

echo "Doing switch_root"
exec switch_root /sysroot /sbin/init
#exec switch_root /sysroot /bin/sh

EOF
}

fileDhcpConfig(){
cat <<"EOF"
#!/bin/sh
################################################################################
#	dhcpConfig	Sets up network interface
#			T.Barnaby,	BEAM Ltd,	16/2/05
################################################################################
#

configureNetwork(){
	ifconfig $interface $ip
	if [ -n "$router" ]; then
		route add default gw $router
	fi
	
	echo "dhcp_interface=$interface" > /tmp/dhcpInfo
	echo "dhcp_ip=$ip" >> /tmp/dhcpInfo
	echo "dhcp_mask=$mask" >> /tmp/dhcpInfo
	echo "dhcp_subnet=$subnet" >> /tmp/dhcpInfo
	echo "dhcp_broadcast=$broadcast" >> /tmp/dhcpInfo
	echo "dhcp_router=$router" >> /tmp/dhcpInfo
	echo "dhcp_dns=$dns" >> /tmp/dhcpInfo
	echo "dhcp_namesvr=$namesvr" >> /tmp/dhcpInfo
	echo "dhcp_hostname=$hostname" >> /tmp/dhcpInfo
	echo "dhcp_domain=$domain" >> /tmp/dhcpInfo
	echo "dhcp_siaddr=$siaddr" >> /tmp/dhcpInfo
	echo "dhcp_rootpath=$rootpath" >> /tmp/dhcpInfo
	echo "dhcp_timesvr=$timesvr" >> /tmp/dhcpInfo
	echo "dhcp_ntpsrv=$ntpsrv" >> /tmp/dhcpInfo
	echo "dhcp_tftp=$tftp" >> /tmp/dhcpInfo
	echo "dhcp_timezone=$timezone" >> /tmp/dhcpInfo
	echo "dhcp_logsvr=$logsvr" >> /tmp/dhcpInfo
	echo "dhcp_swapsvr=$swapsvr" >> /tmp/dhcpInfo
}

case $1 in
	deconfig)	ifconfig $interface 0.0.0.0;;
	bound)		configureNetwork;;
esac

exit 0
EOF
}

##############################################################################
#	Functions
##############################################################################
#

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

    [ -n "$verbose" ] && echo -n "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 } } \
                /^.*/ { show(); \
                           orig=modname($1); dep=""; \
                           if ($2) { for (i = 2; i <= NF; i++) { dep=sprintf("%s %s", dep, modname($i)); } } } \
                /^	/ { dep=sprintf("%s %s", dep, modname($1));  } \
                END      { show(); exit(rc) }' $baseDir/lib/modules/$kernelVersion/modules.dep $1)
    [ -n "$verbose" ] && echo -e "\t$deps"
}

findmodule() {
    skiperrors=""

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

    local modName=$1

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

    if [ $(echo $modName | cut -b1) = "-" ]; then
	skiperrors=--skiperrors
	modName=$(echo $modName | cut -b2-)
    fi

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

    # special cases
    if [ "$modName" = "i2o_block" ]; then
	findmodule i2o_core
	findmodule -i2o_pci
	modName="i2o_block"
    elif [ "$modName" = "ppa" ]; then
	findmodule parport
	findmodule parport_pc
	modName="ppa"
    elif [ "$modName" = "sbp2" ]; then
	findmodule ieee1394
	findmodule ohci1394
	modName="sbp2"
    elif [ "$modName" = "igb" ]; then
	findmodule pps_core
	findmodule i2c-core
	findmodule i2c-algo-bit
	findmodule dca
	modName="igb"
    else
	moduledep $modName
	for i in $deps; do
	    findmodule $i
	done
    fi

    for modExt in o.gz o ko ; do
	if [ -d $baseDir/lib/modules/$kernelVersion/updates ]; then
	    fmPath=`(cd $baseDir/lib/modules/$kernelVersion/updates; echo find . -name $modName.$modExt -type f | /bin/awk {'print $1; exit;'}`
	fi
	
	if [ -f $baseDir/lib/modules/$kernelVersion/updates/$fmPath ]; then
	    fmPath=updates/$fmPath
	    break
	fi

	fmPath=`(cd $baseDir/lib/modules/$kernelVersion; find . -name $modName.$modExt -type f) | /bin/awk {'print $1; exit;'}`
	if [ -f $baseDir/lib/modules/$kernelVersion/$fmPath ]; then
	    break
	fi
    done

    if [ ! -f $baseDir/lib/modules/$kernelVersion/$fmPath ]; then
	if [ -n "$skiperrors" ]; then
	    return
	fi

        # ignore the absence of the scsi modules
	for n in $PRESCSIMODS; do
	    if [ "$n" = "$modName" ]; then
		return;
	    fi
	done;

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

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

inst() {
    if [ "$#" != "2" ];then
        echo "usage: inst <file> <destination>"
        return
    fi 
    [ -n "$verbose" ] && echo "cp $1 -> $2"
    cp $1 $2
}

usage () {
    echo "usage: `basename $0` [-v][-d baseDir] <initrd-image> <kernel-version>" >&2
    echo "" >&2
    echo "       (ex: `basename $0` initrd-2.6.10-1.760_FC3 2.6.10-1.760_FC3)" >&2
    exit 1
}

##############################################################################
#	Main code
##############################################################################
#

while [ $# -gt 0 ]; do
    case $1 in
	-v)
	    verbose=-v
	    ;;
	-d)
	    shift
	    baseDir=$1
	    ;;
	*)
	    if [ -z "$target" ]; then
		target=$1
	    elif [ -z "$kernelVersion" ]; then
		kernelVersion=$1
	    else
		usage
	    fi
	    ;;
    esac

    shift
done

echo "BaseDir: $baseDir";

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

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

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

# find a temporary directory which doesn't use tmpfs
TMPDIR=""
for t in /tmp /var/tmp /root ${PWD}; do
    if [ ! -d $t ]; then continue; fi
    if ! echo access -w $t; then continue; fi

    fs=$(df -T $t 2>/dev/null | awk '{line=$1;} END {printf $2;}')
    if [ "$fs" != "tmpfs" ]; then 
	TMPDIR=$t
	break
    fi
done

if [ -z "$TMPDIR" ]; then
    echo "no temporary directory could be found" >&2
    exit 1
fi

if [ $TMPDIR = "/root" -o $TMPDIR = "${PWD}" ]; then 
    echo "WARNING: using $TMPDIR for temporary files" >&2
fi


# Add preload modules
for n in $modulesPreload; do
	findmodule $n
done

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

#echo "TMPDIR: $TMPDIR"
#exit 0

##############################################################################
#	Main wor
##############################################################################
#
MNTIMAGE=`mktemp -d ${TMPDIR}/initrd.XXXXXX`
IMAGE=`mktemp ${TMPDIR}/initrd.img.XXXXXX`

#MNTIMAGE=/tmp/initrd

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

echo "MNTIMAGE: $MNTIMAGE"

mkdir -p $MNTIMAGE
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
mkdir -p $MNTIMAGE/usr
mkdir -p $MNTIMAGE/usr/bin
mkdir -p $MNTIMAGE/usr/sbin
mkdir -p $MNTIMAGE/var
mkdir -p $MNTIMAGE/var/lib/nfs/rpc_pipefs
mkdir -p $MNTIMAGE/tmp
rm -f $MNTIMAGE/sbin
ln -s bin $MNTIMAGE/sbin

# Install needed programs
#inst /sbin/nash "$MNTIMAGE/bin/nash"
#inst /sbin/insmod.static "$MNTIMAGE/bin/insmod"
#ln -s /sbin/nash $MNTIMAGE/sbin/modprobe
#inst /bin/bash $MNTIMAGE/bin
#ln -s bash $MNTIMAGE/bin/sh

# Test progs
if false; then
# Install libs
inst /lib/libtermcap.so.2 $MNTIMAGE/lib
inst /lib/libdl.so.2 $MNTIMAGE/lib
inst /lib/libc.so.6 $MNTIMAGE/lib
inst /lib/ld-linux.so.2 $MNTIMAGE/lib

#inst /sbin/ifconfig $MNTIMAGE/bin/ifconfig1
#inst /bin/dmesg $MNTIMAGE/bin
inst /usr/bin/strace $MNTIMAGE/bin
#inst /sbin/lsmod $MNTIMAGE/bin
fi

# Install busybox
inst /sbin/busybox-beam $MNTIMAGE/bin/busybox
for p in $busyboxProgs; do
	ln -sf busybox $MNTIMAGE/bin/$p
done

# Copy modules
for m in $modules; do
    echo "Copy kernel module: $m"
    if [ -x /usr/bin/strip ]; then
	/usr/bin/strip -g $baseDir/lib/modules/$kernelVersion/$m -o $MNTIMAGE/lib/$(basename $m)
    else
	cp -a $baseDir/lib/modules/$kernelVersion/$m $MNTIMAGE/lib
    fi
done

if false; then
# Create main devices
mknod $MNTIMAGE/dev/console c 5 1
mknod $MNTIMAGE/dev/null c 1 3
mknod $MNTIMAGE/dev/ram b 1 1
mknod $MNTIMAGE/dev/urandom c 1 9
mknod $MNTIMAGE/dev/systty c 4 0
mknod $MNTIMAGE/dev/tty c 5 0
for i in 1 2 3 4; do
    mknod $MNTIMAGE/dev/tty$i c 4 $i
done
fi

#touch $MNTIMAGE/etc/fstab

# Setup udev
#inst /sbin/udev.static $MNTIMAGE/sbin/udev
#ln -s udev $MNTIMAGE/sbin/udevstart
#mkdir -p $MNTIMAGE/etc/udev
#inst /etc/udev/udev.conf $MNTIMAGE/etc/udev/udev.conf
#ln -s /sbin/nash $MNTIMAGE/sbin/hotplug


# Create rc script filea
fileInit > $MNTIMAGE/init
fileDhcpConfig > $MNTIMAGE/dhcpConfig
chmod +x $MNTIMAGE/init
chmod +x $MNTIMAGE/dhcpConfig

(cd $MNTIMAGE; find . | cpio --quiet -c -o) > $IMAGE
gzip -9 < $IMAGE > $target || rc=1

rm -rf $MNTIMAGE $IMAGE

exit 0