#!/bin/bash

#################################################################################
# Copyright (c) 2019-2021 TUXEDO Computers GmbH <tux@tuxedocomputers.com>
# This file is part of TUXEDO Control Center.
#
# TUXEDO Control Center 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 3 of the License, or
# (at your option) any later version.
#
# TUXEDO Control Center 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 TUXEDO Control Center.  If not, see <https://www.gnu.org/licenses/>.
#################################################################################

set +x
set +m
shopt -s lastpipe

vendorid="0x2646"
deviceid="0x2263"
firmwareversion="S5Z42109"

upgradeDevice() {
	printf "\ndevice to be updated: %s\n" $1
	nvme fw-download $1 -f /lib/firmware/a2000/${firmwareversion}.bin
	nvme fw-activate $1 --slot=1 --action=1
	upgrade[$2-1]="reboot pending"
}

checkUID() {
	if [ "$UID" -ne "0" ]; then
		printf "Firmware update requires 'root' user privileges\n";
		exit 1
	fi
}

checkNvme() {
	if ! command -v nvme &> /dev/null; then
		printf "nvme is not installed.\n"
		printf "Please install it with e.g: sudo apt install nvme-cli\n";
		exit 1
	fi
}

checkFwData() {
	if [ ! -f /lib/firmware/a2000/S5Z42109.bin ]; then
		printf "Firmware data cannot be found in /lib/firmware/a2000\n"
		exit 1
	fi
}

checkUID
checkNvme
checkFwData

while true
do
	bootnecessary=0
	i=0
	nvme list |
		while IFS= read -r line; do
			if [[ ${line} == /dev/nvme* ]]; then
				device[i]="${line:0:16}";
				model[i]="${line:38:40}";
				fwversion[i]="${line:133:8}";
				((i++));
			fi
		done

	nrupgradabledevices=0

	devlenght=${#device[@]}
	printf "\n"
	for (( i=1; i<${devlenght}+1; i++ )); do
		if [[ ${model[i-1]} == *SA2000M8250G* ]] || [[ ${model[i-1]} == *SA2000M8500G* ]] || [[ ${model[i-1]} == *SA2000M81000G* ]]; then
			validmodel=1
		else
			validmodel=0
		fi
		vendoridfile=$( cat /sys/class/nvme${device[i-1]:4:6}/device/vendor );
		deviceidfile=$( cat /sys/class/nvme${device[i-1]:4:6}/device/device );
		if [[ "${vendorid}" == "${vendoridfile}" ]] &&
			[[ "${deviceid}" == "${deviceidfile}" ]] &&
			[[ ${validmodel} == "1" ]]; then
			if [[ "${upgrade[i-1]}" == "reboot pending" ]]; then
				bootnecessary=1;
			elif [[ "${fwversion[i-1]}" < "${firmwareversion}" ]]; then
				upgrade[i-1]="update necessary";
				((nrupgradabledevices++));
			elif [[ "${fwversion[i-1]}" = "${firmwareversion}" ]]; then
				upgrade[i-1]="already updated";
			else
				upgrade[i-1]="firmware is newer than update";
			fi
		else
			upgrade[i-1]="update not possible";
		fi
		printf "(%u) %-16s %-40s %-8s - %-14s\n" ${i} ${device[i-1]} "${model[i-1]}" ${fwversion[i-1]} "${upgrade[i-1]}"
	done

	if [ ${nrupgradabledevices} -eq 0 ]; then
		printf "\nno updatable devices present ... exiting\n"
		if ((${bootnecessary} != 0)); then
			printf "Please reboot the system, there is at least one pending updated device\n"
		fi
		exit 0
	else
		printf "\nPlease choose which device you want to update (x=exit)\n"
		read selection
		if [[ "${selection}" =~ ^[1-"${devlenght}"] ]] && [[ "${upgrade[${selection}-1]}" == "update necessary" ]]; then
			printf "\nThe system has to remain active while the firmware is being updated.\n"
			printf "Any interruption could cause the device to be bricked.\n"
			printf "We do not take responsibility in case of failure.\n\n"
			printf "Are you sure you want to update the firmware on device %s ?\n" ${device[${selection}-1]}
			while true; do
				read -p "(Yes/No) " yesno
				case ${yesno} in
					Yes ) upgradeDevice ${device[${selection}-1]} ${selection}; break;;
					No ) break;;
				esac
			done
		elif [[ ${selection} == "x" ]]; then
			exit 0
		else
			printf "\nThe selected device: (%s) cannot be updated\n" "${selection}"
		fi
	fi
done

