#!/bin/sh
#
# Contact: Neil MacLeod <maemo@nmacleod.com>
#
# v1.22 nupgrade.sh
#
# Script to "clone" IT OS to an internal or external memory card.
#
# In order to better support the N810, this script will attempt to
# identify an appropriate memory card as the "target" based on
# available partitions and partition types - only partition
# type 83 (Linux) will be considered. The internal card will be
# checked first, followed by the external card. Only the second
# partition on each device is currently supported by this script.
#
# Individual cloning phases (0-6) can be executed manually, or two
# grouped activites are available:
#
#      wipe  - Format the target with an ext2|3 filesystem then clone the OS [phases 0-4]
#      clone - Retain the existing filesystem and clone the OS [phases 1-4]
#
# v1.00 - 08 Aug 2007: Initial release
# v1.10 - 12 Dec 2007: Add "clone" parameter support
# v1.20 - 22 Jan 2008: Add "wipe" parameter support, partition detection, rewritten
# v1.21 - 23 Jan 2008: Added optional ext3 support
# v1.22 - 30 Jan 2008: Added external/internal and yes parameters
# v1.23 - 01 Mar 2008: Tighten up prompt validation
#
#

showUsage ()
{
	echo Usage "$0 0-6|wipe|clone [internal | external] [ext2 | ext3] [sardine | herring] [yes]"
}

# Set BINDIR
getBinDir ()
{
	BINDIR=/mnt/initfs/lib/modules/current
	[ ! -d $BINDIR ] && BINDIR=/mnt/initfs/lib/modules/2.6.18-omap1
	[ ! -d $BINDIR ] && BINDIR=/mnt/initfs/lib/modules/`uname -r`

	if [ ! -f $BINDIR/mbcache.ko ]; then
		echo "Unable to locate mbcache.ko - aborting"
		exit 1
	fi
}

# Set Target device and partition
getTarget ()
{
# Return immediately if already determined
	[ ! -z $TARGET ] && return

	INTERNAL=/dev/mmcblk0
	EXTERNAL=/dev/mmcblk1
	PARTITION=p2
	LINUXFS=83
	
# Start with internal card, second partition
	if [ -z $TARGET ]; then
		if [ "$USER_DEVICE" != "external" ]; then
			device=$INTERNAL
			partition=${device}${PARTITION}
			fstype=`sfdisk -l -d $device | grep $partition | sed "s/Id= *//g" | awk '{print $7}'`
			if [ "$fstype" = "$LINUXFS" ]; then
				TARGET=$partition
				TDESC="Internal Flash card, second partition"
			fi
		fi
	fi

# then check external card, second partition
	if [ -z $TARGET ]; then
		if [ "$USER_DEVICE" != "internal" ]; then
			device=$EXTERNAL
			partition=${device}${PARTITION}
			fstype=`sfdisk -l -d $device | grep $partition | sed "s/Id= *//g" | awk '{print $7}'`
			if [ "$fstype" = "$LINUXFS" ]; then
				TARGET=$partition
				TDESC="External Flash card, second partition"
			fi
		fi
	fi

	if [ ! -z $TARGET ]; then
		echo
		echo "      Target device: $TDESC ($TARGET)"
		echo "   Using filesystem: ${FILESYSTEM}fs"

		[ "$CONFIRM" = "N" ] && return

		echo -n "Continue? (YES/no) : "
		read ans
		ans=`echo $ans|tr 'a-z' 'A-Z'`
		[ "$ans" = "" ] && return
		[ "$ans" = "YES" ] && return
	else
		echo "Unable to identify target device and partition with a valid Linux filesystem (type $LINUXFS)"
	fi

	echo "*** TERMINATING ***"
	exit 1
}

loadModules ()
{
	getBinDir

	[ "`lsmod|grep mbcache`" = "" ] && insmod $BINDIR/mbcache.ko

	if [ $FILESYSTEM = ext3 ]; then
		[ "`lsmod|grep jbd`" = "" ] && insmod $BINDIR/jbd.ko
		FILESYSTEM_OPTIONS="-o noatime"
	fi

	[ "`lsmod|grep $FILESYSTEM`" = "" ] && insmod $BINDIR/$FILESYSTEM.ko
}

phase0 ()
{
	echo "Reformatting $TDESC for ${DNAME} using ${FILESYSTEM}fs..."

	loadModules

	mkfs.$FILESYSTEM -L $DNAME $TARGET

	sync
	sync
	sync
}

phase1 ()
{
	echo "Installing $FILESYSTEM.ko module and mounting $TDESC..."

	loadModules

	[ ! -d /opt ] && mkdir /opt
	[ "`grep "/opt " /etc/mtab`" = "" ] && mount $TARGET /opt $FILESYSTEM_OPTIONS
	
	return 0
}

phase2 ()
{
	echo "Mouting jffs2 root partition on /floppy loopback"

	[ ! -d /floppy ] && mkdir /floppy
	[ "`grep "/floppy " /etc/mtab`" = "" ] && mount -t jffs2 /dev/mtdblock4 /floppy -o rw,rpsize=1024,rpuid=0,rpuid=30000

	return 0
}

phase3 ()
{
	echo "Copying Flash filesystem to $TDESC"

	/home/user/bin/tar cf - -C /floppy . | /home/user/bin/tar xvf - -C /opt
	touch /opt/CLONE-COPY
}

phase4 ()
{
	echo "Committing updates and Unmounting filesystems"

	sync
	sync
	sync

	[ "`grep "/opt " /etc/mtab`" != "" ] && umount /opt
	[ "`grep "/floppy " /etc/mtab`" != "" ] && umount /floppy

	return 0
}

phase5 ()
{
	echo "Mounting $TDESC and changing root context"

	loadModules

	[ "`grep "/opt " /etc/mtab`" = "" ] && mount $TARGET /opt/ $FILESYSTEM_OPTIONS
	chroot /opt/
}

phase6 ()
{
	echo "Upgrading $TDESC to ${DNAME}..."

	[ -f /CLONE-COPY ] && rm /CLONE-COPY
	touch /CLONE-`echo $DISTRO | tr 'a-z' 'A-Z'`

	cd /etc/apt

	mkdir /tmp/.run

	echo "#maemo:essential" >sources.list
	echo "deb http://repository.maemo.org/${DISTRO} unstable main non-free" >>sources.list

	if [ $DISTRO = sardine ]; then
		apt-get update
		apt-get install hildon-application-framework
		apt-get -y --force-yes upgrade
	else
		apt-get update
		apt-get -y --force-yes upgrade
	fi

	sync
	sync
	sync
}

phasewipe ()
{
	phase0 || exit 0
	phaseclone || exit 0
}

phaseclone ()
{
	phase1 || exit 0
	phase2 || exit 0
	phase3 || exit 0
	phase4 || exit 0
}

# Main

DISTRO=sardine
DNAME=Sardine
FILESYSTEM=ext2
FILESYSTEM_OPTIONS=

BINDIR=
TARGET=
TDESC=
PHASE=
CONFIRM=Y
USER_DEVICE=

if [ `id -u` != 0 ]; then
	echo "You must be logged in as root to execute this script"
	exit 0
fi

if [ $# = 0 ]; then
	showUsage
	exit 1
fi

for arg in $*;
do
	case $arg in
		[0-6]|wipe|clone) PHASE=$arg;;
		ext2|ext3) FILESYSTEM=$arg;;
		sardine) DISTRO=$arg; DNAME=Sardine;;
		herring) DISTRO=$arg; DNAME=Herring;;
		internal|external) USER_DEVICE=$arg;;
		yes) CONFIRM=N;;
		*)	echo Argument with value $arg is invalid;
			showUsage;
			exit 1;;
	esac
done

[ -z $PHASE ] && (echo "Phase argument 0-6|clone|wipe must be specified!"; showUsage; exit 1;)

# Setup the target device/partition
getTarget

# Call the requested phase
phase$PHASE

echo Done
