#!/bin/sh
#
# Maemo ULTimate BOOTloader
#
# Copyright (C) 2010  Jay Cartman
#

# Search path
export PATH=/usr/sbin:/usr/bin:/sbin:/bin

# Timeout for the menu
MAIN_TIMEOUT=30

# Configuration directory
CONFIG_D=/etc/multiboot.d

# init searchlist
INIT_SEARCH="sbin/preinit sbin/init bin/init init linuxrc"

# vmlinuz searchlist
VMLINUZ_SEARCH="boot/multiboot/vmlinuz- boot/multiboot/zImage- boot/vmlinuz- boot/zImage-"

# modules.boot searchlist
MODULES_SEARCH="lib/modules/current/modules.boot etc/modules.boot system/etc/modules.boot"

# slide switch search list
SLIDE_SEARCH="slide sw_lid"

# Boot files
BOOT_ITEM="/boot/multiboot/.multiboot.item"
BOOT_FAST="/boot/multiboot/.multiboot.fast"
BOOT_LOG0="/boot/multiboot/.multiboot.log"

# MMC Cards
EXT_CARD="mmcblk0"
INT_CARD="mmcblk1"

# Predefined items
ARRAY__NAME__0__="Maemo (default)"
ARRAY__KERNEL__0__="2.6.28-omap1"

# Flags
FAST_BOOT=NO
BOOT_STATE=USER

# Colours
if [ -e /etc/INSIDE_QEMU ]
then
	BLACK=0x000000
	WHITE=0xFFFFFF
	BLUE=0x0000FF
	RED=0xFF0000
else
	BLACK=0x0000
	WHITE=0xFFFF
	BLUE=0x001F
	RED=0xF800
fi


################################################################################################
#
# UTILITY FUNCTIONS
#
################################################################################################


array()
{
	if [ -z "$3" ]
	then
		eval echo "\$ARRAY__${1}__${2}__"
	else
		eval ARRAY__$1__$2__="$3"
	fi
}


log()
{
	echo -e "$1" >> ${BOOT_LOG0}
	echo -e "$1"
}


error()
{
	echo -e "ERROR: $1" >> ${BOOT_LOG0}

	error_screen "$1"
	get_key 20000
	safe_reboot
}


safe_reboot()
{
	echo -n ${BOOT_STATE} > /var/lib/dsme/saved_state

	log "Rebooting..."

	mount / -o ro,remount
	sync
	reboot -f
}


safe_poweroff()
{
	echo -n ${BOOT_STATE} > /var/lib/dsme/saved_state

	log "Poweroff..."

	mount / -o ro,remount
	sync
	poweroff -f
}


get_boot_state()
{
	local state reason saved

	reason=$(cat /proc/bootreason)

	log "Boot reason: $reason"

	if [ -e /var/lib/dsme/saved_state ]
	then
		saved=$(cat /var/lib/dsme/saved_state)
	else
		saved=MALF
	fi

	case "${reason}" in
		pwr_key)	state=USER	;;
		update)		state=FLASH	;;
		usb)		state=ACT_DEAD	;;
		charger)	state=ACT_DEAD	;;
		rtc_alarm)	state=ACT_DEAD	;;

		sw_rst)		state=${saved}	;;

		por)		state=${saved}	;;
		32wd_to)	state=${saved}	;;
		swdg_to)	state=${saved}	;;

		*)		state=MALF	;;
	esac

	log "Boot state: $state"

	BOOT_STATE=${state}
}


get_key()
{
	evkey -u -t "$1" /dev/event1
}


is_slide_open()
{
	local name
	local state

	for name in ${SLIDE_SEARCH}
	do
		if [ -d /sys/devices/platform/gpio-switch/$name ]
		then
			state=$(cat /sys/devices/platform/gpio-switch/$name/state)
			log "Slide state from GPIO[$name]: $state"

			if [ X${state} = Xopen ]
			then
				return 0
			else
				return 1
			fi
		fi
	done

	state=$( evkey -s 0 /dev/event2 )
	if [ X$state = X1 ]
	then
		return 1
	fi

	state=$( evkey -s 0 /dev/event3 )
	if [ X$state = X1 ]
	then
		return 1
	fi

	log "Slide state unknown"

	return 0
}


is_fast_boot()
{
	test X${FAST_BOOT} = XYES -a -f ${BOOT_ITEM}
}


is_proc_mounted()
{
	test -f /proc/sys/kernel/version
}


is_sys_mounted()
{
	test -d /sys/devices/system/cpu
}


is_tmp_mounted()
{
	if is_proc_mounted
	then
		cat /proc/mounts | cut -d' ' -f 2 | grep -E -q '^/tmp$'
	else
		return 1
	fi
}


is_dev_mounted()
{
	if is_proc_mounted
	then
		cat /proc/mounts | cut -d' ' -f 2 | grep -E -q '^/dev$'
	else
		return 1
	fi
}


is_pts_mounted()
{
	if is_proc_mounted
	then
		cat /proc/mounts | cut -d' ' -f 2 | grep -E -q '^/dev/pts$'
	else
		return 1
	fi
}


is_mod_mounted()
{
	if is_proc_mounted
	then
		cat /proc/mounts | cut -d' ' -f 2 | grep -E -q '^/lib/modules/'
	else
		return 1
	fi
}


mknod_misc()
{
	local NAME="$1"
	local DEV="$2"

	local a b c
	local minor=""

	if is_proc_mounted
	then
		minor=$(cat /proc/misc | grep -F "$DEV" | cut -f 1 -d' ')
	else
		case "$DEV" in
			watchdog)	minor=130 ;;
			twl4030_wdt)	minor=142 ;;
			twl4030-adc)	minor=58  ;;
			*)		minor=""  ;;
		esac
	fi

	if [ -n "${minor}" ]
	then
		mknod "$NAME" c 10 "${minor}"
	fi
}


wait_root_device()
{
	local dev=$1
	local wait=$2

	while [ $wait -gt 0 ]
	do
		if grep -F -q $dev /proc/partitions
		then
			if [ -b /dev/$dev ]
			then
				log "Root device $dev OK"
				return 0
			else
				error "Device node /dev/$dev NOT found!"
				return 1
			fi
		fi

		wait=$(expr $wait - 1)
		sleep 1
	done

	error "Root filesystem $dev NOT available!"

	return 1
}


load_kernel_modules()
{
	local FILE=""

	local file module args

	for file in ${MODULES_SEARCH}
	do
		if [ -e $file ]
		then
			FILE=$file
			break
		fi
	done

	if [ -f "${FILE}" ]
	then
		log "Loading kernel modules from ${FILE}"

		cat ${FILE} | grep -E -v '^#' | while read module args
		do
			if [ -n "${module}" ]
			then
				log "Loading module ${module}"
				modprobe -i -q ${module} ${args}
			fi
		done
	fi
}


load_modules()
{
	local module

	for module
	do
		log "Loading module $module"
		modprobe -i -q $module
	done
}


load_pmconfig()
{
	local FILE=$1/etc/power.conf

	if [ -e $FILE ]
	then
		log "Loading kernel power configuration from $FILE"
		powerconfig $FILE
	fi
}


read_config()
{
	local file
	local i=1

	ITEM_LIST=""

	for file in ${CONFIG_D}/*.item
	do
		if [ -e "$file" ]
		then
			log "Reading boot item [$i] from file $file"

			eval $( /sbin/multiboot_read_item FN=$i $file )

			ITEM_LIST="${ITEM_LIST} $i"
			i=$(expr $i + 1)

			if [ $i -gt 9 ]
			then
				return
			fi
		fi
	done
}


load_config()
{
	local file="$2"

	if [ -f "$file" ]
	then
		log "Reading boot item [$1] from file $file"

		eval $( /sbin/multiboot_read_item FN=$1 $file )
	fi
}


store_config()
{
	local file="$2"

	log "Storing boot configuration into file $file"

	(
		echo "ITEM_ID=\"$( array ID $1 )\""
		echo "ITEM_NAME=\"$( array NAME $1 )\""
		echo "ITEM_KERNEL=\"$( array KERNEL $1 )\""
		echo "ITEM_MODULES=\"$( array MODULES $1 )\""
		echo "ITEM_PARAMS=\"$( array PARAMS $1 )\""
		echo "ITEM_DEVICE=\"$( array FS_ROOT $1 )\""
		echo "ITEM_FSTYPE=\"$( array FS_TYPE $1 )\""
		echo "ITEM_FSOPTIONS=\"$( array FS_OPTS $1 )\""
		echo "ITEM_LINUXRC=\"$( array INITRC $1 )\""
		echo "ITEM_INITFS=\"$( array INITFS $1 )\""
	) > $file
}


flash_kernel()
{
	log "Flashing kernel file $1"

	ifconfig lo 127.0.0.1 netmask 255.0.0.0 up

	softupd --local --verbose --stdout --standalone &
	flasher --local -f -k $1

	ifconfig lo down
}


swap_kernel()
{
	local KERNEL=$( array KERNEL $1 )
	local VMLINUZ='none'

	for prefix in ${VMLINUZ_SEARCH}
	do
		if [ -f ${prefix}${KERNEL} -a -d /lib/modules/${KERNEL} ]
		then
			VMLINUZ=${prefix}${KERNEL}
			break
		fi
	done

	if [ -f ${VMLINUZ} ]
	then
		store_config $1 ${BOOT_ITEM}
		touch ${BOOT_FAST}

		flash_kernel ${VMLINUZ}

		safe_reboot
	else
		error "Can't flash kernel, required files not found"
	fi
}



################################################################################################
#
# SCREEN FUNCTIONS
#
################################################################################################

wait_keypress()
{
	local t

	t=$MAIN_TIMEOUT

	while [ $t -gt 0 ]
	do
		text2screen -t "[$t] " -s 2 -x 700 -y 108 -B ${BLACK} -T ${WHITE}

		if get_key 1000
		then
			return 0
		fi

		t=$(expr $t - 1)
	done

	echo "D"

	return 1
}


init_screen()
{
	echo -e '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
	echo -e '\r---------------------------------------------------------------------------------------------------\r'
}


clear_screen()
{
	text2screen -c -x 0 -y 0 -w 800 -h 480 -B ${BLACK}
}


wait_screen()
{
        text2screen -c -x 0 -y 0   -w 790 -h 464 -B ${WHITE}
	text2screen -c -x 0 -y 100 -w 790 -h 30  -B ${BLACK}
	text2screen -c -x 0 -y 464 -w 800 -h 16  -B ${BLACK}
	text2screen -c -x 790 -y 0 -w 10 -h 480  -B ${BLACK}

	text2screen -t "$(array NAME $1)" -s 3 -x 40 -y 40 -T ${BLUE} -B ${WHITE}
	text2screen -t "BOOTING - PLEASE WAIT" -s 2 -x 40 -y 108 -T ${WHITE} -B ${BLACK}

	text2screen -t "Kernel  : $(array KERNEL $1)"  -s 2 -x 20 -y 160 -T ${BLACK} -B ${WHITE}
	text2screen -t "Params  : $(array PARAMS $1)"  -s 2 -x 20 -y 180 -T ${BLACK} -B ${WHITE}
	text2screen -t "Modules : $(array MODULES $1)" -s 2 -x 20 -y 200 -T ${BLACK} -B ${WHITE}
	text2screen -t "Device  : $(array FS_ROOT $1)" -s 2 -x 20 -y 220 -T ${BLACK} -B ${WHITE}
	text2screen -t "FS type : $(array FS_TYPE $1)" -s 2 -x 20 -y 240 -T ${BLACK} -B ${WHITE}
	text2screen -t "FS opts : $(array FS_OPTS $1)" -s 2 -x 20 -y 260 -T ${BLACK} -B ${WHITE}
	text2screen -t "linuxrc : $(array INITRC $1)" -s 2 -x 20 -y 280 -T ${BLACK} -B ${WHITE}
	text2screen -t "initfs  : $(array INITFS $1)" -s 2 -x 20 -y 300 -T ${BLACK} -B ${WHITE}
}


error_screen()
{
	text2screen -c -x 0 -y   0 -w 790 -h 100 -B ${RED}
	text2screen -c -x 0 -y 100 -w 790 -h 364 -B ${WHITE}
	text2screen -c -x 10 -y 10 -w 770 -h  80 -B ${BLACK}

	text2screen -t "$1" -s 2 -x 40 -y 30 -T ${RED} -B ${BLACK}
	text2screen -t "Guru Meditation #00000025.62017712" -s 2 -x 120 -y 60 -T ${RED} -B ${BLACK}

	text2screen -t "Hit any key to panic" -s 1 -x 320 -y 260 -T ${BLACK} -B ${WHITE}
}


print_menu()
{
	local x y i

        text2screen -c -x 0 -y 0   -w 790 -h 464 -B ${WHITE}
	text2screen -c -x 0 -y 100 -w 790 -h 30  -B ${BLACK}
	text2screen -c -x 0 -y 464 -w 800 -h 16  -B ${BLACK}
	text2screen -c -x 790 -y 0 -w 10  -h 480 -B ${BLACK}

	text2screen -t "NOKIA N900 - MULTIBOOT" -s 3 -x 40 -y 40 -T ${BLUE} -B ${WHITE}
	text2screen -t "Press a key to select" -s 2 -x 40 -y 108 -T ${WHITE} -B ${BLACK}

	x=60
	y=160

	for i in ${ITEM_LIST}
	do
		text2screen -t "$i - $(array NAME $i)" -x $x -y $y -T ${BLACK} -B ${WHITE} -s 2
		y=$(expr $y + 22)
	done
}



################################################################################################
#
# BOOTING FUNCTIONS
#
################################################################################################


init_log()
{
	test -f ${BOOT_LOG0}.5  &&  mv -f ${BOOT_LOG0}.5 ${BOOT_LOG0}.6
	test -f ${BOOT_LOG0}.4  &&  mv -f ${BOOT_LOG0}.4 ${BOOT_LOG0}.5
	test -f ${BOOT_LOG0}.3  &&  mv -f ${BOOT_LOG0}.3 ${BOOT_LOG0}.4
	test -f ${BOOT_LOG0}.2  &&  mv -f ${BOOT_LOG0}.2 ${BOOT_LOG0}.3
	test -f ${BOOT_LOG0}.1  &&  mv -f ${BOOT_LOG0}.1 ${BOOT_LOG0}.2
	test -f ${BOOT_LOG0}    &&  mv -f ${BOOT_LOG0}   ${BOOT_LOG0}.1

	log "MULTIBOOT starting up"
}


init_hw()
{
	log "Initializing HW"

	## Kernel modules required in bootup

	load_modules omap_wdt twl4030_wdt
	load_modules omap_hsmmc mmc_core mmc_block
	load_modules twl4030-madc
	load_modules led-class leds-lp5523
}


init_backlight()
{
	log "Initializing backlights"

	for i in 1 2 3 4 5 6 ; do
		echo 208 > /sys/class/leds/lp5523:kb${i}/brightness
	done

	echo 120 > /sys/class/backlight/acx565akm/brightness
}


init_pm()
{
	log "Initializing default power configuration"

	## Default values for Maemo

	echo 1  > /sys/power/enable_off_mode
	echo 1  > /sys/power/sleep_while_idle
	echo 1  > /sys/power/clocks_off_while_idle
	echo 1  > /sys/power/voltage_off_while_idle
	echo 0  > /sys/power/sr_vdd1_autocomp
	echo 0  > /sys/power/sr_vdd2_autocomp

	echo ondemand  > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
	echo 600000    > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
	echo 250000    > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq

	echo 600000    > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
}


init_fs()
{
	log "Mounting filesystems: proc sys tmp dev"

	# Mount point for new root
	test -d /mnt || mkdir -m 0700 /mnt

	# Mount pseudo filesystems
	is_proc_mounted || mount -t proc  none /proc
	is_sys_mounted  || mount -t sysfs none /sys
        is_dev_mounted  || mount -t tmpfs none -o size=128K /dev
        is_tmp_mounted  || mount -t tmpfs none -o size=512K /tmp

	# Mount for pts
	if ! is_pts_mounted
	then
		mkdir /dev/pts
##		mount -t devpts devpts /dev/pts -o gid=5,mode=0620
	fi

	# Dev nodes
	log "Creating device nodes in /dev"

        mknod /dev/mem  c 1 1
        mknod /dev/null c 1 3
        mknod /dev/zero c 1 5
        mknod /dev/kmem c 1 2
        mknod /dev/kmsg c 1 11

        mknod /dev/mtd0 c 90 0
        mknod /dev/mtd1 c 90 2
        mknod /dev/mtd2 c 90 4
        mknod /dev/mtd3 c 90 6
        mknod /dev/mtd4 c 90 8
        mknod /dev/mtd5 c 90 10

	mknod /dev/mmcblk0   b 179 0
	mknod /dev/mmcblk0p1 b 179 1
	mknod /dev/mmcblk0p2 b 179 2
	mknod /dev/mmcblk0p3 b 179 3
	mknod /dev/mmcblk0p4 b 179 4
	mknod /dev/mmcblk0p5 b 179 5
	mknod /dev/mmcblk0p6 b 179 6
	mknod /dev/mmcblk0p7 b 179 7

	mknod /dev/mmcblk1   b 179 8
	mknod /dev/mmcblk1p1 b 179 9
	mknod /dev/mmcblk1p2 b 179 10
	mknod /dev/mmcblk1p3 b 179 11
	mknod /dev/mmcblk1p4 b 179 12
	mknod /dev/mmcblk1p5 b 179 13
	mknod /dev/mmcblk1p6 b 179 14
	mknod /dev/mmcblk1p7 b 179 15

        mknod /dev/i2c-1 c 89 1
        mknod /dev/i2c-2 c 89 2
        mknod /dev/i2c-3 c 89 3

	mknod /dev/event0 c 13 64
	mknod /dev/event1 c 13 65
	mknod /dev/event2 c 13 66
	mknod /dev/event3 c 13 67

        mknod /dev/console c 5 1

	mknod /dev/fb0 c 29 0
	mknod /dev/fb1 c 29 1
	mknod /dev/fb2 c 29 2

        mknod_misc /dev/watchdog      watchdog
        mknod_misc /dev/twl4030_wdt   twl4030_wdt
        mknod_misc /dev/twl4030-adc   twl4030-adc
        mknod_misc /dev/twl4030-madc  twl4030-adc

	mkdir -m 0755 /dev/shm

        ln -s /proc/self/fd   /dev/fd
        ln -s /proc/self/fd/0 /dev/stdin
        ln -s /proc/self/fd/1 /dev/stdout
        ln -s /proc/self/fd/2 /dev/stderr

	## Modules
	log "Configuring modules for $(uname -r)"

	# Current link
	rm -f /lib/modules/current
	ln -s $(uname -r) /lib/modules/current

	# Depmod
	depmod -A $(uname -r)

	# Boot reason
	get_boot_state
}


done_fs()
{
	log "Unmounting filesystems: pts dev tmp sys proc"

	# Unmount filesystems
	is_mod_mounted     && umount /lib/modules/$(uname -r)
	is_pts_mounted     && umount /dev/pts
	is_dev_mounted     && umount /dev
	is_tmp_mounted     && umount /tmp
	is_sys_mounted     && umount /sys
	is_proc_mounted    && umount /proc

	# All written to disks
	sync
}


mount_root()
{
	local FS_ROOT=$(array FS_ROOT $1)
	local FS_TYPE=$(array FS_TYPE $1)
	local FS_OPTS=$(array FS_OPTS $1)
	local MODULES=$(array MODULES $1)

	local OPTS=""

	if [ -n "$FS_TYPE" ]
	then
		OPTS="${OPTS} -t $FS_TYPE"
	fi

	if [ -n "$FS_OPTS" ]
	then
		OPTS="${OPTS} -o $FS_OPTS"
	fi

	if [ -n "$MODULES" ]
	then
		load_modules $MODULES
	fi

	if wait_root_device "$FS_ROOT" 10
	then
		if mount $OPTS /dev/${FS_ROOT} /mnt
		then
			log "Mounted root device ${FS_ROOT} on /mnt"
		else
			error "Mounting root device ${FS_ROOT} FAILED"
			return 1
		fi
	else
		error "Root device ${FS_ROOT} not accessible"
		return 1
	fi

	return 0
}


umount_root()
{
	local FS_ROOT=$(array FS_ROOT $1)

	log "Unmounting root ${FS_ROOT}"

	umount "$FS_ROOT"
}


prepare_root()
{
	local ROOT="$1"
	local INITFS="$2"
	local MPATH="/lib/modules/$(uname -r)"

	log "Preparing root filesystem"

	# Must have initfs mount point
	if [ ! -d ${ROOT}/${INITFS} ]
	then
		rm -f ${ROOT}/${INITFS}
		mkdir -m 0755 ${ROOT}/${INITFS}
	fi

	# Current link in modules
	rm -f ${ROOT}/lib/modules/current
	ln -s $(uname -r) ${ROOT}/lib/modules/current

	# Modules overlay
	mount -o bind ${ROOT}/${MPATH} ${MPATH}

	# Depencies - now using the overlay
	depmod -A $(uname -r)
}


boot_maemo()
{
	log "Booting Maemo default configuration"

	# Booting ok - save as default
	case ${BOOT_STATE} in
		BOOT|USER|FLASH|SHUTDOWN)
			store_config $1 ${BOOT_ITEM}
			;;
	esac

	# Load all kernel modules
	load_kernel_modules

	# Limits
	ulimit -c unlimited
	ulimit -l unlimited

	# HW Settings
	echo active  > /sys/devices/platform/gpio-switch/cmt_bsi/state
	echo 10  > /sys/devices/platform/serial8250.0/sleep_timeout

	# init RUNLEVEL
	case ${BOOT_STATE} in
		BOOT)		INITLEVEL=6  ;;
		USER|FLASH)	INITLEVEL=2  ;;
		ACT_DEAD)	INITLEVEL=5  ;;
		LOCAL|TEST)	INITLEVEL=3  ;;
		SHUTDOWN)	INITLEVEL=0  ;;
	        *) 		INITLEVEL=2  ;;
	esac

	# let me see then, what thereat is and this mistery explore
##	fiasco-do-update

	# Done with filesystems
	done_fs

	# Start init
	log "Starting /sbin/init ${INITLEVEL}"

	# Switch over
	exec /sbin/init ${INITLEVEL}

	# Fatal error
	error "Excuting Maemo /sbin/init FAILED"

	# Fallback
	safe_reboot
}


boot_script()
{
	log "Running script $*"

	# Clear screen
	clear_screen

	# Done with filesystems
	done_fs

	# Start the script
	exec "$@"

	# Fallback
	safe_reboot
}


boot_chroot()
{
	local INITRC=$(array INITRC $1)
	local INITFS=$(array INITFS $1)

	# No initfs defined
	if [ -z "${INITFS}" ]
	then
		INITFS="mnt/initfs"
	else
		INITFS=${INITFS##/}
	fi

	log "initfs in ${INITFS}"

	# Mount new root filesystem
	if mount_root $1
	then
		# Booting ok - save as default
		store_config $1 ${BOOT_ITEM}

		# Prepare root filesystem
		prepare_root /mnt ${INITFS}

		# Load all kernel modules
		load_kernel_modules

		# PM configuration
		load_pmconfig /mnt

		# Done with extra filesystems
		done_fs

		# Must log before pivot
		log "Switching over to init"

		# New root location
		cd /mnt || return 1

		# Pivot root into initfs
		pivot_root . ${INITFS}

		# Switch over
		for file in ${INITRC} ${INIT_SEARCH}
		do
			if [ -x ${file} ]
			then
				exec chroot . ${file}
				error "Excuting target ${file} FAILED"
			fi
		done

		# Fatal error
		error "Can't find init binary in target OS"
	fi
}


boot_kexec()
{
	local KERNEL=$(array KERNEL $1)
	local PARAMS=$(array PARAMS $1)
	local ROOT=$(array FS_ROOT $1)
	local CMDLINE
	local PREFIX="/"

	# New root FS needed
	if [ -n "$ROOT" ]
	then
		if mount_root $1
		then
			PREFIX="/mnt"
		else
			return 1
		fi
	fi

	# Command line
	if [ -n "${PARAMS}" ]
	then
		CMDLINE="${PARAMS}"
	else
		CMDLINE="$(cat /proc/cmdline)"
	fi

	log "Booting [${PREFIX}]${KERNEL} ${CMDLINE}"

	if [ -e "${PREFIX}${KERNEL}" ]
	then
		# Load new kernel
		kexec -l "${PREFIX}${KERNEL}" --command-line="${CMDLINE}"

		# Say something
		log "kexec now..."

		# Done with FS access
		done_fs
		sync

		# Start the kernel
		exec kexec -f -e
	else
		error "kernel version ${KERNEL} not found."
	fi

	return 1
}


boot_item()
{
	local NAME=$(array NAME $1)
	local ROOT=$(array FS_ROOT $1)
	local KERNEL=$(array KERNEL $1)

	log "Booting item #$1"

	if [ -n "$NAME" ]
	then
		if [ -z "$KERNEL" -o "$KERNEL" == "$(uname -r)" ]
		then
			if [ -z "$ROOT" ]
			then
				boot_maemo $1
			else
				boot_chroot $1
			fi

			safe_reboot
		else
			if [ X${FAST_BOOT} != XYES ]
			then
				swap_kernel $1
			fi
		fi
	fi
}


boot_shell()
{
	log "Starting shell"

	clear_screen

	echo -e "\n\nEntering a root shell.\nType 'exit' to leave."

	if [ -x /sbin/getty ]
	then
		/sbin/getty 115200 console -n -l /bin/sh
	else
		/bin/sh
	fi

	log "Rebooting..."

	sleep 3

	safe_reboot
}


main()
{
	local sel i

	init_log
	init_hw
	init_fs
	init_pm

	if [  ${BOOT_STATE} = ACT_DEAD ]
	then
		boot_maemo
	fi

	if [ -f ${BOOT_FAST} ]
	then
		FAST_BOOT=YES
		rm -f ${BOOT_FAST}
	fi

	if [ -f ${BOOT_ITEM} ]
	then
		load_config 99 ${BOOT_ITEM}
	fi

	if is_fast_boot || ! is_slide_open
	then
		boot_item 99
	fi

	init_screen
	init_backlight

	read_config

	while :
	do
		print_menu

		sel=$(wait_keypress)

		echo -e -n '\r'

		case $sel in

			# Timeout
			D)   sel=99 ;;

			# Enter
		        28)  sel=99 ;;

			# 0-9
			16)  sel=1 ;;
			17)  sel=2 ;;
			18)  sel=3 ;;
			19)  sel=4 ;;
			20)  sel=5 ;;
			21)  sel=6 ;;
			22)  sel=7 ;;
			23)  sel=8 ;;
			24)  sel=9 ;;
			25)  sel=0 ;;

		        # B - Boot default
		        48)  sel=0 ;;

			# S - shell
			31)  boot_shell ;;

		        # Backscape - reboot
		        14)  safe_reboot ;;

			# X - poweroff
                        45)  safe_poweroff ;;

			# D -  Debugging another script
			32)  boot_script /sbin/multiboot_debug  ;;

		esac

		if [ -n "$(array NAME $sel)" ]
		then
			wait_screen $sel
			boot_item $sel
		fi

		log "Booting item #${sel} failed. Trying again."
	done
}


main

# End
