#!/bin/sh

version=0.1

##############################################################################
# This is a script to install a second system on a wrap-board. A second      #
# system is an easy way for remote updates and desaster recovery. But as you #
# might know, living is at you own risk, so is using this script. It plays   #
# around with the boot loader (grub), and there is always a risk to loose    #
# your working system - so dont blame me if you have to show up personally   #
# at your router installation.                                               #
# Requirements: you need to have the grub-package installed, there is a      #
#  packaged version available at the place where you found this script or    #
#  you can compile one yourself using the OpenWrt Software Development Kit.  #
#  Additionally, you need to have the script sync_spare_partition_config     #
#  installed. So the configuration of your new system will be synchronized   #
#  with the current one to give you access after rebooting in the new        #
#  system.                                                                   #
# License: the code is licensed by Rene Ejury in 2007 under the GPL          #
##############################################################################

dir="/tmp/" # watch out not missing the last "/"
kernel_file="openwrt-x86-2.6-ext2.image.kernel"
fs_file="openwrt-x86-2.6-ext2.fs"

fecho() {
	spaces=$((73-${#1}))
	spacestr=""
	while [ $((spaces--)) -gt 0 ]; do spacestr=$spacestr" "; done
	echo "| $1$spacestr |"
}

fline() {
	echo "+---------------------------------------------------------------------------+"
}

fline
fecho "install_new_system version $version"
fline
fecho "ATTENTION: Please read the output of the script before rebooting the"
fecho "           router carefully. Errors might occure."
fline; echo


cd $dir

fline
fecho "checking if the new kernel and filesystem images are in $dir"
# check if new images are in memory and are the right size
if [ -e $fs_file ]; then
	fecho "found new filesystem image at $dir$fs_file"
else	
	echo "ERROR: $dir$fs_file missing"
	fline; exit 1
fi

if [ -e $kernel_file ]; then
	fecho "found new kernel image at $dir$kernel_file"
else	
	echo "ERROR: $dir$kernel_file missing"
	fline; exit 1
fi
fline; echo


fline
fecho "testing md5-checksums"

# check if new images are in memory and are the right size
if ! [ -e $fs_file".md5" ]; then
	fecho "md5sum: $(md5sum $fs_file)"
	echo "Continue? <y/N>"
	read REPLY
	if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]; then
		echo "aborted."
		fline; exit 1
	fi
fi
if ! [ -e $kernel_file".md5" ]; then
	fecho "md5sum: $(md5sum $kernel_file)"
	echo "Continue? <y/N>"
	read REPLY
	if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]; then
		echo "aborted."
		fline; exit 1
	fi
fi
fline; echo


fline
fecho "determine the working system partitions..."
# first check on which partitions we are working
work_system=$(ls -al /dev/root 2>/dev/null | awk 'BEGIN{FS="hda"}{print $2}')
if [ "$work_system" != "2" ] && [ "$work_system" != "4" ]; then
	fecho "ERROR: your working system seems to be partition /dev/hda$work_system"
	fecho "       this script is not made for your system, expecting root partition"
	fecho "       as partition /dev/hda2 or /dev/hda4"
	fline; exit 1
fi
fecho "ok, current working partition is /dev/hda$work_system"
fline; echo
if [ "$work_system" == "2" ]; then
	cur_kernel_part="1"; kernel_part="3"; fs_part="4"; new_grub_default="2"
else
	cur_kernel_part="3"; kernel_part="1"; fs_part="2"; new_grub_default="0"
fi


fline
fecho "checking if spare Partitions existing and big enough..."

kernel_part_size_blocks=$(awk '/hda'"$kernel_part"'/ {print $3}' /proc/partitions) 2>/dev/null
[ $? != 0 ] && { "ERROR: second partition for kernel not found."; exit 1; }
kernel_part_size_bytes=$(((($kernel_part_size_blocks*2)+1)*512))
kernel_file_size_bytes=$(ls -al $kernel_file | awk '{print $5}')
if [ $kernel_part_size_bytes -lt $kernel_file_size_bytes ]; then
	echo "ERROR: second kernel partition has size of $kernel_part_size_bytes bytes,"
	echo "       min. requiered size is $kernel_file_size_bytes bytes."
	echo "       please adapt your partition table. I won't do this for you."
	exit 1;
fi
fecho "partition /dev/hda$kernel_part (size: $kernel_part_size_bytes bytes) ..."
fecho " -> big enough for kernel (size: $kernel_file_size_bytes bytes)"

fs_part_size_blocks=$(awk '/hda'"$fs_part"'/ {print $3}' /proc/partitions) 2>/dev/null
[ $? != 0 ] && { "ERROR: second partition for filesystem not found."; exit 1; }
fs_part_size_bytes=$(((($fs_part_size_blocks*2)+1)*512))
fs_file_size_bytes=$(ls -al $fs_file | awk '{print $5}')
if [ $fs_part_size_bytes -lt $fs_file_size_bytes ]; then
	echo "ERROR: second filesystem partition has size of $fs_part_size_bytes bytes,"
	echo "       min. requiered size is $fs_file_size_bytes bytes."
	echo "       please adapt your partition table. I won't do this for you."
	exit 1;
fi
fecho "partition /dev/hda$fs_part (size: $fs_part_size_bytes bytes) ..."
fecho " -> big enough for filesystem (size: $fs_file_size_bytes bytes)"

fecho "ok, partition-table is looing ok."
fline; echo


fline
fecho "*** start to write the new system on partition /dev/hda$fs_part ***"
dd if=$fs_file of=/dev/hda$fs_part bs=512k
[ $? != 0 ] && { "ERROR: system partition dump failed"; exit 1; }
fecho "done."
#rm $dir$fs_file
fline; echo

fline
fecho "*** start to write the new kernel on partition /dev/hda$kernel_part ***"
dd if=$kernel_file of=/dev/hda$kernel_part bs=512k
[ $? != 0 ] && { "ERROR: kernel partition dump failed"; exit 1; }
fecho "done."
#rm $dir$kernel_file
fline; echo

fline; fecho "*** checking new system on partition /dev/hda$fs_part ***"
e2fsck /dev/hda$fs_part
[ $? != 0 ] && { "ERROR: system partition broken"; exit 1; }
fecho "done."; fline; echo

fline; fecho "*** checking new kernel on partition /dev/hda$kernel_part ***"
e2fsck /dev/hda$kernel_part
[ $? != 0 ] && { "ERROR: kernel partition broken"; exit 1; }
fecho "done."; fline; echo

# replace menu.lst (use new one as a base)
fline
fecho "*** Adapting boot menu to use new system ***"
mkdir -p /tmp/boot_old
mount /dev/hda$cur_kernel_part /tmp/boot_old
mkdir -p /tmp/boot_new
mount /dev/hda$kernel_part /tmp/boot_new

awk '{if ($0 ~ "default") print "default '"$new_grub_default"'"; else {gsub("OpenWrt","OpenWrt-1"); if (/kernel/ && !/nodma/) print $0" ide=nodma"; else print}}' /tmp/boot_new/boot/grub/menu.lst >/tmp/menu.lst
echo >>/tmp/menu.lst
awk '{if (/title/) start=1; if (start == 1) {gsub("OpenWrt","OpenWrt-2"); gsub("hda2","hda4"); gsub("hd0,0","hd0,2"); if (/kernel/ && !/nodma/) print $0" ide=nodma"; else print}}' /tmp/boot_new/boot/grub/menu.lst >>/tmp/menu.lst

cp /tmp/menu.lst /tmp/boot_new/boot/grub/menu.lst
mv /tmp/menu.lst /tmp/boot_old/boot/grub/menu.lst

umount /tmp/boot_old
umount /tmp/boot_new

fecho "done."
fline; echo



fline
fecho "*** Starting grub and writing new boot loader... ***"
grub --batch --no-curses --no-floppy <<EOF
device (hd0) /dev/hda
root (hd0,0)
setup (hd0)
quit
EOF
[ $? != 0 ] && { "ERROR: grub failed"; exit 1; }
fecho "done."
fline; echo

fline
fecho "*** syncing configuration of new partition ***"
/usr/sbin/sync_spare_partition_config
fline; echo

fline
fecho "Ok, it's done. Your new system seems ready to boot. Just restart the router"
fline