#!/bin/bash

show_help() {
    echo "usage: boot-state bootenv show [var]"
    echo "       boot-state bootenv set <var> <value>"
    echo "       boot-state bootenv unset <var>"
    echo "       boot-state boot-path"
    echo "       boot-state wait-core-post-boot"
    echo ""
    echo "Get information and manages the boot loader for the current system"
    echo ""
    echo "COMMANDS:"
    echo "  bootenv show:         prints the whole bootenv or just the variable passed as parameter"
    echo "  bootenv set:          sets the given var and value on boot configuration"
    echo "  bootenv unset:        unsets the given var from boot configuration"
    echo "  boot-path:            prints the boot path"
    echo "  wait-core-post-boot:  waits until the snap_mode bootenv var is empty"
}

get_grub_editenv() {
    if [ -e /boot/grub2/grubenv ]; then
        command -v grub2-editenv
    elif [ -e /boot/grub/grubenv ]; then
        command -v grub-editenv
    fi
}

run_grub_editenv() {
    "$(get_grub_editenv)" "$@"
}

get_grub_envfile() {
    if [ -e /boot/grub2/grubenv ]; then
        echo /boot/grub2/grubenv
    elif [ -e /boot/grub/grubenv ]; then
        echo /boot/grub/grubenv
    else
        echo ""
    fi
}

bootenv() {
    case "${1:-}" in
        show)
            shift
            bootenv_show "$@"
            exit
            ;;
        set)
            shift
            bootenv_set "$@"
            exit
            ;;
        unset)
            shift
            bootenv_unset "$@"
            exit
            ;;
        *)
            echo "boot-state: unsupported bootenv sub-command $1" >&2
            show_help
            exit 1
            ;;
    esac
}

bootenv_show() {
    local var="${1:-}"
    local grubenv_file
    grubenv_file="$(get_grub_envfile)"

    if [ -z "$var" ]; then
        if run_grub_editenv list; then
            return
        elif [ -s "$grubenv_file" ]; then
            cat "$grubenv_file"
        else
            fw_printenv
        fi
    else
        # TODO: fix that, it could be problematic if var ends up with regular expression
        if run_grub_editenv list | grep "^$var"; then
            return
        elif [ -s "$grubenv_file" ]; then
            grep "^$var" "$grubenv_file"
        else
            fw_printenv "$1"
        fi | sed "s/^${var}=//"
    fi
}

bootenv_set() {
    local var="$1"
    local value="$2"

    if [ -z "$var" ] || [ -z "$value" ]; then
        echo "boot-state: variable and value required to set in bootenv" >&2
        show_help
        exit 1
    fi
    local grubenv_file
    grubenv_file="$(get_grub_envfile)"

    if run_grub_editenv set "$var=$value"; then
        return
    elif [ -s "$grubenv_file" ]; then
        sed -i "/^$var=/d" "$grubenv_file"
        #The grubenv file could not have a new line at the end
        if [ -n "$(tail -n 1 "$grubenv_file")" ]; then
            echo "" >> "$grubenv_file"
        fi
        echo "$var=$value" >> "$grubenv_file"
    else
        fw_setenv "$var" "$value"
    fi
}

bootenv_unset() {
    local var="$1"

    if [ -z "$var" ]; then
        echo "boot-state: variable required to unset from bootenv" >&2
        show_help
        exit 1
    fi
    local grubenv_file
    grubenv_file="$(get_grub_envfile)"

    if run_grub_editenv "$grubenv_file" unset "$var"; then
        return
    elif [ -s "$grubenv_file" ]; then
        sed -i "/^$var=/d" "$grubenv_file"
    else
        fw_setenv "$var"
    fi
}

boot_path() {
    if [ -f /boot/uboot/uboot.env ] || [ -f /boot/uboot/boot.sel ]; then
        # uc16/uc18 have /boot/uboot/uboot.env
        # uc20 has /boot/uboot/boot.sel
        echo "/boot/uboot/"
    elif [ -f /boot/grub/grubenv ]; then
        echo "/boot/grub/"
    elif [ -f /boot/grub2/grubenv ]; then
        echo "/boot/grub2/"
    else
        echo "boot-state: cannot determine boot path" >&2
        ls -alR /boot
        exit 1
    fi
}

wait_core_post_boot() {
    for _ in $(seq 120); do
        if [ "$(bootenv_show snap_mode)" = "" ]; then
            return
        fi
        sleep 1
    done
    echo "boot-state: timeout reached waiting for core after boot" >&2
    exit 1
}

main() {
    if [ $# -eq 0 ]; then
        show_help
        exit 0
    fi

    case "$1" in
        -h|--help)
            show_help
            exit
            ;;
        bootenv)
            shift
            bootenv "$@"
            exit
            ;;
        boot-path)
            boot_path
            exit
            ;;
        wait-core-post-boot)
            wait_core_post_boot
            exit
            ;;
        *)
            echo "boot-state: unsupported parameter $1" >&2
            show_help
            exit 1
            ;;
    esac
}

main "$@"
