#!/bin/bash
#
# Auto-Installer for Debian on the Openmoko Neo phones (GTA01 and GTA02)
#
# Copyright 2008 Joachim Breitner <nomeata@debian.org>
# Copyright 2008-2009 Luca Capello <luca@pca.it>
# Copyright 2009 Steffen Moeller <moeller@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


set -e

# This helper function expects names of variables as arguments
# and converts all their contents to lower case.
lc () {
	# chosing a rarely seen variable name to avoid masking
	for i_____i in $*
	do
		cmd="$i_____i=\$(echo \$$i_____i|tr 'A-Z' 'a-z')"
		#echo $cmd
		eval $cmd
	done
}

#
# INSTALLER CONFIGURATION
#

# user variables
APT_OPTIONS=${APT_OPTIONS:- --yes}
APT_RECOMMENDS=${APT_RECOMMENDS:-false}
BOOTSTRAPPER=${BOOTSTRAPPER:-cdebootstrap}
CDEBOOTSTRAP_EXTRA_FLAGS=${CDEBOOTSTRAP_EXTRA_FLAGS:-}
DASH_BINSH=${DASH_BINSH:-true}
DEBOOTSTRAP_EXTRA_FLAGS=${DEBOOTSTRAP_EXTRA_FLAGS:-}
DISPLAY_MANAGER=${DISPLAY_MANAGER:-nodm}
FSO_MIRROR=${FSO_MIRROR:-http://pkg-fso.alioth.debian.org/debian}
INST_DIR=${INST_DIR:-/mnt/debian}
INST_MIRROR=${INST_MIRROR:-http://ftp2.de.debian.org/debian}
LOCALEPURGE=${LOCALEPURGE:-}
QI=${QI:-false}
QI_VERBOSE_BOOT=${QI_VERBOSE_BOOT:-false}
ROOT_PASSWORD=${ROOT_PASSWORD:-changeme}
SD_DEVICE=${SD_DEVICE:-/dev/mmcblk0}
SD_SYS_BLK=${SD_SYS_BLK:-/sys/block/${SD_DEVICE#/dev/}}
SD_PART1_FS=${SD_PART1_FS:-ext2}
SD_PART1_SIZE=${SD_PART1_SIZE:-8}
SD_PART2_FS=${SD_PART2_FS:-ext3}
SD_SWAP_SIZE=${SD_SWAP_SIZE:-0}
SINGLE_PART=${SINGLE_PART:-$QI}
TRAYER=${TRAYER:-trayer}
ZHONE=${ZHONE:-true}

# let us all see the same error messages and possibly suppress some by apt-get
export LANG=C.UTF-8

# hardening for the case that a user uses capitals
lc APT_RECOMMENDS BOOTSTRAPPER FSO_DEVICE QI QI_VERBOSE_BOOT SD_PART1_FS SD_PART2_FS 

# device autodetection if the user has not set FSO_DEVICE
FSO_DEVICE_AUTODETECTED=`grep GTA /proc/cpuinfo | awk '{print $3}' | tr "[:upper:]" "[:lower:]"`
if [ -z "$FSO_DEVICE" -a -n "$FSO_DEVICE_AUTODETECTED" ]; then
	FSO_DEVICE=$FSO_DEVICE_AUTODETECTED
fi

# this is an user variable, which by default depends on the FSO_DEVICE value
HOSTNAME=${HOSTNAME:-debian}
if [ "$HOSTNAME" = debian ]; then
    HOSTNAME="debian-$FSO_DEVICE"
fi

# general variables
VERBOSE=${VERBOSE:-}
TESTHOST=${TESTHOST:-www.debian.org}
RDATEHOST=${RDATEHOST:-ntp.fu-berlin.de}
DROPBEAR_KEYS="/etc/dropbear/dropbear_rsa_host_key /etc/dropbear/dropbear_dss_host_key"
MOUNT_PROC=true

# internal variables
internal_version="3.1"		# the version of this file
intern_instdir_already_present="" 
intern_no_partitioning=""

# debootstrap and cdebootstrap options
# with packages for a basic debian with network connectivity
CDEBOOTSTRAP_FLAVOUR=minimal
DEBOOTSTRAP_VARIANT=minbase
CDEBOOTSTRAP_PACKAGE=$INST_MIRROR/pool/main/c/cdebootstrap/cdebootstrap-static_0.5.9_armel.deb
DEBOOTSTRAP_PACKAGE=$INST_MIRROR/pool/main/d/debootstrap/debootstrap_1.0.42_all.deb
CDEBOOTSTRAP_EXTRA_PACKAGES=
DEBOOTSTRAP_EXTRA_PACKAGES=install-info
# This gets passed to boot strappers. currently not used
BOOTSTRAP_EXCLUDE_PACKAGES=hello

# Those packages should be installed with every Debian install, invariant of the bootstrapper used.
DEBIAN_EXTRA_PACKAGES=ifupdown,dropbear,udev,procps,netbase,vim-tiny,module-init-tools,wget,openssh-client

# freesmartphone.org packages
# because of some apt-get bug, console-setup must be listed
# before any other X.Org package, for more information see
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=435662#45
FSO_PACKAGES="matchbox-window-manager fso-frameworkd openmoko-panel-plugin dbus-x11 $TRAYER fso-utils mtd-utils \
console-setup xserver-xorg-core xorg omhacks xserver-xorg-video-glamo xserver-xorg-input-tslib xterm xinit xfonts-base x11-xserver-utils"

# well-suited software for the FreeRunner
PACKAGES_TASK_AUDIO="intone"
PACKAGES_TASK_GAMES="mokomaze sgt-puzzles"
PACKAGES_TASK_GPS="gpsd foxtrotgps monav navit"
PACKAGES_TASK_COM="phoneui-apps pidgin"
PACKAGES_TASK_NET="inetutils-ping host iptables"
PACKAGES_TASK_TEXT="less"
PACKAGES_TASK_WEB="midori epdfview"
PACKAGES_TASK_WIFI="wicd dhcp3-client wpasupplicant wireless-tools"
PACKAGES_TASK_UTILS="scrot debfoster"
# tasks defined
intern_tasks_defined="AUDIO,GAMES,GPS,COM,NET,TEXT,WEB,WIFI,UTILS"

# device-specific values
UBOOT_ENV_SIZE=262144

# mkfs.vfat is not installed by default in most of the Openmoko images
DOSFSTOOLS_PACKAGE=$INST_MIRROR/pool/main/d/dosfstools/dosfstools_3.0.1-1_armel.deb

# FSO-MS5 busybox's tar does not support -z
TAR_PACKAGE=$INST_MIRROR/pool/main/t/tar/tar_1.26-2_armel.deb
TAR_APPLICATION=tar


#
# FUNCTIONS
#

# for the installation of packages, /proc is sometimes required to be
# installed. cdebootstrap is installing it itself.
ensure_proc_is_mounted () {

	if  [ -z "$MOUNT_PROC" ]; then
		if [ ! -r "$INST_DIR"/proc/cpuinfo ]; then
			echo "W: /proc not mounted in chroot, install may fail."
		fi
		return 0;
	fi

	if [ ! -d "$INST_DIR/proc" ]; then mkdir "$INST_DIR/proc"; fi

	if mount | grep -q "$INST_DIR/proc"; then
		if [ -n "$VERBOSE" ]; then
			echo "I: /proc is already mounted in chroot"
		fi
		return 0;
	fi

	if mount -t proc none "$INST_DIR/proc"; then
		echo "I: installed /proc in chroot"
		return 0;
	else
		echo "E: could not mount /proc in chroot"
		return 1;
	fi

}

# cdebootstrap performs that automatically, but we need to take some
# extra precaution when installing packages that would normally
# start services. Those might interfere with local services or just
# expect bits to be mounted that are not mounted or ... you name it.
diverting_invoke_rc_d () {
	if [ ! -r "$INST_DIR"/usr/sbin/invoke-rc.d.diverted ]; then
		mv "$INST_DIR"/usr/sbin/invoke-rc.d "$INST_DIR"/usr/sbin/invoke-rc.d.diverted
		echo "I: diverted invoke-rc.d"
	else
		echo "I: invoke-rc.d is already diverted - was previous install interrupted?"
		# continuing anyway, since functional existence of dummy is not guaranteed.
	fi
	cat > "$INST_DIR"/usr/sbin/invoke-rc.d <<EOINVOKERCD
#!/bin/sh
echo "I: ignoring call to invoke-rc.d '\$*'"
EOINVOKERCD
	chmod 755 "$INST_DIR"/usr/sbin/invoke-rc.d 
}


# this function complements the action of diverting_invoke_rc_d
restoring_invoke_rc_d () {
	if [ -f "$INST_DIR"/usr/sbin/invoke-rc.d.diverted ]; then
		mv "$INST_DIR"/usr/sbin/invoke-rc.d.diverted "$INST_DIR"/usr/sbin/invoke-rc.d 
		echo "I: restored invoke-rc.d"
	else
		echo "E: no invoke-rc.d found to be put back in place. Investigate!"
	fi
}


# fight against auto-mounting
umount_all () {
	if [ -n "$VERBOSE" ]; then echo "Now unmounting all SD devices."; fi
	for I in $(seq 0 9); do
		cmd="mount | grep -q '^${SD_DEVICE}p$I'"
		if [ -n "$VERBOSE" ]; then echo -n " testing #$I ($cmd)"; fi
		if mount | grep -q "^${SD_DEVICE}p$I" ; then
			if [ -n "$VERBOSE" ]; then 
				echo " unmounting"
			else
				echo "W: ${SD_DEVICE}p$I is mounted, unmounting"
			fi
			umount ${SD_DEVICE}p$I
		#	if mount | grep -q ^${SD_DEVICE}p$I; then
		#		echo "E: Unmount failed"
		#		exit 1
		#	fi
		elif [ -n "$VERBOSE" ]; then
			echo 'not mounted'
		fi
	done
	if [ -n "$VERBOSE" ]; then echo "All SD devices unmounted."; fi
}

five_seconds_to_quit () {
	# since dash doesn't support 'read' -t and -n options, this script
	# should be executed only by /bin/bash.  However, all official
	# Openmoko images use busybox, which doesn't provide /bin/bash
	# The nested invocation of the bash circumvents a bug in the bash
	# distributed with Om2008.12.
	intern_var=$(read -t 5 -n 1 intern_var || intern_var=continue; echo $intern_var)
	if [ "$intern_var" != "continue" ]; then
		echo "E: aborting on user request"
		exit 1
	fi
}

card_data_warning () {

	cat <<__END__
Starting to $1 the microSD card

***********
* WARNING *
***********

This will destroy all the data on the microSD card!!!

Press any key within 5 seconds to quit
__END__

	five_seconds_to_quit

}

root_password_warning () {
	cat <<__END__
***********
* WARNING *
***********

Starting from version 3.0, the root password is no more empty,
but defaults to 'changeme'.  You can configure it through the
ROOT_PASSWORD variable.

Press any key within 5 seconds to quit
__END__

	five_seconds_to_quit

}

usage () {
	cat <<__END__

NAME
	install.sh - Auto-Installer for Debian on the Openmoko Neo phones (GTA01 and GTA02) v$internal_version

SYNOPSIS
	[variable1=value1 variable2 ...] `basename $0` [options] all
	[variable1=value1 variable2 ...] `basename $0` [options] <stages>

DESCRIPTION

	This script is to be executed on an OpenMoko Neo devices
	(either 1973 or FreeRunner), two openly designed telephones,
	to install the Debian operating system on an SD card. The
	system goes through multiple stages, and can be modified to
	adapt to local preferences.

	The individual stages are described below. The script uses
	cdebootstrap or debootstrap to prepare a directory to which
	it can chroot(8) and complete the configuration. 

ENVIRONMENT

	To influence the program's behaviour, set the following
	environment variables or leave the default values.

	APT_OPTIONS  extra parameters sent to apt for installing packages (set
                     to '$APT_OPTIONS').
	HOSTNAME     the name of the machine (set to '$HOSTNAME').
	SD_DEVICE    the character device to access the microSD card (set to
                     '$SD_DEVICE').
	SD_SYS_BLK   the directory under /sys/block that refers to the microSD
                     card (set to '$SD_SYS_BLK', or derived from the
                     value of SD_DEVICE).
	SD_PART1_FS  the filesystem for the first microSD card partition, i.e.
                     the one containing the uImage.bin (set to '$SD_PART1_FS', possible
                     values are ext2/vfat, also ext3 when using Qi as
                     bootloader).
	SD_PART1_SIZE
                     number of megabytes for first partition (set to '$SD_PART1_SIZE').
	SD_SWAP_SIZE
                     number of megabytes of swap partition (set to '$SD_SWAP_SIZE').
	INST_DIR     the directory where the microSD card partitions will be
                     mounted to (set to '$INST_DIR').
	INST_MIRROR  the Debian mirror used during installation, it should be
                     set to a mirror nearby that carries armel binaries for
                     unstable (set to
                     '$INST_MIRROR').
	LOCALEPURGE  set this to true, if you want to install the package of the
                     same name. It reduces disk space enormously, but needs user
                     interaction for the install (set to '$LOCALEPURGE').
	APT_RECOMMENDS
                     control if APT should install recommends by default (set to
                     '$APT_RECOMMENDS', possible values are false/true).
	BOOTSTRAPPER determines the bootstrapper to use, should be set to
                     deboostrap or cdebootstrap - cdebootstrap is somewhat
                     faster and you may have to "opkg install perl", but it
                     seems to work less reliably (set to '$BOOTSTRAPPER').
                     For debootstrap please do not run anything besides
                     install.sh as you will need all your memory.
	CDEBOOTSTRAP_EXTRA_FLAGS
                     parameters to be added to invocation of cdebootstrap, only
                     active if BOOTSTRAPPER is not set to debootstrap.
	DASH_BINSH   configure dash as default /bin/sh (set to '$DASH_BINSH', possible
                     values are true/false).
	DEBOOTSTRAP_EXTRA_FLAGS
                     parameters to be added to invocation of debootstrap, only
                     active if BOOTSTRAPPER is not set to cdebootstrap.
	FSO_MIRROR   the Debian freesmartphone.org repository (set to
                     '$FSO_MIRROR').
	FSO_DEVICE   the device the installation is being performed on (set to
                     '$FSO_DEVICE', default to autodetection, possible values are
                     gta01/gta02).
	QI           if you use Qi bootloader set this to true (set to '$QI').
	QI_VERBOSE_BOOT
                     set this to true if you want to see the kernel messages; do
                     this only when QI=true (set to '$QI_VERBOSE_BOOT').
	RDATEHOST    machine with which to sync against with ntp (set to
                     '$RDATEHOST').
	SINGLE_PART  set this to true if only one partition should be created;
                     this is true by default for QI=true and false if
                     SD_PART1_FS=vfat (set to '$SINGLE_PART').
	TRAYER       name of package to fill the menu bar, supported are
	             'trayer' and 'stalonetray' (set to '$TRAYER').
	TESTHOST     name of machine that should be tested for availability
                     (set to '$TESTHOST').
	VERBOSE      increase amount of information that is forwarded to stdout
                     (set to '$VERBOSE').
	DISPLAY_MANAGER
                     choose the Display Manager to be installed (default to
                     '$DISPLAY_MANAGER', possible values are any *dm package in the Debian
                     archive, which could require a LOT of disk space; set this
                     to none if you do not want a Display Manager).
	ZHONE        set this to true to install the Zhone GUI (set to '$ZHONE').
	ROOT_PASSWORD
                     the password for the root account (set to '$ROOT_PASSWORD').

    Stages:

	all          Runs all the stages in the following order:
                                testing time partition format mount
                                debian apt fso configuration tasks
                                kernel cleanup unmount
	testing      Verifys that everything is in place for this
                     installer to work
	time         Fetches the current time from $RDATEHOST via rdate
	partition    Partitions the microSD card found in $SD_DEVICE
                     (WARNING, this will destroy all the data on the
                     microSD card unless the partioning is the same as
                     used before; this can be used to recover a broken
                     partiton table due to the suspend/resume problem)
	format       Formats the microSD card found in '$SD_DEVICE'
                     (WARNING, this will destroy all the data on the
                     microSD card)
	mount        Mounts microSD card partitions under '$INST_DIR'
	debian       Installs a basic Debian system, including an SSH server
	apt          Configure APT
	fso          Install freesmartphone.org packages (by default this
                     also include the Zhone GUI, see the ZHONE variable)
	tasks        Installs packages for a series of tasks. Supported are
                       AUDIO  ($PACKAGES_TASK_AUDIO)
                       COM    software supporting the communication of
                              users ($PACKAGES_TASK_COM). 
                       GAMES  installs games that were designed with
                              FreeRunner-like devices in mind or that have
                              been found compatible ($PACKAGES_TASK_GAMES)
                       GPS    software for GPS, geocaching and navigation
                              ($PACKAGES_TASK_GPS)
                       NET    software that is beneficial to investigate
                              the network setup and/or forward traffic
                              to USB-attached devices, e.g. to connect a
                              a laptop to the internet via the freephone's
                              internet connection (GPRS or Wifi).  See
                              http://wiki.openmoko.org/wiki/Tethering for
                              the setup ($PACKAGES_TASK_NET).
                       TEXT   allows improved handling of text
                              ($PACKAGES_TASK_TEXT)
                       WEB    ($PACKAGES_TASK_WEB)
                       WIFI   ($PACKAGES_TASK_WIFI)
                       UTILS  whatever was wanted that does not belong to the
                              other classes ($PACKAGES_TASK_UTILS)
                       ALL    Selection of all the tasks listed above.

                     To specify the tasks shall be assigned to the TASKS
                     environment variable as a comma separated list (set to
                     '$TASKS').
	configuration    Configures various parts of the system, such as
                     the X server
	kernel       Downloads and installs the Debian kernel package (only
                     when SD_PART1_FS is set to ext2, now '$SD_PART1_FS')
	cleanup      Remove unnecessary package and clean APT cache
	unmount      Unmounts the Debian filesystem mounted at '$INST_DIR'

    Unsupported or buggy stages, use at your own risk:

	uboot	     Configures the U-Boot environment to boot Debian (it
                     needs to run between the debian and the unmount stage,
                     only when SD_PART1_FS is set to ext2, now '$SD_PART1_FS')

OPTIONS
	For users uncomfortable with setting environment variables, the following
	options have been implemented to be set as arguments:

        -h|--help    shows this information
	--verbose    same as invocation with VERBOSE=true as environment variable
	--apt-options <options>
                     sets the APT_OPTIONS variable
	--hostname <name>
                     sets the HOSTNAME variable
	--mount-proc
                     mounts /proc directory in Debian chroot
	-np|--no-partitioning
                     disable the partitioning when otherwise doing "all"
	--part1-fs <vfat|ext2|ext3>
                     sets the SD_PART1_FS variable
	--part1-size <megabytes>
                     sets the SD_PART1_SIZE variable
	--swap-size <megabytes>
                     sets the SD_SWAP_SIZE variable
	--with-tasks <tasks>
                     sets the TASKS variable
	--with-localepurge
                     will install the localepurge package
	--trayer <trayer>
                     sets the TRAYER variable
	--bootstrapper (debootstrap|cdebootstrap)
                     sets the BOOTSTRAPPER variable

EXAMPLE

	Next to your install.sh script you may want to create a file
	that remembers the parameters for you that you have chosen for
	your previous setup.

	./install.sh --part1-fs vfat --part1-size 16  all

	Performs a complete installation. Tasks would be addressed if the
	TASKS environment variable would have been set.

	TASKS="GAMES,GPS" ./install.sh --part1-fs vfat --part1-size 16  all

	As before, but now extra packages are installed (and configured)
	to prepare a selection of games and a reasonably complete utilisation
	of the GPS funcionality.

	TASKS="GAMES,GPS" ./install.sh --part1-fs vfat --part1-size 16  tasks

	This is the delta between the prior two examples.

	TASKS="GAMES,GPS" ./install.sh --part1-fs vfat --part1-size 16

	E: This does nothing since no install target is defined.

BUGS
	Only the current (second) generation of devices is fully supported.
	This script should be functional with the GTA01 except for the
	installation of the kernel.

	For comments or contributions, you can directly send emails
	to the list mentioned below. However, please be aware of the
	pkg-fso git repository that helps orchestrating our efforts. You
	can check it out with
	  git clone git://git.debian.org/pkg-fso/files.git
	perform your changes and prepare patches with
	  git format-patch origin/master
	to send to the authors or to the pkg-fso mailing list
	pkg-fso-maint@lists.alioth.debian.org .

AUTHORS
	Copyright 2008 Joachim Breitner <nomeata@debian.org>
	Copyright 2008 Luca Capello <luca@pca.it>
	Copyright 2009 Steffen Moeller <moeller@debian.org>

	This program is licensed under the terms of GNU General Public
	License either version 2, or (at your option) any later version.

SEE ALSO
	This project's homepage: http://wiki.debian.org/DebianOnFreeRunner
	The OpenMoko project: http://www.openmoko.org

__END__

	exit 0
}



vfat_check () {
# /boot on vfat is no more supported (http://bugs.debian.org/315493)
# http://lists.linuxtogo.org/pipermail/smartphones-userland/2008-November/000502.html
	if [ "$SD_PART1_FS" = "vfat" ]; then
		cat <<__END__
***********
* WARNING *
***********

For the /boot partition you have chosen to use vfat, which is not a
POSIX-compliant filesystem.

Because dpkg, the Debian package manager, does not support non-POSIX
filesystems, the Debian kernel package can not be installed.  More
information are available at http://bugs.debian.org/315493.

Press any key within 5 seconds to quit
__END__
		five_seconds_to_quit
		SINGLE_PART="false"
	fi
}


#
# Stage all
#

action_all () {
	cat <<__END__
I: Running all stages with these settings:
I: hostname set to $HOSTNAME
I: microSD card device at $SD_DEVICE
I: $SD_PART1_FS as filesystem for the first microSD card partition
I: installing into '$INST_DIR'
I: using Debian mirror at $INST_MIRROR
I: APT recommends set to $APT_RECOMMENDS
I: dash as default /bin/sh set to $DASH_BINSH

__END__

	for f in testing time partition format mount debian apt fso configuration tasks kernel cleanup unmount
	do
		case "$f" in
			"partition")
				if [ -n "$intern_no_partitioning" ]; then
					echo " * Skipping partitioning since --no-partitioning flag set"
				else
					action_partition
				fi
				;;
			"tasks")
				if [ -z "$TASKS" ]; then
					echo " * Skipping over installing tasks since none were specified"
				else
					action_tasks
				fi
				;;
			*)
				if [ -n "$VERBOSE" ]; then echo "calling '$f'"; fi
				action_$f
				;;
		esac
	done
	cat <<__END__

I: All done!

__END__

	if [ "$SD_PART1_FS" = "vfat" ]; then
		echo "Now reboot, switch on the Openmoko FreeRunner with both AUX+PWR,"
		echo "buttons, choose \"Boot from microSD (FAT+ext2)\" and wait!"
	else
		echo "Now reboot, and hope for the best!"
	fi
	echo
	exit 0
}


#
# Stage test
#

action_testing () {

	echo "I: Testing system setup"

	intern_packages_required="wget ping fdisk mount umount mkfs.$SD_PART1_FS mkswap gunzip dd sed rdate ar basename dirname"
	if [ "mkfs.$SD_PART2_FS" != "mkfs.$SD_PART1_FS" ]; then
		intern_packages_required="$intern_packages_required mkfs.$SD_PART2_FS"
	fi
	if [ "deboostrap" = "$BOOTSTRAPPER" ]; then
		intern_packages_required="$intern_packages_required perl"
	fi

	intern_packages_missing=""
	intern_extra_information=""
	for intern_binary in $intern_packages_required; do
		if ! which $intern_binary > /dev/null; then
			if [ -n "$VERBOSE" ]; then
				echo " * Missing binary '$intern_binary'"
			fi
			intern_packages_missing="$intern_packages_missing $intern_binary"
			if [ "ar" = "$intern_binary" ]; then
				intern_extra_information="${intern_extra_information}\n  the 'ar' binary is expected to ship with a package named 'binutils'"   
			fi
		fi
		if [ -n "$VERBOSE" ]; then
			echo " * $intern_binary installed"
		fi
	done

	if [ -n "$intern_packages_missing" ]; then
		echo -e "E: Could not find the following binaries: $intern_packages_missing.$intern_extra_information"
		exit 1
	fi

	if ! test -e $SD_DEVICE; then
		echo "E: Could not find microSD card device file $SD_DEVICE"
		exit 1
	fi
	echo " * microSD card device: $SD_DEVICE present"

	if $TAR_APPLICATION --help 2>&1 | grep "Usage: $TAR_APPLICATION \-\[cxtvO\]" >/dev/null; then
		echo "W: $TAR_APPLICATION does not support gzip archives"
		echo "Downloading tar package"
		wget $TAR_PACKAGE -O /tmp/tar.deb
		rm -f /tmp/data.tar.gz # FIXME: ar should just overwrite it
		( cd /tmp && ar -x tar.deb data.tar.gz )
		mkdir -p /usr/local
		gunzip -c /tmp/data.tar.gz | $TAR_APPLICATION -x -C /usr/local/
		TAR_APPLICATION=/usr/local/bin/tar
		rm -f /tmp/data.tar.gz
		rm -f /tmp/tar.deb
	fi

	if [ "$SD_PART1_FS" = "vfat" ]; then
		if ! which mkfs.vfat >/dev/null; then
			echo "W: Could not find mkfs.vfat binary"
			# it should try first to install dosfstools through opkg
			# and then try to install the Debian dosfstools
			echo "Downloading dosfstools package"
			wget $DOSFSTOOLS_PACKAGE -O /tmp/dosfstools.deb
			rm -f /tmp/data.tar.gz # FIXME: ar should just overwrite it
			( cd /tmp && ar -x dosfstools.deb data.tar.gz )
			$TAR_APPLICATION -xz -C / -f /tmp/data.tar.gz
			rm -f /tmp/data.tar.gz
			rm -f /tmp/dosfstools.deb
		fi

		# let's test again for safety reasons
		if ! which mkfs.vfat >/dev/null; then
			echo "E: Could not find mkfs.vfat binary"
			exit 1
		else
			echo " * mkfs.vfat installed"
		fi
	fi

	if [ $(uname -m) != armv4tl ]; then
		echo "E: System is not claiming to be an armv4tl."
		echo "   Are you sure that this is your Openmoko FreeRunner (GTA02)?"
		exit 1
	fi

	if ! ping -c 2 $TESTHOST > /dev/null; then
		echo "E: Could not ping $TESTHOST, is the network running?"
		exit 1
	fi

	echo " * network running"

	if ps -C qpe >/dev/null; then
		echo "E: Qtopia wants to continually access /media/card.  You need to"
		echo -n "   stop it with "
		if [ -x "/etc/init.d/qpe" ]; then
			echo -n "\`/etc/init.d/qpe stop\` or"
		elif [ -x "/etc/init.d/qpe.sh" ]; then
			echo -n "\`/etc/init.d/qpe.sh stop\` or"
		fi
		echo " \`killall qpe\`"
		echo "   and then restart the installation!"
		exit 1
	fi

	echo "I: Testing system setup - done - looks good"
}

#
# Stage time
#

action_time () {
	echo "Fetching time from $RDATEHOST with rdate"
	rdate -s "$RDATEHOST" >/dev/null 2>&1
	echo "I: Time is now `date`"
}

#
# Stage partitioning
#

action_partition () {

	echo "I: Partitioning SD"

	card_data_warning partition
	umount_all

	# put the partition table in a "known state"
	echo " * Clearing MBR of SD."
	if ! dd if=/dev/zero of=$SD_DEVICE bs=512 count=1 >/dev/null 2>&1; then
		echo "Clearing MBR of SD with dd failed ($?)."
		exit 1
	fi

	# run partitioner
	bootfstypeno=83

	if [ -z "$SD_SWAP_SIZE" ]; then SD_SWAP_SIZE=0; fi

	mb=$(( $(cat /sys/block/mmcblk0/size) * 8 / 15625 ))
	# If one were willing to assume that cylinders are always 64 * 512, then we could calculate the
	# next line thus:   $(( $(cat /sys/block/mmcblk0/size) / 64 ))
	cylinders=$(echo -e "p\nq" | fdisk ${SD_DEVICE} | grep cylinders|grep heads|cut -f 5 -d\ )
	lastcylinder=$(($cylinders-($cylinders*$SD_SWAP_SIZE/$mb)))

##### TODO: Evaluate the suggestion by x
#+#	mb=$(echo pq | fdisk /dev/mmcblk0 | grep Disk | cut -f 3 -d \ )
#+	mb=$(sfdisk -s ${SD_DEVICE} 2>/dev/null)
#+#	cylinders=$(echo -e "p\nq" | fdisk /dev/mmcblk0 | grep cylinders | grep heads | cut -f 5 -d\ )
#+	cylinders=$(sfdisk -G ${SD_DEVICE} 2>/dev/null | grep "^${SD_DEVICE}" | awk "{ print \$2 }")
#+	lastcylinder=$(($cylinders-($cylinders*$SD_SWAP_SIZE/($mb/1024))))
#


	if [ "vfat" = "$SD_PART1_FS" ]; then
		bootfstypeno=4
	fi

	partitionno=0
	if [ "$SINGLE_PART" = "true" ]; then
		echo "Preparing SD as a single Linux device."
		partitionno=$(($partitionno+1))
		cat <<EOSINGLECONF > /tmp/argsToFdisk$$
n
p
$partitionno

$lastcylinder
EOSINGLECONF

	else
		partitionno=$(($partitionno+1))
		cat <<EOBOOTCONF > /tmp/argsToFdisk$$
n
p
$partitionno

+${SD_PART1_SIZE}M
t
$bootfstypeno
EOBOOTCONF

		partitionno=$(($partitionno+1))
		cat <<EOROOTCONF >> /tmp/argsToFdisk$$
n
p
$partitionno

$lastcylinder
t
$partitionno
83
EOROOTCONF
	fi

	if [ 0 -lt "$SD_SWAP_SIZE" ]; then
		partitionno=$(($partitionno+1))
		cat <<EOSWAPCONF >> /tmp/argsToFdisk$$
n
p
$partitionno


t
$partitionno
82
p
EOSWAPCONF
	fi
	echo "w" >> /tmp/argsToFdisk$$

	if fdisk $SD_DEVICE < /tmp/argsToFdisk$$; then
		echo "Partitioning was successful."
		if [ -n "$VERBOSE" ]; then
			echo "The following partitions have been created:"
			echo -e "p\nq" | fdisk $SD_DEVICE
		fi
		#rm /tmp/argsToFdisk$$
	else
		echo "Partitioning failed, could not execute with fdisk:"
		cat /tmp/argsToFdisk$$
		exit 1
	fi


	echo " * Waiting for partitions to appear"
	intern_sleep_seconds=3
	if [ "$SINGLE_PART" = "true" ]; then
		intern_devtest="test -e ${SD_DEVICE}p1"
	else
		intern_devtest="test -e ${SD_DEVICE}p1 -a -e ${SD_DEVICE}p2"
	fi

	while ! $intern_devtest; do
		if [ "$intern_sleep_seconds" = 15 ]; then
			echo "E: Partitioning has failed, partitions have not been created"
			exit 1
		fi
		sleep 3
		intern_sleep_seconds=$(( $intern_sleep_seconds + 3 ))
	done

	echo "I: Partitioning SD - done - Partition table created"
}

#
# Stage format
#

action_format () {
	echo "I: Formatting SD"
	card_data_warning format
	umount_all

	if [ -z "$SD_SWAP_SIZE" ]; then SD_SWAP_SIZE=0; fi

	echo " * Formatting ${SD_PART1_FS} on ${SD_DEVICE}p1"
	mkfs.$SD_PART1_FS ${SD_DEVICE}p1
	nextpart=2
	if [ "$SINGLE_PART" != "true" ]; then
		echo " * Formatting ${SD_PART2_FS} on ${SD_DEVICE}p2"
		mkfs.$SD_PART2_FS ${SD_DEVICE}p2
		nextpart=3
	fi
	if [ 0 -lt "$SD_SWAP_SIZE" ]; then
		echo " * Formatting swap on ${SD_DEVICE}p${nextpart}"
		mkswap ${SD_DEVICE}p${nextpart}
	fi

	echo "I: Formatting SD - done - microSD card ready"
}

#
# Stage mount
#

action_mount () {

	echo "I: Mounting the newly created system"

	if [ ! -d "$INST_DIR" ]; then
		mkdir -p "$INST_DIR"; 
		intern_instdir_already_present="" 
	elif [ -n "$VERBOSE" ]; then
		echo "Not creating directory '$INST_DIR', it is already existing."
		intern_instdir_already_present="true" 
	fi
	if [ "$SINGLE_PART" = "true" ]; then
		if [ -n "$VERBOSE" ]; then echo "Preparing single ext2 device."; fi
		mount -t auto ${SD_DEVICE}p1 "$INST_DIR"
		mkdir -p "$INST_DIR/boot"
	else
		if [ -n "$VERBOSE" ]; then echo "Mounting root partition to '$INST_DIR'."; fi
		mount -t auto ${SD_DEVICE}p2 "$INST_DIR"
		if [ "vfat" = "$SD_PART1_FS" ]; then
			echo "You have a vfat boot filesystem. This is not mounted to /boot."
		else
			if [ ! -d "$INST_DIR/boot" ]; then mkdir "$INST_DIR/boot"; fi
			mount -t auto ${SD_DEVICE}p1 "$INST_DIR/boot"
		fi
	fi

	echo "I: Mounting the newly created system - done - microSD card partitions mounted"
}


#
# Stage debian
#

action_debian () {
	echo "I: Install a basic Debian system"
	
	#For users of local apt proxy
	mkdir -p $INST_DIR/etc
	if [ -f /etc/hosts ]; then
		cp /etc/hosts $INST_DIR/etc
		echo "I: /etc/hosts copied from this machine"
	fi	 	   

	intern_bootstrapper_package=
	if [ "cdebootstrap" = "$BOOTSTRAPPER" ]; then
		intern_bootstrapper_package=$CDEBOOTSTRAP_PACKAGE
	elif [ "debootstrap" = "$BOOTSTRAPPER" ]; then
		intern_bootstrapper_package=$DEBOOTSTRAP_PACKAGE
	else
		echo "Unknown bootstrapper: '$BOOTSTRAPPER'"
		exit 1
	fi

	if [ -x /usr/bin/"$BOOTSTRAPPER" ]; then
		echo
		echo "I: Found $BOOTSTRAPPER installed,"
                echo "   will nonetheless download reference version."
		echo
        fi
	echo " * Downloading bootstrapper package '`basename $intern_bootstrapper_package`'"
        if [ -n "$VERBOSE" ]; then echo "   from $intern_bootstrapper_package"; fi
	internal_localpackagename=/tmp/debootstrapOrCdebootstrap.deb
	if ! wget $intern_bootstrapper_package -O "$internal_localpackagename"; then
		echo <<EOWGETFAILURE
E: Could not download debian bootstrap tool '$BOOTSTRAPPER'. Check
   with page http://packages.debian.org/sid/$BOOTSTRAPPER if the
   version shown is the same as in
   $intern_bootstrapper_package .
EOWGETFAILURE
		exit -1
	fi
	rm -f /tmp/data.tar.gz # FIXME: ar should just overwrite it
	(
		cd /tmp
		if ! ar -x "$internal_localpackagename" data.tar.gz ; then
			echo "E: Could not extract files from .deb for bootstrapper '$BOOTSTRAPER'."
			exit 1
		else
			echo "I: Successfully extracted files from bootstrapper's .deb."
		fi
	)
	rm -f "$internal_localpackagename"
	intern_taroptions=
	if [ -n "$VERBOSE" ]; then intern_taroptions="${intern_taroptions}v"; fi
	if ! $TAR_APPLICATION -x${intern_taroptions}z -C / -f /tmp/data.tar.gz; then
		echo "E: Could not untar binaries for bootstrapper from /tmp/data.tar.gz"
		exit 1
	else
		echo "I: Successfully extracted binaries for bootstapper."
	fi
	rm -f /tmp/data.tar.gz

	echo " * Running '$BOOTSTRAPPER' to install the system (might take a while)"
	if [ -n "$VERBOSE" ]; then
		if [ "cdebootstrap" = "$BOOTSTRAPPER" ]; then
			CDEBOOTSTRAP_EXTRA_FLAGS="$CDEBOOTSTRAP_EXTRA_FLAGS -v"
			echo "   CDEBOOTSTRAP_VARIANT='$CDEBOOTSTRAP_VARIANT'"
			echo "   CDEBOOTSTRAP_EXTRA_FLAGS='$CDEBOOTSTRAP_EXTRA_FLAGS'"
			echo "   CDEBOOTSTRAP_EXTRA_PACKAGES='$CDEBOOTSTRAP_EXTRA_PACKAGES'"
		elif [ "debootstrap" = "$BOOTSTRAPPER" ]; then
			DEBOOTSTRAP_EXTRA_FLAGS="$DEBOOTSTRAP_EXTRA_FLAGS --verbose"
			echo "   DEBOOTSTRAP_VARIANT='$DEBOOTSTRAP_VARIANT'"
			echo "   DEBOOTSTRAP_EXTRA_FLAGS='$DEBOOTSTRAP_EXTRA_FLAGS'"
			echo "   DEBOOTSTRAP_EXTRA_PACKAGES='$DEBOOTSTRAP_EXTRA_PACKAGES'"
		fi
	fi

	if [ "cdebootstrap" = "$BOOTSTRAPPER" ]; then
		cdebootstrap-static $CDEBOOTSTRAP_EXTRA_FLAGS --allow-unauthenticated --flavour $CDEBOOTSTRAP_FLAVOUR \
			--exclude=$BOOTSTRAP_EXCLUDE_PACKAGES \
			--include=$CDEBOOTSTRAP_EXTRA_PACKAGES \
			sid "$INST_DIR" $INST_MIRROR
	elif [ "debootstrap" = "$BOOTSTRAPPER" ]; then
		debootstrap --arch=armel $DEBOOTSTRAP_EXTRA_FLAGS --variant $DEBOOTSTRAP_VARIANT \
			--exclude=$BOOTSTRAP_EXCLUDE_PACKAGES \
			--include=$DEBOOTSTRAP_EXTRA_PACKAGES \
			 sid "$INST_DIR" $INST_MIRROR
	else	# redundant, but when things go wrong, then things go wrong, left as precaution
		echo "Unknown bootstrapper: '$BOOTSTRAPPER'"
		exit 1
	fi
	
	# Bug #542955 (won't fix) for cdebootstrap directs us to use apt-get for versioned
        # (direct or indirect) dependencies. The DEBIAN_EXTRA_PACKAGES are consequently
        # installed in the action_apt

	echo "I: Install a basic Debian system - done - Basic Debian system installed - please also install apt"
}


#
# Stage apt
#

action_apt () {
	echo "I: Configuring APT"

	if ! ensure_proc_is_mounted; then
		echo "  /proc is needed for APT configuration - please investigate."
		exit 1
	fi

	echo " * Populating /etc/apt/sources.list"
	cat >> "$INST_DIR/etc/apt/sources.list" <<__END__
deb $INST_MIRROR unstable main
deb $FSO_MIRROR unstable main
__END__

	echo " * Install APT recommends by default: $APT_RECOMMENDS"
	echo "APT::Install-Recommends \"$APT_RECOMMENDS\";" > "$INST_DIR/etc/apt/apt.conf.d/99recommends"

	echo " * Learning public key for pkg-fso-keyring"
	chroot "$INST_DIR" apt-key add - <<__END__
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (GNU/Linux)

mQGiBEicYhYRBACvesYUC+rkRpp0j/PTEimmuPkZqjLuRnpXqlCXV9Y1TZxvPmFl
TwoeBHYoh3Uipbj0WypAJ3N989OQPiPo+lyrPNscRYc9+H/k7Q47Oc0ms23EQSWX
AdnuhRezNF98cW/bmykVO9uZo+OjA501R9SCrMkhkbuifB57OMdXA0o67wCg0NWM
EOAqQ/DCoo9Nqnb5sWotwisD/15dgunBY1BCyz8o7Ky1gn+Cel3LfNaqCIHwgCNf
oxdAzHViNHMJa13Hab/nBY1GPpfJ3VIvLNs309JTDoKnYFvUkinvt+OJcY4z/3XN
yloHhUoFBOSuZUy/xqB5PVrlQYJ07WKQHOkjvcp5LCH7pTLjCu8ih+YIIr4uipNl
ZjBwA/9bCGQysO4xaHCR+qEZcQ1J4tW2A1g6Kr8p2CHxvGVCCQW7hhIRVIVGXF83
EViOVobmG8RHZFpAJzdsrJ/jkYBZp62wCs1DTljxLdMfY9vlKzpui3RSPv10fdPX
t2iPG4Qc9Qm2H6LkWDfSJx6FLzDKrcj8tmbLTpr+fdJZtehudLRNcGtnLWZzbyBB
cmNoaXZlIEF1dG9tYXRpYyBTaWduaW5nIEtleSA8cGtnLWZzby1tYWludEBsaXN0
cy5hbGlvdGguZGViaWFuLm9yZz6IYAQTEQIAIAIbAwYLCQgHAwIEFQIIAwQWAgMB
Ah4BAheABQJKfuQXAAoJEOK53mqOezI71/IAnR6ZRbCHzuDRZecGvOtd8qNtcW+Q
AJ9Cbbi6oyybgvrJ2KGjWXkoYTJnfw==
=IG3W
-----END PGP PUBLIC KEY BLOCK-----
__END__

	echo " * Updating APT database"
	chroot "$INST_DIR" apt-get update

	echo " * Installing pkg-fso keyring"
	diverting_invoke_rc_d   # to ensure to avoid problem from previously failed installs
                                # to spot this separate apt-get invocation cost me about 2h
	chroot "$INST_DIR" apt-get $APT_OPTIONS install pkg-fso-keyring
	restoring_invoke_rc_d

	echo " * Completing install of Debian basic packages to circumvent bug #542955"


	# dropbear at least cannot be installed without preventing the restart to happen
	diverting_invoke_rc_d
	chroot "$INST_DIR" apt-get $APT_OPTIONS install $(echo $DEBIAN_EXTRA_PACKAGES | tr "," " ")
	restoring_invoke_rc_d

	echo " * Cleaning APT cache"
	chroot "$INST_DIR" apt-get clean

	echo "I: Configuring APT - done - APT configured"
}


#
# Stage fso
#

action_fso () {
	echo "I: Installing freesmartphone.org software"

	ensure_proc_is_mounted

	echo "* core packages"
	diverting_invoke_rc_d
	chroot "$INST_DIR" /bin/sh -e <<__END_CHROOT__
export DEBIAN_FRONTEND=noninteractive
apt-get $APT_OPTIONS install $FSO_PACKAGES
apt-get clean
__END_CHROOT__
	restoring_invoke_rc_d

	echo "skipped (\$ZHONE=$ZHONE)"

	echo "I: Installing freesmartphone.org software - done"
}


#
# Stage tasks
#
#	These steps shall be executed only after all basic packages
#	have been installed.
#

action_tasks () {

	if  [ -z "$TASKS" ]; then
		if [ -n "$VERBOSE" ]; then
			echo
			echo "No task selected."
			echo
		fi
		return 0;
	fi

        # tasks should be defined case-invariantly
        TASKS=$(echo "$TASKS"|tr "a-z" "A-Z")

	if [ "ALL" = "$TASKS" ]; then
		TASKS="$intern_tasks_defined"
	fi

	echo "I: Performing selected tasks: $TASKS"

	ensure_proc_is_mounted

	for intern_task in $( echo $TASKS|tr "," " ")
	do
		echo " * task: $intern_task"
		eval chroot "$INST_DIR" apt-get install $APT_OPTIONS \$PACKAGES_TASK_$intern_task
		chroot "$INST_DIR" apt-get clean
		echo "I: Selection of packages for task '$intern_task' successfully installed."

		case "$intern_task" in
		  "WIFI")

			echo " * modifying .xsession to autostart wicd-client"
			sed -i '/^exec/i#wicd-client --no-animate &' "$INST_DIR/root/.xsession"
			echo " * Installing wicd for wifi setup"
			if [ -r "$INST_DIR/etc/wicd/manager-settings.conf" ]; then
				grep -v ^wired_interface "$INST_DIR/etc/wicd/manager-settings.conf" > \
					"$INST_DIR/etc/wicd/manager-settings.conf"
			else
				mkdir "$INST_DIR/etc/wicd"
				echo "[Settings]" >> "$INST_DIR/etc/wicd/manager-settings.conf"
			fi
			echo "wired_interface =" >> "$INST_DIR/etc/wicd/manager-settings.conf"
			chroot "$INST_DIR" apt-get install $APT_OPTIONS wicd
			echo " * All extra activity for task '$intern_task' completed."
			;;

		  *)
			echo " * No extra activity for task '$intern_task'."
			;;
		esac
	done

	echo "I: Performing selected tasks - done"
}


#
# Stage configuration
#

action_configuration () {
	echo "I: Configuring system files for ${FSO_DEVICE}"

	root_password_warning

	ensure_proc_is_mounted

	if [ "true" = "$LOCALEPURGE" ]; then
		echo " * installing localepurge"
		echo "     ... skipped since Erich reported it to break unsupervised install"
		#chroot "$INST_DIR" apt-get $APT_OPTIONS install localepurge
	fi

	if [ -z "$SD_SWAP_SIZE" ]; then SD_SWAP_SIZE=0; fi

	echo " * Installing the fso-${FSO_DEVICE} package"
	chroot "$INST_DIR" apt-get $APT_OPTIONS install fso-${FSO_DEVICE}

	echo " * Creating /etc/X11/xorg.conf"
	cat > "$INST_DIR/etc/X11/xorg.conf" <<__END__
# Xorg configuration for an Openmoko FreeRunner

Section "Module"
       Load    "glx"
       Load    "dri2"
EndSection

Section "Monitor"
       Identifier      "LCD Panel"
EndSection

Section "Device"
       Identifier      "Glamo Graphics Chip"
       Driver          "glamo"
EndSection

Section "Screen"
       Identifier      "Default Screen"
       Device          "Glamo Graphics Chip"
       Monitor         "LCD Panel"
EndSection

Section "InputDevice"
       Identifier      "Power Button"
       Driver          "evdev"
       Option          "Device"        "/dev/input/event0"
EndSection


Section "InputDevice"
       Identifier      "AUX Button"
       Driver          "evdev"
       Option          "Device"        "/dev/input/event2"
EndSection


Section "InputDevice"
       Identifier      "Touchscreen"
       Driver          "evdev"
       Option          "Device"        "/dev/input/event1"
       Option          "Calibration"  "107 918 911 98"
       Option          "SwapAxes"     "On"
EndSection

Section "ServerFlags"
       Option "AutoAddDevices" "False"
EndSection

Section "ServerLayout"
       Identifier      "Default Layout"
       Screen          "Default Screen"
       InputDevice     "Power Button"
       InputDevice     "AUX Button"
       InputDevice     "Touchscreen"
EndSection

__END__

	echo " * Creating /etc/inittab (all but tty1 disabled to save memory)"
	cat > "$INST_DIR/etc/inittab" <<__END__
id:2:initdefault:
si::sysinit:/etc/init.d/rcS
~~:S:wait:/sbin/sulogin
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
z6:6:respawn:/sbin/sulogin
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop
1:2345:respawn:/sbin/getty 38400 tty1
#2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
__END__


	if [ -r "$INST_DIR"/etc/frameworkd.conf ]; then
		echo " * Disabling automated screen lock " # FIXME: should become optional
		if [ ! -r "$INST_DIR"/etc/frameworkd.conf.orig ]; then
			chroot "$INST_DIR" cp /etc/frameworkd.conf /etc/frameworkd.conf.orig
		fi
		cat "$INST_DIR"/etc/frameworkd.conf.orig | sed -e 's/^idle_prelock.*/idle_prelock = 0/' -e 's/^lock.*/lock = 0/' > "$INST_DIR"/etc/frameworkd.conf
	else
		echo "W: Missing file /etc/frameworkd.conf to disable automated screen lock"
	fi

	if [ -r "$INST_DIR"/etc/freesmartphone/oevents/rules.yaml ]; then
		echo " * Allow screen unlock to work without shutting off (AUX pressed, followed by Power shortly pressed)"
		if [ ! -r "$INST_DIR"/etc/freesmartphone/oevents/rules.yaml.orig ]; then
			chroot "$INST_DIR" cp /etc/freesmartphone/oevents/rules.yaml /etc/freesmartphone/oevents/rules.yaml.orig
		fi
		cat "$INST_DIR"/etc/freesmartphone/oevents/rules.yaml.orig | sed -e '/Suspend Handling/,/Suspend\(\)/ d' > "$INST_DIR"/etc/freesmartphone/oevents/rules.yaml
	else
		echo "W: Missing file /etc/freesmartphone/oevents/rules.yaml to allow screen unlock to work without shutting off"
	fi

	echo " * Creating /etc/modules"
	cat > "$INST_DIR/etc/modules" <<__END__
# USB RNDIS/Ethernet Gadget
g_ether

# bluetooth
ohci-hcd
hci_usb

# buttons
neo1973kbd

__END__
	if [ "$FSO_DEVICE" = gta01 ]; then
		cat >> "$INST_DIR/etc/modules" <<__END__
# audio
snd-soc-neo1973-wm8753
__END__
	else
		cat >> "$INST_DIR/etc/modules" <<__END__
# audio
snd-soc-neo1973-gta02-wm8753

# leds
leds-neo1973-gta02
__END__
	fi

	echo " * Setting FSCKFIX=yes in /etc/default/rcS"
	sed -i 's/FSCKFIX=.*/FSCKFIX=yes'/ "$INST_DIR/etc/default/rcS"

	echo " * Creating /etc/fstab"
	mkdir -p "$INST_DIR/mnt/flash"
	cat > "$INST_DIR/etc/fstab" <<__END__
rootfs	/		auto	defaults,errors=remount-ro,noatime	0 1
__END__

	if [ "$SINGLE_PART" != "true" ]; then
		if [ "ext2" = "$SD_PART1_FS" -o "ext3" = "$SD_PART1_FS" ]; then
			cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mmcblk0p1	/boot	auto	defaults,noatime			0 2
__END__

		else
			cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mmcblk0p1	/boot	auto	defaults,noatime,noauto			0 2
__END__

		fi

		if [ 0 -lt "$SD_SWAP_SIZE" ]; then
			cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mmcblk0p3  none    swap     sw                                     0 0
__END__

		fi
	else
		# $SINGLE_PART = "true"
		if [ 0 -lt "$SD_SWAP_SIZE" ]; then
			cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mmcblk0p2  none   swap     sw                                     0 0
__END__
		fi
	fi

	if [ "$FSO_DEVICE" = gta01 ]; then
	    cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mtdblock4	/mnt/flash	jffs2	defaults,noatime,noauto		0 2
__END__
	else
	    cat >> "$INST_DIR/etc/fstab" <<__END__
/dev/mtdblock6	/mnt/flash	jffs2	defaults,noatime,noauto		0 2
__END__
	fi

	cat >> "$INST_DIR/etc/fstab" <<__END__
proc	/proc		proc	defaults				0 0
tmpfs	/tmp		tmpfs	defaults,noatime			0 0
__END__

	echo " * Setting /etc/hostname to $HOSTNAME"
	echo "$HOSTNAME" > "$INST_DIR/etc/hostname"

	for FILE in /etc/network/interfaces /etc/resolv.conf; do
		echo " * $FILE copied from this machine"
		cat > "$INST_DIR$FILE" <$FILE
	done

	# empty passwords now require modification to PAM
	# http://lists.alioth.debian.org/pipermail/pkg-fso-maint/2009-May/001225.html
	# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=525153
	echo " * Setting root password to '$ROOT_PASSWORD'"
	echo "root:$ROOT_PASSWORD" | chroot "$INST_DIR" chpasswd

	for HOST_KEY in $DROPBEAR_KEYS; do
		if [ -f "$HOST_KEY" ]; then
			echo " * copying ssh host key $HOST_KEY"
			intern_d=`dirname $INST_DIR$HOST_KEY`
			if [ ! -d "$intern_d" ]; then
				echo "   Creating directory '$intern_d'"
				mkdir -p "$intern_d"
			fi
			cat >"$INST_DIR$HOST_KEY" <$HOST_KEY
		fi
	done


	echo " * Installing dash as /bin/sh: $DASH_BINSH"
	echo 'dash dash/sh string $DASH_BINSH' | chroot "$INST_DIR" debconf-set-selections
	chroot "$INST_DIR" apt-get $APT_OPTIONS install dash

	echo " * Installing /root/.xsession"
	cat > "$INST_DIR"/root/.xsession <<EOXSESSION
#!/bin/sh
$TRAYER &
openmoko-panel-plugin &
EOXSESSION

	if [ -x "$INST_DIR"/usr/bin/zhone ]; then
		cat >> "$INST_DIR"/root/.xsession <<EOXSESSION
zhone &
EOXSESSION
	else
		echo "   Not finding zhone application to autostart - omitted"
	fi

	cat >> "$INST_DIR"/root/.xsession <<EOXSESSION
exec matchbox-window-manager -use_titlebar no -use_cursor no
EOXSESSION

	if  [ "stalonetray" = "$TRAYER" ]; then
		cat >> "$INST_DIR"/root/.stalonetrayrc <<EOTRAYRC
# see /usr/share/doc/stalonetray/examples/stalonetrayrc.sample.gz
# with ideas for the configuration.
EOTRAYRC
	elif [ "trayer" = "$TRAYER" ]; then
		# let the trayer appear at the top of the screen
		sed -i "s/$TRAYER/$TRAYER --edge top/" "$INST_DIR"/root/.xsession
	fi

	# FIXME: the battery is deconfigured and should be
	#        put back on when the problems on .xsession-errors
	#        have been resolved.
	# Update:  Erich seems to have no problems.  2009/09/20
	echo " * Installing /root/.panel-pluginrc"
	cat > "$INST_DIR"/root/.panel-pluginrc <<EOPANELPLUGIN
[main]
plugins = buttons, gsm, wifi, gps, keyboard, brightness, screenlock, bluetooth, usb, battery
[buttons]
handleauxshortexternalcommand = exec /usr/bin/matchbox-keyboard
EOPANELPLUGIN

	if [ "$DISPLAY_MANAGER" = none ]; then
		echo " * Not installing the Display Manager"
	else
		echo " * Installing Display Manager $DISPLAY_MANAGER"
		if [ "$DISPLAY_MANAGER" = nodm ]; then
			echo 'nodm nodm/x_options string -nolisten tcp' | chroot "$INST_DIR" debconf-set-selections
			echo 'nodm nodm/first_vt string 3' | chroot "$INST_DIR" debconf-set-selections
			echo 'nodm nodm/enabled string true' | chroot "$INST_DIR" debconf-set-selections
		fi
		chroot "$INST_DIR" apt-get $APT_OPTIONS install $DISPLAY_MANAGER
	fi

	echo "I: Configuring system files for ${FSO_DEVICE} - done - System configured"
}


#
# Stage kernel
#

action_kernel () {
	echo "I: Installing kernel package"

	if [ "$FSO_DEVICE" != gta02 ]; then
		cat <<EOF

***********
* WARNING *
***********

Debian does not provide any kernel for the Openmoko Neo 1973.
You should install an official Openmoko kernel from

  http://wiki.openmoko.org/wiki/Kernel

EOF
	else
		ensure_proc_is_mounted

		intern_cmd="apt-get $APT_OPTIONS install linux-image-2.6.34-openmoko-gta02"

		if [ "$SD_PART1_FS" = "vfat" ]; then
			intern_bootmountpoint=$(mount | grep "^${SD_DEVICE}p1"| cut -f3 -d\ )
			if [ -z "$intern_bootmountpoint" -o "boot" != "$(basename "$intern_bootmountpoint")" ]; then
				echo " * installing to /boot"
				chroot "$INST_DIR" $intern_cmd
				echo " * cleaning apt cache"
				chroot "$INST_DIR" apt-get clean
				echo " * copying /boot/uImage.bin to first partition"
				if [ -z "$intern_bootmountpoint" ]; then
					if [ -n "$VERBOSE" ]; then
						echo "    Mounting first partition to /mnt/tmp_first_part_$$";
					fi
					mkdir /mnt/tmp_first_part_$$
					mount ${SD_DEVICE}p1 /mnt/tmp_first_part_$$

					if [ -n "$VERBOSE" ]; then
						echo "    Copying '$INST_DIR/boot/uImage.bin' to '/mnt/tmp_first_part_$$/'"
					fi
					cp "$INST_DIR/boot/uImage.bin" "/mnt/tmp_first_part_$$/"

					if [ -n "$VERBOSE" ]; then
						echo "    Unmounting first partition from /mnt/tmp_first_part_$$"
					fi
					umount /mnt/tmp_first_part_$$
					rmdir /mnt/tmp_first_part_$$
				else 
					if [ -n "$VERBOSE" ]; then
						echo "    Found first partitional already mounted to '$intern_bootmountpoint'."
					fi
					if [ -n "$VERBOSE" ]; then
						echo "    Copying '$INST_DIR/boot/uImage.bin' to '$intern_bootmountpoint/'."
					fi
					cp "$INST_DIR/boot/uImage.bin" "$intern_bootmountpoint/"
				fi
			
			else
				echo "W: when using $SD_PART1_FS as filesystem for the first microSD card"
				echo "   partition, you should manually install the kernel, since dpkg"
				echo "   does not support non-POSIX filesystems:"
				echo "     http://bugs.debian.org/bug=315493"
				echo
				echo "   The fix is to cp or mv the files manually. Just have everything"
				echo "   on regular extX partitions when running the installation, i.e."
				echo "   make sure, the first partition is not mounted to the /boot"
				echo "   directory when the installation is started. Then "
				echo "      '$intern_cmd'"
				echo "   and copy /boot/uImage.bin to your first partition mounted at some"
				echo "   other directory. Check the /etc/fstab afterwards. When no longer"
				echo "   mounted to /boot, you may also rerun "
				echo "     '$0 --part1-fs vfat kernel'."
				return 0
			fi
		else
			chroot "$INST_DIR" /bin/sh -e <<__END_CHROOT__
$intern_cmd
apt-get clean
__END_CHROOT__
		fi

		echo "I: Kernel installed"

		if [ "$QI" = "true" ]; then
			echo "Prepare system for booting with Qi"
			BOOT_DIR="$INST_DIR/boot/boot"
			if [ "$SINGLE_PART" = "true" ]; then
				BOOT_DIR="$INST_DIR/boot"
				ln -fs uImage.bin $BOOT_DIR/uImage-GTA02.bin
			else
				mkdir $BOOT_DIR
				ln -fs ../uImage.bin $BOOT_DIR/uImage-GTA02.bin
			fi
	
			if [ "$SINGLE_PART" = "true" ]; then
				ROOT_PART=${SD_DEVICE}p1
			else
				ROOT_PART=${SD_DEVICE}p2
			fi

			if [ "$QI_VERBOSE_BOOT" = "true" ]; then
				echo "root=$ROOT_PART console=tty0 loglevel=8" >$BOOT_DIR/append-GTA02
			else
				echo "root=$ROOT_PART rootdelay=1" >$BOOT_DIR/append-GTA02
			fi	
		fi
	fi

	echo "I: Installing kernel package - done"
}


#
# Stage uboot
#

action_uboot () {
	echo "I: Modifying U-Boot bootloader menu"

	if [ "$SD_PART1_FS" = "vfat" ]; then
		echo "W: When using $SD_PART1_FS as filesystem for the first microSD card"
		echo "   partition, you should not modify the U-Boot environment."
		return 1
	fi

	cat > "$INST_DIR/root/uboot_menu.in" <<'__END__'
bootcmd=
  setenv bootargs
    ${bootargs_base} ${mtdparts}
    rootfstype=ext2 root=/dev/mmcblk0p2 rootdelay=5;
  mmcinit;
  ext2load mmc 1 0x32000000 ${sd_image_name};
  bootm 0x32000000

menu_1=
  Boot from Flash:
  setenv bootargs
    ${bootargs_base} ${mtdparts};
  nand read.e 0x32000000 kernel 0x200000;
  bootm 0x32000000

menu_2=
  Reboot:
  reset

menu_3=
  Power off:
  neo1973 power-off

menu_4=
  Set console to USB:
  setenv stdin usbtty;
  setenv stdout usbtty;
  setenv stderr usbtty

menu_5=
  Set console to serial:
  setenv stdin serial;
  setenv stdout serial;
  setenv stderr serial

menu_6=

menu_7=

menu_8=
__END__

	echo " * Checking for a sane MTD configuration"
	if ! fgrep mtd2 < /proc/mtd |fgrep -q "u-boot_env"; then
		echo "E: U-Boot environment not found at expected location in mtd2"
		exit 1
	fi

	echo " * Mounting /dev inside the chroot at '$INST_DIR'"
	mount -o bind /dev "$INST_DIR/dev"
	chroot "$INST_DIR" /bin/sh -e <<__END_CHROOT__
echo " * Dumping current U-Boot environment"
#dd if=/dev/mtdblock2 of=\$INST_DIR/root/env.orig
nanddump /dev/mtd2 -o -b -f /root/env.orig
if [ ! \$(wc -c /root/env.orig | awk '{print \$1}') -eq $UBOOT_ENV_SIZE ]; then
	echo "Environment did not have the expected size of $UBOOT_ENV_SIZE"
	exit 1
fi
echo " * Merging Debian menu entries into U-Boot environment (can take up to 70s)"
uboot-envedit -i /root/env.orig -f /root/uboot_menu.in -o /root/env.new
if [ ! \$(wc -c /root/env.new | awk '{print \$1}') -eq $UBOOT_ENV_SIZE ]; then
	echo "Newly created environment did not have the expected size of $UBOOT_ENV_SIZE"
	exit 1
fi
echo " * Writing back U-Boot environment"
flash_eraseall /dev/mtd2
nandwrite /dev/mtd2 /root/env.new
__END_CHROOT__

	echo " * Unmounting /dev"
	umount "$INST_DIR/dev"

	echo "I: Modifying U-Boot bootloader menu - done"
}


#
# Stage cleaunp
#

action_cleanup () {

	echo "I: Cleaning the environment"

	echo " * Remove additional packages"
	intern_delenda=''
	intern_proposed_delenda='cdebootstrap-helper-rc.d xserver-xorg-input-synaptics' #carthago'
	for pakket in $intern_proposed_delenda; do
		if dpkg -s $pakket > /dev/null 2> /dev/null; then
			intern_delenda="$intern_delenda $pakket"
		fi
	done
	chroot "$INST_DIR" apt-get --yes --purge remove $intern_delenda

	echo " * Cleaning APT cache"
	chroot "$INST_DIR" apt-get clean

	echo "I: Cleaning the environment - done - the environment is now clean!"
}


#
# Stage unmount
#

action_unmount () {

	echo "I: Unmounting - start"

	if mount | grep -q "$INST_DIR/proc"; then
		echo -n " * Unmounting proc from install directory"
		if umount "$INST_DIR/proc"; then
			echo " [ok]"
		else
			echo " [failed]"
		fi
	elif [ -n "$VERBOSE" ]; then
		echo "I: /proc directory not mounted to install directory"
	fi


	echo " * Unmounting microSD card partitions"
	if [ "$SINGLE_PART" != "true" ]; then
		umount "$INST_DIR/boot"
	fi
	if ! umount "$INST_DIR"; then
		echo "W: Could not unmount install directory '$INST_DIR'."
		return 1;
	fi
	echo "I: microSD card partitions unmounted"

	intern_fstablines='E: the intern_fstablines remained unset'
	intern_line_or_lines='E: the intern_fstablines remained unset'
	if [ -z "$intern_instdir_already_present" -o "no" = "$intern_instdir_already_present" ]; then
		if ! rmdir "$INST_DIR"; then
			echo "W: Could not remove directory '$INST_DIR'."
			echo
		fi
		
		if [ "$SINGLE_PART" = "true" ]; then
			intern_fstablines="${SD_DEVICE}p1  $INST_DIR  auto  defaults,async  0  0"
			intern_line_or_lines="line"
		else
			intern_fstablines="${SD_DEVICE}p1  $INST_DIR/boot  auto  defaults,async  0  0
${SD_DEVICE}p2  $INST_DIR  auto  defaults,async  0  0"
			intern_line_or_lines="lines"
		fi
		
		cat <<EOINSTRUCTIONS

The partition on which Debian was installed is no
longer mounted. You may want to consider to recreate
the directory '$INST_DIR' (if necessary) with

if [ ! -d $INST_DIR ]; then mkdir "$INST_DIR"; fi

and add the $intern_line_or_lines

$intern_fstablines

to the file /etc/fstab, so it will be mounted with subsequent
boots into the current system.

EOINSTRUCTIONS
	fi

	echo "I: Unmounting - done"
	return 0
}

#
#     MAIN PROGRAM
#

if [ $# -eq 0 ]; then
  usage
fi

# internal variable

showHelp=""

# parse options

assignVariablename=""
assignParametername=""

vfat_check

for i in $*
do
        if [ -z "$assignVariablename" ]; then
                case "$i" in
                 "-h"|"--help"|"What's up, doc?")
                        showHelp="true"
                        ;;
                 "--verbose")
                        VERBOSE="true"
                        ;;
                 "-v")
                        echo "$internal_version"
			exit 0
                        ;;
		 "--apt-options")
                        assignParametername="$i"
                        assignVariablename="APT_OPTIONS"
			;;
	         "--bootstrapper")
			assignParametername="$i"
			assignVariablename="BOOTSTRAPPER"
			assignRegex='^(deboostrap|cdebootstrap)$'
			;;
		 "--hostname")
                        assignParametername="$i"
                        assignVariablename="HOSTNAME"
			;;
		 "--mount-proc")
			MOUNT_PROC="true"
			;;
		 "--no-mount-proc")
			MOUNT_PROC=""
			;;
		 "--no-partitioning")
			intern_no_partitioning="true"
			;;
		 "--part1-fs")
                        assignParametername="$i"
			assignVariablename="SD_PART1_FS"
			;;
		 "--part1-size")
                        assignParametername="$i"
			assignNumeric="true"
			assignVariablename="SD_PART1_SIZE"
			;;
		 "--swap-size")
                        assignParametername="$i"
			assignNumeric="true"
			assignVariablename="SD_SWAP_SIZE"
			;;
	         "--trayer")
			assignParametername="$i"
			assignVariablename="TRAYER"
			assignRegex='^(trayer|stalonetray)$'
			;;
		 "--with-localepurge")
			LOCALEPURGE="true"
			;;
		 "--with-tasks")
                        assignParametername="$i"
			assignVariablename="TASKS"
			;;
		 "all")
			if [ -z "$showHelp" ]; then
				echo "Running all stages"
				if [ "$FSO_DEVICE" != gta01 -a "$FSO_DEVICE" != gta02 ]; then
					echo "E: unsupported FSO_DEVICE '$FSO_DEVICE'"
					exit 1
				fi
				action_all
				echo
				echo "I: Done with all stages"
			fi
			;;
		 "testing"|"time"|"partition"|"format"|"mount"|"debian"|"apt"|"fso"|"configuration"|"kernel"|"unmount"|"uboot"|"tasks"|"cleanup")
			if [ -z "$showHelp" ]; then
				if [ -n "$VERBOSE" ]; then echo "I: Invoking stage $i"; fi
				if [ "$FSO_DEVICE" != gta01 -a "$FSO_DEVICE" != gta02 ]; then
					echo "E: unsupported FSO_DEVICE '$FSO_DEVICE'"
					exit 1
				fi
				action_$i
				if [ -n "$VERBOSE" ]; then echo "I: Done with stage $i"; fi
			fi
			;;
                *)
                        echo "Unknown option '$i'."
                        echo
                        showHelp="true"
                        ;;
                esac
        else
                eval $assignVariablename="$i"
                if [ "true" = "$assignNumeric" ]; then
                        # Testing if argument is indeed numerical
                        if ! echo $i | egrep -q '^[0-9]+$'; then
                                echo
                                echo "Usage error: argument '$assignParametername' needs a numerical argument, not something like '$i'."
                                echo
                                showHelp="true"
                        fi
		elif [ -n "$assignRegex" ]; then
			if ! echo "$i" | egrep -q "$assignRegex"; then
				echo
				echo "Usage error: argument '$assignParametername' does not match '$assignRegex'."
				echo 
                                showHelp="true"
			fi
                fi
                assignVariablename=""
                assignParametername=""
                assignNumeric=""
		assignRegex=""
        fi
done

if [ -n "$assignParametername" ]; then
        echo "Error: expected value for parameter '$assignParametername'."
        showHelp="true"
fi

if [ -n "$showHelp" ]; then
	usage
fi


exit 0
