#! /bin/sh
# Title: 
#    build-devosl.sh
# Function: 
#    Combine standard t20 image file with DSL kernel/initrd and patched 
#    grub files, to make a t20 image which will boot DSL off an external 
#    USB flash drive.
# Revisions:
#    v1.0 -    Apr 2007 - initial release
#    v1.1 -  6 May 2007 - minor tidying
# Usage:
#    ./build-devosl [SourceImage]
#
# If SourceImage is not specified, then the T20_STANDARD_FIRMWARE listed 
# below will be used.

T20_STANDARD_FIRMWARE="./U96CPQ163.bin"
GRUB_DIR="./grub-0.97"
MNT="./mnt-DEvoSL"
IMAGE="./bootp.bin"
LOOP="/dev/loop1"
KERNEL="./linux24"
INITRD="./minirt24.gz"


###########################################################################
## Exit with error message.
## First param is return code, remaining params are lines of error message.
#
Fail() {
   ExitCode=$1
   shift
   echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
   echo "$(basename $0): FATAL ERROR" >&2
   while [ $# -gt 0 ]; do
      echo "$1" >&2
      shift
   done
   sleep 2
   exit $ExitCode
}

###########################################################################
GRUB1="$GRUB_DIR/stage1/stage1"
GRUB2="$GRUB_DIR/stage2/stage2"

# allow firmware source image to be specified on command-line. 
[ "$1" ] && T20_STANDARD_FIRMWARE="$1"

echo "=== Sanity checks ================================================="

[ "$(whoami)" = "root" ] || {
   echo "!!! Warning - you don't seem to be root - this probably won't work...";
   sleep 4; 
   echo "Continuing anyway."
}

echo "Check that we can use losetup."
which losetup >/dev/null 2>/dev/null \
   || Fail 3 "Couldn't find losetup - is it installed?"

echo "Check that the chosen loop device exists."
ls "$LOOP" >/dev/null 2>/dev/null \
   || Fail 3 "Couldn't find loop device $LOOP" \
             "Maybe you need to use the MAKEDEV script?"

echo "Check that we can use dd."
which dd >/dev/null 2>/dev/null \
   || Fail 3 "Couldn't find dd - is it installed?"

echo "Check that we can use mkfs.vfat"
which mkfs.vfat >/dev/null 2>/dev/null \
   || Fail 3 "Couldn't find mkfs.vfat"

echo "Check that we can use the strings command."
which strings >/dev/null 2>/dev/null \
   || Fail 3 "Couldn't find strings command"

echo "Check/setup mount directory."
[ -e "$MNT" ] || {
   mkdir -p "$MNT" \
      || Fail 3 "Couldn't create mountpoint '$MNT'"
   chmod a+rwx "$MNT" \
      || Fail 3 "Couldn't chmod mountpoint '$MNT'"
}
[ -d "$MNT" ] \
   || Fail 3 "Mountpoint '$MNT' is not a directory."
[ -w "$MNT" ] \
   || Fail 3 "Mountpoint '$MNT' is not writable."

echo "Check source image exists and is readable."
[ -r "$T20_STANDARD_FIRMWARE" ] \
   || Fail 3 "Can't read from standard firmware '$T20_STANDARD_FIRMWARE'"

echo "Check grub stage1 and stage2 exist and are readable."
[ -r "$GRUB1" ] \
   || Fail 3 "Can't read grub stage1 '$GRUB1' - have you built it?"

[ -r "$GRUB2" ] \
   || Fail 3 "Can't read grub stage2 '$GRUB2' - have you built it?"


echo "Check kernel and initrd exist and are readable."
[ -r "$KERNEL" ] \
   || Fail 3 "Can't read kernel '$KERNEL'"
[ -r "$INITRD" ] \
   || Fail 3 "Can't read initrd '$INITRD'"


echo "=== Start working ================================================="
echo "Copying standard firmware '$T20_STANDARD_FIRMWARE' to working file '$IMAGE'"
cp "$T20_STANDARD_FIRMWARE" "$IMAGE" \
   || Fail 3 "Couldn't copy source '$T20_STANDARD_FIRMWARE' to working file '$IMAGE'"

echo "Searching for Master Boot Record."
MBR_SEARCH=$(strings -n20 -td "$IMAGE" | grep -Em1 "( )*[0-9]+( )+Invalid partition table$")
[ "$MBR_SEARCH" ] \
   || Fail 3 "Couldn't find MBR search string in image '$IMAGE'"

MBR_SEARCH_LOCATION=$(echo "$MBR_SEARCH" | grep -Eo '[0-9]+')

DISK_START=$(( $MBR_SEARCH_LOCATION - 139 ))
PART_TYPE_DD_SEEK=$(( $DISK_START + 450 ))
PART_START=$(( $DISK_START + 512 ))

echo "=== Make bootable ================================================="
echo "Setting the partition type as FAT (standard was NTFS)."
# Tweak byte at 0x1C2 offset from start of disk - change it to 6.
# Grub seems to want this to know how to handle the disk (most other things don't care).
# Use tail to make sure we get what we want regardless of which version of echo gets used.
# The use of tail is a workaround for differences between bash and dash.
echo -n -e '\006' | tail -c1 \
   | dd of="$IMAGE" bs=1 count=1 conv=notrunc seek=$PART_TYPE_DD_SEEK \
      || Fail 3 "Couldn't set partition type."

echo "Setting up loop for partition (start at $PART_START)."
losetup -o $PART_START "$LOOP" "$IMAGE" \
   || Fail 3 "Couldn't setup loop."

echo "Cleaning the partition, for tidiness."
dd if=/dev/zero of="$LOOP" 2>/dev/null

echo "Creating FAT filesystem with large reserved space (for grub)."
mkfs.vfat -R 200 "$LOOP" \
   || Fail 3 "Couldn't create filesystem."

echo "Installing grub stage1 (part1)."
# copy JMP from stage1
dd if="$GRUB1" of="$LOOP" bs=1 seek=0 skip=0 count=3 \
   || Fail 3 "Couldn't copy first part of stage1"

# leave FAT boot parameter block alone.

echo "Installing grub stage1 (part2)."
dd if="$GRUB1" of="$LOOP" bs=1 seek=62 skip=62 \
   || Fail 3 "Couldn't copy second part of stage1"

echo "Installing grub stage2."
dd if="$GRUB2" of="$LOOP" bs=512 seek=1 \
   || Fail 3 "Couldn't copy stage2"

echo "=== Copy files ===================================================="
echo "Mounting image."
mount "$LOOP" "$MNT" -t vfat \
   || Fail 3 "Couldn't mount loop '$LOOP'"

echo "Copying kernel."
cp "$KERNEL" "$MNT" \
   || Fail 3 "Couldn't copy kernel '$KERNEL'"

echo "Copying initrd."
cp "$INITRD" "$MNT" \
   || Fail 3 "Couldn't copy initrd '$INITRD'"

echo "=== Close up ======================================================"
echo "Unmounting image"
umount "$MNT" \
   || Fail 3 "Couldn't unmount loop."

echo "Detaching loop."
losetup -d "$LOOP" \
   || Fail 3 "Couldn't detach loop."

echo "Making image '$IMAGE' accessible by anyone."
chmod a+rw "$IMAGE" \
   || echo "WARNING: Couldn't chmod image."


echo "=== Finished! ====================================================="
echo "Done!  You should now flash the T20 with '$IMAGE'"
