#!/bin/bash


#### Usage ####

function exit_usage() {
    echo "       fwupdate current"
    echo "           shows the current version"
    echo "       fwupdate latest"
    echo "           shows the latest available version with details"
    echo "       fwupdate list [<stable|beta|all>]"
    echo "           list available firmware versions"
    echo "       fwupdate download <version|latest|url|file>"
    echo "           downloads a specific firmware OS image"
    echo "       fwupdate extract"
    echo "           extracts the downloaded firmware archive"
    echo "       fwupdate flashboot"
    echo "           flashes the boot partition from extracted image"
    echo "       fwupdate flashreboot"
    echo "           prepares for reboot + root partition flashing"
    echo "       fwupdate status"
    echo "           shows the current firmware installing process status; see below"
    echo "       fwupdate install <version|latest|url|file>"
    echo "           performs all the operations necessary for installing a certain firmware version"
    echo "       fwupdate auto [on|off]"
    echo "           controls the automatic firmware update mechanism"
    echo "       fwupdate prereleases [on|off]"
    echo "           enables or disables prereleases (beta) channel"
    echo ""
    echo "Statuses:"
    echo "       idle"
    echo "       downloading [version]"
    echo "       downloaded [version]"
    echo "       extracting [version]"
    echo "       extracted [version]"
    echo "       flashing boot [version]"
    echo "       boot flashed [version]"
    echo "       rebooting [version]"
    echo ""

    exit 1
}

if [[ -z "$1" ]]; then
    exit_usage
fi

#### Configuration ####

set -a
set -e

LATEST_VERSION_CMD=/usr/libexec/os-latest-version

MIN_FREE_DISK=500  # MB
DISK_CLEANUP_SCRIPT=/usr/libexec/disk-cleanup
FW_DIR=/data/.fwupdate

FW_FILE_GZ=${FW_DIR}/firmware.img.gz
FW_FILE_XZ=${FW_DIR}/firmware.img.xz
FW_FILE_EXTR=${FW_DIR}/firmware.img

VER_FILE=${FW_DIR}/version

BOOT_INFO_FILE=${FW_DIR}/boot_info
ROOT_INFO_FILE=${FW_DIR}/root_info

DOWNLOAD_STARTED_FILE=${FW_DIR}/download_started
DOWNLOAD_DONE_FILE=${FW_DIR}/download_done
EXTRACT_STARTED_FILE=${FW_DIR}/extract_started
EXTRACT_DONE_FILE=${FW_DIR}/extract_done
FLASH_BOOT_STARTED_FILE=${FW_DIR}/flash_boot_started
FLASH_BOOT_DONE_FILE=${FW_DIR}/flash_boot_done
FLASH_REBOOT_STARTED_FILE=${FW_DIR}/flash_reboot_started
ERROR_FILE=${FW_DIR}/error


TMP_BOOT_DIR=/tmp/fwupdate_boot
TMP_ROOT_DIR=/tmp/fwupdate_root

CURL_LOG_FILE=${FW_DIR}/curl.log
CURL_PID_FILE=${FW_DIR}/curl.pid

GUNZIP_LOG_FILE=${FW_DIR}/gunzip.log
GUNZIP_PID_FILE=${FW_DIR}/gunzip.pid

XZCAT_LOG_FILE=${FW_DIR}/xzcat.log
XZCAT_PID_FILE=${FW_DIR}/xzcat.pid

DD_LOG_FILE=${FW_DIR}/dd.log
DD_PID_FILE=${FW_DIR}/dd.pid

BOOT_LOOP="/dev/loop3"
ROOT_LOOP="/dev/loop4"

boot_mounted_rw=false

source /etc/init.d/base

#### Utils ####

function expand_placeholders() {
    # $1 - template with placeholders
    # $2 - optional version
    echo "$1" | \
        sed "s,\${platform},${BOARD_NAME},g" | \
        sed "s,\${os_prefix},${OS_PREFIX},g" | \
        sed "s,\${os_short_name},${OS_SHORT_NAME},g" | \
        sed "s,\${version},$2,g"
}


#### Cleanup on exit ####

function cleanup_on_exit() {
    set +e

    if [[ -f /sbin/reboot.bak ]]; then
        rm -f /sbin/reboot
        mv /sbin/reboot.bak /sbin/reboot
    fi

    umount ${TMP_BOOT_DIR} 2>/dev/null
    umount ${TMP_ROOT_DIR} 2>/dev/null
    losetup -d ${BOOT_LOOP} 2>/dev/null
    losetup -d ${ROOT_LOOP} 2>/dev/null

    if [[ ${boot_mounted_rw} == true ]]; then
        mount -T /tmp/fstab.disk -o ro /boot 2>/dev/null
    fi
    
    # remove *started files since corresponding processes have normally exited
    rm -f ${DOWNLOAD_STARTED_FILE}
    rm -f ${EXTRACT_STARTED_FILE}
    rm -f ${FLASH_BOOT_STARTED_FILE}
    rm -f ${FLASH_REBOOT_STARTED_FILE}
}


#### Disk & partition devices ####

source /tmp/disk_info

function reallocate_boot_part() {
    current_boot_info=$(fdisk --bytes -l -o device,start,end,size ${DISK_DEV} | grep "${BOOT_DEV}")
    current_boot_info=(${current_boot_info})

    current_root_info=$(fdisk --bytes -l -o device,start,end,size ${DISK_DEV} | grep "${ROOT_DEV}")
    current_root_info=(${current_root_info})

    boot_info=($(cat ${BOOT_INFO_FILE}))

    if [[ ${current_boot_info[1]} == ${boot_info[0]} ]] &&
       [[ ${current_boot_info[3]} -ge $((${boot_info[2]} * 512)) ]]; then

        return  # all good
    fi

    echo "reallocating boot partition"

    # check overlapping with root partition
    if [[ ${boot_info[1]} -ge ${current_root_info[1]} ]]; then
        echo "cannot reallocate boot partition: will overlap with root"
        return 1
    fi

    fdisk -w auto ${DISK_DEV} >/dev/null <<END
d
1
n
p
1
${boot_info[0]}
${boot_info[1]}
t
1
c
w
END
    sync
}

function reallocate_root_part() {
    current_root_info=$(fdisk --bytes -l -o device,start,end,size ${DISK_DEV} | grep "${ROOT_DEV}")
    current_root_info=(${current_root_info})

    current_data_info=$(fdisk --bytes -l -o device,start,end,size ${DISK_DEV} | grep "${DATA_DEV}")
    current_data_info=(${current_data_info})

    root_info=($(cat ${ROOT_INFO_FILE}))

    if [[ ${current_root_info[1]} == ${root_info[0]} ]] &&
       [[ ${current_root_info[3]} -ge $((${root_info[2]} * 512)) ]]; then

        return  # all good
    fi

    echo "reallocating root partition"

    # check overlapping with data partition
    if [[ ${root_info[1]} -ge ${current_data_info[1]} ]]; then
        echo "cannot reallocate root partition: will overlap with data"
        return 1
    fi

    fdisk -w auto ${DISK_DEV} >/dev/null <<END
d
2
n
p
2
${root_info[0]}
${root_info[1]}
t
2
83
w
END
    sync
}


#### Current version ####

function show_current() {
    echo ${OS_VERSION}
}


#### Latest version ####

function show_latest() {
    if [[ ${OS_PRERELEASES} == true ]]; then
        os_firmware_latest=${OS_FIRMWARE_LATEST_BETA}
    else
        os_firmware_latest=${OS_FIRMWARE_LATEST_STABLE}
    fi

    if [[ -n "${os_firmware_latest}" ]]; then
        os_firmware_latest=$(expand_placeholders ${os_firmware_latest})
        latest=$(curl --fail -sSL ${os_firmware_latest})
        latest=$(jq -r '.url,.path,.version,.date' <<< "${latest}")
        latest=(${latest})
        url=${latest[0]}
        path=${latest[1]}
        version=${latest[2]}
        date=${latest[3]}
        if [[ "${url}" == null ]]; then
            url="$(cut -d / -f 1,2,3 <<< ${os_firmware_latest})${path}"
        fi
        url=$(expand_placeholders ${url})
    else
        # Command specified by ${LATEST_VERSION_CMD} returns two lines:
        # * the first one is the stable version
        # * the second one being the "beta" version
        # Each line contains three space-separated fields, representing:
        #  * the version name
        #  * download URL
        #  * release date
        IFS=$'\n' version_lines=($(${LATEST_VERSION_CMD})); unset IFS
        if [[ ${OS_PRERELEASES} == true ]]; then
            version_line=(${version_lines[1]:-${version_lines[0]}})
        else
            version_line=(${version_lines[0]})
        fi

        version=${version_line[0]}
        url=${version_line[1]}
        date=${version_line[2]}
    fi

    echo "${version}  ${url}  ${date}"
}


#### Show all versions ####

function list_versions() {
    check_versions=${1,,}
    if [[ -z ${check_versions} ]]; then
        if [[ ${OS_PRERELEASES} == true ]]; then
            check_versions="all"
        else
            check_versions="stable"
        fi
    fi

    versions_stable="[]"
    if [[ ${check_versions} == "stable" || ${check_versions} == "all" ]]; then
      # get stable versions
      url=$(expand_placeholders ${OS_FIRMWARE_VERSIONS_STABLE})
      versions_stable=$(curl --fail -sSL ${url})
    fi

    versions_beta="[]"
    if [[ ${check_versions} == "beta" || ${check_versions} == "all" ]]; then
      # get beta versions
      url=$(expand_placeholders ${OS_FIRMWARE_VERSIONS_BETA})
      versions_beta=$(curl --fail -sSL ${url})
    fi

    versions_all=$(echo -e "${versions_stable}\n${versions_beta}" | jq -s 'add')

    jq -r '.[] | [ .version, .date, .url ] | @tsv' <<< ${versions_all} | semver-sort -k 1 -t $'\t' -r
}


#### Download ####

function do_download() {
    rm -rf ${FW_DIR}/*
    mkdir -p ${FW_DIR}

    rm -f ${DOWNLOAD_DONE_FILE}
    rm -f ${EXTRACT_STARTED_FILE}
    rm -f ${EXTRACT_DONE_FILE}
    rm -f ${FLASH_BOOT_STARTED_FILE}
    rm -f ${FLASH_BOOT_DONE_FILE}
    rm -f ${FLASH_REBOOT_STARTED_FILE}
    rm -f ${ERROR_FILE}

    trap cleanup_on_exit EXIT

    # Look for local file first
    if [[ -f "$1" ]]; then
        version="custom"
        FNAME=`basename $1`
        FILEEXT=${FNAME##*.}
        DST_FNAME=""
        if [[ "${FILEEXT}" == "xz" ]]; then
            DST_FNAME=${FW_FILE_XZ}
        elif [[ "${FILEEXT}" == "gz" ]]; then
            DST_FNAME=${FW_FILE_GZ}
        fi
        if [[ -n "${DST_FNAME}" ]]; then
            cp -f $1 ${DST_FNAME}
            echo ${version} > ${VER_FILE}
            touch ${DOWNLOAD_DONE_FILE}
            return
        fi
    fi

    if [[ "$1" == latest ]]; then
        latest=($(show_latest | tr -s ' '))
        version=${latest[0]}
        url=${latest[1]}
    elif [[ "$1" == http* ]]; then  # a URL
        version="custom"
        url=$1
    elif [[ -n "${OS_FIRMWARE_URL}" ]]; then
        version=$1
        url=$(expand_placeholders ${OS_FIRMWARE_URL} ${version})
    else
        echo "Variable OS_FIRMWARE_URL is not defined"
        exit 1
    fi

    echo "downloading ${version} from ${url}"
    
    free_disk=$(df /data | tail -n 1 | tr -s ' ' | cut -d ' ' -f 4)
    if [[ "${free_disk}" -lt $((MIN_FREE_DISK * 1024)) ]]; then
        echo "not enough disk space" | tee 1>&2 ${ERROR_FILE}
        if [[ -x ${DISK_CLEANUP_SCRIPT} ]]; then
            echo "running the cleanup script" | tee 1>&2 ${ERROR_FILE}
            ${DISK_CLEANUP_SCRIPT}
        else
            rm ${DOWNLOAD_STARTED_FILE}
            exit 1
        fi
    fi

    outfile=${FW_FILE_GZ}
    format=$(echo ${url} | sed -rn 's/.*\.img\.([a-z]+)$/\1/ p')
    if [[ "${format}" == "xz" ]]; then
        outfile=${FW_FILE_XZ}
    fi

    echo ${version} > ${VER_FILE}
    touch ${DOWNLOAD_STARTED_FILE}

    curl_opts="-S -f -L"
    curl ${curl_opts} -o ${outfile} "${url}" &> ${CURL_LOG_FILE} &
    pid=$!
    echo ${pid} > ${CURL_PID_FILE}

    set +e  # don't exit on error
    wait ${pid}

    if [[ "$?" != 0 ]]; then
        echo "download failed" | tee 1>&2 ${ERROR_FILE}
        rm ${DOWNLOAD_STARTED_FILE}
        exit 1
    fi

    touch ${DOWNLOAD_DONE_FILE}
    set -e
}


#### Extract ####

function run_pre_upgrade() {
    which losetup &>/dev/null || return 0

    boot_info=($(cat ${BOOT_INFO_FILE}))
    root_info=($(cat ${ROOT_INFO_FILE}))
    pre_upgrade="${TMP_ROOT_DIR}/usr/share/pre-upgrade"

    mkdir -p ${TMP_BOOT_DIR}
    mkdir -p ${TMP_ROOT_DIR}
    losetup -o $((boot_info[0] * 512)) ${BOOT_LOOP} ${FW_FILE_EXTR}
    losetup -o $((root_info[0] * 512)) ${ROOT_LOOP} ${FW_FILE_EXTR}
    mount ${BOOT_LOOP} ${TMP_BOOT_DIR}
    mount ${ROOT_LOOP} ${TMP_ROOT_DIR}
    
    if [[ -f ${TMP_ROOT_DIR}/usr/libexec/fw-restore-boot-cfg ]]; then
        cp ${TMP_ROOT_DIR}/usr/libexec/fw-restore-boot-cfg /usr/libexec/fw-restore-boot-cfg
    else
        rm -f /usr/libexec/fw-restore-boot-cfg
    fi

    if [[ -d ${pre_upgrade} ]]; then
        for script in ${pre_upgrade}/*.sh; do
            echo "running pre-upgrade script $(basename ${script})"
            if [[ -x ${script} ]] && ! ${script}; then
                # Non-zero exit status of pre-upgrade script indicates that
                # the upgrade process must not be continued

                echo "aborted by pre-upgrade script" | tee 1>&2 ${ERROR_FILE}
                return 1
            fi
        done
    fi

    umount ${TMP_BOOT_DIR}
    umount ${TMP_ROOT_DIR}
    losetup -d ${BOOT_LOOP}
    losetup -d ${ROOT_LOOP}
}

function do_extract() {
    if ! [[ -f ${FW_FILE_GZ} || -f ${FW_FILE_XZ} ]] || ! [[ -f ${DOWNLOAD_DONE_FILE} ]]; then
        echo "firmware file not downloaded" | tee 1>&2 ${ERROR_FILE}
        exit 1
    fi

    rm -f ${EXTRACT_DONE_FILE}
    rm -f ${FLASH_BOOT_STARTED_FILE}
    rm -f ${FLASH_BOOT_DONE_FILE}
    rm -f ${FLASH_REBOOT_STARTED_FILE}
    rm -f ${ERROR_FILE}
    rm -f ${FW_FILE_EXTR}
    touch ${EXTRACT_STARTED_FILE}

    echo "extracting"

    trap cleanup_on_exit EXIT

    format="gz"
    if [[ -f ${FW_FILE_XZ} ]]; then
        format="xz"
    fi

    rm -f ${FW_FILE_EXTR}
    rm -f ${GUNZIP_PID_FILE} ${XZCAT_PID_FILE}

    if [[ "${format}" == "xz" ]]; then
        DECOMPRESS_LOG_FILE=${XZCAT_LOG_FILE}
        DECOMPRESS_PID_FILE=${XZCAT_PID_FILE}
        xzcat ${FW_FILE_XZ} > ${FW_FILE_EXTR} 2>${XZCAT_LOG_FILE} &
    elif [[ "${format}" == "gz" ]]; then
        DECOMPRESS_LOG_FILE=${GUNZIP_LOG_FILE}
        DECOMPRESS_PID_FILE=${GUNZIP_PID_FILE}
        gunzip -k -c ${FW_FILE_GZ} > ${FW_FILE_EXTR} 2>${GUNZIP_LOG_FILE} &
    else
        echo "firmware compression format ${format} not supported" 1>&2 | tee 1>&2 ${ERROR_FILE}
        exit 1
    fi

    pid=$!
    echo ${pid} > ${DECOMPRESS_PID_FILE}
    wait ${pid}

    if [[ "$?" != 0 ]]; then
        cat ${DECOMPRESS_LOG_FILE}
        exit 1
    fi

    # TODO verify hash

    boot_info=$(fdisk --bytes -l -o device,start,end,size ${FW_FILE_EXTR} | grep "${FW_FILE_EXTR}1")
    boot_info=(${boot_info})
    boot_start=${boot_info[1]}
    boot_end=${boot_info[2]}
    boot_size=$((boot_info[3] / 512))

    root_info=$(fdisk --bytes -l -o device,start,end,size ${FW_FILE_EXTR} | grep "${FW_FILE_EXTR}2")
    root_info=(${root_info})
    root_start=${root_info[1]}
    root_end=${root_info[2]}
    root_size=$((root_info[3] / 512))

    echo ${boot_start} ${boot_end} ${boot_size} > ${BOOT_INFO_FILE}
    echo ${root_start} ${root_end} ${root_size} > ${ROOT_INFO_FILE}

    run_pre_upgrade

    touch ${EXTRACT_DONE_FILE}
}


#### Flash boot ####

function do_flash_boot() {
    if ! [[ -f ${FW_FILE_EXTR} ]] || ! [[ -f ${EXTRACT_DONE_FILE} ]]; then
        echo "extracted firmware not present" | tee 1>&2 ${ERROR_FILE}
        return 1
    fi

    rm -f ${FLASH_BOOT_DONE_FILE}
    rm -f ${FLASH_REBOOT_STARTED_FILE}
    rm -f ${ERROR_FILE}
    touch ${FLASH_BOOT_STARTED_FILE}

    echo "flashing boot"

    trap cleanup_on_exit EXIT

    boot_info=($(cat ${BOOT_INFO_FILE}))

    cp -r /boot ${FW_DIR}/old_boot
    umount /boot
    
    # Prevent unwanted reboots during firmware install
    panic inhibit
    mount -o remount,rw /
    mv /sbin/reboot /sbin/reboot.bak
    ln -s /bin/true /sbin/reboot

    reallocate_boot_part

    dd if=${FW_FILE_EXTR} \
       skip=$((boot_info[0] / 2048)) \
       of=${BOOT_DEV} bs=1048576 \
       count=$((boot_info[2] / 2048)) &>${DD_LOG_FILE} &
    pid=$!
    echo ${pid} > ${DD_PID_FILE}
    wait ${pid}

    mount -T /tmp/fstab.disk -o rw /boot
    boot_mounted_rw=true

    # The /boot/factory-defaults.tar.xz file is always preserved across updates
    if [[ -s ${FW_DIR}/old_boot/factory-defaults.tar.xz ]]; then
        cp ${FW_DIR}/old_boot/factory-defaults.tar.xz /boot
    fi

    # The /usr/libexec/fw-restore-boot-cfg script, if present, takes the old (backup) boot dir as argument
    # and should restore any /boot configuration that needs to be preserved across updates
    # from the old boot dir to the current (new) /boot dir
    if [[ -x /usr/libexec/fw-restore-boot-cfg ]]; then
        /usr/libexec/fw-restore-boot-cfg ${FW_DIR}/old_boot 2>/dev/null || true
    fi

    touch ${FLASH_BOOT_DONE_FILE}
}


#### Flash reboot ####

function do_flash_reboot() {
    if ! [[ -f ${ROOT_INFO_FILE} ]] || ! [[ -f ${FLASH_BOOT_DONE_FILE} ]]; then
        echo "root partition info file not present" | tee 1>&2 ${ERROR_FILE}
        return 1
    fi

    rm -f ${ERROR_FILE}
    touch ${FLASH_REBOOT_STARTED_FILE}

    echo "preparing for reboot"

    trap cleanup_on_exit EXIT

    reallocate_root_part

    root_info=($(cat ${ROOT_INFO_FILE}))

    mkdir -p ${TMP_ROOT_DIR}
    losetup -o $((root_info[0] * 512)) ${ROOT_LOOP} ${FW_FILE_EXTR}
    mount ${ROOT_LOOP} ${TMP_ROOT_DIR}

    # The /usr/libexec/fw-prepare-boot script should be present and should
    # make the necessary changes to the current boot configuration so that
    # the firmware update initramfs will be used by the next boot.
    #
    # We prefer to use the script coming with the new firmware.

    mount -o remount,rw /boot
    boot_mounted_rw=true
    if [[ -x ${TMP_ROOT_DIR}/usr/libexec/fw-prepare-boot ]]; then
        ${TMP_ROOT_DIR}/usr/libexec/fw-prepare-boot
    elif [[ -x /usr/libexec/fw-prepare-boot ]]; then
        /usr/libexec/fw-prepare-boot
    fi

    umount ${TMP_ROOT_DIR}
    losetup -d ${ROOT_LOOP}

    echo "rebooting"
    test -x /sbin/reboot.bak && /sbin/reboot.bak || /sbin/reboot &
    # Guard forced reboot after 3 minutes
    sleep 180 && echo b > /proc/sysrq-trigger

    exit 0
}


#### Status ####

function show_status() {
    if [[ -f ${VER_FILE} ]]; then
        new_version=$(cat ${VER_FILE} 2>&1 || true)
    fi

    if [[ -f ${ERROR_FILE} ]]; then
        echo -n "error: "
        cat ${ERROR_FILE}
    elif [[ -f ${FLASH_REBOOT_STARTED_FILE} ]]; then
        echo "rebooting [${new_version}]"
    elif [[ -f ${FLASH_BOOT_DONE_FILE} ]]; then
        echo "boot flashed [${new_version}]"
    elif [[ -f ${FLASH_BOOT_STARTED_FILE} ]]; then
        echo "flashing boot [${new_version}]"
    elif [[ -f ${EXTRACT_DONE_FILE} ]]; then
        echo "extracted [${new_version}]"
    elif [[ -f ${EXTRACT_STARTED_FILE} ]]; then
        echo "extracting [${new_version}]"
    elif [[ -f ${DOWNLOAD_DONE_FILE} ]]; then
        echo "downloaded [${new_version}]"
    elif [[ -f ${DOWNLOAD_STARTED_FILE} ]]; then
        echo "downloading [${new_version}]"
    else
        echo "idle"
    fi
}


#### Install ####

function do_install() {
    latest=($(show_latest))
    latest_version=${latest[0]}
    if [[ "$1" == latest ]] && [[ "${OS_VERSION}" == "${latest_version}" ]]; then
        echo "already running latest version"
        return
    fi

    echo "installing $1"

    do_download "$1"
    show_status

    do_extract
    show_status

    do_flash_boot
    show_status

    do_flash_reboot
}


#### Automatic firmware update ####

function show_auto() {
    if [[ ${OS_FIRMWARE_AUTO_UPDATE} == true ]]; then
        echo on
    else
        echo off
    fi
}

function set_auto() {
    if [[ -s /data/etc/os.conf ]]; then
        cat /data/etc/os.conf | grep -v OS_FIRMWARE_AUTO_UPDATE > /data/etc/os.conf.new || true
        mv /data/etc/os.conf.new /data/etc/os.conf
    fi

    echo "OS_FIRMWARE_AUTO_UPDATE=$1" >> /data/etc/os.conf
}

function do_auto() {
    if [[ -z "$1" ]]; then
        show_auto
    elif [[ "$1" == on ]]; then
        set_auto true
        source /etc/init.d/os_conf
        show_auto
    elif [[ "$1" == off ]]; then
        set_auto false
        source /etc/init.d/os_conf
        show_auto
    fi
}


#### Prereleases ####

function show_prereleases() {
    if [[ ${OS_PRERELEASES} == true ]]; then
        echo on
    else
        echo off
    fi
}

function set_prereleases() {
    if [[ -s /data/etc/os.conf ]]; then
        cat /data/etc/os.conf | grep -v OS_PRERELEASES > /data/etc/os.conf.new || true
        mv /data/etc/os.conf.new /data/etc/os.conf
    fi

    echo "OS_PRERELEASES=$1" >> /data/etc/os.conf
}

function do_prereleases() {
    if [[ -z "$1" ]]; then
        show_prereleases
    elif [[ "$1" == on ]]; then
        set_prereleases true
        source /etc/init.d/os_conf
        show_prereleases
    elif [[ "$1" == off ]]; then
        set_prereleases false
        source /etc/init.d/os_conf
        show_prereleases
    fi
}


#### Main ####

case "$1" in
    current)
        show_current
        ;;

    latest)
        show_latest
        ;;

    list)
        if [[ -z ${OS_FIRMWARE_VERSIONS_STABLE} || -z {OS_FIRMWARE_VERSIONS_BETA} ]]; then
            echo "No firmware version list available"
            exit 2
        fi

        list_versions "$2"
        ;;

    download)
        if [[ -z "$2" ]]; then
            exit_usage
        fi

        do_download "$2"
        show_status
        ;;

    extract)
        do_extract
        show_status
        ;;

    flashboot)
        do_flash_boot
        show_status
        ;;

    flashreboot)
        do_flash_reboot
        ;;

    status)
        show_status
        ;;

    install)
        if [[ -z "$2" ]]; then
            exit_usage
        fi

        do_install "$2"
        ;;

    auto)
        do_auto ${@:2}
        ;;

    prereleases)
        do_prereleases ${@:2}
        ;;

    *)
        exit_usage
        ;;
esac
