#!/bin/sh -eu

. shell-error
. shell-getopt
. shell-var

mbr_bin='mbr.bin'
BOOTDEVICE=
ROOTDIR=
ADD_KERNELS='yes'
KERNELS_GROUP='Details Menu'
TEST=

show_help() {
	cat <<-EOF
	Usage: $PROG [options] [extlinux options]

	[Options]
	  -b, --boot=DEVICE  specify the boot device;
	  -r, --root=DIR     use the system rooted at DIR;
	  -d, --dry-run      show what will be done and exit;
	  -v, --verbose      print a message for each action;
	  -h, --help         show this text and exit.

	Report bugs to authors.

	EOF
	exit
}

print_version() {
	cat <<-EOF
	$PROG version 1.0
	Written by Alexey Gladkov.

	Copyright (C) 2010  Alexey Gladkov <gladkov.alexey@gmail.com>
	This is free software; see the source for copying conditions.  There is NO
	warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	EOF
	exit
}

UUID=
DEVNAME=
mountpoint_device() {
	local dev mpoint dummy rdir
	rdir="$(readlink -m "$1")"
	while read dev mpoint dummy; do
		[ "$mpoint" = "$rdir" -a "$dev" != 'rootfs' ] || continue
		DEVNAME="$dev"
		break
	done < /proc/mounts
	[ -n "$DEVNAME" ] ||
		return 1
	UUID="$(blkid -o value -s UUID -c /dev/null "$DEVNAME")"
}

check_bootable() {
	fdisk -l | grep '^[^[:space:]]\+[[:space:]]\+\*[[:space:]]' |
	while read dev dummy; do
		[ "$dev" != "$1" ] ||
			exit 1
	done || return 0
	return 1
}

GETOPT_ALLOW_UNKNOWN=1
TEMP=`getopt -n $PROG -o b:,d,r:,v,V,h -l boot:,dry-run,root:,verbose,version,help -- "$@"` ||
	show_help
eval set -- "$TEMP"

while :; do
	case "$1" in
		-b|--boot) shift
			BOOTDEVICE="$1"
			;;
		-r|--root) shift
			ROOTDIR="${1%/}"
			;;
		-d|--dry-run)
			TEST=message
			verbose=-v
			;;
		-v|--verbose) verbose=-v
			;;
		-V|--version) show_version
			;;
		-h|--help) show_help
			;;
		--) shift; break
			;;
	esac
	shift
done

. "$ROOTDIR"/etc/sysconfig/extlinux

if ! mountpoint_device "$ROOTDIR/boot"; then
	mountpoint_device "$ROOTDIR/" ||
		fatal "Unable to get device info '$ROOTDIR/boot'"
else
	[ -L "$ROOTDIR/boot/boot" ] ||
		fatal "$ROOTDIR/boot a separate partition, but there's no '/boot/boot' symlink"
fi

check_bootable "$DEVNAME" ||
	fatal "$DEVNAME: not bootable"

mountpoint_device "$ROOTDIR/" ||
	fatal "Unable to get device info '$ROOTDIR/'"

cd "$ROOTDIR/boot/extlinux"

if [ -z "$TEST" ]; then
	verbose "Replace 'root=@ROOTDEV@' by 'root=UUID=$UUID'"

	for f in extlinux.conf extlinux.conf.d/*.conf; do
		[ ! -f "$f" ] ||
			sed -i -e "s#@ROOTDEV@#UUID=$UUID#ig" "$f"
	done
fi

rm $verbose -f -- extlinux.conf.d/kernels.conf
if shell_var_is_yes "$ADD_KERNELS"; then
	verbose "Creating new extlinux.conf.d/kernels.conf ..."

	printf '# Generated by %s. Do not edit manually.\n' "$PROG" \
		> extlinux.conf.d/kernels.conf

	if [ -n "$KERNELS_GROUP" ]; then
		cat >> extlinux.conf.d/kernels.conf <<-EOF
		MENU BEGIN
		MENU TITLE $KERNELS_GROUP
		EOF
	fi

	for f in "$ROOTDIR"/boot/vmlinuz*; do
		[ -f "$f" ] || continue

		vmlinuz="${f##*/}"
		version="${vmlinuz#vmlinuz}"
		initrd="initrd$version.img"

		[ -f "$ROOTDIR/boot/$initrd" ] ||
			initrd=

		[ -n "$version" ] &&
			label="Kernel ${version:+(${version#-})}" ||
			label='Kernel image'

		cat <<-EOF
		LABEL ${vmlinuz##*/}
		MENU LABEL $label
		LINUX  /boot/$vmlinuz${initrd:+
		INITRD /boot/$initrd}${APPEND:+
		APPEND $APPEND}
		EOF
	done >> extlinux.conf.d/kernels.conf

	if [ -n "$KERNELS_GROUP" ]; then
		cat >> extlinux.conf.d/kernels.conf <<-EOF
		MENU SEPARATOR
		LABEL return_main
		MENU LABEL ^Return to main Menu
		MENU EXIT
		MENU END
		EOF
	fi
fi

verbose "Creating new extlinux.conf.d/.index.conf ..."
printf '# Generated by %s. Do not edit manually.\n' "$PROG" \
	> extlinux.conf.d/.index.conf

def_label=
for f in extlinux.conf.d/*.conf; do
	[ -f "$f" ] || continue
	if [ -z "$def_label" ]; then
		while read name value; do
			case "$name" in
				[Ll][Aa][Bb][Ee][Ll])
					def_label="$value"
					break
					;;
			esac
		done < "$f"
		printf 'DEFAULT %s\n' "$def_label"
	fi
	printf 'INCLUDE %s\n' "$f"
done >> extlinux.conf.d/.index.conf

mode='install'
if [ -b "$BOOTDEVICE" ]; then
	ldr="$(sha1sum < "$mbr_bin")"
	siz="$(stat -c '%s' "$mbr_bin")"
	mbr="$(dd ibs="$siz" count=1 if="$BOOTDEVICE" 2>/dev/null |sha1sum)"

	[ "$mbr" != "$ldr" ] || mode='update'
	verbose "Using $mode mode"
fi

if [ "$mode" = 'install' ]; then
	if [ -b "$BOOTDEVICE" ]; then
		verbose "installing master boot record: $BOOTDEVICE"
		$TEST dd if="$mbr_bin"  of="$BOOTDEVICE"
	else
		message "WARNING: MBR not installed. BOOTDEVICE not specified."
	fi
fi

$TEST extlinux --$mode "$PWD" "$@"
