#!/bin/sh


#
# Copyright (C) 2017  Hiveon Holding LTD
# Distributed under Business Source License 1.1
# License information can be found in the LICENSE.txt file or at https://github.com/minershive/hiveos-asic/blob/master/LICENSE.txt
#
# Linted by shellcheck 0.7.0
# shellcheck shell=ash
#


readonly script_mission='Client for ASICs: Update/install Client from repository'
readonly script_version='0.18.7'
readonly script_basename="${0##*/}"


#
# functions: printers
#

print_script_version () {
	echo -e "${YELLOW}${script_mission}, version ${script_version}${NOCOLOR}"
	echo
}

print_info () {

	# consts

	local print_format='%b%23.23s: %b%s%b\n'
	local label_color="${GRAY}"
	local text_color="${NOCOLOR}"

	# vars

	local client_local_version='<not installed>' # default
	local client_repo_version='<no connection>' # default

	# code

	if [ "$local_release_version" != '0' ]; then
		client_local_version="${local_release_version}"
		if [ "$local_build_version" = '0' ]; then
			client_local_version="${client_local_version}-release"
		else
			client_local_version="${client_local_version}-${local_build_version}"
		fi
	fi

	if [ "$repo_connectivity_status_exitcode" -eq 0 ] || [ -n "$remote_release_version" ]; then
		client_repo_version="${remote_release_version}-$remote_build_version $repo_description"
	fi

	# shellcheck disable=SC2059
	printf "$print_format" "$label_color" 'Manufacturer' "$text_color" "$ASIC_MANUFACTURER" "${NOCOLOR}"
	# shellcheck disable=SC2059
	printf "$print_format" "$label_color" 'ASIC model' "$text_color" "$ASIC_MODEL" "${NOCOLOR}"
	echo
	# shellcheck disable=SC2059
	printf "$print_format" "$label_color" 'Client local version' "$text_color" "$client_local_version" "${NOCOLOR}"
	# shellcheck disable=SC2059
	printf "$print_format" "$label_color" 'Client repo version' "$text_color" "$client_repo_version" "${NOCOLOR}"
}

print_update_info () {

	# consts

	local print_format='%b%23.23s: %b%s%b\n'
	local label_color="${GRAY}"
	local text_color="${NOCOLOR}"

	# var

	local label text
	local is_exit_now=0

	# code

	if [ "$master_FLAG" -eq 1 ]; then
		label='Update to dev build'
	else
		label='Update to release'
	fi

	if [ "$dont_have_to_update_FLAG" -eq 1 ]; then
		if [ "$force_update_mode_FLAG" -eq 1 ]; then
			text="$release_version_to_install (forced update)"
		else
			text="$release_version_to_install"
			is_exit_now=1
		fi
	else
		if [ -z "$user_defined_version_ARG" ]; then
			text="$release_version_to_install"
		else
			text="$user_defined_version_ARG (user-defined)"
		fi
	fi

	# shellcheck disable=SC2059
	printf "$print_format" "$label_color" "$label" "$text_color" "$text" "${NOCOLOR}"
	echo

	if [ -n "$FARM_HASH" ]; then
		if [ "${#FARM_HASH}" -eq 40 ]; then
			# shellcheck disable=SC2059
			printf "$print_format" "$label_color" 'User-defined Farm hash' "${BYELLOW}" "${FARM_HASH}" "${NOCOLOR}"
		else
			# shellcheck disable=SC2059
			printf "$print_format" "$label_color" 'User-defined Farm hash' "${BRED}" "${FARM_HASH} (invalid, will not be used)" "${NOCOLOR}"
			# reset it. damn, still cannot figure out a better place in the code to do it
			FARM_HASH=
		fi
	fi

	if [ -n "$HIVE_HOST_URL" ]; then
		# shellcheck disable=SC2059
		case "$HIVE_HOST_URL" in
			http*://*.*.*/)
				printf "$print_format" "$label_color" 'User-defined API server' "${BYELLOW}" "$HIVE_HOST_URL" "${NOCOLOR}"
				;;
			*)
				printf "$print_format" "$label_color" 'User-defined API server' "${BRED}" "$HIVE_HOST_URL (invalid, will not be used)" "${NOCOLOR}"
				# reset it. damn, still cannot figure out a better place in the code to do it
				HIVE_HOST_URL=
				;;
		esac
		echo
	fi

	if [ "$is_exit_now" -eq 1 ]; then
		echo
		echo -e "  ${GREEN}Client is up to date, don't need to update${NOCOLOR}"
		echo
		echo
		echo -e "Hint: ${GRAY}you can run ${CYAN}$script_basename --force${NOCOLOR} or ${CYAN}$script_basename 0.1-13 --force${NOCOLOR} to force update"
		exit "$repo_connectivity_status_exitcode" # die() isn't suitable here
	fi

	echo

	if [ "$bulk_download_mode_FLAG" -eq 1 ]; then
		echo -e "${BYELLOW}"
		echo '  WARNING: Bulk update optimization ON'
		echo '  Selfupgrade will be trying to download a package paying NO attention to ANY network errors'
		echo '  Operation can take up to 1 hour'
		echo -e "${NOCOLOR}"
		echo
	fi
}

print_script_usage () {
	echo -e "Update to a specific release or dev build"
	echo -e "Default repository is ${default_download_server_URL}${our_server_repo_path}"
	echo
	echo -e "  Usage: ${CYAN}${script_basename} [n.n-nn|master]${NOCOLOR}"
	echo
	echo -e "         ${CYAN}${script_basename}${NOCOLOR}                       update to the latest release version"
	echo -e "         ${CYAN}${script_basename} 0.1-13${NOCOLOR}                update to release 0.1-13"
	echo -e "         ${CYAN}${script_basename} 0.1-13 --force${NOCOLOR}        force update to release 0.1-13"
	echo
	echo -e "         ${CYAN}${script_basename} master${NOCOLOR}                stable dev build (beta)"
	echo
	echo -e "         ${CYAN}${script_basename} ${DGRAY}master github${NOCOLOR}         DEPRECATED, will be removed soon"
	echo -e "         ${CYAN}${script_basename} ${DGRAY}master dev347${NOCOLOR}         DEPRECATED, will be removed soon"
	echo
	echo '  Download source options:'
	echo
	echo -e "    ${WHITE}-g, --github${NOCOLOR}                           update from Github repo"
	echo -e "    ${WHITE}-m, --mirror${NOCOLOR}                           update from Github repo (mirror)"
	echo -e "    ${WHITE}--url=http://yourserver.com/repo/${NOCOLOR}      update from a custom URL, you have to"
	echo -e "                                           copy ALL files from the default repo"
#	echo
	echo '  Other options:'
	echo
	echo -e "    ${WHITE}-b, --bulk${NOCOLOR}                             turn on bulk update optimization"
	echo -e "    ${WHITE}-f, --force${NOCOLOR}                            forced update"
	echo -e "    ${WHITE}--farm-hash=${NOCOLOR}your_FARM_HASH             user-defined Farm hash"
	echo -e "    ${WHITE}--hive-host-url=${NOCOLOR}your_HIVE_HOST_URL     user-defined API server URL"
	echo -e "    ${WHITE}--skip-build=${NOCOLOR}devNNN                    skip update if local build = 'devNNN'"
	echo
}


#
# functions: arguments
#

parse_arguments () {
	#
	# Usage: parse_arguments
	#
	# Parse arguments, set global vars
	#

	# vars

	local this_ARG=''

	# code

	for this_ARG in "$@"; do
		case "$this_ARG" in
			'master')
				master_FLAG=1
				;;
			'-b' | '--bulk')
				bulk_download_mode_FLAG=1
				;;
			'-f' | '--force')
				force_update_mode_FLAG=1
				;;
			'--farm-hash='*)
				# ain't need no flags, just set the var
				FARM_HASH="${this_ARG#*=}"
				;;
			'-g' | '--github' | 'github')
				download_from_github_repo_FLAG=1
				;;
			'--hive-host-url='*)
				# ain't need no flags, just set the var
				HIVE_HOST_URL="${this_ARG#*=}"
				;;
			'-m' | '--mirror')
				download_from_github_mirror_repo_FLAG=1
				;;
			'--skip-build='*)
				build_to_skip_ARG="${this_ARG#*=}"
				[ "$local_build_version" = "$build_to_skip_ARG" ] && die "Local build is $local_build_version, skipped"
				;;
			'--url='*)
				custom_repo_URL="${this_ARG#*=}"
				download_from_custom_repo_FLAG=1
				;;
			*[0-9].[0-9]*)
				# roughly correct pattern for Client release version: 0.1 / 0.1-13
				user_defined_version_ARG="$this_ARG"
				;;
			'--help' | '-h' | *)
				# here goes all other incorrect stuff
				print_script_usage
				exit
				;;
		esac
	done
}


#
# functions: script infrastructure
#

echo_action () {
	echo "${GRAY}${script_basename}>${NOCOLOR} ${*}..."
}

echo_info () {
	echo "${GRAY}${script_basename}:${NOCOLOR} ${*}"
}

echo_error () {
	echo "${RED}${script_basename}:${NOCOLOR} ${*}"
} 1>&2

die () {
	local incoming_exitcode=$? # !!! must be the first line in a function to catch an incoming error code -- do not move

	# args

	local message="$1"
	local exitcode="${2:-$incoming_exitcode}"

	# code

	[ -n "$message" ] && echo -e "${BRED}${script_basename}:${NOCOLOR} $message"
	exit "$exitcode"
} 1>&2


#
# functions: downloads
#

is_curl_available () {
	# shellcheck disable=SC2230
	# bc we don't have command -v in some embedded shells (surprise!)
	which curl > /dev/null
}

download_from_URL_to_file () {
	#
	# Usage: download_from_URL_to_file 'URL' 'output_file' ['pretty_name']
	#
	# download using curl or wget
	#

	# args

	local URL="$1"
	local output_file="$2"
	local pretty_name="$3"

	# vars

	local downloader_output=''
	local downloader_exitcode="$exitcode_OK"

	# code

	[ -z "$pretty_name" ] && pretty_name="$output_file"

	echo_action "Downloading package to ${pretty_name}"
	if is_curl_available; then
		downloader_output="$( curl --insecure --location --fail --silent --show-error --connect-timeout 15 --retry 3 --output "$output_file" "$URL" 2>&1 )"
	else
		downloader_output="$( wget --quiet --output-document="$output_file" "$URL" 2>&1 )"
	fi

	downloader_exitcode=$?

	if [ "$downloader_exitcode" -eq 0 ]; then
		echo_info 'Downloaded OK'
	else
		echo_error "$downloader_output"
		echo_error "$URL failed to download"
	fi

	sleep 2 # ???
	return "$downloader_exitcode"
}

get_tar_gz_at_any_cost () {
	#
	# Usage: get_tar_gz_at_any_cost 'URL' 'output_file' ['pretty_name']
	#
	# nb: overwrites output file only on success
	#

	# args

	local URL="$1"
	local output_file="$2"
	local pretty_name="$3"

	# consts

	local retries_limit_standard=1
	local retries_limit_bulk=16 # max.time from 10m to 60m
	local temporary_file="${output_file}.${script_basename}-download"

	# vars

	local retries_counter=1
	local base_snooze_time=0 snooze_time=0 snooze_counter=0 retries_limit=0

	# code

	base_snooze_time="$( get_random_number_between 5 30 )"

	if [ "$bulk_download_mode_FLAG" -eq 1 ]; then
		retries_limit="$retries_limit_bulk"
		# random pause at the start
		echo_action "Wait for random ${base_snooze_time}s"
		sleep "$base_snooze_time"
		base_snooze_time="$( get_random_number_between 5 30 )" # srand() again -- a better randomness
	else
		retries_limit="$retries_limit_standard"
	fi

	until download_from_URL_to_file "$URL" "$temporary_file" "$output_file" && check_gz_integrity "$temporary_file" "$output_file"; do
		if [ "$retries_counter" -ge "$retries_limit" ]; then
			if [ "$bulk_download_mode_FLAG" -eq 1 ]; then
				echo_info "No success yet, $retries_counter attempt(s) were made in ${snooze_counter}s"
			else
				echo
				echo -e "Hint: ${GRAY}if you want to update from the current repo at any cost, you can run ${CYAN}$script_basename --bulk${NOCOLOR}"
			fi
			[ -f "$temporary_file" ] && rm -f "$temporary_file"
			die
		fi
		: $(( retries_counter += 1 ))
		: $(( snooze_time = base_snooze_time * retries_counter )) # every attempt will be later and later
		: $(( snooze_counter += snooze_time ))
		echo_info "Take a break, attempt #${retries_counter} in ${snooze_time}s"
		sleep "$snooze_time"
	done

	if [ -f "$temporary_file" ]; then
		cp -f "$temporary_file" "$output_file"
		rm -f "$temporary_file"
	fi

	sync

	return "$exitcode_OK"
}


#
# functions: files
#

check_gz_integrity () {
	#
	# Usage: check_gz_integrity 'gz_to_check' ['pretty_name']
	#

	# args

	local gz_to_check="$1"
	local pretty_name="$2"

	# code

	[ -z "$pretty_name" ] && pretty_name="$gz_to_check"

	echo_action "Checking $pretty_name integrity"

	if [ ! -s "$gz_to_check" ]; then
		echo_error "$pretty_name not found or empty"
		return 1
	elif ! gunzip -tf "$gz_to_check" >/dev/null 2>&1 && ! tar -tvzf "$gz_to_check" >/dev/null 2>&1; then
		echo_error "$pretty_name integrity check failed with error $?"
		return 1
	else
		echo_info "Checked OK"
		return 0
	fi
}

untar_then_remove () {
	#
	# Usage: untar_then_remove 'file_to_extract' ['DO NOT REMOVE']
	#
	# in case of tar error, show output and die, else say mere 'ok'
	#

	# args

	local file_to_extract="${1:-SAFE}"
	local do_not_remove="${2}"

	# vars

	local tar_output=''

	# code

	echo_action "Extracting ${file_to_extract}"
	if ! tar_output="$( tar -xzv -f "$file_to_extract" 2>&1 )"; then
		die "${tar_output}\n\nError extracting $file_to_extract, exiting"
	else
		if [ "$do_not_remove" = 'DO NOT REMOVE' ]; then
			echo_info 'Extracted OK'
		else
			echo_action "Extracted OK, removing ${file_to_extract}"
			rm -f "$file_to_extract"
		fi
	fi
}

goto_temp_dir () {
	#
	# global vars being set: temp_dir
	#

	# vars

	local existing_temp_dir=''

	# code

	existing_temp_dir="$( df -h | grep -F '/tmp' | awk '{print $NF}' | head -1 )" # find an existing temp dir
	[ -n "$existing_temp_dir" ] && temp_dir="$existing_temp_dir"
	cd "$temp_dir" || die "cannot change directory to $temp_dir, exiting"
}

remove_needless_files () {
	#
	# remove_needless_files 'filename' ['file'...]
	#
	# wildcards inside the double quotes are supported
	#

	# args

	[ $# -eq 0 ] && return

	# vars

	local is_something_happened_FLAG=0
	local file_to_remove='' f='' message_body=''

	# code

	for file_to_remove in "$@"; do
		# iterate over the arguments
		for f in $file_to_remove; do
			# auxiliary loop is just for expanding the glob -- note 'break' statement
			if [ -e "$f" ]; then
				message_body="${message_body}${file_to_remove}"
				# shellcheck disable=SC2086
				if rm -rf $file_to_remove > /dev/null 2>&1; then
					message_body="${message_body} "
				else
					message_body="${message_body} (FAIL) "
				fi
				is_something_happened_FLAG=1
			fi
			break
		done
	done

	if [ "$is_something_happened_FLAG" -gt 0 ]; then
		echo_action "Cleaning: $message_body"
	fi
}

wait_for_file () { # OBSOLETE, NOT USED ANYMORE
	#
	# wait_for_file 'file_to_wait' ['timeout_in_seconds'(default:300s)]
	#
	# waits for file or directory
	#

	# args

	if [ $# -lt 1 ]; then
		return 2
	fi
	local file_to_wait="$1"
	local timeout_in_seconds="${2:-300}"

	# consts

	local sleep_interval_in_seconds=1
	local print_message_every=30

	# vars

	local countdown="$timeout_in_seconds"
	local is_file_found=0
	local waiting_time=0

	# code

	until [ "$countdown" -le 0 ]; do
		if [ -e "$file_to_wait" ]; then
			is_file_found=1
			break
		else
			waiting_time=$(( timeout_in_seconds - countdown ))
			message="We have to wait ${countdown}s for '${file_to_wait}'... "
			if [ $(( waiting_time % print_message_every )) -eq 0 ] && [ ! -t 1 ]; then
				# print every 30s -- if file not found yet and no terminal connected
				echo_action "$message"
			elif [ $(( waiting_time % 5 )) -eq 0 ] && [ -t 1 ]; then
				# print every step on the same line -- if file not found yet and terminal connected
				echo -e -n "\r${GRAY}${script_basename}>${NOCOLOR} ${message}..."
			fi
			: $(( countdown -= 1 ))
			sleep "$sleep_interval_in_seconds"
		fi
	done


	if [ "$is_file_found" -ne 1 ]; then
		[ -t 1 ] && echo -n -e '\r'
		echo_info "$script_basename has been waiting for $(( waiting_time + 1 ))s: '${file_to_wait}' still not found."
	elif [ "$waiting_time" -ne 0 ]; then
		[ -t 1 ] && echo -n -e '\r'
		echo_info "$script_basename has been waiting for $(( waiting_time + 1 ))s: '${file_to_wait}' found!"
	fi

	return $(( is_file_found==0 ))
}


#
# functions: model-specific install routines
#

do_install_for () {

	# args

	local install_type="$1"

	# code

	get_tar_gz_at_any_cost "$package_file_URL" "$package_file_to_download"
	if [ "$install_type" != 'antminer_bmminer_ro' ]; then
		untar_then_remove "$package_file_to_download"
	else
		untar_then_remove "$package_file_to_download" 'DO NOT REMOVE' # hehe we'll need it later
	fi
	remove_needless_files "hiveos-asic-${release_version_to_install}/hive/sbin/teleconsole" # remove the legacy teleconsole before copying

	"install_$install_type"
}

execute_install_routine () {
	echo -e -n "${GRAY}${script_basename}>${NOCOLOR} Installing Client for "

	case "$ASIC_MODEL" in

		# Antminer, exact match

		'Antminer A3'			|\
		'Antminer D3'			|\
		'Antminer DR3'			|\
		'Antminer L3++'			|\
		'Antminer S7'			|\
		'Antminer X3')			echo "$ASIC_MODEL"			;	do_install_for 'antminer_cgminer'		;;

		'Antminer E3'			|\
		'Antminer S9 Hydro'		|\
		'Antminer S9'			|\
		'Antminer S9i'			|\
		'Antminer S9j'			|\
		'Antminer S11'			|\
		'Antminer T9'			|\
		'Minecenter S9')		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;

		'Antminer S9 SE'*		|\
		'Antminer S9k'*			|\
		'Antminer S15'			|\
		'Antminer T15')			echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;

		'Antminer Z9-Mini')		echo "$ASIC_MODEL"			;	do_install_for 'antminer_Z9_cgminer'	;;

		'Antminer ')			echo 'Antminer B3'			;	do_install_for 'antminer_bmminer'		;;

		# Antminer, partial match

		'Antminer D3 Blissz'*)	echo "$ASIC_MODEL"			;	do_install_for 'antminer_cgminer'		;;
		'Antminer L3+'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_cgminer'		;;
		'Antminer S9 (vnish'*)	echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;
		'Antminer S9'*)			echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;
		'Antminer S10'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;
		'Antminer S17'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;
		'Antminer S19'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;
		'Antminer T19'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;
		'Antminer T9+'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;
		'Antminer T9'*)			echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer'		;;
		'Antminer T17'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;
		'Antminer X17'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_bmminer_ro'	;;
		'Antminer Z9'*)			echo "$ASIC_MODEL"			;	do_install_for 'antminer_Z9_cgminer'	;;
		'Antminer Z11'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_Z9_cgminer'	;;

		# Innosilicon, dragonMint

		'b29+.g19')				echo 'Innosilicon A9'		;	do_install_for 'innosilicon'			;;
		'a9+.g19')				echo 'Innosilicon A9+'		;	do_install_for 'innosilicon'			;;
		'd9.g19')				echo 'Innosilicon D9'		;	do_install_for 'innosilicon'			;;
		's11.g19')				echo 'Innosilicon S11'		;	do_install_for 'innosilicon'			;;
		't2th.soc')				echo 'Innosilicon T2Th'		;	do_install_for 'innosilicon'			;;
		't2thf.soc')			echo 'Innosilicon T2Thf'	;	do_install_for 'innosilicon'			;;
		't2thm.soc')			echo 'Innosilicon T2Thm'	;	do_install_for 'innosilicon'			;;
		't2t.soc')				echo 'Innosilicon T2T-24T'	;	do_install_for 'innosilicon'			;;
		't2t+.soc')				echo 'Innosilicon T2T+(32T)';	do_install_for 'innosilicon'			;;
		't2th+.soc')			echo 'Innosilicon T2TH+'	;	do_install_for 'innosilicon'			;;
		't2thf+.soc')			echo 'Innosilicon T2THf+'	;	do_install_for 'innosilicon'			;;
		't2thl+.soc')			echo 'Innosilicon T2THl+'	;	do_install_for 'innosilicon'			;;
		't2ti.soc')				echo 'Innosilicon T2Ti-25T'	;	do_install_for 'innosilicon'			;;
		't2ts.soc')				echo 'Innosilicon T2Ts-26T'	;	do_install_for 'innosilicon'			;;
		't2tz.soc')				echo 'Innosilicon T2Tz-30T'	;	do_install_for 'innosilicon'			;;
		't3.soc')				echo 'Innosilicon T3'		;	do_install_for 'innosilicon'			;;
		't3+.soc')				echo 'Innosilicon T3+'		;	do_install_for 'innosilicon'			;;
		't3h+.soc')				echo 'Innosilicon T3H+'		;	do_install_for 'innosilicon'			;;
		'T4.G19')				echo 'Innosilicon A8'		;	do_install_for 'innosilicon_innominer'	;;
		't1.g19')				echo 'DragonMint T1'		;	do_install_for 'dragonMint'				;;

		# Zig

		'Zig Z1+'				|\
		'Zig Z1')				echo "$ASIC_MODEL"			;	do_install_for 'zig'					;;

		# Todek Toddminer C1 and C1 PRO eaglesong ASICs

		'Toddminer C1'*)		echo "$ASIC_MODEL"			;	do_install_for 'todd'					;;

		# HashAltCoin FPGA Blackminer F1 series (multialgo)

		'Blackminer F1'*)		echo "$ASIC_MODEL"			;	do_install_for 'antminer_cgminer'		;;

		# Avalon

		'Avalon'*)				echo "$ASIC_MODEL"			;	do_install_for 'avalon'					;;

		# unknown

		*)
			echo "'$ASIC_MODEL'"
			echo
			echo 'Model is not supported'
			echo
			echo 'Please contact us: https://t.me/hiveonasic_en'
			echo '                   https://t.me/hiveonasic_ru'
			echo '                   bee@hiveos.farm'
			echo
			die '' "$exitcode_NOT_OK"
			;;
	esac
}

install_antminer_bmminer () {
	#
	# bmminer, / - rw, cron
	#

	[ ! -d /config/hive/hive-config ] && mkdir -p /config/hive/hive-config
	[ -L /hive ] && rm /hive

	echo_action 'Copying to /'
	cp -rf "hiveos-asic-${release_version_to_install}/hive" / || die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib
	#[ -d /hive && ! -L /hive ] && mv -f /hive /config/hive/
	[ -d /hive-config ] && [ ! -L /hive-config ] && mv -f /hive-config /config/hive/

	if [ ! -e /hive-config ]; then
		#ln -s /config/hive/hive/ /hive
		ln -s /config/hive/hive-config/ /hive-config
	fi
	cp -rf /hive/share/S9/S69hive /etc/rcS.d/
	cp -rf /hive/share/S9/.profile /home/root/

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	sleep 2

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_antminer_cgminer () {
	#
	# cgminer, / - ro, no cron
	#

	[ ! -d /config/hive ] && mkdir /config/hive

	echo_action 'Copying to /config/hive/'
	cp -rf "hiveos-asic-${release_version_to_install}/"* /config/hive/ || die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	if [ ! -e /hive ]; then
		ln -s /config/hive/hive/ /hive
		ln -s /config/hive/hive-config/ /hive-config
		ln -s /config/hive/home/root/.profile /home/root/.profile
	fi

	if grep -Fq '### HIVE AUTORUN ###' /config/network.conf || grep -Fq 'ln -s /config/hive/hive/ /hive' /config/network.conf || [ -n "$HIVEON_VERSION" ]; then
		echo_info 'Hiveon firmware found, /config/network.conf tampering skipped'
	else
		echo_info 'No Hiveon firmware found, injecting autorun into /config/network.conf'
		cat >> /config/network.conf <<-FILEEOF

			### HIVE AUTORUN ###
			[ -e /config/hive_autorun ] && nohup /bin/sh -c '/config/hive_autorun' > /dev/null 2>&1 &
		FILEEOF
	fi
	cp -rf /hive/bin/hive_autorun /config/hive_autorun

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	#on cgminer's antminer no cron daemon, run tasks in background
# legacy cron imitation
# now it's a /hive/bin/controller built-in
#	nohup bash -c 'sleep 60; /hive/bin/cron1' > /dev/null 2>&1 &
#	nohup bash -c 'sleep 60; /hive/bin/cron2' > /dev/null 2>&1 &

	sleep 2

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_antminer_Z9_cgminer () {
	#
	# cgminer, / - rw, no cron
	#

	if [ -e /hive ] && [ ! -L /hive ]; then
		mkdir -p /config/hive
		mv -f /hive /config/hive/
		mv -f /hive-config /config/hive/
		mv -f /home/root/.profile /config/hive/home/root/
		ln -s /config/hive/hive/ /hive
		ln -s /config/hive/hive-config/ /hive-config
		ln -s /config/hive/home/root/.profile /home/root/.profile
	fi
	[ ! -d /config/hive ] && mkdir /config/hive

	echo_action 'Copying to /config/hive/'
	cp -rf "hiveos-asic-${release_version_to_install}/"* /config/hive/ || die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	if [ ! -e /hive ]; then
		ln -s /config/hive/hive/ /hive
		ln -s /config/hive/hive-config/ /hive-config
		ln -s /config/hive/home/root/.profile /home/root/.profile
	fi

	if grep -Fq '### HIVE AUTORUN ###' /config/network.conf || grep -Fq 'ln -s /config/hive/hive/ /hive' /config/network.conf; then
		echo_info '/config/network.conf skipped'
	else
		cat >> /config/network.conf <<-FILEEOF

			### HIVE AUTORUN ###
			[ -e /config/hive_autorun ] && nohup /bin/sh -c '/config/hive_autorun' > /dev/null 2>&1 &
		FILEEOF
	fi
	cp -rf /hive/bin/hive_autorun /config/hive_autorun

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	#on cgminer's antminer no cron daemon, run tasks in background
# legacy cron imitation
# now it's a /hive/bin/controller built-in
#	nohup bash -c 'sleep 60; /hive/bin/cron1' > /dev/null 2>&1 &
#	nohup bash -c 'sleep 60; /hive/bin/cron2' > /dev/null 2>&1 &

	sleep 2

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_innosilicon () {
	#
	#
	#

	mount -o remount,rw,relatime,ubi=0,vol=0 -t ubifs ubi0:rootfs /
	[ ! -d /config/hive ]	&& mkdir -p /config/hive
	[ ! -d /hive ]			&& mkdir /hive

	### untar was right here

	echo_action 'Copying'
	cp -rf "hiveos-asic-${release_version_to_install}/hive-config" /config/hive/						|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/bin" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/etc" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/sbin" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/lib" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/home/root/.profile" /etc/profile.d/hive.sh		|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/share/innosilicon/"* /etc/systemd/system/	|| die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	[ ! -L /hive/bin ]		&& [ ! -e /hive/bin ]		&& ln -s /config/hive/bin /hive/bin
	[ ! -L /hive/etc ]		&& [ ! -e /hive/etc ]		&& ln -s /config/hive/etc /hive/etc
	[ ! -L /hive-config ]	&& [ ! -e /hive-config ]	&& ln -s /config/hive/hive-config/ /hive-config
	[ ! -L /hive/sbin/nc ]	&& [ ! -e /hive/sbin/nc ]	&& ln -s /hive/sbin/busybox.nosuid /hive/sbin/nc

	#systemd autorun and cron
	systemctl daemon-reload
	systemctl is-enabled hive.service > /dev/null
	[ $? -eq 1 ] && systemctl enable hive.service
	systemctl start hive.service
	systemctl is-enabled hive-agent-screen.timer > /dev/null
	[ $? -eq 1 ] && systemctl enable hive-agent-screen.timer
	systemctl start hive-agent-screen.timer
	systemctl is-enabled hive-cache-ip.timer > /dev/null
	[ $? -eq 1 ] && systemctl enable hive-cache-ip.timer
	systemctl start hive-cache-ip.timer

	sleep 2
	nohup sync && sleep 600 && mount -o remount,ro,relatime,ubi=0,vol=0 -t ubifs ubi0:rootfs / &

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
	systemctl start hive.service
}

install_dragonMint () {
	#
	#
	#

	mount -o remount,rw,relatime -t ubifs ubi0:rootfs /
	[ ! -d /config/hive ]	&& mkdir -p /config/hive
	[ ! -d /hive ]			&& mkdir /hive

	### untar was right here

	echo_action 'Copying'
	cp -rf "hiveos-asic-${release_version_to_install}/hive-config" /config/hive/						|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/bin" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/etc" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/sbin" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/lib" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/home/root/.profile" /etc/profile.d/hive.sh		|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/share/innosilicon/"* /etc/systemd/system/	|| die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	[ ! -L /hive/bin ]		&& [ ! -e /hive/bin ]		&& ln -s /config/hive/bin /hive/bin
	[ ! -L /hive/etc ]		&& [ ! -e /hive/etc ]		&& ln -s /config/hive/etc /hive/etc
	[ ! -L /hive-config ]	&& [ ! -e /hive-config ]	&& ln -s /config/hive/hive-config/ /hive-config
	[ ! -L /hive/sbin/nc ]	&& [ ! -e /hive/sbin/nc ]	&& ln -s /hive/sbin/busybox.nosuid /hive/sbin/nc

	#systemd autorun and cron
	systemctl daemon-reload
	systemctl is-enabled hive.service > /dev/null
	[ $? -eq 1 ] && systemctl enable hive.service
	systemctl start hive.service
	systemctl is-enabled hive-agent-screen.timer > /dev/null
	[ $? -eq 1 ] && systemctl enable hive-agent-screen.timer
	systemctl start hive-agent-screen.timer
	systemctl is-enabled hive-cache-ip.timer > /dev/null
	[ $? -eq 1 ] && systemctl enable hive-cache-ip.timer
	systemctl start hive-cache-ip.timer

	sleep 2
	nohup sync && sleep 600 && mount -o remount,ro,relatime -t ubifs ubi0:rootfs / &

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
	systemctl start hive.service
}

install_innosilicon_innominer () {
	#
	#
	#

	mount -o remount,rw,relatime -t jffs2 /dev/root /
	[ ! -d /hive ] && mkdir /hive

	### untar was right here

	echo_action 'Copying to /innocfg'
	cp -rf "hiveos-asic-${release_version_to_install}/hive-config" /innocfg/						|| die 'Copy error'
	echo_action 'Copying to /'
	cp -rf "hiveos-asic-${release_version_to_install}/hive" /										|| die 'Copy error'
#	cp -rf "hiveos-asic-${release_version_to_install}/home/root/.profile" /etc/profile.d/hive.sh	|| die 'Copy error'

	[ ! -L /hive-config ] && [ ! -e /hive-config ] && ln -s /innocfg/hive-config/ /hive-config

	#autorun
	if grep -Fq '### HIVE AUTORUN ###' /etc/init.d/rcS; then
		echo_info '/etc/init.d/rcS skipped'
	else
		cat >> /etc/init.d/rcS <<-FILEEOF

			### HIVE AUTORUN ###
			[ -e /hive/bin/hive ] && nohup /hive/sbin/bash -c 'sleep 30; /hive/bin/hive > /tmp/client-boot.log 2>&1; echo "Running The Client..."' > /dev/null 2>&1 &
			[ -e /hive/bin/hello ] && nohup /hive/sbin/bash -c 'sleep 40; /hive/bin/hello' > /dev/null 2>&1 &
		FILEEOF
# legacy cron imitation
# now it's a /hive/bin/controller built-in
#			[ -e /hive/bin/cron1 ] && nohup /hive/sbin/bash -c 'sleep 60; /hive/bin/cron1' > /dev/null 2>&1 &
#			[ -e /hive/bin/cron2 ] && nohup /hive/sbin/bash -c 'sleep 60; /hive/bin/cron2' > /dev/null 2>&1 &
	fi

	#PATH
	if grep -Fq '### HIVE PROFILE ###' /etc/profile; then
		echo_info '/etc/profile skipped'
	else
		cat >> /etc/profile <<-FILEEOF

			### HIVE PROFILE ###
			case "\$PATH" in
			    *'/hive/bin:/hive/sbin'*)	: ok good to go								;;
			    *)							export PATH="\$PATH:/hive/bin:/hive/sbin"	;;
			esac
			export LD_LIBRARY_PATH=/hive/lib
		FILEEOF
	fi

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	sync
	sleep 5
	mount -o remount,ro,relatime -t jffs2 /dev/root /

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_zig () {
	#
	#
	#

	echo_action 'Copying to /'
	cp -rf "hiveos-asic-${release_version_to_install}/"* / || die 'Copy error'

	sleep 2

	ln -s /bin/busybox /bin/nc
	cp -rf /hive/share/zig/crontab.root /etc/cron.d/hive
	cp -rf /home/root/.profile /etc/profile.d/hive.sh
	/etc/init.d/cron restart
	apt update
	apt install -y curl screen jq
	sed -i 's/#!\/bin\/sh/#!\/bin\/bash/g' "/hive/bin/$script_basename"
	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	sleep 2

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_todd () {
	#
	#
	#

	echo_action 'Copying to /'
	cp -rf "hiveos-asic-${release_version_to_install}/"* / || die 'Copy error'

	sleep 2

	cp -rf /hive/share/zig/crontab.root /etc/cron.d/hive
	cp -rf /home/root/.profile /etc/profile.d/hive.sh
	/etc/init.d/cron restart
	apt update
	apt install -y curl screen jq dnsutils
	sed -i 's/#!\/bin\/sh/#!\/bin\/bash/g' "/hive/bin/$script_basename"
	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	echo_action 'Booting The Client'
	/hive/bin/hive > /tmp/client-boot.log 2>&1

	sleep 2

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
}

install_antminer_bmminer_ro () {
	#
	# bmminer, / - ro, cron
	#

	# consts

	local system_S69hive='/etc/rcS.d/S69hive'
	local updated_S69hive='/hive/share/ant_15_17/S69hive'

	# code

	echo_action 'Moving downloaded package to NVRAM'
	mv -f "$package_file_to_download" "${NVRAM_path}/${persistent_package_filename}" || die 'Move error'
	sync && echo 3 > /proc/sys/vm/drop_caches

	remove_needless_files "${NVRAM_path}/latest_new.tar.gz" # delete a file from a legacy selfupgrade

	[ ! -d /config/hive ]	&& mkdir -p /config/hive/hive-config
	[ -L /hive ]			&& rm /hive
	[ -e /hive ]			&& rm -rf /hive

	echo_action 'Copying extracted files to /hive and /home'
	cp -rf "hiveos-asic-${release_version_to_install}/hive" / || die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/home" / || die 'Copy error'

	echo_action 'Copying finished, removing temporary files'
	rm -rf hiveos-asic-* || echo_info 'Temporary files removing error'

	# update system S69hive, to ease the debugging that happens from time to time
	if [ ! -f "$system_S69hive" ] || ! cmp -s "$system_S69hive" "$updated_S69hive"; then
		cp -f "$updated_S69hive" "$system_S69hive"
	fi

	[ -d /hive-config ] && [ ! -L /hive-config ] && mv -f /hive-config /config/hive/
	[ ! -L /hive-config ] && [ ! -e /hive-config ] && ln -s /config/hive/hive-config/ /hive-config

	echo_info "Installed build: $( cat /hive/etc/build )"
	sync
	sleep 1 # ???

	#/etc/rcS.d/S69hive
	# actually we don't need S69hive, let's boot Client directly:

	echo_action 'Booting The Client'

	if [ -n "$FARM_HASH" ]; then
		# FARM_HASH could be defined externaly or by command-line option
		/hive/bin/firstrun "$FARM_HASH"
		remove_needless_files "${FARM_HASH_file:-SAFE}"
	fi
	/hive/bin/hive > /tmp/client-boot.log 2>&1
}

install_avalon () {
	#
	#
	#

	[ ! -d /config/hive ]	&& mkdir -p /config/hive
	[ ! -d /hive ]			&& mkdir /hive

	### untar was right here

	echo_action 'Copying'
	cp -rf "hiveos-asic-${release_version_to_install}/hive-config" /config/hive/						|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/bin" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/etc" /config/hive/							|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/sbin" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/lib" /hive/									|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/home/root/.profile" /etc/profile.d/hive.sh		|| die 'Copy error'
	cp -rf "hiveos-asic-${release_version_to_install}/hive/share/avalon/"* /etc/systemd/system/			|| die 'Copy error'

	sleep 2

	case "$PATH" in
		*'/hive/bin:/hive/sbin'*)	: ok good to go								;;
		*)							export PATH="$PATH:/hive/bin:/hive/sbin"	;;
	esac
	export LD_LIBRARY_PATH=/hive/lib

	[ ! -L /hive/bin ]		&& [ ! -e /hive/bin ]		&& ln -s /config/hive/bin /hive/bin
	[ ! -L /hive/etc ]		&& [ ! -e /hive/etc ]		&& ln -s /config/hive/etc /hive/etc
	[ ! -L /hive-config ]	&& [ ! -e /hive-config ]	&& ln -s /config/hive/hive-config/ /hive-config

	apt update
	apt install -y curl screen jq

	#systemd autorun and cron
	systemctl daemon-reload
	systemctl is-enabled hive.service > /dev/null
	[ $? -eq 1 ] && systemctl enable hive.service
	systemctl start hive.service
	systemctl is-enabled hive-agent-screen.timer > /dev/null
	[ $? -eq 1 ] && systemctl enable hive-agent-screen.timer
	systemctl start hive-agent-screen.timer
#	systemctl is-enabled hive-cache-ip.timer > /dev/null
#	[ $? -eq 1 ] && systemctl enable hive-cache-ip.timer
#	systemctl start hive-cache-ip.timer

	# FARM_HASH could be defined externaly or by command-line option
	/hive/bin/firstrun "$FARM_HASH"
	systemctl start hive.service
}


#
# functions: setters
#

set_ASIC_MANUFACTURER_and_ASIC_MODEL_variables () {
	#
	# !!! shall be sh-friendly
	# !!! copied from 'asic-model' script, PLEASE KEEP IT IN SYNC
	#
	ASIC_MODEL='<unknown>'
	ASIC_MANUFACTURER='<unknown>'

	# Bitmain Antminer
	if [ -s /usr/bin/compile_time ]; then
		ASIC_MANUFACTURER='Bitmain'
		ASIC_MODEL="$( sed -n '2p' /usr/bin/compile_time )"
		case "$ASIC_MODEL" in
			'Blackminer F1'*)
				ASIC_MANUFACTURER='HashAltCoin'
			;;
		esac
	fi

	# Ebang Ebit
	if [ -f /opt/system/bank.conf ]; then
		ASIC_MANUFACTURER='Ebang'
		ASIC_MODEL='ebit'
	fi

	# Innosilicon
	if [ -s /etc/hwrevision ]; then
		ASIC_MANUFACTURER='Innosilicon'
		ASIC_MODEL="$( cut -d' ' -f 2 /etc/hwrevision )"
	elif [ -s /tmp/type ]; then
		# Innosilicon A5/8
		ASIC_MANUFACTURER='Innosilicon'
		ASIC_MODEL="$( cat /tmp/type ).$( cat /tmp/hwver )"
	fi
	# TODO for refactor: place hwrevision to ASIC_HWREVISION and then place a human-friendly name to ASIC_MODEL='T2Thf' ??? way too much work...

	# Dayun Zig
	if [ -s /var/www/html/src/Template/Layout/signin.twig ]; then
		ASIC_MANUFACTURER='Dayun'
		# Zig old firmware
		ASIC_MODEL="$(
			{
				grep -Fs -e 'Zig' /var/www/html/src/Template/Layout/signin.twig ||
				grep -Fs -e 'Zig' /var/www/html/src/Template/Users/login.twig
			} |
				grep -Es -e 'title|<a><b>' | sed 's/<[^>]*>//g; s/^ *//g; s/ *$//g'
		)"
		# Zig new firmware
		if [ -s /var/www/html/TYPE ]; then
			# shellcheck disable=SC2001
			ASIC_MODEL="$( echo "$ASIC_MODEL" | sed "s/{{ type() }}/$( cat /var/www/html/TYPE )/" )" #"# syntax highliting fix
		fi
	fi

	# Todek Toddminer C1 / C1 PRO
	if [ -x /home/sm/miner/build/cpuminer ] && [ -e /flask/setHashinJson ]; then
		ASIC_MANUFACTURER='Todek'
		ASIC_MODEL='Toddminer C1'
		if /home/sm/miner/build/cpuminer -V | head -1 | grep -Fq 'pro'; then
			ASIC_MODEL="$ASIC_MODEL PRO"
		fi
	fi

	# Canaan Avalon
	if [ -d /home/pi ]; then
		ASIC_MANUFACTURER='Canaan'
		ASIC_MODEL='Avalon AV8-0'
	fi
}

set_HIVEON_VERSION_variable () {
	#
	# !!! shall be sh-friendly
	# !!! copied from 'asic-model' script, PLEASE KEEP IT IN SYNC
	#

	# vars
	HIVEON_VER='' # deprecated in favor of the more clear HIVEON_VERSION
	HIVEON_VERSION=''
	HIVEON_VERSION_major=-1 # default: no Hiveon

	# code
	if [ -s /usr/bin/compile_ver ]; then
		HIVEON_VERSION="$( awk -F'@' 'NR==3 {print $1; exit}' < /usr/bin/compile_ver )"
		# shellcheck disable=SC2034
		HIVEON_VER="$HIVEON_VERSION" # legacy
		# shellcheck disable=SC2034
		# take a part before the first dot                                  vvvvvvvvvvvvvvvvvv
		# and then remove leading zeroes, if any             vvvvvvvvvvv
		[ -n "$HIVEON_VERSION" ] && HIVEON_VERSION_major="$( printf '%d' "${HIVEON_VERSION%%.*}" 2> /dev/null )"
	fi
}

set_NVRAM_path () {
	#
	# global vars being set: NVRAM_path
	#

	if [ -d "$NVRAM_path_quirk" ]; then
		NVRAM_path="$NVRAM_path_quirk" # duct tape for dear Vitya
	else
		NVRAM_path="$NVRAM_path_default"
	fi
}

#
# Client boot, taken from S69hive
#

set_FARM_HASH () {
	# if FARM_HASH is not supplied by user and FARM_HASH file exists
	if [ -z "$FARM_HASH" ] && [ -s "$FARM_HASH_file" ]; then
		FARM_HASH=$( cat "$FARM_HASH_file" )
		echo -e "${DGRAY}External FARM_HASH '$FARM_HASH' found in ${FARM_HASH_file}${NOCOLOR}"
	fi
}

set_download_server_URL () {
	#
	# Usage: set_download_server_URL
	#
	# Process whitelabels and/or an external HIVE_HOST_URL
	#
	# global vars being set: download_server_URL
	#

	# conts

	# sorted by prio, from high to low
	local whitelabel_HIVE_DOWNLOADS_URL_file_in_FW='/etc/hive-downloads-url' # prio 1
	#local                      HIVE_HOST_URL_file='/config/HIVE_HOST_URL' # prio 2 # already declared as a global readonly, !!! should refactor later
	local   whitelabel_HIVE_HOST_URL_file_in_NVRAM='/config/hive-url' # prio 3
	local      whitelabel_HIVE_HOST_URL_file_in_FW='/etc/hive-url' # prio 4

	# define collection (whitespace delimited) and priority (prio increases from left to right)
	local download_server_URL_files_collection="${whitelabel_HIVE_HOST_URL_file_in_FW} ${whitelabel_HIVE_HOST_URL_file_in_NVRAM} ${HIVE_HOST_URL_file} ${whitelabel_HIVE_DOWNLOADS_URL_file_in_FW}"

	# vars

	local this_file
	local something_happen=0

	# code

	# !!! potential problem: API server with a pure IP address AND firewalled *.hiveos.farm
	for this_file in $download_server_URL_files_collection; do
		if [ -s "$this_file" ]; then
			# remove ;|" chars then replace 'api.' with 'download.'
			download_server_URL="$( tr -d ';|"' < "$this_file" | sed 's|api\.|download\.|' )" #'# syntax highlighting fix
			echo -e "${DGRAY}Server URL '$download_server_URL' found in ${this_file}${NOCOLOR}"
			something_happen=1
		fi
	done

	if [ "$something_happen" -eq 1 ]; then
		# url refining
		case "$download_server_URL" in
			*'download'*)
				: ok good to go
				;;
			'')
				echo -e "${DGRAY}WARNING: Empty server URL, using default $default_download_server_URL${NOCOLOR}"
				download_server_URL="$default_download_server_URL"
				;;
			*)
				echo -e "${DGRAY}WARNING: Invalid server URL '$download_server_URL', using default $default_download_server_URL${NOCOLOR}"
				download_server_URL="$default_download_server_URL"
				;;
		esac
		echo
	fi
}

set_repo_URLs () {
	#
	# Usage: set_repo_URLs
	#
	# assign global vars based on flags
	#
	# global vars being set: repo_base_URL, repo_version_URL, repo_description
	#

	# vars

	local last_character=''
	local download_server_URL="$default_download_server_URL"

	# code

	if [ "$download_from_github_repo_FLAG" -eq 1 ]; then

		repo_base_URL="$github_repo_URL"
		repo_description="$github_repo_description"
		repo_version_URL="$github_repo_version_URL" # due to a different paths at the repo and github

	elif [ "$download_from_github_mirror_repo_FLAG" -eq 1 ]; then

		repo_base_URL="${download_server_URL}${github_mirror_repo_path}"
		repo_description="$github_mirror_repo_description"
		repo_version_URL="$repo_base_URL"

	elif [ "$download_from_custom_repo_FLAG" -eq 1 ]; then

		last_character="$( echo -n "$custom_repo_URL" | tail -c 1 )"
		if [ "$last_character" != '/' ]; then
			custom_repo_URL="${custom_repo_URL}/"
		fi

		repo_base_URL="$custom_repo_URL"
		repo_description="($custom_repo_URL)"
		repo_version_URL="$repo_base_URL"

	else

		set_download_server_URL # take into account the whitelabels and/or an external HIVE_HOST_URL

		repo_base_URL="${download_server_URL}${our_server_repo_path}"
		repo_description="$our_server_repo_description"
		repo_version_URL="$repo_base_URL"

	fi
}

set_package_URL_and_file () {
	#
	# Usage: set_package_URL_and_file
	#
	# global vars being set: package_file_to_download, package_file_URL, release_version_to_install
	#

	# vars

	local local_build_version_numeric remote_build_version_numeric

	# code

	if [ "$master_FLAG" -eq 1 ]; then
		release_version_to_install='master'
		package_file_to_download="${release_version_to_install}.tar.gz"

		# ash/dash lacks arrays and/or BASH_REMATCH, so there's a simplified approach to compare the versions:
		# filter only first group of consecutive digits from a build version string
		local_build_version_numeric="$( echo "$local_build_version" | sed -nre 's/^[^0-9]*([0-9]+).*/\1/p' )"
		[ -z "$local_build_version_numeric" ] && local_build_version_numeric=0
		remote_build_version_numeric="$( echo "$remote_build_version" | sed -nre 's/^[^0-9]*([0-9]+).*/\1/p' )"
		[ -z "$remote_build_version_numeric" ] && remote_build_version_numeric=0

		# sometimes we don't get the remote build version properly (curl timeouts etc.)
		# in these cases let's assume that the remote version always greater than local
		[ -z "$remote_build_version_numeric" ] && remote_build_version_numeric=9999999999

		# numeric comparison
		if [ "$local_release_version" = "$remote_release_version" ] && [ "$local_build_version_numeric" -ge "$remote_build_version_numeric" ]; then
			dont_have_to_update_FLAG=1 # TODO REFACTOR relocate to a separate function like do_we_have_to_update_or_not()
		fi
	elif [ -n "$user_defined_version_ARG" ]; then
		release_version_to_install="$user_defined_version_ARG"
		package_file_to_download="v${release_version_to_install}.tar.gz"
		[ "$user_defined_version_ARG" = "$local_release_version" ] && dont_have_to_update_FLAG=1 # TODO REFACTOR relocate to a separate function like do_we_have_to_update_or_not()
	else
		release_version_to_install="$remote_release_version"
		package_file_to_download="v${release_version_to_install}.tar.gz"
		[ "$local_release_version" = "$remote_release_version" ] && dont_have_to_update_FLAG=1 # TODO REFACTOR relocate to a separate function like do_we_have_to_update_or_not()
	fi

	package_file_URL="${repo_base_URL}${package_file_to_download}"
}


#
# functions: getters
#

get_remote_version_of () {
	#
	# get_remote_version_of 'release'|'build' 'version_URL'
	#

	# args

	local release_or_build="$1"
	local version_URL="$2"

	# vars

	local downloader_output='' downloader_exitcode="$exitcode_OK" download_URL=''

	# code

	case "$release_or_build" in
		'release')		download_URL="${version_URL}${release_file_name}"	;;
		'build')		download_URL="${version_URL}${build_file_name}"		;;
	esac

	if is_curl_available; then
		if [ "$bulk_download_mode_FLAG" -eq 1 ]; then
			downloader_output="$( curl --insecure --location --fail --silent --show-error --connect-timeout 15 --retry 10 "$download_URL" 2>&1 )"
		else
			downloader_output="$( curl --insecure --location --fail --silent --show-error --connect-timeout 7 --retry 5 --max-time 35 "$download_URL" 2>&1 )" # 10 seconds tops
		fi
	else
		downloader_output="$( wget --quiet --output-document=- "$download_URL" 2>&1 )"
	fi

	downloader_exitcode=$?

	if [ "$downloader_exitcode" -ne 0 ]; then
		echo_error "$downloader_output"
	else
		echo "$downloader_output"
	fi

	return "$downloader_exitcode"
}

get_local_version_of () {
	#
	# get_local_version 'release'|'build'
	#

	# args

	local release_or_build=${1-"release"}

	# consts

	local release_file="/hive/etc/${release_file_name}"
	local build_file="/hive/etc/${build_file_name}"

	# vars

	local local_file_with_version=''
	local local_version=''

	# code

	case "$release_or_build" in
		'release')		local_file_with_version="$release_file"		;;
		'build')		local_file_with_version="$build_file"		;;
	esac

	if [ -s "$local_file_with_version" ]; then
		local_version="$( cat "$local_file_with_version" )"
	else
		local_version='0'
	fi

	echo "$local_version"
}

get_local_versions () {
	local_release_version="$( get_local_version_of 'release' )"
	local_build_version="$( get_local_version_of 'build' )"
}

get_remote_versions () {
	remote_release_version="$( get_remote_version_of 'release' "$repo_version_URL" )"; repo_connectivity_status_exitcode=$?
	remote_build_version="$( get_remote_version_of 'build' "$repo_version_URL" )" || echo_error 'Error getting build version'
}


#
# functions: auxillary
#

get_random_number_between () {
	#
	# Usage: get_random_number_between 'min_value' 'max_value'
	#

	# args

	local min_value="$1"
	local max_value="$2"

	# code

	awk -v min="$min_value" -v max="$max_value" 'BEGIN{ srand(); print int( min+rand() * (max-min+1) ) }'
}

exit_if_no_repository_available () {
	if [ "$repo_connectivity_status_exitcode" -ne 0 ] || [ -z "$remote_release_version" ]; then
		echo
		die "Can't get files from repository. Check your internet connection." "$repo_connectivity_status_exitcode"
	fi
}

delayed_agent_screen_restart () {
	echo_action 'Deploying delayed agent restart'

	(
		{
			trap -- '' INT HUP # allow a child to inherit disabled signals
			sleep 5
			/hive/bin/agent-screen restart
		} < /dev/null > /tmp/selfupgrade-agent-restart.log 2>&1 & # double fork: init (PID 1) should inherit this process
	)

	# delete a file created by a legacy selfupgrade
	remove_needless_files '/tmp/selfupgrade-agent-screen-restart.log'
}


#
# global consts
#

# paths
readonly temp_dir_default='/tmp'
readonly NVRAM_path_default='/nvdata'
readonly NVRAM_path_quirk='/opt'
readonly HIVE_HOST_URL_file='/config/HIVE_HOST_URL'
readonly FARM_HASH_file='/config/FARM_HASH'
readonly persistent_package_filename='latest.tar.gz'

# repos
readonly default_download_server_URL='http://download.hiveos.farm'

readonly github_repo_URL='http://github.com/minershive/hiveos-asic/archive/'
readonly github_repo_description='(Github repo)'
readonly github_repo_version_URL='https://raw.githubusercontent.com/minershive/hiveos-asic/master/hive/etc/'

readonly github_mirror_repo_path='/_asic/client/'
readonly github_mirror_repo_description='(Github mirror repo)'

readonly our_server_repo_path='/asic/client/'
readonly our_server_repo_description='(default repo)' # not used atm

readonly release_file_name='VERSION'
readonly build_file_name='build'

# exitcodes
readonly exitcode_OK=0
readonly exitcode_NOT_OK=1


#
# global sources
#

[ -s /hive/bin/colors ] && . /hive/bin/colors


#
# global vars
#

NVRAM_path="$NVRAM_path_default"
temp_dir="$temp_dir_default"

remote_release_version=''
remote_build_version=''
local_release_version=''
local_build_version=''

repo_connectivity_status_exitcode=0

bulk_download_mode_FLAG=0
dont_have_to_update_FLAG=0
download_from_custom_repo_FLAG=0
download_from_github_repo_FLAG=0
download_from_github_mirror_repo_FLAG=0
force_update_mode_FLAG=0
master_FLAG=0

user_defined_version_ARG=''
build_to_skip_ARG=''

release_version_to_install=''

package_file_to_download=''
package_file_URL=''

download_server_URL=''
repo_base_URL=''
repo_version_URL=''
custom_repo_URL=''
repo_description=''


#
# code
#

print_script_version
set_ASIC_MANUFACTURER_and_ASIC_MODEL_variables
set_HIVEON_VERSION_variable
get_local_versions
parse_arguments "$@"
set_repo_URLs
set_FARM_HASH
get_remote_versions
print_info
exit_if_no_repository_available
set_package_URL_and_file
print_update_info
goto_temp_dir
set_NVRAM_path

remove_needless_files \
	"${temp_dir:-SAFE}/master.tar.gz" \
	"${temp_dir:-SAFE}/v*.tar.gz" \
	"${temp_dir:-SAFE}/${package_file_to_download:-SAFE}" \
	"${temp_dir:-SAFE}/hive/*" \
	"${temp_dir:-SAFE}/hiveos-asic*" \
	"${temp_dir:-SAFE}/${script_basename:-SAFE}" \
	"${NVRAM_path:-SAFE}/nohup.out" # gosh, never be too careful

execute_install_routine
remove_needless_files "${temp_dir:-SAFE}/hiveos-asic-*"
delayed_agent_screen_restart

echo
echo
echo -e "  ${GREEN}Update complete. Have a happy mining.${NOCOLOR}"
echo
echo

sync
exit "$exitcode_OK"