#! /bin/bash
# by Andrew Clausen <clausen@gnu.org>
# Copyright (C) 2003 Silicon Graphics, Inc.
#
# This program is free software.  It may be modified and/or distributed
# under the terms of the GNU General Public Licence version 2 or later,
# as published by the Free Software Foundation, Inc.  There is NO WARRANTY.
#
#
# "All problems in software engineering can be solved by adding another
#  layer of indirection"
#	-- folklore (?)
#
# This file can be found at http://members.optusnet.com.au/clausen/sgi
#
# This shell script makes ip22 and ip27 bootable CDs.  It modifies
# prepared Debian install CDs.  Note that you must create a big empty file
# (for ip27) on the CD image.
# 
#
# In the ip22 case (untested): the "internal" (-i) option should be used.
# This creates an entry in the volume header for a particular file on the ISO.
#
# In the ip27 case: the "external" (-e) option should be used.  This copies
# an external file onto an XFS image which is stored in the "empty" file.
# The empty file is mapped onto a partition, which the PROM can read from.
# The motivation for this mess is:
#	(1) the PROM can't read from the volume header.  (The ip27 PROM
# is broken)  It must therefore read from an xfs partition.
#	(2) Linux doesn't support partition tables on CDs.
# To satisfy both Linux and the PROM, Linux must believe there is no
# partition table, and the PROM must believe there is one.  This is all
# complicated by partition table requirements for cylinder alignment and
# such.  Hence the smoke and mirrors.  Here's some ASCII art describing the
# ip27 situation:
#
#	+---------------------------------------------------------------+
#	| +-----------+			+---------------------------+	|
#	| | Volume    |			| "empty file"		    |	|
#	| | Header    |	ISO image	|	+-----------------+ |	|
#	| |	      |			|	| XFS partition   | |	|
#	| | +-------+ |			|	| +------------+  | |	|
#	| | | linux ======POINTS==================>linux kernel|  | |	|
#	| | +-------+ |			|	| +------------+  | |	|
#	| +-----------+			|	+-----------------+ |	|
#	|				+---------------------------+	|
#	+---------------------------------------+-----------------------+
#						|
#						^ cylinder boundary
#
#
#  You probably want to build CDs like this:
#
#	mkdir iso_mnt
#	mkdir cd_contents
#	mount -o loop debian-mips-cd1.iso iso_mnt
#	(cd iso_mnt; tar c .) | (cd cd_contents; tar x)
#	dd if=/dev/zero of=cd_contents/bootdata bs=20M count=1
#	cp indy-kernel-if-you-want.img iso_mnt/indy-linux
#	umount iso_mnt
#
#	mkisofs -o iso.img -R cd_contents/
#
#	./gen-mips-cd iso.img bootdata -e vmlinux.64 linux -i linux indy-linux


fail() {
	umount xfs_mnt
	umount iso_mnt
	exit 1
}

error() {
	echo $1
	fail
}

warn() {
	echo "warning: $1"
}

usage() {
	cat << EOF
use: gen-mips-cd iso empty-file [-i name:path]... [-e path:path]...

iso		the official Debian MIPS CD1 ISO image to be boot-ified.
		It need not be mounted (gen-mips-cd will mount it)
empty-file	the path of the big empty file inside the iso that
		can be overwritten
[-i name path]	add an internal boot file: this file should already
		exist on the iso, and will be added to the volume
		header.  The path should be relative to the root
		of the iso-in root.
[-e dst-path src-path]	add an external boot file.  It will
		be stored in an xfs partition on the CD that is
		stored in empty-file... so there must be room!
EOF
	fail
}

if [ $# -lt 2 ]; then
	usage
fi

echo "gen-mips-cd, by Andrew Clausen <clausen@gnu.org>"
echo "Copyright (C) 2003 Silicon Graphics"

ISO=$1
EMPTY_FILE=$2
shift 2

BLOCK_SIZE=2048
CYL_BLOCKS=8

[ ! -e iso_mnt ] && mkdir iso_mnt
[ ! -e xfs_mnt ] && mkdir xfs_mnt

echo mounting iso...
echo mount $ISO iso_mnt -o loop || fail
mount $ISO iso_mnt -o loop || fail
[ -e iso_mnt/$EMPTY_FILE ] || error "$EMPTY_FILE doesn't exist"

BLOCK_RANGE=$(./fblocks iso_mnt/$EMPTY_FILE $BLOCK_SIZE | tail -1)
BLOCK_START=$(echo $BLOCK_RANGE | sed s/+.*//)
BLOCK_LEN=$(echo $BLOCK_RANGE | sed s/.*+//)
SAFE_LEN=$[$BLOCK_LEN - 2 * $CYL_BLOCKS]

echo creating xfs image...
[ -e xfs_image ] && rm xfs_image
dd if=/dev/zero of=xfs_image bs=$BLOCK_SIZE count=$SAFE_LEN || fail
/sbin/mkfs.xfs xfs_image || fail

echo mounting xfs image...
mount -o loop xfs_image xfs_mnt || fail

while [ $# -gt 0 ]; do
	case $1 in
		-i)	echo internal $2 $3
			F_BLOCK_RANGE=$(./fblocks iso_mnt/$3 $BLOCK_SIZE \
					| tail -1)
			F_BLOCK_START=$(echo $F_BLOCK_RANGE | sed s/+.*//)
			F_BLOCK_LEN=$(echo $F_BLOCK_RANGE | sed s/.*+//)
			F_START=$[$BLOCK_START * $BLOCK_SIZE]
			F_LEN=$[$BLOCK_LEN * $BLOCK_SIZE]
			GENISOVH_CMD="$GENISOVH_CMD $2:$F_START,$F_LEN"
			shift 3;;

		-e)	echo adding $3 to xfs_mnt/$2
			cp $3 xfs_mnt/$2 || fail
			shift 3;;

		*)	echo "invalid option '$1'"; usage;;
	esac
done

umount xfs_mnt
umount iso_mnt

echo ./genisovh $ISO $GENISOVH_CMD \
	4:$[$BLOCK_START * $BLOCK_SIZE],$[$BLOCK_LEN * $BLOCK_SIZE],xfs_image

./genisovh $ISO $GENISOVH_CMD \
	4:$[$BLOCK_START * $BLOCK_SIZE],$[$BLOCK_LEN * $BLOCK_SIZE],xfs_image

