#!/bin/sh
set -e

# /usr/share/bilibop/grub_device_map_manager

# Replace /boot/grub/device.map by a symlink to /run/bilibop/grub-device.map
# is a way to always keep the file up to date. Or create a persistent fake
# device map.
#
# Options:
# -h, --help	Print help message on stdout and exit
# -f, --fake	Replace device map content by a fake
# -l, --link	Link grub device map to /run/bilibop/grub-device.map
# -r, --remove	Remove /boot/grub/device.map
# -s, --show	Display grub device map location and content
# -u, --update	Run grub-mkdevicemap

### BEGIN ###

PATH="/usr/sbin:/sbin:/usr/bin:/bin"
PROG="${0##*/}"
SOPTS="fhlrsu"
LOPTS="fake,help,link,remove,show,update"

. /lib/bilibop/common.sh
get_udev_root
get_bilibop_variables

GRUB_DEVICE_MAP="/boot/grub/device.map"

short_usage() {
	cat <<EOF
Usage:
  ${PROG} -h|--help
  ${PROG} [-l|--link] [-r|--remove] [[-f|--fake]|[-u|--update]] [-s|--show]
EOF
}

usage() {
	cat <<EOF
${PROG}: modify grub device map location and content.
Usage:
  ${PROG} [OPTIONS]

Options:
  -f, --fake	Replace device map content by a fake
  -h, --help	Print this help on stdout and exit
  -l, --link	Link grub device map to ${BILIBOP_RUNDIR}/grub-device.map
  -r, --remove	Remove ${GRUB_DEVICE_MAP}
  -s, --show	Display grub device map location and content
  -u, --update	Run 'grub-mkdevicemap'

For your system, a fake device map content should be:
$(fake_device_map)
EOF
}

link_device_map() {
	[ -d "${BILIBOP_RUNDIR}" ] || mkdir -p ${BILIBOP_RUNDIR}
	if [ -h "${1}" ]; then
		if [ "$(readlink -f ${1})" != "${BILIBOP_RUNDIR}/grub-device.map" ]; then
			rm -f ${1}
			ln -s ${BILIBOP_RUNDIR}/grub-device.map ${1}
		fi
	else
		rm -f ${1}
		ln -s ${BILIBOP_RUNDIR}/grub-device.map ${1}
	fi
}

fake_device_map() {
	for symlink in $(udevadm info --root --query symlink --name "$(physical_hard_disk /boot)"); do
		case "${symlink}" in
			${udev_root}/disk/by-id/*)
				echo "(hd0)	${symlink}"
				break
				;;
		esac
	done
}

show_device_map() {
	if [ -h "${1}" -o -f "${1}" ]; then
		printf "GRUB device map location:\n\t$(readlink -f ${1})\n\n"
	else
		echo "${1} don't exist."
		return 1
	fi

	if [ -s "${1}" ]; then
		echo "GRUB device map contents:"
		echo "========================="
		cat ${1}
		echo "========================="
	elif [ -f "${1}" ]; then
		echo "${1} is empty."
	else
		echo "${1} is a broken symlink: the target don't exist yet."
	fi
}

remove="false"
update="false"
fake="false"
link="false"
show="false"

set +e
### Parse options ##############################################################
ARGS="$(getopt -o ${SOPTS} --long ${LOPTS} -n ${PROG} -- "${@}")"
if [ "${?}" != "0" ]; then
	short_usage >&2
	exit 1
else
	eval set -- "${ARGS}"
fi
################################################################################
set -e

if [ "${1}" = "--" ]; then
	show="true"
fi

while true; do
	case "${1}" in
		-f|--fake)
			fake="true"
			shift
			;;
		-h|--help)
			usage
			exit 0
			;;
		-l|--link)
			link="true"
			shift
			;;
		-r|--remove)
			remove="true"
			shift
			;;
		-s|--show)
			show="true"
			shift
			;;
		-u|--update)
			update="true"
			shift
			;;
		--)
			shift
			break
			;;
		*)
			unknown_argument "${1}" >&2
			short_usage >&2
			exit 1
			;;
	esac
done

if [ ! -d "/boot/grub" ]; then
	echo "${PROG}: /boot/grub directory doesn't exist." >&2
	exit 3
fi

if [ "${fake}" = "true" -a "${update}" = "true" ]; then
	echo "${PROG}: --fake and --update options are not compatible." >&2
	exit 1
fi

# Run now...
if [ "${remove}" = "true" ]; then
	rm -f ${GRUB_DEVICE_MAP}
fi

if [ "${link}" = "true" ]; then
	link_device_map ${GRUB_DEVICE_MAP}
fi

if [ "${update}" = "true" ]; then
	grub-mkdevicemap
fi

if [ "${fake}" = "true" ]; then
	fake_device_map >${GRUB_DEVICE_MAP}
fi

if [ "${show}" = "true" ]; then
	show_device_map ${GRUB_DEVICE_MAP}
fi

### END ###
# vim: ts=4 sts=4 sw=4
