#! /bin/sh

# DIET-PC build script

# Copyright (C) 2002-2005 Paul A. Whittaker <whitpa@users.sourceforge.net>

# 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

# To use this script you must have a kernel compiled with either (a) ramdisk
# support as an external module (CONFIG_BLK_DEV_RAM=m), or (b) loopback device
# support (CONFIG_BLK_DEV_LOOP=y or CONFIG_BLK_DEV_LOOP=m).

# Increase these values if you need more free space at run-time.
SLACK_SPACE=2048	# kilobytes to allow above anticipated requirement
SLACK_INODES=2048	# inodes to allow above anticipated requirement

# Ext2 compression algorithm. One of bzip[2], lzo[1x1], lzrw3a, lzv[1],
# gzip[1-9], none.  Defer (an alias for none), never and auto are also
# accepted by chattr, but are not supported by this script.  You may ignore
# this setting if you have no e2compr kernel support on your build host.
E2COMPR_ALGO=gzip9

cd `dirname $0`/..

umask 022
PATH=/bin:`pwd`/tools:/sbin:/usr/bin:/usr/sbin
export PATH

trap 'mount | awk "\$3 ~ /initrd/ {printf \"umount %s\n\", \$3}" | sort -r | \
	sh 2>/dev/null; [ "`cat initrd.lock 2>/dev/null`" = "$$" ] && rm -f \
	initrd.lock; exit 255' 2
 
usage () {
cat 1>&2 <<EOF
Usage: `basename $0` [options]
Options:
	-f cpio.gz|cramfs|e2compr|ext2.gz|jffs2|squashfs
		(Preferred format for final image)
	-noupx
		(Don't UPX binaries in initramfs/inittar)
	-nv
		(Populate nonvolatile filesystems)
EOF
exit 1
}

USE_UPX=TRUE
MOUNT_NON_VOLATILE=
PREF_FORMAT=
NON_OPTION=
ROOTDEV=
until [ "$NON_OPTION" ]; do
    case "$1" in
    -f)
	shift
	PREF_FORMAT="$1"
	case "$PREF_FORMAT" in
	cpio.gz|cramfs|e2compr|ext2.gz|jffs2|squashfs)
	    ;;
	*)
	    usage
	    ;;
	esac
	shift
	;;
    -noupx)
	USE_UPX=
	shift
	;;
    -nv)
	MOUNT_NON_VOLATILE=TRUE
	shift
	;;
    *)
	NON_OPTION=TRUE
	;;
    esac
done
# No non-optional arguments are expected.
[ $# -gt 0 ] && usage

NV_FSTAB="/tmp/nv-fstab.$$"
NV_EXCLUDELIST="/tmp/nv-excludelist.$$"
IPK_LIST="/tmp/ipks.$$"
SYSMAP="/tmp/sysmap.$$"

if [ "`id -u`" -ne 0 ]; then
    echo "`basename $0` must be run as root." 1>&2
    exit 2
fi

if [ ! "`which ed 2>/dev/null`" ]; then
    cat 1>&2 <<EOF
Cannot find "ed" text editor (required).
Your Linux distribution may not have installed "ed" by default.
Please install it and try again.
EOF
    exit 3
fi

until [ ! -f initrd.lock ]; do
    echo 'Build in progress - waiting for completion ...' 1>&2
    sleep 15
done
echo $$>initrd.lock

cat /dev/null >$SYSMAP
PKG=`grep '^CONFIG_KERNEL_IMAGE_[^=]\+=y$' .config | sed -e 's/^CONFIG_//' \
	-e 's/=y$//' | tr '[_A-Z]' '[\055a-z]'`
if [ "`echo \"$PKG\" | wc -l`" -gt 1 ]; then
    PKG=`echo "$PKG" | head -n 1`
    cat 1>&2 <<EOF
WARNING: Multiple kernel images specified - this shouldn't happen!
Only examining the capabilities of the first one ($PKG).

EOF
fi
if [ -e "metadata/$PKG" ]; then
    VERSION=`grep '^Version:' metadata/$PKG | sed 's/^Version:\s*//'`
    ARCH=`grep '^Architecture:' metadata/$PKG | sed 's/^Architecture:\s*//'`
    PLATFORM=`echo "$PKG" | cut -f3- -d-`
    ar p "$ARCH/${PKG}_${VERSION}_${ARCH}.ipk" data.tar.gz | tar xzOf - \
	    "./boot/System.map-$VERSION-$PLATFORM.gz" | gunzip -c >$SYSMAP
fi
if [ ! -s $SYSMAP ]; then
    cat <<EOF
Can't find your kernel's System.map file.
As the build process relies on this file to determine capabilities of the
target system, it will be forced to use pessimistic assumptions for this build.

EOF
fi
CRAMFS_AVAIL=
INITRAMFS_AVAIL=
JFFS2_AVAIL=
SQUASHFS_AVAIL=
SQUASHFS_V2=TRUE
SQUASHFS_V4=TRUE
UNIONFS_AVAIL=
TMPFS_AVAIL=
E2COMPR_AVAIL=
CRAMFS_SYM='init_cramfs_fs'
INITRAMFS_SYM='__initramfs_start'
JFFS2_SYM='init_jffs2_fs'
SQUASHFS_SYM='init_squashfs_fs'
SQUASHFS_3PLUS_SYM='__initcall_init_squashfs_fs6'
SQUASHFS_3MINUS_SYM='squashfs_2_0_supported'
UNIONFS_SYM='init_unionfs_fs'
TMPFS_SYM='tmpfs_fs_type'
ALGO_SYM="ext2_r`echo $E2COMPR_ALGO | sed -e 's/[0-9].*$//' | tr '[a-z]' \
	'[A-Z]'`"
# Check the target system's capabilities.
eval `awk '$NF == "'$CRAMFS_SYM'" {printf "CRAMFS_AVAIL=TRUE\n"} \
	$NF == "'$INITRAMFS_SYM'" {printf "INITRAMFS_AVAIL=TRUE\n"} \
	$NF == "'$JFFS2_SYM'" {printf "JFFS2_AVAIL=TRUE\n"} \
	$NF == "'$SQUASHFS_SYM'" {printf "SQUASHFS_AVAIL=TRUE\n"} \
	$NF == "'$SQUASHFS_3PLUS_SYM'" {printf "SQUASHFS_V2=\n"} \
	$NF == "'$SQUASHFS_3MINUS_SYM'" {printf "SQUASHFS_V4=\n"} \
	$NF == "'$UNIONFS_SYM'" {printf "UNIONFS_AVAIL=TRUE\n"} \
	$NF == "'$TMPFS_SYM'" {printf "TMPFS_AVAIL=TRUE\n"} \
	$NF == "'$ALGO_SYM'" {printf "E2COMPR_AVAIL=TRUE\n"}' \
	$SYSMAP 2>/dev/null`
echo -e 'The target system \c'
[ "$CRAMFS_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' compiled-in support for cramfs.'
echo -e 'The target system \c'
[ "$INITRAMFS_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' initramfs (CPIO) support.'
echo -e 'The target system \c'
[ "$JFFS2_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' compiled-in support for jffs2.'
echo -e 'The target system \c'
[ "$SQUASHFS_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' compiled-in support for squashfs.'
echo -e 'The target system \c'
[ "$UNIONFS_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' compiled-in support for unionfs.'
echo -e 'The target system \c'
[ "$TMPFS_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo ' compiled-in support for tmpfs/shmfs.'
if [ ! "$TMPFS_AVAIL" ]; then
    echo 'That means that a cramfs/squashfs + tmpfs union will not be possible.'
fi
echo -e 'The target system \c'
[ "$E2COMPR_AVAIL" ] && echo -e 'has\c' || echo -e 'lacks\c'
echo " compiled-in support for the $E2COMPR_ALGO e2compr algorithm."
echo

compute_installation_order () {
    grep -v '^#' .config | sed 's/^CONFIG_\(.*\).*=y$/\1/' | tr '[_A-Z]' \
	    '[\055a-z]' | while read PKG; do
	[ ! -f "metadata/$PKG" ] && continue
	grep '^Depends:' metadata/$PKG | sed -e 's/^Depends://' -e \
		's/([^,]*)//g' | tr ' \t,' '\012' | while read DEP; do
	    [ "$DEP" ] && echo "$PKG $DEP"
	done
	ALIAS=`grep '^Provides:' metadata/$PKG | sed 's/^Provides:\W*//'`
	if [ "$ALIAS" = 'kernel-image' ]; then
	    grep -q '^CONFIG_EMBED_KERNEL_IMAGE=y$' .config || continue
	fi
	[ "$ALIAS" ] && echo "$ALIAS $PKG"
    done | tsort | tac
}

build_initrd () {

# PRUNE indicates whether or not to omit files from known non-initrd subtrees.
# There are four cases, depending on whether or not saved information about
# non-initrd persistent filesystems (generated by a previous pass) is also
# present:
#
# - If false and saved information is present, then use that information to
#   perform submounts prior to loading package contents.
# - If false and no saved information is present, then collect that
#   information.
# - If true and saved information is present then use it to exclude relevant
#   trees from file transfers.
# - If true and no saved information is present, then delete relevant subtrees
#   after collecting the information.
    if [ "$1" = '-prune' ]; then
	PRUNE=TRUE
	shift
    else
	PRUNE=
    fi

# $1 is the required size in 1k blocks.  $2 is the required number of inodes.
    if [ $# -ne 2 ]; then
	echo 'Usage: build_initrd [-prune] num_blocks num_inodes' 1>&2
	return
    fi

# Mount a ramdisk or temporary loopback device in which to assemble the initrd.
# The device is zeroised before creating the ext2 filesystem in order to
# maximise compression of unallocated space.
    rmmod rd 2>/dev/null
    modprobe rd rd_size=$1 2>/dev/null && USE_LOOP= || USE_LOOP=TRUE
    [ "$USE_LOOP" ] && INITRD_DEV="tmp_initrd" || INITRD_DEV="/dev/ram0"
    dd if=/dev/zero of=$INITRD_DEV bs=1024 count=$1 2>/dev/null
    mkfs.ext2 -I 128 -F -N $2 -m 0 $INITRD_DEV >/dev/null 2>&1
    [ "$USE_LOOP" ] && MOUNT_OPTS="-o loop" || MOUNT_OPTS=
    mount -t ext2 $MOUNT_OPTS $INITRD_DEV initrd
    if [ $? -ne 0 ]; then
	echo 'Initrd mount failed - aborting.' 1>&2
	kill -INT $$
	sleep 1
	exit 255
    fi

    if [ -s "$NV_FSTAB" ]; then
# If pruning is requested, create a list of subtrees to exclude from saved
# fstab entries.
	awk 'NF > 1 {print $2}' $NV_FSTAB | cut -c2- >$NV_EXCLUDELIST
	while read MNTPT; do
	    mkdir -p initrd/$MNTPT
	done <$NV_EXCLUDELIST
# If pruning is not requested, mount known non-root persistent filesystems
# under the initrd.  Initial creation of these filesystems, and ensuring that
# they are available read-write to the build host, is the user's
# responsibility.
#
# ISO9660 is a special case, since the medium is inherently read-only.  In this
# case, the working area used for preparing the DIET-PC ISO image is mounted
# instead.
	if [ ! "$PRUNE" ]; then
	    >$NV_EXCLUDELIST
	    awk 'NF > 3 {if ($3 ~ /iso9660/) printf \
		    "mount --bind cdimage initrd%s\n", $2; else printf \
		    "mount -t %s -o %s %s initrd%s\n", $3, $4, $1, $2}' \
		    $NV_FSTAB | sh
# If pruning is requested and it has previously been determined that the root
# filesystem is nonvolatile, then the final initrd is destined to be empty and
# nothing will be copied to nonvolatile storage. This is almost certainly not
# what the user intended.
	elif [ "$ROOTDEV" ]; then
	    echo -e '\tEmpty initrd - did you forget "BUILD_NON_VOLATILE=yes"?'
	    return
	fi
    else
	>$NV_EXCLUDELIST
    fi

# Assemble the initrd.

# Test to see whether the build platform has kernel support for e2compr.
# Ideally chattr should either do nothing or return a non-zero exit code, but
# unfortunately it semi-works in an unsafe fashion.  Hence test on an
# expendable directory.
    if [ "$E2COMPR_AVAIL" -a \( ! "$PREF_FORMAT" -o "$PREF_FORMAT" = \
	    'e2compr' \) ]; then
	mkdir initrd/comptest.$$
	RESULT=`chattr -m $E2COMPR_ALGO +c initrd/comptest.$$ 2>&1 | wc -l`
	rmdir initrd/comptest.$$
	if [ "$RESULT" -eq 0 ]; then
	    echo -e "\tThe host supports the $E2COMPR_ALGO e2compr algorithm."
# Set the compression attribute on the root directory such that all files in
# the initrd will inherit it.
	    chattr -m $E2COMPR_ALGO +c initrd
	else
	    echo -e "\tThe host does not support the $E2COMPR_ALGO e2compr "\
'algorithm.'
	    echo -e '\tE2compr cannot be used.'
	    E2COMPR_AVAIL=
	fi
	echo
    fi

    echo -e '\tInstalling packages ... \c'
    while read IPK; do
	DEST_SYM="CONFIG_`basename $IPK | cut -f1 -d_ | tr '[\055a-z]' \
		'[_A-Z]'`_DEST"
	eval 'DEST=$'"$DEST_SYM"
	ipkg -f ipkg.conf -V 0 -o initrd -d ${DEST:-root} install $IPK
    done <$IPK_LIST
    echo 'done.'

# If no saved information on non-root persistent filesystems is present, then
# create that information now.
# The sed command at the end changes "ro" options to "rw" throughout.
    if [ ! -s "$NV_FSTAB" ]; then
	awk '$1 !~ /^#/ && $3 != "swap" && $4 !~ /noauto/ {print $0}' \
		initrd/etc/fstab | sed 's/\<ro\>/rw/g' >$NV_FSTAB
# If pruning was requested but we didn't know what to prune, do so now that we
# do.
	if [ -s "$NV_FSTAB" -a "$PRUNE" ]; then
	    awk 'NF > 1 {printf "rm -rf initrd%s 2>/dev/null\n", $2}' \
		    $NV_FSTAB | sh
	fi
    fi

# Check to see whether UnionFS and TmpFS are (plausibly) available as modules.
    if [ ! "$UNIONFS_AVAIL" -a \
	    "`echo initrd/lib/modules/*/kernel/fs/unionfs/unionfs.ko*`" != \
	    'initrd/lib/modules/*/kernel/fs/unionfs/unionfs.ko*' ]; then
	echo -e '\tThe target system (probably) has modular support for unionfs.'
	UNIONFS_AVAIL=TRUE
    fi
    if [ ! "$TMPFS_AVAIL" -a \
	    "`echo initrd/lib/modules/*/kernel/fs/tmpfs/tmpfs.ko*`" != \
	    'initrd/lib/modules/*/kernel/fs/tmpfs/tmpfs.ko*' ]; then
	echo -e '\tThe target system (probably) has modular support for tmpfs.'
	TMPFS_AVAIL=TRUE
    fi

    awk 'NF > 1 {printf "mkdir -p initrd%s\n", $2}' $NV_FSTAB | sh
# Create /dev/console.  Init needs to be able to find this at boot - definitely
# before udev, and possibly before devfs.
    mkdir -p initrd/dev
    mknod -m 644 initrd/dev/console c 5 1 2>/dev/null
# /dev/null is also advisable:
    mknod -m 666 initrd/dev/null c 1 3 2>/dev/null
# If building a non-initrd system, a device node for the root filesystem is
# also essential, so copy this from the host system.
    ROOTDEV=`awk '$2 == "/" {print $1; exit}' $NV_FSTAB`
    [ "$ROOTDEV" ] && tar -chf - "$ROOTDEV" 2>/dev/null | tar -C initrd -xf -
# Initialiase /etc/ld.so.cache
    ldconfig -r initrd 2>/dev/null
}

# Set *_DEST environment variables.
. ./.config
# Construct an ordered list ($IPK_LIST) of ipk files to be installed.
cat /dev/null >$IPK_LIST
compute_installation_order | while read PKG; do
    [ ! -f "metadata/$PKG" ] && continue
    VERSION=`grep '^Version:' metadata/$PKG | sed 's/^Version:\s*//'`
    ARCH=`grep '^Architecture:' metadata/$PKG | sed 's/^Architecture:\s*//'`
    echo "$ARCH/${PKG}_${VERSION}_${ARCH}.ipk" >>$IPK_LIST
done

# Inspect ipk file contents to compute a rough estimate of an upper limit for
# the number of kilobytes and the number of inodes that the initrd may require.
PASS1_SIZE=`
    {
    echo $SLACK_SPACE
    while read IPK; do
	ar p $IPK data.tar.gz | tar tvzf - | awk 'BEGIN {s=0} {s = s + \
		int($3)} END {print int(s/1024)}'
	echo '+'
    done <$IPK_LIST
    echo 'p'
    } | dc
`
PASS1_INODES=`
    {
    echo $SLACK_INODES
    while read IPK; do
	ar p $IPK data.tar.gz | tar tzf - | wc -l
	echo '+'
    done <$IPK_LIST
    echo 'p'
    } | dc
`
# The first pass is always pruned, so that we can get accurate initrd size
# information and avoid writing data external to the initrd twice.
printf "First pass: %u kilobytes %u inodes.\n\n" $PASS1_SIZE $PASS1_INODES
build_initrd -prune $PASS1_SIZE $PASS1_INODES

#echo -e '\nThe target system \c'
#[ "$UNIONFS_AVAIL" ] && echo -e 'supports\c' || echo -e 'does not support\c'
#echo ' unionfs.'
#if [ ! "$UNIONFS_AVAIL" ]; then
#   echo 'That means that a cramfs/squashfs + tmpfs union will not be possible.'
#fi

# Perform a second pass to further reduce the size of the initrd, using more
# accurate parameters derived from the result of the first.
PASS2_SIZE=`(df -k initrd | tail -1 | awk '{if ($1 ~ /^[0-9]/) print $2; else \
	print $3}'; echo "$SLACK_SPACE + p") | dc`
PASS2_INODES=`(df -i initrd | tail -1 | awk '{if ($1 ~ /^[0-9]/) print $2; \
	else print $3}'; echo "$SLACK_INODES + p") | dc`
umount initrd
SIZE_RATIO=`echo "1k $PASS2_SIZE 100 * $PASS1_SIZE / p" | dc`
INODES_RATIO=`echo "1k $PASS2_INODES 100 * $PASS1_INODES / p" | dc`
printf '\nSecond pass: %u kilobytes %u inodes.\n'\
'(%.1f%% and %.1f%% of first pass estimates)\n\n' $PASS2_SIZE $PASS2_INODES \
	$SIZE_RATIO $INODES_RATIO
if [ "$MOUNT_NON_VOLATILE" ]; then
    echo -e '\tSafety checking non-volatile mounts ... \c'
    awk '{print $1}' $NV_FSTAB | while read DEV; do
	if [ "$DEV" = '/dev/root' ]; then
	    echo 'unsafe (use of /dev/root).'
	    echo 'fstab must specify the real root device (eg. /dev/hda1).'
	    echo 'Aborting script.' 1>&2
	    exit 255
	elif [ ! -b "$DEV" ]; then
	    echo "unsafe ($DEV does not exist on host system)."
	    echo 'Aborting script.' 1>&2
	    exit 255
	elif [ "`mount | awk '$1 == \"$DEV\" {print $0}'`" ]; then
	    echo "unsafe ($DEV is currently mounted)."
	    echo 'Aborting script.' 1>&2
	    exit 255
	fi
    done
    echo -e 'ok.\n'
    build_initrd $PASS2_SIZE $PASS2_INODES
    awk 'NF > 1 {printf "umount initrd%s\n", $2}' $NV_FSTAB | sort -r | sh
else
    build_initrd -prune $PASS2_SIZE $PASS2_INODES
fi

echo

# JFFS2 is available by request only.
if [ "$JFFS2_AVAIL" -a "$PREF_FORMAT" = 'jffs2' ]; then
    echo 'Root filesystem image will be a jffs2 with integral compression.'
    mkfs.jffs2 -r initrd -e 131072 -m size -n -p -U -o initrd.img
    if [ $? -ne 0 ]; then
	echo 'Operation failed (maybe: "apt-get install mtd-tools"?)' 1>&2
    fi
    ROOTDEV='/dev/mdtblockN rootfstype=jffs2'
    umount initrd
# The first and best option is a squashfs + tmpfs union.
elif [ "$SQUASHFS_AVAIL" -a "$TMPFS_AVAIL" -a "$UNIONFS_AVAIL" -a \( ! \
	"$PREF_FORMAT" -o "$PREF_FORMAT" = 'squashfs' \) ]; then
    echo 'Root filesystem image will be a SquashFS initrd with integral '\
'compression.'
    if [ "$SQUASHFS_V2" ]; then
	SUFFIX='2'
    elif [ "$SQUASHFS_V4" ]; then
	SUFFIX='4'
    else
	SUFFIX='3'
    fi
    mksquashfs$SUFFIX initrd initrd.img >/dev/null
    umount initrd
# Then a cramfs + tmpfs union.
elif [ "$CRAMFS_AVAIL" -a "$TMPFS_AVAIL" -a "$UNIONFS_AVAIL" -a \( ! \
	"$PREF_FORMAT" -o "$PREF_FORMAT" = 'cramfs' \) ]; then
    echo 'Root filesystem image will be a CRAMFS initrd with integral '\
'compression.'
    mkfs.cramfs initrd initrd.img >/dev/null
    umount initrd
# Next best is ext2 with e2compr.
elif [ "$E2COMPR_AVAIL" -a \( ! "$PREF_FORMAT" -o "$PREF_FORMAT" = 'e2compr' \
	\) ]; then
    echo 'Root filesystem image will be a Ext2 initrd with integral '\
'compression.'
    umount initrd
    cat $INITRD_DEV >initrd.img
# Then initramfs.
elif [ "$INITRAMFS_AVAIL" -a \( ! "$PREF_FORMAT" -o "$PREF_FORMAT" = \
	    'cpio.gz' \) ]; then
    echo 'Root filesystem image will be an initramfs (CPIO) with post '\
'compression.'
    if [ "$USE_UPX" ]; then
# Since initramfs lacks run-time compression, compress all binaries with UPX
# to save some RAM.
	echo -e '\nUPXing executables ... \c'
# Busybox find has neither "-exec" nor "-o".  Sigh.
	{
	    find initrd -type d -name bin -print
	    find initrd -type d -name sbin -print
	} | while read dir; do
		upx -q --best --overlay=skip $dir/* >/dev/null 2>&1
	done
# Never UPX init or busybox - this will cause problems.
	upx -q -d initrd/sbin/init initrd/bin/busybox >/dev/null 2>&1
	echo 'done.'
    fi
    (cd initrd; find . -print | cpio -o --quiet -H newc) | gzip -9f >initrd.img
    umount initrd
# Last resort is a conventional ext2 initrd.
# UPX won't do any good here - to save any memory, it would have to be used as
# we copy rather than afterward.
else
    echo 'Root filesystem image will be an Ext2 initrd with post compression.'
    umount initrd
    echo -e '\nCompressing initrd ... \c'
    gzip -9f <$INITRD_DEV >initrd.img
    echo 'done.'
fi
COMP_SIZE=`ls -s initrd.img | awk '{print $1}'`
COMP_RATIO=`echo "1k $COMP_SIZE 100 * $PASS2_SIZE / p" | dc`
printf "\nFinal image size is %uk - %.1f%% of uncompressed size (%uk).\n" \
	$COMP_SIZE $COMP_RATIO $PASS2_SIZE
chown `ls -ld . | awk '{printf "%s:%s\n", $3, $4}'` initrd.img
sync
[ "$ROOTDEV" ] && cat <<EOF

You appear to be building a non-initrd system.

Please note that boot loader templates are configured for initrd booting by
default.  You must change the relevant boot loader configuration file (in the
"templates" directory) such that it specifies "root=$ROOTDEV ro"
instead of "root=/dev/ram0 rw" prior to running "make install-<loader>".
EOF
rm -f initrd.lock $NV_FSTAB $NV_EXCLUDELIST $IPK_LIST $SYSMAP \
	${USE_LOOP:+${INITRD_DEV}}
exit 0
