#!/bin/sh
#
# nitdroid-installer	Install NITDroid, an Android port to N900
#
#	Copyright (c) 2010  Jay Cartman <jay.cartman@gmail.com>
#

## Config

# Version
VER=0.2.6

# Nitdroid manifest file
MANIFEST_FILE=nitdroid.manifest
MANIFEST_URL=http://downloads.nitdroid.com/nitinstaller/${MANIFEST_FILE}

# Root device
ROOT_DEV='/dev/mmcblk1p2'

# Filesystem options
ROOT_OPTS='rw,noatime,errors=remount-ro'

# Options
FDISK_MMC='TRUE'
FORMAT_VFAT='TRUE'
FORMAT_ROOT='TRUE'
PURGE_KERNELS='TRUE'

# Package storage
PKGDIR='/home/user/MyDocs/.nitdroid'

# Verbose log file
LOG_FILE="${PKGDIR}/installer.log"


## Logging Functions

INIT()
{
	set -e

	trap ERROR SIGINT
	trap ERROR SIGHUP
	trap ERROR SIGQUIT

	test -d ${PKGDIR} || mkdir -p -m 0755 ${PKGDIR}

	exec 5>$LOG_FILE

	echo -e "\n*** NITDroid installer ${VER} on $(date)\n" >&5

	safe uname -a
	safe sfdisk -l
	safe df -h
}

ERROR()
{
	echo "*** ERROR - CLEANING UP THE CRAP" >&5

	quiet umount /and

	quiet resume_process ke-recv

	exit 1
}

FAIL()
{
	echo "!!!" "$@" >&5
	echo "FAILURE. Bailing out." >&2
	ERROR
}

MSG()
{
	echo "***" "$@" >&5
	echo -ne "$@" "..." >&2
}

END()
{
	echo "*** DONE" >&5
	echo "done" >&2
}

LOG()
{
	echo "===" "$@" >&5
	echo -e "$@"  >&2
}

RUN()
{
	eval "$@" >&5 2>&5
}

safe()
{
	echo "--- RUN [$@]" >&5
	RUN "$@" || FAIL "ERROR:$?" "$@"
	echo "--- END [$@]" >&5
}

quiet()
{
	eval "$@" >/dev/null 2>/dev/null
}


## Utility functions

suspend_process()
{
	PID=$(pidof $1)
	if [ -f /proc/$PID/status ]
	then
		kill -STOP $PID
	fi
}


resume_process()
{
	PID=$(pidof $1)
	if [ -f /proc/$PID/status ]
	then
		kill -CONT $PID
	fi
}


## Uninstall functions

init_fake_and()
{
	safe install -d -m 0700 /and
	safe mount -t tmpfs -o rw,nosuid,noatime,size=256k,mode=755 tmpfs /and
	safe install -d /and/system/etc
}

done_fake_and()
{
	safe umount /and
}


uninstall_crap()
{
	MSG "Uninstalling any incompatible software"
	  safe dpkg --purge bootmenu
	  safe dpkg --purge bootmenu-n900
	  safe dpkg --purge multiboot-extras
	END

	## Remove old kernels

	if [ X${PURGE_KERNELS} = XTRUE ]
	then
		init_fake_and

		for list in /var/lib/dpkg/info/nitdroid-kernel-*.list
		do
			if [ -f $list ]
			then
				pkg=${list##*/nitdroid-kernel-}
				ver=${pkg%%.list}

				MSG "Uninstalling kernel $ver"
				  safe dpkg --purge nitdroid-kernel-$ver
				END
        		fi
		done

		for mod in /lib/modules/2.6.28.NIT.*
		do
			if [ -d $mod ]
			then
				ver=${mod##*/}

                		MSG "Removing manual kernel $ver"
				  rm -f /boot/vmlinuz-$ver
				  rm -f /boot/multiboot/vmlinuz-$ver
				  rm -f -r $mod
				END
			fi
        	done

		done_fake_and
	fi
}

create_uninstall_icon()
{
echo "[Desktop Entry]
Encoding=UTF-8
Version=1.0
Name=NITDroid Uninstaller
Comment=Partitions a microSD and installs nitdroid on it
Exec=sudo nitdroid-uninstaller
Icon=nitdroid-installer
Terminal=true
Type=Application" > /usr/share/applications/hildon/nitdroid-installer.desktop
touch /usr/share/applications/hildon/nitdroid-installer.desktop
}


## MMC Functions

get_mmc_size()
{
	sfdisk -s /dev/mmcblk1
}


get_fat_size()
{
	MMC=$(get_mmc_size)

	if [ $MMC -gt 3840000 ] ; then
		FAT=$(expr $MMC - 2000000)
	elif [ $MMC -gt 1920000 ] ; then
		FAT=$(expr $MMC - 1000000)
	elif [ $MMC -gt 960000 ] ; then
		FAT=$(expr $MMC - 500000)
	elif [ $MMC -gt 480000 ] ; then
		FAT=$(expr $MMC - 250000)
	else
		FAIL "Your MMC card (${MMC}kb) is not big enough for NITDroid. Sorry."
	fi

	echo ${FAT}
}


erase_block()
{
	quiet dd if=/dev/zero of=$1 bs=1k count=$2
}


try_erase()
{
	T=$3

	until erase_block $1 $2
	do
		T=$(expr $T - 1)
		test $T -gt 0 || return 1
		sleep 1
	done
}


unmount_ext_mmc()
{
	cat /proc/mounts | while read dev dir rest
	do
		case $dev in
		    /dev/mmcblk1*)
			MSG "Unmounting $dev"
			  safe umount $dev
			  sync
			END
			;;
		esac
	done
}


fdisk_ext_mmc()
{
	if [ X${FDISK_MMC} = XTRUE ]
	then
		MMC=$(get_mmc_size)
		FAT=$(get_fat_size)

		MSG "Creating partitions"

		  safe sfdisk -R /dev/mmcblk1

		  safe sfdisk -uB /dev/mmcblk1 << EOM
0,$FAT,C
,,L
,,
,,
EOM

		  sync
		  safe sfdisk -R /dev/mmcblk1
		  sleep 5
		  sync

		END
	else
		LOG "Using existing partitions"
	fi

	echo
	sfdisk -l /dev/mmcblk1 | grep 'mmcblk1p'
	echo
}


format_ext_mmc()
{
	if [ X${FORMAT_VFAT} = XTRUE ]
	then
		MSG "Formatting /dev/mmcblk1p1 (vfat)"
		  if try_erase /dev/mmcblk1p1 30 1k
		  then
			safe mkfs.vfat -n 'sdcard' /dev/mmcblk1p1
			sync
		  fi
		END
	fi

	if [ X${FORMAT_ROOT} = XTRUE ]
	then
		MSG "Formatting ${ROOT_DEV} (ext3)"
		  if try_erase ${ROOT_DEV} 30 1k
		  then
			safe mkfs.ext3 -m0 -L 'NITDroid' ${ROOT_DEV}
			sync
		  fi
		END
	fi
}


mount_root_dev()
{
	test -d /and  || safe install -d -m 0700 /and

	MSG "Mounting ${ROOT_DEV}"
	  safe mount ${ROOT_DEV} /and -o ${ROOT_OPTS}
	END
}


## Package handling functions

check_md5()
{
	echo "$2  $1" | quiet md5sum -c
}


download_file()
{
	name=${1##*/}
	file=${PKGDIR}/${name}

	MSG "Downloading $name"

	test -f ${file}   && rm -f ${file}

	case $1 in
	  http:*)	safe wget -P ${PKGDIR} $1	;;
	  file:*)	safe cp ${1##file://} ${PKGDIR} ;;
	esac

	END
}


download_files()
{
	LOG "\nGoing to download the installation files. This will take a rather long time!\n"

	download_file ${MANIFEST_URL}

	cat ${PKGDIR}/${MANIFEST_FILE} | egrep -v '(^#)|(^[ \t]*$)' | while read tag url sum
	do
		if [ -n "${sum}" ]
		then
			name=${url##*/}
			file=${PKGDIR}/${name}

			if [ -f ${file} ]
			then
				if ! check_md5 $file $sum
				then
					download_file $url
				fi
			else
				download_file $url
			fi

			if ! check_md5 $file $sum
			then
				FAIL "MD5 checksum mismatch on ${name}"
			fi
		fi
	done
}


extract_files()
{
	safe cd /and

	cat ${PKGDIR}/${MANIFEST_FILE} | egrep '^rootfs' | while read tag url md5
	do
		FILE=${url##*/}
		MSG "Extracting ${FILE}"
		  cat ${PKGDIR}/${FILE} | bunzip2 | safe tar xv
		END
	done

	cd /tmp
}


install_debs()
{
	local tag url md5

	cat ${PKGDIR}/${MANIFEST_FILE} | egrep "^package" | while read tag url md5
	do
		FILE=${url##*/}
		MSG "Installing ${FILE}"
		  safe dpkg -i ${PKGDIR}/${FILE}
		END
	done
}


install_apts()
{
	local tag name

	cat ${PKGDIR}/${MANIFEST_FILE} | egrep "^install" | while read tag name
	do
		MSG "Installing ${name}"
		  safe apt-get -y install ${name}
		END
	done
}


## Environment functions

check_n900()
{
	# Maemo has osso-product-info
	test -x /usr/bin/osso-product-info  || return 1

	# HW must be RX-51
	test $( osso-product-info | fgrep 'HARDWARE' | cut -f2 -d'=' ) = "'RX-51'"  || return 1

	return 0
}


check_root()
{
	test $(id -u) = '0'
}


get_opts()
{
	local opt

	for opt
	do
		case "${opt}" in

		  --no-format)
		  	FORMAT_ROOT=FALSE
			;;

		  --no-purge)
			PURGE_KERNELS=FALSE
			;;

		  --android-dev=*)
		  	ROOT_DEV=${opt##*=}
			FDISK_MMC=FALSE
			FORMAT_VFAT=FALSE
			;;

		  http:*|file:*)
			MANIFEST_URL="${opt}"
			MANIFEST_FILE="${opt##*/}"
			;;

		  *)
		  	FAIL "Don't understand '${opt}'"
			;;
		esac
	done
}


## GUI Functions

print_banner()
{
	if ! check_n900
	then
		echo "ERROR: this program is for N900 only!"
		exit 1
	fi

	if ! check_root
	then
		echo "ERROR: You must be root to run this program!"
		exit 1
	fi

cat << EOM

**********************************************************
*                                                        *
* This installer will automatically download and install *
*      NITDroid, an Android port to Nokia N900.          *
*                                                        *
*                       WARNING!                         *
*    THIS PROGRAM WILL INSTALL APPS ONTO YOUR DEVICE     *
*     AND FORMAT YOUR MICROSD WITHOUT ANY WARNINGS.      *
*   THERE IS A SLIGHT RISK THAT THIS WILL RENDER YOUR    *
*     DEVICE UNUSABLE, REQUIRING FULL MAEMO REFLASH.     *
*                                                        *
*      PLEASE BACKUP YOUR DATA BEFORE PROCEEDING         *
*                                                        *
*                 YOU HAVE BEEN WARNED                   *
*                                                        *
**********************************************************

EOM

	read -t 60 -p "Type 'YES' if you accept the terms and take the risk >" msg

	if [ "${msg}" = "YES" ]
	then
		echo -e "\nGood! Here we go.\n"
	else
		echo -e "\nYou typed '${msg}' instead of 'YES', so not doing anything. Bye.\n"
		exit 1
	fi
}


print_trailer()
{
cat << 'EOM'

**********************************************************
                   _____   ___   ___   ___      ___
      |\   ||  /| /____/  |   \ |   \ |   \ /| |   \ 
      | \  ||  ||   |     |   | |___/ |   | || |   |
      || \ ||  ||   ||    ||  | ||\\  ||  | || ||  |
      ||  \||  ||   ||    ||__/ || \\ ||__| || ||__/

**********************************************************
*                                                        *
*           has been succesfully installed!              *
*                                                        *
*    You may now reboot the device with keyboard open    *
*              to boot into NITDroid.                    *
*                                                        *
**********************************************************

EOM
}


## MAIN

print_banner

INIT

get_opts "$@"

suspend_process ke-recv

unmount_ext_mmc

uninstall_crap

unmount_ext_mmc
format_ext_mmc

download_files

mount_root_dev

extract_files
install_debs
install_apts

unmount_ext_mmc

resume_process ke-recv

create_uninstall_icon

print_trailer

exit 0

## END.
