#!/bin/sh
#
# Update U-boot boot config
#
# Copyright (C) 2015,2016 Cumulus Networks, Inc.

# 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

UBOOT_DRYRUN=""
UBOOT_DEBUG=""
FW_SETENV="fw_setenv"
# from CM-10546, Cumulus u-boot apparently supported a -f option
# to make fw_setenv non interactive. That's broken in 4.0/Buster,
# as it's version of fw_setenv does not recognize it, so roll it back.
#FW_SETENV_OPTS="-f -s -"
FW_SETENV_OPTS="-s -"
CP="cp"
MOUNT="mount"
UMOUNT="umount"

. "${UBOOT_DEBUG_PREFIX}"/usr/share/onie-u-boot/functions

usage()
{
	echo "Usage: update-u-boot -i [-dnh]"
	test "$1" = "long" || return;
	echo "
Configure an ONIE U-boot bootloader to boot GRUB kernel.

Commands:
  -i                   install the boot script glue into U-Boot's environment
                       with fw_setenv.

Options:
  -n,--dry-run         pretend to do actions, don't acutally do them
  -d,--debug           enable extra debigging messages as well as
                       keep temporary directories
  -h,--help            this help output
"
}

ARGS=$(getopt -o "dnhi" -l "debug,dry-run,help" -- "$@")

if test $? -ne 0; then
	exit 2
fi

eval set -- "$ARGS"

while true; do
	case "$1" in
	-d|--debug)
		UBOOT_DEBUG="yes"
		shift;
		;;
	-h|--help)
		usage "long"
		exit 0;
		shift;
		;;
	-n|--dry-run)
		UBOOT_DRYRUN="yes"
		shift;
		FW_SETENV="cat"
		FW_SETENV_OPTS=""
		CP="echo Would run: cp"
		MOUNT="echo Would run: mount"
		UMOUNT="echo Would run: umount"
		;;
	-i)
		ACTION="${1#-}"
		shift;
		;;
	--)
		shift;
		break;
		;;
	esac
done

UBOOT_DIR="$(get_uboot_path)"
# make sure UBOOT_DIR is mounted, assume UBOOT_DIR is readable by
# uboot if it is a separate mount.
fstab_line="$(grep -v "^#" "${UBOOT_DEBUG_PREFIX}"/etc/fstab| \
	    grep "\s${UBOOT_DIR}\s")"
test $? -eq 0 -a -n "${fstab_line}" && {
	# make sure UBOOT_DIR is a supported filesystem
	fs="$(echo "${fstab_line}" | awk '{print $3}')"
	if test "ext2" != "$fs"; then
		logerr "Unsupported filesystem for $UBOOT_DIR: $fs"
		exit 1
	fi

	# make sure UBOOT_DIR is mounted
	if ! mount | grep -q "\s${UBOOT_DIR}\s"; then
		logerr "U-Boot partition is not mounted: ${UBOOT_DIR}"
                exit 1
	fi
}

mntpt="$(df -P "${UBOOT_DIR}" | awk 'END{print $NF}')"
dev="$(df -P "${UBOOT_DIR}" | awk 'END{print $1}')"
dev="$(basename "${dev}")"

if echo "$dev" | grep -q mmcblk ; then
	partnum="${dev##*p}"
	dev="${dev%%p*}"
	devicetype="mmc"
else
	partnum="$(echo "$dev" | sed -e 's/^[^0-9]*\([0-9]*\)$/\1/')"
	dev=$(echo "$dev" | sed -e 's/[0-9]*$//')
	if readlink -f /sys/block/${dev}/device | grep -q usb; then
		devicetype="usb"
	elif test "scsi" = "$(basename "$(readlink -f /sys/block/${dev}/device/subsystem)")"; then
		devicetype="disk"
	else
		logerr "unknown device type for device: /sys/block/$dev"
		exit 1
	fi
fi

# check if the needed files are in UBOOT_DIR
grubpath="$(get_uboot_grub_kernel)"
if test ! -f "${grubpath}"; then
	logerr "GRUB kernel file '${grubpath}' does not exist"
	exit 1
fi
grubkernel="$(basename $grubpath)"
grubaddr="$(get_grub_address)"

if test "xi" = "x${ACTION}"; then
	bootcmd=""
	devid="0"

	case "$devicetype" in
	usb)
		bootcmd="${bootcmd} usb start && usbiddev && "
		devid="\${usbdev}"
		;;
	disk)
		;;
	*)
		logerr "unsupported device type: $devicetype"
		exit 1
		;;
	esac

	bootcmd="${bootcmd} ext2load ${devicetype} ${devid}:${partnum}"
	bootcmd="${bootcmd} ${grubaddr} ${grubkernel} && "
	bootcmd="${bootcmd} echo 'Loading GRUB ...' && bootm"
	if test "yes" = "${UBOOT_DRYRUN}"; then
		echo "Would set the following U-Boot environment variables with fw_setenv:"
	fi
	{
		/bin/echo -e "nos_bootcmd ${bootcmd}"
	} | ${FW_SETENV} ${FW_SETENV_OPTS} || {
		logerr "fw_setenv failed to write U-Boot environment variables."
		exit 1
	}
fi

exit 0
