#! /bin/sh

exec 2>/var/log/kickstart-custom-firmware
set -x

PATH="$PATH:/sbin:/usr/sbin"

# Use multiple of 4096 as blocksize for dd.
dd_bs=$((4096 * 10))

echo -e "Content-Type: multipart/mixed; boundary=BoUnDaRy\r"
echo -e "\r"
echo -e "--BoUnDaRy\r"
echo -e "Content-Type: text/html\r"
echo -e "Content-Disposition: inline\r"
echo -e "\r"

cat << EOT
<html>
<head>
	<title>Custom Firmware</title>
</head>
<body>
<h3>Custom Firmware</h3>
<p>
A new firmware image will be generated. The default settings of the new
firmware will be the current setting of this unit. You can use the generated
firmware to upgrade this unit and units identical to this unit. This unit will
not be altered by this operation.
</p>

<h4>Progress</h4>
EOT

fail() {
	trap "" EXIT PIPE
	echo "</p><p><b>FAILED!</b></p></body></html>" || :
	kill $! 2>/dev/null || :
	wait

	# Restore release file
	[ "$etc_release_old" ] && echo "$etc_release_old" > /etc/release
	etc_release_old=
	[ "$cleanup_rw" ] && eval $cleanup_rw
	cleanup_rw=
	[ "$cleanup_ro" ] && eval $cleanup_ro
	cleanup_ro=

	init 3
	exit 1
}

# waitfor "Text to be displayed while waiting" command
waitfor() {
	echo -n "<p>$1. . . . . "
	while eval $2; do
		sleep 1
		echo -n ". "
	done
	echo " done</p>"
}

# hex2dec hexcode
hex2dec() {
	hex="$1"
	dec=0
	mult=1

	while [ "$hex" ]; do
		hexdigit=`echo "$hex" | sed 's/^.*\(.\)$/\1/'`
		hex=`echo "$hex" | sed 's/^\(.*\).$/\1/'`

		case $hexdigit in
			[Aa])
				decdigit=10
				;;
			[Bb])
				decdigit=11
				;;
			[Cc])
				decdigit=12
				;;
			[Dd])
				decdigit=13
				;;
			[Ee])
				decdigit=14
				;;
			[Ff])
				decdigit=15
				;;
			*)
				decdigit=$hexdigit
				;;
		esac

		dec=$(($dec + ( $decdigit * $mult ) ))
		mult=$(($mult * 16))
	done

	echo $dec
}

# filesize filename
filesize() {
	ls -l "$1" | sed 's/ \+/ /g' | cut -d ' ' -f 5
}

# append srcfile destfile
append() {
	mkdir split
	size=`filesize $1`
	count=$(($size / $dd_bs))
	while [ $count -gt 0 ]; do
		dd if="$1" of="split/$count" bs=$dd_bs skip=$count
		dd if=/dev/null of="$1" bs=$dd_bs seek=$count
		count=$(($count - 1))
		echo -n ". "
	done
	mv "$1" "split/0"
	cd split
	for file in `echo * | tr ' ' '\n' | sort -n`; do
		cat $file >> ../$2
		rm $file
		echo -n ". "
	done
	cd ..
	rmdir split
}

# pad filename sizeofpadding
pad() {
	count=$(($2 / $dd_bs))
	remainder=$(($2 % $dd_bs))
	if [ $count -gt 0 ]; then
		dd if=/dev/zero bs=$dd_bs count=$count | tr '\0' '\377' >> $1
	fi
	if [ $remainder -gt 0 ]; then
		dd if=/dev/zero bs=$remainder count=1 | tr '\0' '\377' >> $1
	fi
}

etc_release_old=
cleanup_rw=
cleanup_ro=
trap fail EXIT PIPE
init 4
set -e

waitfor "Waiting for processes to be stopped" \
	'ps | grep -v grep | grep "/etc/init.d/rc 4" > /dev/null'

echo -n "<p>Generating new release string: "
. /usr/share/axis-release/variables
custom_version=`echo "$RELEASE" | sed 's/^.*-custom\([0-9]\+\)$/\1/'`
if [ "$custom_version" = "$RELEASE" ]; then
	custom_version=0
else
	RELEASE=`echo "$RELEASE" | sed "s/^\(.*\)-custom[0-9]\+$/\1/"`
fi
RELEASE="$RELEASE-custom$(($custom_version + 1))"
echo "\"<code>$RELEASE</code>\"</p>"

echo -n "<p>Changing values of unit-unique parameters. . . . . "
# Find out fs type and mount point of rw-filesystem
fstype="${MOUNT#*-t }"
if [ ! -z $fstype ]; then
	fstype="${fstype%% *}"
	mpoint="${MOUNT#*/dev/* }"
	mpoint="${mpoint%% *}"
else
	fstype="$FS_TYPE_part_rwfs"
	mpoint=`mount | grep rwfsblock | cut -d' ' -f3`
fi


# Hide all but the read-write partition itself
mkdir rw
cleanup_rw="rmdir rw"
mount --bind $mpoint rw
cleanup_rw="umount rw && $cleanup_rw"

# Copy conf.d and replace some variables
mount -t tmpfs tmpfs rw/etc/conf.d/
cleanup_rw="umount rw/etc/conf.d && $cleanup_rw"
cp -a /etc/conf.d/* rw/etc/conf.d/
#if [ -e /etc/conf.d/ftpbanner ]; then
#	sed 's/^[[:space:]]*FTPBANNER_SET_BANNER=.*/FTPBANNER_SET_BANNER=yes/' \
#		/etc/conf.d/ftpbanner > rw/etc/conf.d/ftpbanner
#fi
if [ -e /etc/conf.d/hostname ]; then
	sed 's/^[[:space:]]*HOSTNAME=.*/HOSTNAME=""/' \
		/etc/conf.d/hostname > rw/etc/conf.d/hostname
fi
if [ -e /etc/conf.d/mac ]; then
	sed 's/^[[:space:]]*MAC=.*"/MAC="00:40:8C:CD:00:00"/' \
		/etc/conf.d/mac > rw/etc/conf.d/mac
fi
#if [ -e /etc/conf.d/parhand ]; then
#	sed 's/^[[:space:]]*PARHAND_SET_DEFAULTS=.*/PARHAND_SET_DEFAULTS=yes/' \
#		/etc/conf.d/parhand > rw/etc/conf.d/parhand
#fi
if [ -e /etc/conf.d/upnp ]; then
	sed 's/^[[:space:]]*UPNP_FRIENDLYNAME=.*/UPNP_FRIENDLYNAME=""/' \
		/etc/conf.d/upnp > rw/etc/conf.d/upnp
fi
if [ -e /etc/conf.d/libupnp ]; then
	sed 's/^[[:space:]]*UPNP_FRIENDLYNAME=.*/UPNP_FRIENDLYNAME=""/' \
		/etc/conf.d/libupnp > rw/etc/conf.d/libupnp
fi
if [ -e /etc/conf.d/rendezvous ]; then
	sed 's/^[[:space:]]*RENDEZVOUS_FRIENDLYNAME=.*/RENDEZVOUS_FRIENDLYNAME=""/' \
		/etc/conf.d/rendezvous > rw/etc/conf.d/rendezvous
fi
mount -t tmpfs tmpfs rw/etc/sysconfig/
cleanup_rw="umount rw/etc/sysconfig && $cleanup_rw"
cp -a /etc/sysconfig/* rw/etc/sysconfig/
if [ -e /etc/sysconfig/rtp.conf ]; then
	sed 's/^[[:space:]]*\(\(\(Audio\)\|\(Video\)\)Address\)[[:space:]]*=.*/\1 = "auto matic"/' \
		/etc/sysconfig/rtp.conf > rw/etc/sysconfig/rtp.conf
fi

# Change JFFSID temporarily
if [ -e /etc/release ]; then
	etc_release_old=`cat /etc/release`
	etc_release=`sed "s/^JFFSID=.*\"/JFFSID=\"$RELEASE\"/" /etc/release`
	echo "$etc_release" > /etc/release
fi

echo " done</p>"

if grep "^cpu[[:space:]]*:[[:space:]]*CRIS" /proc/cpuinfo >/dev/null; then
	pagesize=8192
else
	pagesize=
fi
mtd2size=`grep '^mtd2:' /proc/mtd | sed "s/^mtd2: \([0-9a-f]\+\).*$/\1/"`
if [ "$fstype" = jffs ]; then
	# Free some space
	rm -f sbin/mkfs.jffs?

	mkfs.jffs -q rw > flash2.img &
else
	# Free some space
	rm -f sbin/mkfs.jffs

	# Assume jffs2 for now
	if [ "$pagesize" ]; then
		pagesize_opt="--pagesize=$pagesize"
	else
		pagesize_opt=
	fi
	mkfs.jffs2 --little-endian $pagesize_opt --cleanmarkers \
		   --pad=0x$mtd2size --root=rw > flash2.img &
fi
waitfor "Creating read-write filesystem" 'test -d /proc/$!'
wait $!

# Free some space
rm -f sbin/mkfs.jffs*

# Restore release file
echo "$etc_release_old" > /etc/release
etc_release_old=

# Cleanup
eval $cleanup_rw
cleanup_rw=

if [ "$fstype" = jffs ]; then
	pad flash2.img $((`hex2dec $mtd2size` - `filesize flash2.img`))
fi

echo -n "<p>Changing version of new firmware. . . . . "

# Hide all but the root partition itself
mkdir ro
cleanup_ro="rmdir ro"
mount -o bind / ro
cleanup_ro="umount ro && $cleanup_ro"

# Add -customN to release string
mount -t tmpfs tmpfs ro/usr/share/axis-release
cleanup_ro="umount ro/usr/share/axis-release && $cleanup_ro"
cp -a /usr/share/axis-release/* ro/usr/share/axis-release/
sed "s/^RELEASE=.*/RELEASE=\"$RELEASE\"/" \
	/usr/share/axis-release/variables > ro/usr/share/axis-release/variables

# Copy defaultfiles, replace jimage and edit jimageid to match jffsid
mount -t tmpfs tmpfs ro/usr/etc/defaultfiles/
cleanup_ro="umount ro/usr/etc/defaultfiles && $cleanup_ro"
cp -a /usr/etc/defaultfiles/* ro/usr/etc/defaultfiles/
cp flash2.img ro/usr/etc/defaultfiles/jimage
if [ -e /etc/release ]; then
	sed "s/^JIMAGEID=.*\"/JIMAGEID=\"$RELEASE\"/" \
		/usr/etc/defaultfiles/jimageid \
		> ro/usr/etc/defaultfiles/jimageid
fi

echo " done</p>"

if [ "$pagesize" ]; then
	blocksize_opt="-b $pagesize"
else
	blocksize_opt=
fi
# Create cramfs image
mkcramfs $blocksize_opt ro rootfs.img >/dev/null &
waitfor "Creating read-only filesystem" 'test -d /proc/$!'
wait $!

# Free some space
rm -f sbin/mkcramfs

# Cleanup
eval $cleanup_ro
cleanup_ro=

echo -n "Assembling firmware image file. . . . . "

# Copy RFL but pad instead of copying bootblock parameters
dd if=/dev/cflash0 of=fimage bs=1024 count=48
pad fimage $((16 * 1024))

# Create new flash1 image
cramfs_offset=`imgtool -f cramfs -p 0 /dev/cflash1`
count=$(($cramfs_offset / $dd_bs))
remainder=$(($cramfs_offset % $dd_bs))
if [ $count -gt 0 ]; then
	dd if=/dev/cflash1 of=flash1.img bs=$dd_bs count=$count
fi
if [ $remainder -gt 0 ]; then
	dd if=/dev/cflash1 of=flash1.img.2 bs=$dd_bs skip=$count count=1
	dd if=flash1.img.2 bs=$(($cramfs_offset % $dd_bs)) count=1 >> flash1.img
	rm flash1.img.2
fi
append rootfs.img flash1.img

# Calculate pad size for flash1
fullsize=`grep '^mtd1:' /proc/mtd | sed "s/^mtd1: \([0-9a-f]\+\).*$/\1/"`
fullsize=`hex2dec $fullsize`
cursize=`filesize flash1.img`
if [ $cursize -gt $fullsize ]; then
	echo "too big! Decrease size of custom modifications and try again."
	fail
fi
padsize=$(($fullsize - $cursize))

# Assemble fimage (memory critical section)
append flash1.img fimage
pad fimage $padsize
append flash2.img fimage

HWID=`bootblocktool -nocgi -x HWID`
HWID="${HWID%%.*}"

imgtool -c -i "$HWID" -s fimage >/dev/null

# Free some space
rm usr/bin/imgtool

length=`filesize fimage`

echo " done</p>"

cat << EOT
<p>The new firmware image is ready and will now be sent to your browser.</p>

<hr>
<p><i>
If your browser displays binary data after this paragraph, it probably does not
support the <code>multipart/mixed MIME type</code>. Or it does not know how to
handle the <code>application/octet-stream</code> MIME type. If there is any
problem receiving the firmware, try a different browser!
</i></p>
EOT

trap - EXIT

echo -e "\r"
echo -e "--BoUnDaRy\r"
echo -e "Content-Type: application/octet-stream\r"
echo -e "Content-Disposition: attachment; filename=\"$RELEASE.bin\"\r"
echo -e "Content-Length: $length\r"
echo -e "\r"

dd if=fimage

echo -e "\r"
echo -e "--BoUnDaRy--\r"

init 3

exit 0
