#!/bin/bash
#
# splash_manager -- a convenience utility to perform various splash-related
#                   tasks in an easy and user-friendly way
#
# Copyright (C) 2005-2007, Michal Januszewski <spock@gentoo.org>
#
# This file is a part of the splashutils package.
#
# This file is subject to the terms and conditions of the GNU General Public
# License v2.  See the file COPYING in the main directory of this archive for
# more details.
#

# TODO:
# - support for icons and scripts in themes
# - support for '-v'
# - support for 8bpp modes

# BUGS:
# - replay won't work correctly when started from a tty with a video mode
#   different from the one used for the silent tty

# System configuration variables
spl_util=splash_util.static
spl_daemon=fbsplashd.static
spl_decor=fbcondecor_ctl
spl_dir="/usr/lib/splash"
spl_fifo=${spl_dir}/cache/.splash
spl_pidfile=${spl_dir}/cache/daemon.pid
themedir="//etc/splash"

spl_daemon_exename="$(basename ${spl_daemon})"
spl_daemon_short="${spl_daemon:0:9}"

cleanup() {
	killall ${spl_daemon_exename} 2>/dev/null
	chvt ${ctty}
}

usage() {
	cat <<EOTB
splash_geninitramfs/splashutils-1.5.4.4
Usage: splash_manager [options] -c <command>

Commands:
 benchmark
 demo    test a splash theme
 list    list available splash themes
 set     set a splash theme on a specific tty
 shot    take a screenshot of a selected splash theme
 switch  switch a splash theme by changing GRUB/LILO config files
 replay  replay a complete boot sequence using splash profile data

Options:
 -c, --cmd=CMD      execute CMD
 -h, --help         display this message
 -t, --theme=THEME  [bdehsr] theme name
     --steps=N      [ d    ] use N steps when testing the silent splash
     --delay=N      [ d    ] delay each step by N seconds
 -m, --mode=(v|s)   [ d h  ] specify which mode to use (verbose/silent)
     --tty=N        [bdeh  ] set the theme on the Nth tty
 -e, --exec=CMD     [   h  ] run CMD on the tty where splash is being tested
     --progress=N   [   h  ] set progress to N (0-65535)
     --msg=MSG      [bd h  ] set the main system message to MSG
     --profile=FILE [     r] read splash profile data from FILE

The letters in the square brackets indicate the commands with which
specific options can be used: b (bechmark) d (demo), e (set), h (shot),
s (switch), r (replay).

Examples:
 splash_manager -c switch -t livecd-2005.0
   (switch to the 'livecd-2005.0' theme; the new theme will be used
    after reboot)

 splash_manager -c set -t linux --tty=8
   (set the 'linux' theme on the 8th tty)

 splash_manager -c demo -t livecd-2005.0 -m s --steps=100
   (run a demonstration of the 'livecd-2005.0' theme, silent mode;
    use 100 steps for the progress bar)

 splash_manager -c shot -t foobar -m s --progress=32767 --msg='Smile!'
   (take a screenshot of the 'foobar' theme, silent mode; set progress
    to 50% and use 'Smile!' as the main system message)
EOTB
}

CGOOD=$'\e[32;01m'
CWARN=$'\e[33;01m'
CBAD=$'\e[31;01m'
CNORM=$'\e[0m'
CHILITE=$'\e[36;01m'
CBRACKET=$'\e[34;01m'

# void err(char *msg)
#   Displays an error message.
err() {
	echo -e "${CBAD}Error:${CNORM} $*" >&2
}

# void einfo(char *msg)
#   Displays an informational message.
einfo() {
	echo -e "${CGOOD}*${CNORM} $*"
}

# void ewarn(char *msg0
#   Display a warning message.
ewarn() {
	echo -e "${CWARN}*${CNORM} $*"
}

# void spl_comm(char *msg)
#   Sends 'msg' to the splash fifo.
spl_comm() {
	if [ ! -e ${spl_pidfile} ]; then
		return 1
	fi

	if [ "$(pgrep ${spl_daemon_short})" == "$(<${spl_pidfile})" ]; then
		echo "$*" > ${spl_fifo} &
	else
		err "Splash daemon not running!"
		rm -f "${spl_pidfile}"
	fi
}

# void chvt(int n)
#   Switches to the n-th tty.
chvt() {
	local ntty=$1

	if [ -x /usr/bin/chvt ] ; then
		/usr/bin/chvt ${ntty}
	else
		echo -en "\e[12;${ntty}]"
	fi
}


# void theme_sanity_check(char *theme)
#   Performs a theme sanity check -- checks whether a theme exists.
theme_sanity_check() {
	local theme=$1
	local t=${res}

	# For verbose mode, we care about the real resolution, not the one
	# fbsplash would be using for the silent mode.
	if [ "${mode}" == "v" ]; then
		t=${rres}
	fi

	if [ -z "${theme}" ]; then
		err "You have to specify a theme name."
		exit 1
	fi

	if [ ! -e "${themedir}/${theme}/${t}.cfg" ]; then
		err "Theme '${theme}' doesn't seem to provide a config file for the current resolution (${t})."
		exit 1
	fi
}

# void set_theme(char *theme, int tty)
#   Sets a theme on a specific tty.
set_theme() {
	local theme=$1
	local tty=$2

	theme_sanity_check "${theme}"
	[ -z "${tty}" ] && tty="${ctty}"
	${spl_decor} -c setcfg -t "${theme}" --tty="${tty}"
	[ "${tty}" == "${ctty}" ] && ${spl_decor} -c setpic -t "${theme}" --tty="${tty}"
	${spl_decor} -c on --tty=${tty}
}

# void get_theme(int tty)
#   Prints the name of the theme that is used on a tty.
get_theme() {
	local ctty=$1
	echo $(${spl_decor} --tty=${ctty} -c getcfg | grep theme | awk '{ print $2 }')
}

# void get_state(int tty)
#   Prints 'on' or 'off', indicating fbsplash state on a tty.
get_state() {
	local ctty=$1
	echo $(${spl_decor} --tty=${ctty} -c getstate | cut -f2 -d: | tr -d ' ')
}

# void check_silent(char *theme, char *res, char *action)
#   Checks whether a theme supports the silent splash mode.
check_silent() {
	local ctheme=$1
	local cres=$2
	local action=$3

	if [ -z $(cat "${themedir}/${ctheme}/${cres}.cfg" 2>/dev/null | egrep "^silent(pic|jpeg)=") ]; then
		[ "${action}" == "test" ] && return 1
		err "Theme '${ctheme}' doesn't support the silent splash mode."
		exit 1
	fi
}

# void check_verbose(char *theme, char *res, char *action)
#   Checks whether a theme supports the verbose splash mode.
check_verbose() {
	local ctheme=$1
	local cres=$2
	local action=$3

	if [ -z $(cat "${themedir}/${ctheme}/${cres}.cfg" 2>/dev/null | egrep "^(pic|jpeg)=") ]; then
		[ "${action}" == "test" ] && return 1
		err "Theme '${ctheme}' doesn't support the silent splash mode."
		exit 1
	fi

	return 0
}

set_silent() {
	trap "cleanup" EXIT

	# Make sure the splash daemon is not running
	killall -9 ${spl_daemon_exename} 2>/dev/null
	${spl_daemon} -t "${theme}" --pidfile ${spl_pidfile} ${util_params}
	pid=$(cat ${spl_pidfile})

	[ -z "${msg}" ] && msg="Testing the '${theme}' theme (\$progress%)..."
	spl_comm "set message ${msg}"
	[ -n "${tty}" ] && spl_comm "set tty silent ${tty}"
	spl_comm "set mode silent"
	spl_comm "repaint"
}

exit_silent() {
	spl_comm "exit"

	while [[ "$(head -n 1 /proc/${pid}/status 2>/dev/null | cut -f2)" == "${spl_daemon_short}" ]]; do
		sleep 0.5
	done

	while [ "`fgconsole`" != ${ctty} ] ; do
		chvt ${ctty}
	done
}

benchmark() {
	check_silent "${theme}" "${res}"
	set_silent

	step=16
	timestart=$(date +"%s.%N")
	for ((i=0;i<65536;i=$i+$step)) ; do
		echo "progress $i" > ${spl_fifo}
		echo "paint" > ${spl_fifo}
	done
	timeend=$(date +"%s.%N")
	exit_silent
	
	echo "Test took $(echo "$timeend - $timestart" | bc) seconds."
}

demo_theme_silent() {
	check_silent "${theme}" "${res}"
	if [ -z "$(echo ${util_params} | grep -- '--type=')" ]; then
		export util_params="${util_params} --type=bootup"
	fi
	set_silent

	# Set the input device if it exists. This will make it possible to use F2 to
	# switch from verbose to silent.
	local t=$(grep -Hsi keyboard /sys/class/input/input*/name | sed -e 's#.*input\([0-9]*\)/name.*#event\1#')
	if [[ -z "${t}" ]]; then
		t=$(grep -Hsi keyboard /sys/class/input/event*/device/driver/description | grep -o 'event[0-9]\+')
		if [[ -z "${t}" ]]; then
			# Try an alternative method of finding the event device. The idea comes
			# from Bombadil <bombadil(at)h3c.de>. We're couting on the keyboard controller
			# being the first device handled by kbd listed in input/devices.
			t=$(/bin/grep -s -m 1 '^H: Handlers=kbd' /proc/bus/input/devices | grep -o 'event[0-9]*')
		fi
	fi

	if [[ -n "${t}" ]]; then
		spl_comm "set event dev /dev/input/${t}"
	fi

	if [[ -n "$(pgrep gpm)" ]]; then
		spl_comm "set gpm"
	fi

	[ -z "${delay}" ] && delay=0.05
	step=$((65535/$steps))

	for ((i=0;i<65536;i=$i+$step)) ; do
		spl_comm "progress $i"
		spl_comm "paint"
		sleep ${delay}
	done
	spl_comm "progress 65535"
	spl_comm "paint"
	exit_silent
}

replay() {
	check_silent "${theme}" "${res}"

	if [[ -z "${profile}" ]]; then
		err "You have to specify a splash profile file."
		exit 1
	fi

	if [[ ! -r "${profile}" ]]; then
		err "Profile file '${profile}' not found."
		exit 1
	fi

	trap "cleanup" EXIT

	ctime=0

	if [[ -e /etc/gentoo-release ]]; then
		export RUNLEVEL="S"
		export SOFTLEVEL=""
	fi

	source //usr/bin/splash-functions.sh
	splash_setup

	export SPLASH_XRES="$xres"
	export SPLASH_YRES="$yres"
	export SPLASH_THEME=${theme}

	while read line ; do
		arr=($line)
		t=${arr[0]:0:$((${#arr[0]}-1))}
		tdec=${t##*.}
		utime=$((${t%.*}*1000 + ${tdec#0*}*10))

		[[ "$ctime" == "0" ]] && ctime=${utime}

		delay=$((${utime} - ${ctime}))
		sleep "$(($delay/1000)).$(printf '%03d' $(($delay%1000)))"
		ctime=${utime}

		# Start the splash daemon after rc_init/pre.
		if [[ -z "${pid}" ]]; then
			if [[ "${arr[1]}" != "pre" || "${arr[2]}" != "rc_init" ]]; then
				BOOT_MSG="$(splash_get_boot_message)" ${spl_daemon} -t ${theme} --pidfile ${spl_pidfile} --type=bootup
				pid=$(cat ${spl_pidfile})
			fi
		fi

		case ${arr[1]} in
			pre)
				if [[ -x ${themedir}/${theme}/scripts/${arr[2]}-pre ]]; then
					${themedir}/${theme}/scripts/${arr[2]}-pre ${arr[*]:3}
				fi
				;;

			post)
				if [[ -x ${themedir}/${theme}/scripts/${arr[2]}-post ]]; then
					${themedir}/${theme}/scripts/${arr[2]}-post ${arr[*]:3}
				fi

				if [[ -e /etc/gentoo-release && ${arr[3]} == 'boot' ]]; then
					export RUNLEVEL="3"
				fi
				;;

			comm)
				spl_comm "${arr[*]:2}"
				;;
		esac
	done < ${profile}
}

set_verbose() {
	[ -z "${tty}" ]		&& tty=${ctty}

	export cstate=$(get_state ${tty})
	[ "${cstate}" == "on" ] && export ctheme=$(get_theme ${tty})

	set_theme "${theme}" "${tty}"
	chvt "${tty}"
}

exit_verbose() {
	chvt "${ctty}"
	if [ "${cstate}" == "on" ]; then
		set_theme "${ctheme}" "${tty}"
	else
		${spl_decor} --tty=${tty} -c off
	fi
}

demo_theme_verbose() {
	[ -z "${delay}" ]	&& delay=5

	check_verbose "${theme}" "${res}"
	set_verbose

	einfo "Testing the '${theme}' theme..." >/dev/tty${tty}
	for (( i = 0 ; i < ${delay} ; i = i+1 )) ; do
		echo -n "$i " >/dev/tty${tty}
		sleep 1
	done
	echo ""

	exit_verbose
}

take_shot_silent() {
	check_silent "${theme}" "${res}"
	set_silent

	[ -z "${progress}" ] && progress=16384
	spl_comm "progress ${progress}"
	spl_comm "repaint"

	sleep 1
	fbgrab ${theme}-${res}-silent.png

	exit_silent
}

take_shot_verbose() {
	check_verbose "${theme}" "${res}"
	set_verbose

	if [ -n "${cexec}" ]; then
		ps -A -o pid,comm,tty > /tmp/spl-shot-$$.pre
		openvt -f -c ${tty} -- ${cexec}
		sleep 2
		ps -A -o pid,comm,tty > /tmp/spl-shot-$$.post
		local ce=$(basename "${cexec}")
		pid=$(diff /tmp/spl-shot-$$.pre /tmp/spl-shot-$$.post | grep "${ce:0:15}" | grep "tty${tty}" | grep '^>' | awk '{ print $2 }')
		rm -f /tmp/spl-shot-$$.pre /tmp/spl-shot-$$.post
	fi

	fbgrab ${theme}-${res}-verbose.png

	if [[ -n "${ce}" && -n "${pid}" &&
	  	  "$(cat /proc/${pid}/status 2>/dev/null | grep 'Name:' | cut -f2)" == "${ce:0:15}" ]]; then
		kill "${pid}"
	fi
	exit_verbose
}

list_themes() {
	for i in "${themedir}"/* ; do
		[ ! -d "${i}" ] && continue
		[ -z "$(ls "${i}"/*.cfg 2>/dev/null)" ] && continue

		tn="${i/$themedir/}"
		tn="${tn//\//}"

		echo -n "$tn:"
		local first=true

		for res in "${i}"/*.cfg ; do
			res=${res##*/}
			res=${res/.cfg/}

			[ "$first" != "true" ] && echo -n ","
			first=false
			echo -n " ${res}"

			local sil ver

			if check_silent "$tn" "$res" "test"; then
				sil=true
			else
				sil=false
			fi

			if check_verbose "$tn" "$res" "test"; then
				ver=true
			else
				ver=false
			fi

			if [[ "$ver" == "true" && "$sil" == "true" ]]; then
				echo -n " (sv)"
			elif [[ "$sil" == "true" ]]; then
				echo -n " (s)"
			else
				echo -n " (v)"
			fi
		done
		echo ""
	done
}

bootloader=""

detect_bootloader() {
	if [[ -e /boot/grub/grub.conf && -e /etc/lilo.conf ]]; then
		ewarn "Both GRUB and LILO seem to be installed and configured. Please"
		ewarn "select which one should be configured by this script:"
		ewarn "  1) GRUB"
		ewarn "  2) LILO"
		while true; do
			echo -n "Your choice [1]: "
			read choice
			if [ -z "${choice}" ]; then
				bootloader="grub"
				return
			elif [ "${choice}" == 1 ]; then
				bootloader="grub"
				return
			elif [ "${choice}" == 2 ]; then
				bootloader="lilo"
				return
			else
				err "You have chosen an invalid number."
			fi
		done
	elif [[ -e /boot/grub/grub.conf ]]; then
		bootloader="grub"
	elif [[ -e /etc/lilo.conf ]]; then
		bootloader="lilo"
	else
		err "It appears that none of the supported bootloaders (GRUB, LILO) is installed"
		err "on your system. Please install one of these or configure fbsplash/splashutils"
		err "manually."
		exit 1
	fi
}

# The code of mount_boot_partition() is stolen from Gentoo's mount-boot.eclass.
mount_boot_partition() {
	# note that /dev/BOOT is in the Gentoo default /etc/fstab file
	local fstabstate="$(cat /etc/fstab | awk '!/^#|^[[:blank:]]+#|^\/dev\/BOOT/ {print $2}' | egrep "^/boot$" )"
	local procstate="$(cat /proc/mounts | awk '{print $2}' | egrep "^/boot$" )"
	local proc_ro="$(cat /proc/mounts | awk '{ print $2, $4 }' | sed -n '/\/boot/{ /[ ,]\?ro[ ,]\?/p }' )"

	if [ -n "${fstabstate}" ] && [ -n "${procstate}" ]; then
		if [ -n "${proc_ro}" ]; then
			einfo "Your boot partition, detected as being mounted as /boot, is read-only."
			einfo "Remounting it in read-write mode ..."
			mount -o remount,rw /boot &>/dev/null
			if [ "$?" -ne 0 ]; then
				err "Unable to remount in rw mode. Please do it manually!"
				exit 1
			fi
		else
			einfo "Your boot partition was detected as being mounted as /boot."
		fi
	elif [ -n "${fstabstate}" ] && [ -z "${procstate}" ]; then
		mount /boot -o rw &>/dev/null
		if [ "$?" -eq 0 ]; then
			einfo "Your boot partition was not mounted as /boot, but this"
			einfo "script was able to mount it without additional intervention."
		else
			err "Cannot automatically mount your /boot partition."
			err "Your boot partition has to be mounted rw before the splash configuration"
			err "can be continued."
			exit 1
		fi
	else
		einfo "Assuming you do not have a separate /boot partition."
	fi
}

# int input_number(int min, int max, int default)
#   Asks the user to enter a number in the range [min;max].
input_number() {
	local min=$1
	local max=$2
	local default=$3
	local done=false

	echo -n "Your choice: "

	while [[ ${done} != "true" ]]; do
		read n
		n=${n%% *}

		if [[ -z "${n}" || "${n}" -lt ${min} || "${n}" -gt ${max} ]]; then
			err "Invalid number. Try again. Enter a number in the range: ${min}-${max}}."
			echo -n "Your choice: "
		else
			done="true"
		fi
	done

	return ${n}
}

# bool input_bool(bool default)
#   Asks the user to enter 'y' or 'n'.
input_bool() {
	local default=$1
	local choice

	echo -n "Your choice "

	if [[ "${default}" == "y" ]]; then
		echo -n "[Y/n]: "
	else
		echo -n "[y/N]: "
	fi

	read choice

	if [[ "${default}" == "y" ]]; then
		if [[ "${choice}" != "n" && "${choice}" != "N" ]]; then
			return 0
		else
			return 1
		fi
	else
		if [[ "${choice}" != "y" && "${choice}" != "Y" ]]; then
			return 1
		else
			return 0
		fi
	fi
}

# void theme_switch_initrd(char *initrd)
#   Asks the user whether (s)he wants to generate and use a new initrd.
theme_switch_initrd() {
	local initrd=$1
	newinitrd=""
	want_initrd=false

	if [ -z "${initrd}" ]; then
		einfo "It appears that you are not using an initrd. Do you want this script"
		einfo "to automatically generate one for use with the '${theme}' theme?"
		if input_bool 'y'; then
			want_initrd=true
		fi
	elif [ "${initrd:0:13}" == "/boot/splash/" ]; then
		want_initrd=true
	else
		echo ""
		einfo "It appears that you are already using an initrd:"
		einfo "  '${initrd}'"
		einfo "Do you want this script to automatically generate another initrd for"
		einfo "use with the '${theme}' theme?"
		einfo "The new initrd will be used instead of the current one."
		if input_bool 'n'; then
			want_initrd=true
		fi
	fi

	if [ ${want_initrd} == "true" ]; then
		[ ! -d /boot/splash ] && mkdir /boot/splash
		newinitrd="/boot/splash/initrd-spl-${theme}-all"
		splash_geninitramfs -g "${newinitrd}" -v "${theme}"
	fi
}

theme_switch_lilo() {
	local cnt=0
	local entries
	local lines
	local want_name=false
	local linecnt=1

	# Display a list of entries from lilo.conf and ask the user to select one of them.
	einfo "Please select which kernel should be configured for use with splashutils:"
	while read i ; do
		line=$(echo ${i})
		if [[ ${i:0:5} == "image" ]]; then
			want_name=true
			lines[$cnt]="$linecnt"
		fi

		if [[ ${want_name} == "true" && ${i:0:5} == "label" ]]; then
			i=$(echo ${i} | cut -d= -f2)
			i=$(echo ${i})
			entries[$cnt]="$i"
			cnt=$(($cnt+1))
			printf "%3d) %s\n" "$cnt" "$i"
			want_name=false
		fi
		linecnt=$(($linecnt+1))
	done < /etc/lilo.conf

	input_number 1 ${cnt} 1
	n=$(($?-1))
	einfo "Configuring '${entries[$n]}'.."

	line=${lines[$n]}
	cp /etc/lilo.conf /etc/lilo.conf.work.$$

	initrd="$(awk "FNR == $line {
				print ;
				while(getline > 0 && \$1 != \"image\") {
						print \$0
				}
			}" /etc/lilo.conf.work.$$ | grep "^[[:space:]]*initrd")"
	initrd=$(echo "$initrd" | cut -f2 -d'=')

	theme_switch_initrd "${initrd}"
	cp /etc/lilo.conf /etc/lilo.conf.backup

	awk "FNR == $(($line+1)) {
		initrd=0
		if (\"${newinitrd}\" != \"\") {
			initrd=1
		}

		do {
			if (\$1 ~ /^append/) {
				break;
			} else if (\$1 ~ /^image/ || \$1 ~ /^other/) {
				print \"\\tappend = \\\"splash=silent,fadein,theme:${theme} console=tty1\\\"\"
				if (initrd == 1) {
					print \"\\\tinitrd = ${newinitrd}\"
				}
				print \$0
				next
			} else {
				if (initrd == 1 && \$1 ~ /^initrd/) {
					sub(/initrd.*/, \"initrd = ${newinitrd}\", \$0)
					initrd=0
				}
				print \$0
			}
		} while (getline > 0)

		splash=0
		cons=0
		quiet=0
		full=\$0
		\$0=gensub(/.*\"([^\"]+)\"/,\"\\\\1\",\"g\",\$0)
		sub(/\".*/,\"\",\$0)
		for(i=1; i<=NF+1; i++) {
			if (substr(\$i,0,6) == \"splash\") {
				splash=1
			} else if (\$i == \"console=tty1\") {
				cons=1
			}
		}
		if (splash == 1) {
			sub(/splash=[^ ]+/, \"splash=silent,fadein,theme:${theme}\", \$0)
		} else {
			\$0=\$0 \" splash=silent,fadein,theme:${theme}\"
		}
		if (cons == 0) {  \$0 = \$0 \" console=tty1\"	}

		sub(/\".*\"/, \"\\\"\" \$0 \"\\\"\", full)
		print full

		if (initrd) {
			getline
			while (!(\$1 ~ /^image/) && !(\$1 ~ /^other/)) {
				if (\$1 ~ /^initrd/) {
					sub(/initrd.*/, \"initrd = ${newinitrd}\", \$0)
					initrd=0
				}
				print \$0
				getline
			}
			if (initrd) {
				print \"\\tinitrd = ${newinitrd}\"
			}
			print \$0
		}
		next
	}

	FNR != $(($line+1)) { print \$0 }" /etc/lilo.conf.work.$$ > /etc/lilo.conf.tmp.$$

	rm /etc/lilo.conf.work.$$
	mv /etc/lilo.conf.tmp.$$ /etc/lilo.conf

	einfo "LILO config file has been updated."
}

theme_switch_grub() {
	local cnt="0"
	local entries
	local lines
	local done=false

	# Display a list of entries from grub.conf and ask the user to select one of them.
	einfo "Please select which kernel should be configured for use with splashutils:"
	grep -n '^[[:space:]]*title' /boot/grub/grub.conf > /tmp/splash_mngr.$$
	while read i ; do
		line=$(echo "${i}" | cut -d: -f1)
		i=$(echo "${i}" | cut -d: -f2)
		i=${i:6}
		entries[$cnt]="$i"
		lines[$cnt]="$line"
		cnt=$(($cnt+1))
		printf "%3d) %s\n" "$cnt" "$i"
	done < /tmp/splash_mngr.$$
	rm /tmp/splash_mngr.$$

	input_number 1 ${cnt} 1
	n=$(($?-1))
	einfo "Configuring '${entries[$n]}'.."

	line=${lines[$n]}
	t="$(sed -e "${line}p" -e 'd' /boot/grub/grub.conf)"

	if [[ "$(echo ${t})" != "title ${entries[$n]}" ]]; then
		err "The GRUB config file appears to have been modified while this script was"
		err "working. Please run it again after making sure no one is modifying"
		err "/boot/grub/grub.conf."
		exit 1
	fi

	cp /boot/grub/grub.conf /boot/grub/grub.conf.work.$$

	initrd="$(awk "FNR == $line {
				print ;
				while(getline > 0 && \$1 != \"title\") {
						print \$0
				}
			}" /boot/grub/grub.conf.work.$$ | grep "^[[:space:]]*initrd")"
	initrd=$(echo "$initrd" | cut -f2 -d' ')

	theme_switch_initrd "${initrd}"
	cp /boot/grub/grub.conf /boot/grub/grub.conf.backup

	awk "FNR == $line {
		initrd=0
		if (\"${newinitrd}\" != \"\") {
			initrd=1
		}

		while(\$1 != \"kernel\") {
			if (initrd == 1 && \$1 == \"initrd\") {
				sub(/initrd .*/, \"initrd ${newinitrd}\", \$0)
				initrd=0
			}
			print \$0
			if (getline <= 0) {
				exit 0
			}
		}
		splash=0
		cons=0
		quiet=0
		for(i=1; i<=NF+1; i++) {
			if (substr(\$i,0,6) == \"splash\") {
				splash=1
			} else if (\$i == \"console=tty1\") {
				cons=1
			}
		}
		if (splash == 1) {
			sub(/splash=[^ ]+/, \"splash=silent,fadein,theme:${theme}\", \$0)
			printf \"%s\",\$0
		} else {
			printf \"%s splash=silent,fadein,theme:${theme}\", \$0
		}
		if (cons == 0) {  printf \" %s\", \"console=tty1\"	}
		printf \"\n\"

		if (initrd) {
			getline
			while (\$1 != \"title\") {
				if (\$1 == \"initrd\") {
					sub(/initrd .*/, \"initrd ${newinitrd}\", \$0)
					initrd=0
				}
				print \$0
				if (getline <= 0) {
					break
				}
			}
			if (initrd) {
				print \"\\tinitrd ${newinitrd}\"
			}
			print \$0
		}
		next
	}

	FNR != $line { print \$0 }" /boot/grub/grub.conf.work.$$
	#> /boot/grub/grub.conf.tmp.$$

	rm /boot/grub/grub.conf.work.$$
#	mv /boot/grub/grub.conf.tmp.$$ /boot/grub/grub.conf

	einfo "GRUB config file has been updated."
}

theme_switch() {
	mount_boot_partition
	detect_bootloader

	if [[ ${bootloader} == "grub" ]]; then
		theme_switch_grub
	else
		theme_switch_lilo
	fi
}

# Set some useful variables that we'll be using in various places
ctty=$(${spl_dir}/bin/fgconsole)

# Default settings
steps=100
mode='s'
cexec=''
progress=''
msg=''
pid=''
profile="${spl_dir}/cache/profile"

args="$@"
temp=`getopt -l help,cmd:,theme:,steps:,delay:,mode:,msg:,tty:,exec:,progress:,profile: c:m:t:he: "$@"`

if [ $? != 0 ]; then
	usage; exit 2
fi

eval set -- "$temp"

for i ; do
	case "$i" in
		-c|--cmd)	op="$2"; shift; shift;;
		-h|--help)	usage; exit 0;;
		-m|--mode)	mode="$2"; shift; shift;;
		-t|--theme)	theme="$2"; shift; shift;;
		-e|--exec)	cexec="$2"; shift; shift;;
		--progress)	progress="$2"; shift; shift;;
		--profile)  profile="$2"; shift; shift;;
		--steps)	steps="$2"; shift; shift;;
		--delay)	delay="$2"; shift; shift;;
		--tty)		tty="$2"; shift; shift;;
		--msg)		msg="$2"; shift; shift;;
		--)			shift; break;;
	esac
done

util_params="$@"

if [ -z "${op}" ]; then
	usage
	exit 0
fi

rres=$(${spl_dir}/bin/fbres)
res=$(${spl_util} -c getres -t ${theme})
yres=${res#*x}
xres=${res%x*}

case "${op}" in
	'set')
		mode='v'
		set_theme "${theme}" "${tty}" ;;
	'demo')
		theme_sanity_check "${theme}"
		if [ ${mode} == 's' ]; then
			demo_theme_silent
		else
			demo_theme_verbose
		fi
		;;

	'benchmark')
		mode='s'
		if [ -z "$(which bc)" ]; then
			err "Benchmarking requires the 'bc' command-line calculator."
			exit 1
		fi
		theme_sanity_check "${theme}"
		benchmark
		;;

	'shot')
		theme_sanity_check "${theme}"
		if [ ! -x /usr/bin/fbgrab ]; then
			err "Cannot find /usr/bin/fbgrab"
			exit 1
		fi

		if [ ${mode} == 's' ]; then
			take_shot_silent
		else
			take_shot_verbose
		fi
		;;

	'switch')
		theme_sanity_check "${theme}"
		theme_switch
		;;

	'list')
		list_themes
		;;

	'replay')
		theme_sanity_check "${theme}"
		replay "${theme}"
		;;

	*)	err "Unrecognized command"
		usage
		;;
esac

exit 0

# vim: set ts=4 sts=4:
