#!/bin/sh
#
# Copyright 2003 Gray Watson
#
# Permission to use, copy, modify, and distribute this software for
# any purpose and without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies, and that the name of Gray Watson not be used in advertising
# or publicity pertaining to distribution of the document or software
# without specific, written prior permission.
#
# Gray Watson makes no representations about the suitability of the
# software described herein for any purpose.  It is provided "as is"
# without express or implied warranty.
#
# The author may be contacted via http://256.com/gray/
#
# $Id: rd_image.sh,v 1.2 2004/01/03 07:41:25 gray Exp $
#

#
# This script builds a boot image to be written into a miniroot
# configured kernel file and booted from a Soekris system.  More
# information online:
#
# http://256.com/gray/docs/soekris_openbsd_diskless/
#

IMAGE_FILE=./image_rd
DISKLABEL_TMP=rd.$$.t
VNODE_DEV=svnd0
VNODE_MOUNT=./__mount_rd__
DEFAULT_ROOT=./root_rd
DEFAULT2_ROOT=./root
FILE_EXTENSION=rd
CF_ROOT=./root_cf
KERNEL_FILE=bsd
RDSETROOT=./rdsetroot

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

cat << __EOF

Kernel Ramdisk Install Script for OpenBSD
Copyright 2003 Gray Watson
http://256.com/gray/docs/soekris_openbsd_diskless/
-------------------------------------

__EOF

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

echo -n "Enter the filename to write the image into: [$IMAGE_FILE] "
read image_file
if [ "$image_file" = "" ]; then
    image_file=$IMAGE_FILE
fi

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

echo "----------"
echo "Checking for the rdsetroot utility."
if [ ! -x $RDSETROOT ]; then
    cat << __EOF
ERROR

I cannot find the $RDSETROOT program which must be executable in the
current directory.  If you have the OpenBSD sources unpacked in
/usr/src/ then you should be able to run:

        cc -o rdsetroot /usr/src/distrib/common/rdsetroot.c

For OpenBSD 3.4+ release users with an ELF kernel, you will get
the error "bad magic number" when the script goes to write the
image into the kernel file.  This means that you need the ELF version
of rdsetroot:

        cc -o rdsetroot /usr/src/distrib/common/elfrdsetroot.c

Please build that program and run the script again.
__EOF
    exit 1
fi

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

echo "----------"
echo -n "Enter the kernel file to write the image into [$KERNEL_FILE]: "
read kernel_file
if [ "$kernel_file" = "" ]; then
    kernel_file=$KERNEL_FILE
fi

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

cat << __EOF
----------
Please enter the configured number of MINIROOTSIZE blocks from your
kernel configuration file.

__EOF
echo -n "MINIROOTSIZE value: [23000] "
read rd_size
if [ "$rd_size" = "" ]; then
        rd_size=23000
fi

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

cat << __EOF
----------
Enter the vnode device to use.  If you do not know what this is then
just press enter to take the default of "$VNODE_DEV".

__EOF
echo -n "Vnode device [$VNODE_DEV]: "
read vnode_device
if [ "$vnode_device" = "" ]; then
    vnode_device=$VNODE_DEV
fi

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

cat << __EOF
----------
Enter the directory path to the files that you want to load into the
ramdisk image.  The default is the directory $DEFAULT_ROOT in the current
directory.  If it doesn't exist then $DEFAULT2_ROOT is tried.  It is
assumed that this directory has the boot configuration files, and all
other information necessary for the system to work.

__EOF

default_root=$DEFAULT_ROOT
if [ ! -d $default_root ]; then
    default_root=$DEFAULT2_ROOT
fi

echo -n "Root filesystem directory [$default_root]: "
read root_dir

if [ "$root_dir" = "" ]; then
    root_dir=$default_root
fi

if [ ! -d $root_dir ]; then
    echo "I cannot see the directory $root_dir"
    exit 1
fi

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

# create the image file
echo "----------"
doit=yes
if [ -f $image_file ]; then
    echo -n "Image file $image_file exists.  Re-zero or re-create it? [yes] "
    read doit
    if [ "$doit" = "" ]; then
        doit=yes
    fi
fi
if [ "$doit" = "yes" ]; then
    echo "Creating image file $image_file"
    rm -f $image_file
    dd if=/dev/zero of=$image_file bs=512 count=$rd_size
    if [ $? -ne 0 ]; then
        echo "dd to $image_file failed"
        exit 1
    fi
fi

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

# now map it into the vnode device
echo "----------"
echo "Mapping $image_file to vnode device $vnode_device."
vnconfig $vnode_device $image_file
if [ $? -ne 0 ]; then
    echo "Mapping $image_file to vnode device $vnode_device failed."
    exit 1
fi

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

# get the current disk label
echo "----------"
echo "Getting the current disklabel from $vnode_device."
disklabel $vnode_device > $DISKLABEL_TMP
if [ $? -ne 0 ]; then
    echo "Getting the new disklabel from vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi

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

# appending to the disk label
echo "----------"
echo "Appending the new partition to the label."
cat >> $DISKLABEL_TMP << __EOF
  a:   $rd_size        0    4.2BSD    1024  8192  16 # (Cyl. 0 - $cylinders*)
__EOF
if [ $? -ne 0 ]; then
    echo "Appending to disklabel failed."
    vnconfig -u $vnode_device
    exit 1
fi

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

# now write the disklable
echo "----------"
echo "Writing the disklabel to $vnode_device."
disklabel -R $vnode_device $DISKLABEL_TMP
if [ $? -ne 0 ]; then
    echo "Writing new disklabel to vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi
rm -f $DISKLABEL_TMP

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

# creating new filesystem
echo "----------"
echo "Creating filesystem on /dev/r${vnode_device}a"
newfs -S 512 /dev/r${vnode_device}a
if [ $? -ne 0 ]; then
    echo "Creating new filesystem on vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi

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

# making the new filesystem directory
echo "----------"
echo "Making mount directory $VNODE_MOUNT."
mkdir $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Mkdir of $VNODE_MOUNT failed."
    vnconfig -u $vnode_device
    exit 1
fi

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

# mounting the new filesystem
echo "----------"
echo "Mounting vnode device /dev/r${vnode_device}a on directory $VNODE_MOUNT."
mount /dev/${vnode_device}a $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Mounting vnode device on $VNODE_MOUNT failed."
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

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

# copy the files over to the new system
FILES=`( cd $root_dir ; ls -d .??* * | egrep -v '^boot|^bsd|^usr' )`
cat << __EOF
----------
Copying files from $root_dir to $VNODE_MOUNT (no boot, bsd*, usr):
$FILES
This may take a while...
__EOF
( cd $root_dir ; tar -cf - $FILES ) | ( cd $VNODE_MOUNT ; tar -xpf - )
if [ $? -ne 0 ]; then
    echo "Copying other files from $root_dir to $VNODE_MOUNT failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

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

# making the /usr directory
cat << __EOF
----------
Making the /usr directory.
__EOF
mkdir $VNODE_MOUNT/usr
if [ $? -ne 0 ]; then
    echo "Mkdir $VNODE_MOUNT/usr failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi
chown root.wheel $VNODE_MOUNT/usr
if [ $? -ne 0 ]; then
    echo "Chown of $VNODE_MOUNT/usr failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi
chmod 755 $VNODE_MOUNT/usr
if [ $? -ne 0 ]; then
    echo "Chmod of $VNODE_MOUNT/usr failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

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

cat << __EOF
----------
If you have the compact flash and the root disk files in the same
directory, then you can put files in $root_dir with a .$FILE_EXTENSION extension
and this script will rename them to the filename without the .$FILE_EXTENSION.
For example, a different etc/fstab file is needed for each image.

__EOF

FILES=`( cd $VNODE_MOUNT ; find . -name '*.'$FILE_EXTENSION )`
if [ "$FILES" = "" ]; then
    echo "No *.$FILE_EXTENSION files found in $root_dir."
else
    for file in $FILES
    do
        new_file=`echo $file | sed -e "s/[.]$FILE_EXTENSION$//"`
        echo -n "Rename $file to $new_file? [yes] "
        read doit
        if [ "$doit" = "" ]; then
            doit=yes
        fi
        if [ "$doit" = "yes" ]; then
            mv $VNODE_MOUNT/$file $VNODE_MOUNT/$new_file
            if [ $? -eq 0 ]; then
                echo "   Done."
            else
                echo "Moving $file to $new_file failed."
                umount $VNODE_MOUNT
                rmdir $VNODE_MOUNT
                vnconfig -u $vnode_device
                exit 1
            fi
        fi
    done
fi

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

# syncing filesystems
sync

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

# unmounting the image
sync
echo "----------"
echo "Unmounting $VNODE_MOUNT."
umount $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Unmounting $VNODE_MOUNT failed."
    exit 1
fi
echo "Removing $VNODE_MOUNT directory."
rmdir $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Remolving directory $VNODE_MOUNT failed."
    # continue
fi

# removing the vnode
echo "Removing vnode device $vnode_device."
vnconfig -u $vnode_device
if [ $? -ne 0 ]; then
    echo "Removing vnode device $vnode_device failed."
    exit 1
fi

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

# writing image into kernel
echo "----------"
echo "Writing image file $image_file into kernel $kernel_file."
$RDSETROOT $kernel_file < $image_file
if [ $? -ne 0 ]; then
    echo "Writing image file $image_file into kernel $kernel_file failed."
    exit 1
fi

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

# sync to disk
sync

echo "----------"
echo "Done.  Updated kernel: $KERNEL_FILE"

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

echo "----------"
cf_root=$CF_ROOT
if [ ! -d $cf_root ]; then
    cf_root=$root_dir
fi

if [ -d $cf_root ]; then
    echo -n "Copy kernel $KERNEL_FILE into CF root directory $cf_root? [yes] "
    read doit
    if [ "$doit" = "" ]; then
        doit=yes
    fi
    if [ "$doit" = "yes" ]; then
        cp $KERNEL_FILE $cf_root
        if [ $? -ne 0 ]; then
            echo "Copying $image_file into CF root directory $cf_root failed."
            exit 1
        fi
        # sync to disk
        sync
        echo "Done."
    fi
fi

