#!/usr/bin/env bash

VERSION="2.3"

# prevent running from pipe
if [ $0 = "sh" ] || [ $0 = "bash" ]; then
	sleep 1
	echo "Hive-replace does not work from pipe, exiting"
	exit 1
fi

if [ -z "$BASH" ] || [ -z "$BASHPID" ] || [ -z "$BASH_VERSION" ]; then
	echo "Hive-replace works only from Bash, exiting"
	exit 1
fi

# download timeout
TIMEOUT=20

MIN_RAM_FREE=2000
MIN_RAM_HIVE=2500
MIN_RAM_OTHER=3000
RAMDISK_SIZE=4000

export PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/usr/local/bin:$PATH"
export LANG=C

set -o pipefail

DIR=`pwd`
SCRIPT_PATH=$( cd $(dirname "${BASH_SOURCE[0]}") && pwd )
SCRIPT_NAME=`basename "$0"`

# repo list
REPO_LIST=/etc/apt/sources.list.d/hiverepo.list

[[ -e /etc/brand.conf ]] && source /etc/brand.conf
if [[ -z $DOWNLOAD_URL ]]; then
	# main url to images repo
	DOWNLOAD_URL=https://download.hiveos.farm
	# direct urls to images
	STABLE_URL=$DOWNLOAD_URL/latest/
	BETA_URL=$DOWNLOAD_URL/beta/
	# images archive
	IMAGES_URL=$DOWNLOAD_URL/history/
else
	IMAGES_URL=$DOWNLOAD_URL
fi

[[ -z $OS_BRAND ]] && OS_BRAND="hiveos"
[[ -z $BRAND ]] && BRAND="Hive"
[[ -z $HIVE_HOST_URL ]] && HIVE_HOST_URL="https://api.hiveos.farm"

# image file mask
IMG_EXT="(zip|xz|gz)"
URL_PROTO="(http|ftp|https)"
OS_REGEX="$OS_BRAND-[^\"]+\.$IMG_EXT"
[[ $SKIP_CHECK -ne 0 ]] && OS_REGEX="[^\"]+\.$IMG_EXT"
URL_MASK="^$URL_PROTO://.+/${OS_REGEX}$"
ARCHIVE_REGEX="(\"|^)\K${OS_REGEX}(?=(\"|$))"


TMPDIR="/run/tmphive"
REPCONF="/replace.conf"
md5_url=
url=
root_dev=""
farm_hash=""
rig_conf=""
force=0
no_confirm=0
smb=0
smbuser=
smbpasswd=
nfs=0
thishive=0
checked=0
curl_checked=0
nosafe=0
select_drive=0
download_path=
archname=


NOCOLOR=$'\033[0m'
BLACK=$'\033[0;30m'
DGRAY=$'\033[1;30m'
RED=$'\033[0;31m'
BRED=$'\033[1;31m'
GREEN=$'\033[0;32m'
BGREEN=$'\033[1;32m'
YELLOW=$'\033[0;33m'
BYELLOW=$'\033[1;33m'
BLUE=$'\033[0;34m'
BBLUE=$'\033[1;34m'
PURPLE=$'\033[0;35m'
BPURPLE=$'\033[1;35m'
CYAN=$'\033[0;36m'
BCYAN=$'\033[1;36m'
LGRAY=$'\033[0;37m'
WHITE=$'\033[1;37m'
GRAY=$'\033[2;37m'

[[ $(uname -sr) == *$OS_BRAND* || -d /hive-config ]] && thishive=1



function exit_handler {
	echo -e "\npress any key to close session"
	if [[ -t 0 ]]; then
		read -n 1
	else
		read -n 1 -t 600
	fi
}


ppstree() {
	ppid=$$
	while [[ $ppid -gt 0 ]]; do
		[[ ! -f /proc/$ppid/stat ]] && return 2
		[[ $(< /proc/$ppid/stat) =~ ^([0-9]+)\ \(([^\)]+)\)[^0-9]+([0-9]+) ]] || return 3
		#[[ $(< /proc/$ppid/stat) =~ ^([0-9]+)\ \(([^\)]+)\)\ .\ ([0-9]+) ]] || return 3
		pid=${BASH_REMATCH[1]}
		name=${BASH_REMATCH[2]}
		ppid=${BASH_REMATCH[3]}
		if [[ -z $1 ]]; then
			echo "$name ($ppid)"
		elif [[ "$name" == $1 || $pid == $1 ]]; then
			return 0
		fi
	done
	[[ ! -z $1 ]] && return 1
	return 0
}


function send_log {
	[[ ! -f /hive/bin/message ]] && return 1
	local arr=("/hive-config/rig.conf" "$TMPDIR/hive-config/rig.conf" "$TMPDIR/rig.conf" "$rig_conf")
	local log=$TMPDIR/screen.log
	[[ -f $log ]] && rm $log
	for conf in "${arr[@]}"; do
		[[ ! -f "$conf" ]] && continue
		screen -S replace -p 0 -X width 80 >/dev/null 2>&1 || return 2
		screen -S replace -p 0 -X hardcopy -h $log >/dev/null 2>&1 || return 3
		[[ ! -f $log ]] && return 4
		(
			export RIG_CONF="$conf"
			msg="Message sent"
			# send log since last msg
			cat $log | awk -v RS="$msg[^\n]+\n" 'END {printf "%s", $0}' | /hive/bin/message ${1:-warn} "Hive-replace${2:+: }$2" >/dev/null &&
				echo -e "${GRAY}$msg: $2${NOCOLOR}"
		)
		return 0
	done
	return 5
}


function check_packages {
	[[ $checked -eq 1 ]] && return 0

	if [[ $1 == "curl" ]]; then
		[[ $curl_checked -eq 1 ]] && return 0
		local need_install=(curl)
	else
		local need_install=(lsof curl wget unzip xz-utils gdisk parted util-linux)
		[[ ! -z $rig_conf || ! -z $farm_hash ]] && need_install+=(fuse ntfs-3g)
		[[ $nosafe -ne 1 ]] && need_install+=(screen)
		[[ $smb -eq 1 ]] && need_install+=(smbclient)
		[[ $nfs -eq 1 ]] && need_install+=(nfs-common)
	fi

	for idx in "${!need_install[@]}"; do
		dpkg -s "${need_install[$idx]}" 2>/dev/null | grep -q "installed" && unset 'need_install[idx]'
	done

	if [[ ! -z "${need_install[*]}" ]]; then
		echo -e
		echo -e "${CYAN}> Installing required packages: ${WHITE}${need_install[*]}${NOCOLOR}"
		apt update
		apt install -y "${need_install[@]}"
		[[ $? -ne 0 ]] && echo -e "${RED}Failed to install required packages${NOCOLOR}" && exit 1
		echo -e
		echo -e "${GREEN}Installed required packages successfully${NOCOLOR}"
	fi

	[[ $1 == "curl" ]] && curl_checked=1 && return 0
	checked=1
}


function url_decode() {
	echo -e "${1//%/\\x}"
}


function get_image_from_url { # return $url
	local from_url=$( url_decode "$1" )
	local name=$2
	check_packages "curl"
	url=`curl --connect-timeout $TIMEOUT --retry 2 -fskL --head -w '%{url_effective}' "$from_url" 2>/dev/null | tail -n 1`
	if [[ $? -eq 0 ]]; then
		[[ "$url" =~ $URL_MASK ]] && return 0
		echo -e "$RED> Got bad url for $name image - $url${NOCOLOR}"
		return 1
	fi
	echo -e "$RED> Unable to get url for $name image${NOCOLOR}"
	return 2
}


function get_image_from_list {
	local select="$1"
	local repo="$2"

	[[ -z "$repo" ]] && URL=$IMAGES_URL || URL="$repo"
	# trailing slash needed
	[[ ! "$URL" =~ /$ ]] && URL+="/"

	echo -e "${CYAN}> Loading $BRAND OS images list from ${BCYAN}${URL}${NOCOLOR}"

	local urls=()
	local arr=()
	declare -A IMAGE=()

	# skip for custom repo
	if [[ -z "$repo" ]]; then
		[[ ! -z $STABLE_URL ]] && get_image_from_url $STABLE_URL "Stable" && urls+=("$url") && IMAGE["$url"]="Latest Stable"
		[[ ! -z $BETA_URL ]] && get_image_from_url $BETA_URL "Beta" && urls+=("$url") && IMAGE["$url"]="Latest Beta"
		url=
	fi

	local list
	if [[ -e "$URL" ]]; then
		# local path
		list=`ls -l "$URL" 2>/dev/null` &&
			readarray -t arr < <( echo "$list" | grep -oP "$OS_REGEX" | sort -n -t "@" -k1 )
	else
		# works for ftp also
		list=`curl -fskL --list --connect-timeout $TIMEOUT --retry 2 "$URL" 2>/dev/null` &&
			readarray -t arr < <( echo "$list" | grep -oP "$ARCHIVE_REGEX" | sed 's/%40/@/g' | sort -r -n -t "@" -k 2 ) ||
				echo -e "${RED}Unable to load images list from repository${NOCOLOR}"
	fi

	local img
	for img in "${arr[@]}"; do
		[[ ! -z "${IMAGE["${URL}${img}"]}" ]] && continue # "
		urls+=("${URL}${img}")
		if [[ -f "${URL}${img}" ]]; then
			IMAGE["${URL}${img}"]="$(stat -c %s ${URL}${img} 2>/dev/null | awk '{printf "%d", $1/1e6}') MB"
		else
			IMAGE["${URL}${img}"]=""
		fi
	done

	[[ ${#urls[@]} -eq 0 ]] && echo -e "${RED}List is empty${NOCOLOR}" && return 1

	# get images description
	local versions=
	# try to get from repo URL if specified
	[[ ! -z "$repo" ]] && versions=`curl -fsLk --connect-timeout $TIMEOUT --retry 2 "${URL}VERSIONS.txt" 2>/dev/null`
	# try to get from Hive server
	[[ -z $versions ]] && versions=`curl -fsLk --connect-timeout $TIMEOUT --retry 2 "${DOWNLOAD_URL}/VERSIONS.txt" 2>/dev/null`
	[[ -z $versions ]] && echo -e "${RED}Unable to load image descriptions${NOCOLOR}"
	local SEP=" · "
	local index=0

	if [[ -z "$download_path" ]]; then
		echo -e "${YELLOW}> Select version to install${NOCOLOR}"
		printf "%b%2s) %b\n" $WHITE $index "exit${NOCOLOR}"
	elif [[ "$select" != -1 ]]; then
		echo -e "${YELLOW}> Select version for download to ${BYELLOW}${download_path}${NOCOLOR}"
		printf "%b%2s) %b\n" $WHITE $index "exit${NOCOLOR}"
	fi

	for img in "${urls[@]}"
	do
		local ver=`basename "$img" 2>/dev/null`
		info=`echo "$versions" | tr '\n' '|' | sed 's/||/\n/g' | grep "$ver" | tr '|' '\n'`
		# try without extension
		if [[ -z "$info" ]]; then
			[[ "$ver" =~ ^(.*)(\.zip|\.img\.xz)$ ]] &&
				name="${BASH_REMATCH[1]}" &&
				info=`echo "$versions" | tr '\n' '|' | sed 's/||/\n/g' | grep "$name" | tr '|' '\n'`
		fi
		#echo "$info"
		[[ ! -z "${IMAGE["$img"]}" ]] && ver+="${SEP}${WHITE}${IMAGE["$img"]}${NOCOLOR}"
		if [[ ! -z "$info" ]]; then
			#[[ "$info" =~ (\ [0-9]+\.[0-9]+\.[0-9]+)- ]] && ver+="${SEP}${CYAN}K${NOCOLOR}${BASH_REMATCH[1]}"
			kernel=`echo "$info" | grep -m1 -ioP "Linux [^0-9]*\K[0-9]+\.[0-9]+\.[0-9]+"` && ver+="${SEP}${CYAN}K${NOCOLOR} $kernel"
			nvidia=`echo "$info" | grep -m1 -ioP "^nvidia[^\s]* \K.*"` && ver+="${SEP}${GREEN}N${NOCOLOR} $nvidia"
			amd=`echo "$info" | grep -m1 -ioP "^amd[^\s]* \K.*"` && ver+="${SEP}${RED}A${NOCOLOR} $amd"
			#boot=`echo "$info" | grep -m1 "^Dual"` && ver+="${SEP}$boot"
			# get last line for desc
			desc=`echo "$info" | tail -n 1 | grep -ivP "^(amd|nvidia|Linux|md5|$OS_BRAND)"` && ver+="${SEP}$desc"
		fi
		((index++))
		printf "%b%2s) %b\n" $WHITE $index "${NOCOLOR}$ver"
	done

	if [[ -z "$select" ]]; then
		# allow to select only in interactive shell
		[[ ! -t 0 ]] && echo -e "${RED}Run in interactive shell to select image or use ${WHITE}--list=${CYAN}N${NOCOLOR}" && return 1
	elif [[ "$select" == -1 ]]; then
		return 0
	else
		[[ ! "$select" =~ ^[0-9]+$ || $select -lt 1 || -z ${urls[$(( select - 1 ))]} ]] &&
			echo -e "${RED}Invalid selection, exiting${NOCOLOR}" &&
			return 1
		url=`url_decode "${urls[$(( $select - 1 ))]}"`
		echo "${GREEN}> $select${NOCOLOR}"
		return 0
	fi

	while true;
	do
		read -p "> " REPLY
		[[ "$REPLY" == "0" || "$REPLY" = "exit" || "$REPLY" = "q" ]] && return 1
		[[ $REPLY -gt 0 && $REPLY -le ${#urls[@]} ]] && break
		echo -e "${RED}Invalid selection${NOCOLOR}"
	done
	((REPLY--))
	url=$( url_decode "${urls[$REPLY]}" )
	return 0
}


# Gets/downloads image
function get_image {
	cd $TMPDIR
	rm $TMPDIR/*$OS_BRAND* > /dev/null 2>&1

	archname=`basename "$url"`

	if [[ $nfs -eq 1 || $smb -eq 1 ]]; then
		[[ ! -d $TMPDIR/share ]] && mkdir $TMPDIR/share
		mnt_flag=1
		mnt_share=1
		grep $TMPDIR/share /proc/mounts> /dev/null 2>&1
		mnt_share=$?
		[[ $mnt_share -eq 0 ]] && mnt_flag=0
		[[ $nfs -eq 1 && $mnt_share -ne 0 ]] && mount -t nfs $(dirname "$url") $TMPDIR/share > /dev/null 2>&1 && mnt_flag=$?
		if [[ $smb -eq 1 && $mnt_share -ne 0 ]]; then
			psw=
			[[ -z $smbuser ]] && smbuser="nobody"
			[[ ! -z $smbpasswd ]] && psw="password=$smbpasswd"
			mount -v -t cifs -o username=$smbuser,$psw,iocharset=utf8,vers=3.0 $(dirname "$url") $TMPDIR/share > /dev/null 2>&1
			mnt_flag=$?
		fi
		[[ $mnt_flag -ne 0 ]] && echo -e "${RED}Can't mount network shared resource.${NOCOLOR}" && return 1
		url="$TMPDIR/share/$archname"
	fi

	echo -e "\n${CYAN}> Getting image size${NOCOLOR}"
	if [[ $nfs -eq 1 || $smb -eq 1 || -e "$url" ]]; then
		archsize=`stat --format=%s "$url" | awk '{print int($1/1000000)}'`
	else
		archsize=`curl -s --head "$url" | grep -ioP "content-length:[^0-9]+\K[0-9]+" | awk '{print int($1/1000000)}'`
	fi

	if [[ $? -eq 0 && ! -z "$archsize" ]]; then
		echo -e "${GREEN}Image size: ${WHITE}$archsize MB${NOCOLOR}"
		reqmem=$(( `free -m | grep 'Mem' | awk '{print $7}'` - archsize ))
		if [[ $force -eq 1 && $reqmem -lt 0 ]]; then
			echo -e "${RED}Image is to big to fit in RAM ($reqmem MB), exiting${NOCOLOR}"
			[[ $thishive -eq 1 ]] && echo -e "${YELLOW}Try to boot in maintenance mode without loading drivers${NOCOLOR}"
			return 1
		fi
		if (( archsize + 500 > RAMDISK_SIZE )); then
			echo -e "${RED}Image is to big to fit on RAM disk, exiting${NOCOLOR}"
			return 1
		fi
	else
		[[ $force -eq 1 ]] && echo -e "${RED}Unable to get image size, exiting${NOCOLOR}" && return 1
		echo -e "${RED}Unable to get image size${NOCOLOR}"
	fi

	# download VERSIONS.txt to get md5 later
	#if [[ $force -ne 1 ]]; then
	#	#default is "http://download.hiveos.farm/VERSIONS.txt"
	#	md5_url=$(dirname "$url")/VERSIONS.txt
	#	#curl -s $md5_url > $TMPDIR/VERSIONS.txt
	#	wget -q -O $TMPDIR/VERSIONS.txt $md5_url
	#	[[ $? -ne 0 ]] && echo -e "${RED}Can't get $md5_url to check MD5 checksum. Use -f to ignore this.${NOCOLOR}" && return 1
	#	mdsum=$(sed -n "/$archname/p" $TMPDIR/VERSIONS.txt | awk '{printf$2}')
	#	[[ -z $mdsum ]] && echo -e "${RED}Can't get md5sum from $md5_url to check MD5 checksum. Use -f to ignore this.${NOCOLOR}" && return 1
	#fi

	# stop miner here to free some memory and prevent rig from rebooting on errors
	#[[ $thishive -eq 1 ]] && miner stop 2>/dev/null

	# Copy|download hive image to tmpfs
	echo -e "\n${CYAN}> Downloading image file${NOCOLOR}"
	if [[ "$url" == http* ||  "$url" == ftp* ]]; then
		echo ""
		wget -t 0 -T $TIMEOUT --no-check-certificate "$url"
		[[ $? -ne 0 ]] && echo -e "${RED}Download $BRAND OS image failed. Check url${NOCOLOR}" && return 1
	else
		[[ ! -f $url ]] && echo -e "${RED}$BRAND OS image not found. Check path${NOCOLOR}" && return 1
		cp -v $url $TMPDIR
		[[ $? -ne 0 ]] && echo -e "${RED}Copy $BRAND OS image failed${NOCOLOR}" && return 1
	fi

	# check md5
	#if [[ $force -ne 1 ]]; then
	#	echo -e "\n${CYAN}> Checking MD5 of image file${NOCOLOR}"
	#	mdsum_hive=$(md5sum $TMPDIR/$archname | awk '{printf$1}')
	#	[[ $mdsum != $mdsum_hive ]] && echo -e "${RED}MD5 checksum of image file does not match${NOCOLOR}\nGot $mdsum_hive, expected $mdsum" && return 1
	#fi

	# check archive integrity
	if [[ $SKIP_CHECK -eq 2 ]]; then
		echo -e "\n${YELLOW}> Checking archive integrity was SKIPPED!!!${NOCOLOR}"
	else
		echo -e "\n${CYAN}> Checking archive integrity${NOCOLOR}"
		if [[ $archname == *\.xz ]]; then
			xz -t --verbose $TMPDIR/$archname > /dev/null
		elif [[ $archname == *\.zip ]]; then
			unzip -t $TMPDIR/$archname > /dev/null
		elif [[ $archname == *\.gz ]]; then
			gzip -t --verbose $TMPDIR/$archname > /dev/null
		fi
		[[ $? -ne 0 ]] && echo -e "${RED}Archive is damaged${NOCOLOR}" && return 1
	fi

	echo -e "${GREEN}$BRAND OS image ready!${NOCOLOR}"
	return 0
}


function check_disk {
	if ppstree "xinit"; then
		if [[ $thishive -ne 1 ]]; then
			echo -e "${RED}Hive-replace does not work in X server console!${NOCOLOR}"
			echo -e "${YELLOW}Run it from text local or remote shell${NOCOLOR}"
			exit 1
		fi
		echo -e "${YELLOW}Hive-replace does not work in X server console!${NOCOLOR}"
		echo -e "${YELLOW}X server will be stopped now and process will continue${NOCOLOR}"
		sleep 5
		# stop X and restart console to resume hive-replace from motd
		hivex stop
		systemctl restart hive-console
	fi

	mem=$(free -m | awk 'NR == 2{print$2}')
	#clear
	echo -e "\n"
	echo -e "${CYAN}*************************************************${NOCOLOR}"
	echo -e "${YELLOW}         $BRAND OS Image Installation v$VERSION${NOCOLOR}"
	echo -e "${CYAN}*************************************************${NOCOLOR}"
	echo
	echo -e "$WHITE$url${NOCOLOR}"
	echo
	echo "Total RAM = $mem MB"
	echo
	if [[ $force -ne 1 ]]; then
		[[ $thishive -eq 1 ]] && minmem=$MIN_RAM_HIVE || minmem=$MIN_RAM_OTHER
		[[ $mem -lt $minmem ]] && echo -e "${RED}At least $minmem MB RAM is required, exiting${NOCOLOR}" && exit 1
	fi

	PART_UUID=`grep -oP "root=UUID=\K[^\s]+" /proc/cmdline` &&
		BOOT_PART=`blkid -U "${PART_UUID}" | sed 's/\(^\/dev\/\)//'` ||
		BOOT_PART=`grep -oP "root=/dev/\K[^\s]+" /proc/cmdline`

	[[ -z $BOOT_PART && ! -z $PART_UUID ]] &&
		echo "Unable to find boot disk by UUID $PART_UUID" &&
		BOOT_PART=`readlink -f /dev/block/$(mountpoint -d /) | grep -oP "/dev/\K[^\s]+"`

	[[ -z $BOOT_PART ]] && echo -e "${RED}Unable to determine boot disk${NOCOLOR}" && exit 1

	BOOT_DISK=$( echo "$BOOT_PART" | grep -oP "(sd[a-z]+|nvme[0-9]+n[0-9]+)" )
	BOOT_SIZE=`grep -w "${BOOT_DISK}$" /proc/partitions | awk '{ printf("%.f",$3/1024)}'`

	echo -e "Current OS booted from ${BPURPLE}$BOOT_DISK${NOCOLOR} and whole drive size is ${WHITE}$BOOT_SIZE${NOCOLOR} MB\n"

	DISK_NAME="$BOOT_DISK"
	if [[ $select_drive -eq 1 ]]; then
		disklist=`parted -mls 2>/dev/null | grep -oP "^/dev/\K(sd|nvme).*"`
		# make boot disk always first
		bootdisk=`echo "$disklist" | grep "^${BOOT_DISK}" | awk -F ':' '{print $1 ": " $7 " " $2 " [BOOT]"}'`
		readarray -t disks < <(echo "$bootdisk"; echo "$disklist" | grep -v "^$BOOT_DISK" | awk -F ':' '{print $1 ": " $7 " " $2}')

		if [[ ${#disks[@]} -eq 1 && "${disks[0]}" =~ $BOOT_DISK ]]; then
			DISK_NAME="${disks[0]%%:*}"
		else
			echo -e "${YELLOW}> Select drive for image install${NOCOLOR}"
			local index=0
			printf "%b%2s) %b\n" $WHITE $index "exit${NOCOLOR}"
			for disk in "${disks[@]}"; do
				((index++))
				printf "%b%2s) %b\n" $WHITE $index "${NOCOLOR}$disk"
			done
			while true;
			do
				read -p "> " REPLY
				[[ "$REPLY" == "0" || "$REPLY" = "exit" || "$REPLY" = "q" ]] && exit 0
				[[ $REPLY =~ ^[0-9]+$ && $REPLY -gt 0 && $REPLY -le ${#disks[@]} ]] && break
				echo -e "${RED}Invalid selection${NOCOLOR}"
			done
			((REPLY--))
			DISK_NAME="${disks[REPLY]%%:*}"
			echo
		fi
	fi

	if [[ ! -z $DISK_NAME ]]; then
		disk_info="$(parted -mls 2>/dev/null | grep -m1 -oP "^/dev/\K${DISK_NAME}.*" | awk -F ':' '{print $7 " " $2}')"
		DISK_SIZE=`grep -w "${DISK_NAME}$" /proc/partitions | awk '{ printf("%.f",$3/1024)}'`
		[[ "$DISK_NAME" == "$BOOT_DISK" ]] &&
			echo -e "Using boot disk ${BPURPLE}$DISK_NAME${NOCOLOR}: ${WHITE}$disk_info${NOCOLOR}" ||
			echo -e "Using disk ${BGREEN}$DISK_NAME${NOCOLOR}: ${WHITE}$disk_info${NOCOLOR}"
		[[ $DISK_SIZE -lt 7300 ]] && echo -e "\n${RED}The minimum disk size for $BRAND OS is 8 GB${NOCOLOR}" && exit 2
	else
		echo -e "\n${RED}No disk for replace${NOCOLOR}" && exit 3
	fi

	if [[ $no_confirm -ne 1 ]]; then
		echo -e "${BYELLOW}Warning: After $BRAND OS installation, all your data on ${BPURPLE}$DISK_NAME${NOCOLOR} ${BYELLOW}will be lost!${NOCOLOR}"
		echo -en "\nIf you want to install $BRAND OS on ${BPURPLE}$DISK_NAME${NOCOLOR} type ${GREEN}\"yes\"${NOCOLOR}: "
		read -t 90 answer
		[[ "$answer" != "yes" ]] && echo -e "${YELLOW}\nBye, bye!${NOCOLOR}" && exit 0
	fi
	if [[ "$DISK_NAME" != "$BOOT_DISK" && ! -f /hive/etc/newuuid ]]; then
		echo -e "\n${CYAN}> Updating UUID for root disk${NOCOLOR}"
		uuid --new && touch /hive/etc/newuuid
	fi
}


find_dep() {
	[[ ! -z ${DEPS["$1"]} ]] && return
	local path
	if [[ -d $1 && ! -L $1 ]]; then
		#echo "DIR $1"
		readarray -t arr < <(find $1 -xtype f -name "*")
	elif [[ -f $1 ]]; then
		#echo "FILE $1"
		DEPS["$1"]="$1"
		readarray -t arr < <(ldd $1 2>/dev/null | grep -oP "\s\K\/[^\s]+")
	else
		#echo "BAD $1"
		return 1
	fi
	for path in "${arr[@]}"; do
		find_dep "$path"
	done
}


prepare_dep() {
	declare -A DEPS=()
	unlink $TMPDIR/deps.list 2>/dev/null
	cmds="env bash sync mount umount cp ls dd xz unzip gzip sgdisk partprobe screen losetup mkdir grep screen tail
		 head sleep pkill cat id readlink dirname uname sudo chmod pwd blkid basename sh awk ntfs-3g"

	if [[ $thishive -eq 1 ]]; then
		cmds="${cmds} base64 cut jq mc curl wc bc date stat ssh-keygen host locale-check locale ssh sshd"

		find_dep /usr/lib/x86_64-linux-gnu/libcurl.so.4
		find_dep /hive/bin
	fi

	for cmd in $cmds; do
		path=$(command -v $cmd)
		[[ -z $path ]] && continue
		find_dep $path
	done

	find_dep /lib/x86_64-linux-gnu
	find_dep /bin
	find_dep /sbin

	find_dep /usr/bin
	find_dep /usr/sbin

	printf "%s\n" "${DEPS[@]}" > $TMPDIR/deps.list
}


function stop_and_umount() {
	# stop services
	echo -e "\n${CYAN}> Stopping services${NOCOLOR}"

	term=`tty | grep -oP "\Ktty[0-9]+"`
	[[ -z $term ]] && con=$(fgconsole) && term="${con:+tty}$con"
	term="${term:+|}$term"

	for service in `initctl list 2>/dev/null | grep "/running" | grep -v -P "network|ssh|ttyd|shellinabox|openvpn$term" | awk '{print $1}'`; do
		initctl stop $service > /dev/null 2>&1 && echo "${NOCOLOR}> stopped ${WHITE}$service${NOCOLOR}"
		sleep 0.1
	done

	for service in `systemctl list-units 2>/dev/null | grep -oP "\K[^\s]+\.(service|socket)" | grep -v -P "ssh|openvpn|ttyd|shellinabox|network|ifup|user|hive|wpa_supplicant$term"`; do
		systemctl stop $service > /dev/null 2>&1 && echo "${NOCOLOR}> stopped ${WHITE}$service${NOCOLOR}"
		sleep 0.1
	done

	# If `motd boot` is active then stop it to prevent artifacts on attached display
	motd_boot_pid=$(ps au | grep -v grep | grep "/hive/bin/motd boot" | awk '{print $2}')
	[[ -n $motd_boot_pid ]] && kill -SIGINT $motd_boot_pid

	ptree=$(ppstree)
	for i in {1..3}; do
		for pid in `lsof / | grep -v -P "^COMMAND|$SCRIPT_NAME| (mem|txt|rtd|cwd) |network|telec|hssh|watchdog|hl340|srrv2|hive-console|watchdog-octofan" | awk '{print $2}'`; do
			cmd=$( { tr '\0' ' ' < /proc/$pid/cmdline; } 2>/dev/null ) || continue
			[[ "$ptree" =~ \($pid\) ]] && continue
			if [[ $i -eq 1 ]]; then
				kill -SIGTERM $pid 2>/dev/null
				echo -e "${NOCOLOR}> stopped ${WHITE}$cmd ${NOCOLOR}($pid)"
			else
				kill -SIGKILL $pid 2>/dev/null
				echo -e "${NOCOLOR}> killed ${WHITE}$cmd ${NOCOLOR}($pid)"
			fi
			sleep 0.1
		done
		sleep 1
	done

	# Readonly remount
	need_ro=0
	sync
	for MOUNT in `grep "/dev/$DISK_NAME" /proc/mounts | awk '{print $2}' | sort -r`; do
		if [[ $MOUNT != "/" ]]; then
			timeout 30 umount -n -f $MOUNT > /dev/null 2>&1 &&
				echo "${NOCOLOR}> unmounted ${WHITE}$MOUNT${NOCOLOR}" &&
				continue
		fi
		timeout 30 mount -n -o remount,ro $MOUNT > /dev/null 2>&1
		exitcode=$?
		if [[ $? -eq 0 ]]; then
			echo "${NOCOLOR}> mounted read-only ${WHITE}$MOUNT${NOCOLOR}"
		else
			echo "${NOCOLOR}> mount failed ($exitcode) $MOUNT${NOCOLOR}"
			need_ro=1
		fi
	done
	if [[ $need_ro -eq 1 ]]; then
		echo "${NOCOLOR}> mounting all read-only"
		sync
		echo u > /proc/sysrq-trigger
		sleep 1
		[[ ! -w $TMPDIR ]] && mount -n -o remount,rw $TMPDIR
	fi
	sync
}


function prepare_replace {
	# create tmpfs
	grep $TMPDIR /proc/mounts >/dev/null 2>&1
	if [[ $? -ne 0 ]]; then
		mkdir -p $TMPDIR
		mem=$(free -m | awk 'NR == 2{print$2}')

		[[ -z $LEGACY && $thishive -eq 1 && $mem -lt 2500 ]] && LEGACY=1 && echo "Using legacy mode due to low RAM amount"

		if [[ $mem -lt $MIN_RAM_FREE || $ZRAM -eq 1 ]]; then
			modprobe zram 2>/dev/null
			if [[ -e /sys/class/zram-control/hot_add ]]; then
				zid=$( < /sys/class/zram-control/hot_add)
				if [[ ! -z $zid ]]; then
					zram=zram$zid
					echo "${RAMDISK_SIZE}M" > /sys/block/$zram/disksize 2>/dev/null
					command -v mkfs.ext4 >/dev/null && opt="-t ext4"
					mkfs $opt /dev/$zram >/dev/null 2>/dev/null &&
						mount /dev/$zram $TMPDIR &&
						echo -e "\nUsing ZRAM for temporary root filesystem"
				fi
				#zid=$( < /sys/class/zram-control/hot_add)
				#if [[ ! -z $zid ]]; then
				#	zram=zram$zid
				#	echo "512M" > /sys/block/$zram/disksize 2>/dev/null
				#	mkswap /dev/$zram >/dev/null 2>/dev/null &&
				#		swapon /dev/$zram &&
				#		echo -e "\nUsing ZRAM for swap"
				#fi
			fi
		fi
		grep $TMPDIR /proc/mounts >/dev/null 2>&1 || mount none $TMPDIR -t tmpfs -o size=${RAMDISK_SIZE}m
	fi

	# stop miner and some services to reduce RAM usage and prevent reboot
	if [[ $thishive -eq 1 ]]; then
		echo -e "\n${CYAN}> Stopping $BRAND OS services${NOCOLOR}"
		autoswitch stop > /dev/null 2>&1
		miner stop > /dev/null 2>&1
		autofan stop > /dev/null 2>&1
		systemctl stop hivex >/dev/null 2>&1
		sleep 1
		killall xinit > /dev/null 2>&1
		systemctl stop hive-watchdog
		#agent-screen stop

		# copy current config files
		mkdir -p $TMPDIR/hive-config
		if [[ -f /hive-config/rig.conf ]]; then
			cp /hive-config/*.conf $TMPDIR/hive-config/
			[[ -d /hive-config/network ]] && cp -R /hive-config/network $TMPDIR/hive-config/
			[[ -d /hive-config/openvpn ]] && cp -R /hive-config/openvpn $TMPDIR/hive-config/
			[[ -d /hive-config/watchdog ]] && cp -R /hive-config/watchdog $TMPDIR/hive-config/
			[[ -d /hive-config/network ]] && cp -R /hive-config/network $TMPDIR/hive-config/
			[[ -f /hive-config/vnc-password.txt ]] && cp /hive-config/vnc-password.txt $TMPDIR/hive-config/
		fi
		[[ -f /hive-config/rig.conf || -f $rig_conf ]] &&
			cache-hive-ip >/dev/null
	fi

	# update config
	if [[ ! -z $rig_conf && -f $rig_conf ]]; then
		cp $rig_conf $TMPDIR/rig.conf
	elif [[ ! -z $farm_hash ]]; then
		echo -e "HIVE_HOST_URL=\"$HIVE_HOST_URL\"" >> $TMPDIR/rig.conf
		echo -e "FARM_HASH=$farm_hash" >> $TMPDIR/rig.conf
	elif [[ $thishive -eq 1 && -f $TMPDIR/hive-config/rig.conf ]]; then
		shadow=$(grep "^user:" /etc/shadow)
		echo -e "\nSHADOW_USER='$shadow'" >> $TMPDIR/hive-config/rig.conf
	fi

	# turn off swap here
	swapoff -a

	# Disable kernel message to tty
	echo 0 > /proc/sys/kernel/printk
	echo 1 > /proc/sys/kernel/sysrq
	echo 0 > /proc/sysrq-trigger
}


function prepare_chroot() {
	# prepare deps in background during download
	if [[ $LEGACY -eq 0 ]]; then
		echo -e "\n${NOCOLOR}${CYAN}> Starting prepare in background${NOCOLOR}"
		set +m
		prepare_dep &
		set -m
		bgpid=$!
	fi

	# get hive zip
	get_image || return
	send_log ok "image ready, preparing"

	# create temp root
	dist=`lsb_release -sr |tr -d "\r\n"`
	echo -e "\n${CYAN}> Creating temporary root filesystem ($dist)${NOCOLOR}"
	dist=${dist//./}
	if [[ $dist -lt "2004" ]]; then
		mkdir -p $TMPDIR/{proc,sys,run,dev,usr,var/log,root,bin,sbin,lib,tmp,usr/lib,usr/share,usr/lib/x86_64-linux-gnu,lib/lsb,home/user}
	else
		mkdir -p $TMPDIR/{proc,sys,run,dev,usr,var/log,root,usr/bin,usr/sbin,tmp,usr/lib,usr/lib64,usr/share,usr/lib/x86_64-linux-gnu,usr/lib/lsb,home/user}
		cp -P {/bin,/sbin,/lib,/lib64} $TMPDIR/
	fi
	if [[ $LEGACY -eq 0 ]]; then
		wait $bgpid
		DEPS=()
		[[ -f $TMPDIR/deps.list ]] && readarray -t DEPS < <(cat $TMPDIR/deps.list)
		steps=10
		cnt=${#DEPS[@]}
		step=$(( cnt / steps ))
		last=0
		if [[ $cnt -ne 0 ]]; then
			for (( i=0; i < cnt; i++ )); do
				(( i >= last + step )) && last=$(( last+step )) && echo -en "Done $((steps*last/step))% \r"
				dep="${DEPS[i]}"
				if [[ -L $dep ]]; then
					path=$(readlink -f $dep)
					[[ -f $path ]] && cp -a --parents "$path" $TMPDIR
				fi
				cp -a -u --parents "$dep" $TMPDIR
			done
			echo -e "Done      "
		else
			LEGACY=1
			echo -e "${YELLOW}Unable to resolve dependencies. Switching to legacy mode${NOCOLOR}"
		fi
	fi

	errors=0
	if [[ $LEGACY -eq 1 ]]; then
		cp -aR /{bin,sbin} $TMPDIR > /dev/null 2>&1 || ((errors++))
		cp -aR /usr/{bin,sbin} $TMPDIR/usr > /dev/null 2>&1 || ((errors++))
		cp -aR /lib/x86_64-linux-gnu $TMPDIR/lib > /dev/null 2>&1 || ((errors++))
		cp -aR /lib64 $TMPDIR > /dev/null 2>&1 || ((errors++))
		cp -aR /usr/lib/sudo $TMPDIR/usr/lib > /dev/null 2>&1 || ((errors++))

		cp -a /usr/lib/x86_64-linux-gnu/libmpfr* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libsigsegv* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libgmp* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libstdc++* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libpopt.so* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libicu*.so* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))

		cp -a /usr/lib/x86_64-linux-gnu/libpcre2*.so* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/liblz4.so* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
		cp -a /usr/lib/x86_64-linux-gnu/libacl.so* $TMPDIR/usr/lib/x86_64-linux-gnu > /dev/null 2>&1 || ((errors++))
	else
		#cp -aR /usr/share/terminfo/x $TMPDIR/usr/share/terminfo > /dev/null 2>&1 || ((errors++))
		cp -aR /usr/share/terminfo $TMPDIR/usr/share > /dev/null 2>&1 || ((errors++))
		cp -aR /lib/terminfo $TMPDIR/lib > /dev/null 2>&1 || ((errors++))
		cp -aR /usr/share/i18n $TMPDIR/usr/share > /dev/null 2>&1 || ((errors++))
		cp -aR /usr/lib/locale $TMPDIR/usr/lib > /dev/null 2>&1 || ((errors++))
		#cp -aR /usr/lib/ssl $TMPDIR/usr/lib > /dev/null 2>&1 || ((errors++))
	fi

	# some more
	cp -aR /etc $TMPDIR > /dev/null 2>&1 || ((errors++))

	[[ $errors -ne 0 ]] && echo -e "There were $errors errors"

	# update etc/resolv.conf
	resolvconf=$TMPDIR/etc/resolv.conf
	rm $resolvconf
	[[ -f /run/systemd/resolve/resolv.conf ]] && cp /run/systemd/resolve/resolv.conf $resolvconf
	for dns in "8.8.8.8" "1.1.1.1" "9.9.9.9" "114.114.114.114"; do
		echo "nameserver $dns" >> $resolvconf
	done

	# create conf for second part
	echo "wr=1" > $TMPDIR$REPCONF
	echo "archname=$archname" >> $TMPDIR$REPCONF
	echo "root_dev=$DISK_NAME" >> $TMPDIR$REPCONF
	echo "boot_dev=$BOOT_DISK" >> $TMPDIR$REPCONF

	# system mounts
	mount -t proc /proc $TMPDIR/proc
	mount -t sysfs /sys $TMPDIR/sys
	mount --rbind /dev $TMPDIR/dev
	mount --rbind /run $TMPDIR/run
	#mount --rbind /var $TMPDIR/var
	ln -s /run $TMPDIR/var/run

	cp $SCRIPT_PATH/$SCRIPT_NAME $TMPDIR/replace.sh &&
		chmod +x $TMPDIR/replace.sh || return 1

	stop_and_umount

	# chroot to temp root
	cd $TMPDIR
	exec chroot . $BASH /replace.sh
}


function prepare_copy() {
	# get hive zip
	get_image || return
	send_log ok "image ready, preparing"

	stop_and_umount

	root_dev="$DISK_NAME"
}


function configure_image {
	local dev=$1 # sda

	[[ ! -f /rig.conf && ! -f /hive-config/rig.conf ]] && return 0

	echo -e "\n${CYAN}> Configuring $BRAND OS${NOCOLOR}"

	# /dev/sda1    2048    43007    40960   20M Microsoft basic data
	IFS=' ' read -a arr < <(fdisk -l /dev/$dev | grep "basic data")
	[[ ! "${arr[0]}" =~ $dev ]] && echo -e "${RED}Unable to find config partition${NOCOLOR}" && return 1
	local part=${arr[0]}
	local ofs=${arr[1]}
	local end=${arr[2]}
	local size=${arr[3]}
	local bs=512
	echo "Config partition ${arr[*]}"

	MIN_PART_OFFSET=1024*1024 # 1MB
	MIN_PART_SIZE=20*1024*1024 # 20MB
	MAX_PART_SIZE=500*1024*1024 # 500MB

	# check data
	(( ofs + size == end + 1 )) 2>/dev/null
	[[ $? -ne 0 ]] && echo -e "${RED}Bad config partition params${NOCOLOR}" && return 1
	if (( size*bs < $MIN_PART_SIZE || size*bs > $MAX_PART_SIZE || ofs*bs < $MIN_PART_OFFSET )); then
		bs=4096
		if (( size*bs < $MIN_PART_SIZE || size*bs > $MAX_PART_SIZE || ofs*bs < $MIN_PART_OFFSET )); then
			echo -e "${RED}Bad partition size or offset${NOCOLOR}"
			return 1
		fi
		echo "Using 4K sector size"
	fi

	local conf_img=/config.img

	dd if=/dev/$dev of=$conf_img skip=$ofs count=$size bs=$bs
	[[ $? -ne 0 ]] && echo -e "${RED}Unable to copy config partition${NOCOLOR}" && return 1

	CFGDIR=/mnt-config
	mkdir -p $CFGDIR

	ntfs-3g $conf_img $CFGDIR
	[[ $? -ne 0 ]] && echo -e "${RED}Unable to mount config partition${NOCOLOR}" && return 1

	if [[ -f /rig.conf ]]; then
		cp /rig.conf $CFGDIR || cat /rig.conf > $CFGDIR/rig.conf
	else
		cp -R /hive-config/* $CFGDIR || cat /hive-config/rig.conf > $CFGDIR/rig.conf
	fi
	[[ $? -ne 0 ]] && echo -e "${RED}Update config parition failed${NOCOLOR}" && return 1
	
	sync
	umount -f $conf_img || echo -e "${RED}Unable to umount config partition${NOCOLOR}"

	dd if=$conf_img of=/dev/$dev seek=$ofs count=$size bs=$bs
	[[ $? -ne 0 ]] && echo -e "${RED}Write config partition failed${NOCOLOR}" && return 1

	echo -e
	echo -e "${GREEN}$BRAND OS configuration complete!${NOCOLOR}"

	return 0
}


# Writing to disk
function write_image {
	[[ $DEBUG -eq 1 ]] && echo "#DEBUG:" && bash

	[[ -z $archname || ! -f $archname ]] && echo -e "${RED}$BRAND OS image not found, exiting${NOCOLOR}" && return 1
	[[ -z $root_dev || ! -b /dev/$root_dev ]] && echo -e "${RED}$root_dev device not found, exiting${NOCOLOR}" && return 1

	echo -e "\n${CYAN}> Writing $BRAND OS filesystem to ${BPURPLE}$root_dev${NOCOLOR}"
	echo -e "Please wait, this can take long"
	echo -e "To prevent damage to your disk device\ndo not turn off your computer until the end of the process.\n"

	send_log ok "writing image"

	if dd --help | grep -q "'progress'"; then
		if [[ $archname == *\.xz ]]; then
			xz -d -c $archname | dd of=/dev/$root_dev bs=1M status=progress
		elif [[ $archname == *\.zip ]]; then
			unzip -p $archname | dd of=/dev/$root_dev bs=1M status=progress
		elif [[ $archname == *\.gz ]]; then
			gzip -d -c $archname | dd of=/dev/$root_dev bs=1M status=progress
		fi
		exitcode=$?
	else
		# show progress
		( sleep 2; while true; do sleep 1; pkill -USR1 -f "dd of=/dev/" || break; echo -en "\r$(tail -n 1 ./progress 2>/dev/null )      "; done) &
		if [[ $archname == *\.xz ]]; then
			xz -d -c $archname | dd of=/dev/$root_dev bs=1M 2>./progress
		elif [[ $archname == *\.zip ]]; then
			unzip -p $archname | dd of=/dev/$root_dev bs=1M 2>./progress
		elif [[ $archname == *\.gz ]]; then
			gzip -d -c $archname | dd of=/dev/$root_dev bs=1M 2>./progress
		fi
		exitcode=$?
		[[ $exitcode -eq 0 ]] && echo -e "\r$(tail -n 1 ./progress 2>/dev/null)      "
	fi
	[[ $exitcode -ne 0 ]] && echo -e "${BRED}Write image failed ($exitcode), exiting${NOCOLOR}" && return 2

	echo -e
	echo -e "${BGREEN}Image writing to ${BPURPLE}$root_dev${BGREEN} is successfull!${NOCOLOR}"

	# we do not need it any more
	rm $archname > /dev/null 2>&1

	# Fix GPT table if needed
	sgdisk -e /dev/$root_dev > /dev/null 2>&1
	sgdisk -C /dev/$root_dev > /dev/null 2>&1
	#partprobe /dev/$root_dev > /dev/null 2>&1

	# Rewrite config partition if needed
	configure_image $root_dev && configured=1 || configured=0

	sync

	[[ $DEBUG -eq 1 ]] && echo "#DEBUG:" && bash

	echo -e
	echo -e
	echo -e "${WHITE}Your rig is ready to work under $BRAND OS!${NOCOLOR}"

	if [[ $configured -eq 1 ]]; then
		# subshell
		(
			RIG_ID=
			RIG_PASSWD=
			FARM_HASH=
			HIVE_HOST_URL=
			if [[ -f /rig.conf ]]; then
				source /rig.conf
			elif [[ -f /hive-config/rig.conf ]]; then
				source /hive-config/rig.conf
			else
				echo -e "${BYELLOW}Empty config (default)${NOCOLOR}"
			fi
			[[ ! -z "$RIG_ID" && ! -z "$RIG_PASSWD" && ! -z "$HIVE_HOST_URL" ]] &&
				echo -e "RIG ID: ${BPURPLE}$RIG_ID${NOCOLOR}, API: ${BPURPLE}$HIVE_HOST_URL${NOCOLOR}"
			[[ ! -z "$FARM_HASH" && ! -z "$HIVE_HOST_URL" && -z "$RIG_ID" ]] &&
				echo "FARM HASH: ${BPURPLE}$FARM_HASH${NOCOLOR}, API: ${BPURPLE}$HIVE_HOST_URL${NOCOLOR}"
		)
	else
		echo -e "${BRED}Empty config (not written)${NOCOLOR}"
	fi

	echo -e
	echo -e "${GREEN}Have a happy mining!${NOCOLOR}"
	echo -e

	[[ $configured -ne 1 ]] && return 100
	return 0
}


function start_or_continue_replace {
	wr=0
	[[ -f $REPCONF ]] && source $REPCONF
	if [[ $wr -ne 1 ]]; then
		[[ -z "$url" ]] && echo -e "${YELLOW}Filesystem path or URL to $BRAND OS image is required.${NOCOLOR}\n" && exit 1
		check_disk
		check_packages
		prepare_replace
		if [[ $DISK_NAME == $BOOT_DISK ]]; then
			prepare_chroot # returns only on error
			exitcode=$?
			send_log error "preparing error"
			exit $exitcode
		fi
		prepare_copy
		exitcode=$?
		if [[ $exitcode -ne 0 ]]; then
			send_log error "preparing error"
			exit $exitcode
		fi
		write_image
		exitcode=$?
	else
		# chrooted
		cd /
		write_image
		exitcode=$?
	fi

	echo -e
	echo -e "${YELLOW}Rebooting in 20 seconds${NOCOLOR}"

	if [[ $exitcode -eq 0 ]]; then
		send_log ok "complete, rebooting"
	elif [[ $exitcode -eq 100 ]]; then
		send_log warn "complete without config, rebooting"
	elif [[ $exitcode -eq 1 ]]; then
		send_log warn "not complete, rebooting"
	else
		send_log error "failed, rebooting"
	fi

	sleep 1

	# Sync
	echo 1 > /proc/sys/kernel/sysrq
	echo s > /proc/sysrq-trigger

	sleep 20

	# Reboot
	echo 1 > /proc/sys/kernel/sysrq
	echo b > /proc/sysrq-trigger
}


function usage {
	local code=$1
	echo -e "${NOCOLOR}Usage:${CYAN} hive-replace [option] <Path or URL to ZIP/XZ file with $BRAND OS image>${NOCOLOR}"
	echo -e "By default replace is running in session that can be resumed by ${CYAN}screen -r replace${NOCOLOR} or ${CYAN}hive-replace${NOCOLOR}"
	echo -e "Options:"
	echo -e "${GREEN}  -l|--list[=NUM]   ${NOCOLOR}List images from $BRAND server and select for install (or download)"
	echo -e "${GREEN}  -s|--stable       ${NOCOLOR}Download and install latest ${BCYAN}Stable${NOCOLOR} image from $BRAND server"
	[[ ! -z $BETA_URL ]] &&
		echo -e "${GREEN}  --beta            ${NOCOLOR}Download and install latest ${CYAN}Beta${NOCOLOR} image from $BRAND server"
	echo -e "${GREEN}  --repo[=URL]      ${NOCOLOR}List images from custom repository (specified by URL) and select for install"
	echo -e "${GREEN}  -y|--yes          ${NOCOLOR}Do not ask for confirmation, answer yes to all questions"
	echo -e "${GREEN}  --force           ${NOCOLOR}Force replace if RAM is less than 3GB. Use on your own risk!"
	echo -e "${GREEN}  --select          ${NOCOLOR}Select disk for image installation (interactive shell only)"
	echo -e "${GREEN}  --download=PATH   ${NOCOLOR}ONLY download image to PATH without replace. Can be used with other options"
	echo -e "${GREEN}  --hash=FARM_HASH  ${NOCOLOR}FARM_HASH from Web-interface. Optional for already configured rig"
	echo -e "${GREEN}  --rigconf[=FILE]  ${NOCOLOR}Use provided rig.conf file for new image (./rig.conf by default)"
	echo -e "${GREEN}  --nfs             ${NOCOLOR}Use NFS Shared resource. e.g.: ${GREEN}IP_NFS_server:/shared_dir/image_file${NOCOLOR}"
	echo -e "${GREEN}  --smb             ${NOCOLOR}Use Windows Shared resource. e.g.: ${GREEN}//IP_Windows/shared/image_file${NOCOLOR}"
	echo -e "${GREEN}  --smbuser=Winuser ${NOCOLOR}Username for Windows Shared resource. Do not set for guest/anonymous access"
	echo -e "${GREEN}  --smbpass=Winpass ${NOCOLOR}Password for Windows Shared resource. Do not set for guest/anonymous access"
	echo -e "${GREEN}  --no-safe         ${NOCOLOR}Do not run replace in safer way in screen session (interactive shell only)"
	#echo -e "${GREEN}  -h|--help             ${NOCOLOR}Show this message"
	[[ ! -z $code ]] && exit $code
	echo -e "Examples:"
	echo -e "${GREEN}  hive-replace --list${NOCOLOR}"
	echo -e "${GREEN}  hive-replace -y --stable${NOCOLOR}"
	echo -e "${GREEN}  hive-replace -y --list=3 --repo=ftp://mylocalserver/images/${NOCOLOR}"
	echo -e "${GREEN}  hive-replace -y --hash=46e9602837d0bda99f0 http://mylocalserver/$OS_BRAND-0.6.zip${NOCOLOR}"
	echo -e "${GREEN}  hive-replace -y --hash=46e9602837d0bda99f0 --nfs 192.168.1.5:/home/john/hive/$OS_BRAND-0.6.zip${NOCOLOR}"
	echo -e "${GREEN}  hive-replace -y --smb --smbuser=winuser --smbpass=secret //192.168.0.1/shared/$OS_BRAND-0.6.xz${NOCOLOR}"
	exit 0
}


[[ $1 == "-h" || $1 == "--help" ]] && usage


# Get root
if [[ $(id -u) -ne 0 ]]; then
	echo "Root privileges required"
	sudo chmod +x $0
	exec sudo $0 "$@"
fi


[[ " $* " =~ " --no-safe " ]] && nosafe=1

if [[ $nosafe -eq 0 ]]; then
	# check screen
	command -v screen >/dev/null || check_packages

	# check for running session and restore to it
	sessions=$(screen -ls replace 2>/dev/null)
	if [[ $sessions =~ [^0-9]+([0-9]+)\.replace ]]; then
		pid=${BASH_REMATCH[1]}
		# skip if we are already there
		if ! ppstree $pid; then
			echo -e "${BYELLOW}Hive-replace session is already running${NOCOLOR}"
			if [[ -t 0 ]]; then
				echo -e "${BYELLOW}Resuming...${NOCOLOR}"
				read -t 2 -n 1
				screen -x -S replace
			else
				echo "Use interactive shell to connect to it with 'hive-replace' or 'screen -r replace' command"
			fi
			exit
		fi
	else
		[[ -z "$*" && ! -f $REPCONF ]] && usage

		echo "${BCYAN}Starting hive-replace session${NOCOLOR}"
		if [[ -t 0 ]]; then
			screen -mS replace $0 "$@" && exit
		else
			screen -dmS replace $0 "$@" &&
				echo "Use interactive shell to connect to it with 'hive-replace' or 'screen -r replace' cmd"
			exit
		fi
		echo -e "${YELLOW}Session start failed. Running in common way...${NOCOLOR}"
	fi
	# set exit handler to pause at the end
	trap exit_handler EXIT

elif [[ $thishive -eq 1 ]]; then
	if [[ ! -t 0 ]]; then
		echo -e "Only interactive shell is supported in unsafe mode!"
		exit
	fi
fi

listparams=

for param in "$@"; do
	case "$param" in
		--safe|--no-safe)
			# ignore it here
		;;
		--force)
			force=1
		;;
		-y|--yes)
			no_confirm=1
		;;
		--nfs)
			nfs=1
		;;
		--smb)
			smb=1
		;;
		--smbuser=*)
			smbuser="${param#*=}"
		;;
		--smbpass=*)
			smbpasswd="${param#*=}"
		;;
		--hash=*)
			farm_hash="${param#*=}"
		;;
		--rigconf)
			rig_conf="./rig.conf"
			[[ ! -f $rig_conf ]] && echo -e "${RED}Rig.conf not found, exiting${NOCOLOR}" && exit 1
		;;
		--rigconf=*)
			rig_conf="${param#*=}"
			[[ ! -f $rig_conf ]] && echo -e "${RED}Rig.conf not found, exiting${NOCOLOR}" && exit 1
		;;
		-l|--list)
			listparams[2]=1
		;;
		-l=*|--list=*)
			[[ ! "${param#*=}" =~ ^[0-9]+$ ]] && echo -e "${RED}Non-numeric value, exiting${NOCOLOR}" && exit 1
			listparams[0]="${param#*=}"
		;;
		--repo)
			[[ ! -f $REPO_LIST ]] && echo -e "${RED}No default repository, exiting${NOCOLOR}" && exit 1
			repo=`grep -m1 -oP "deb\s*\K[^\s]+/repo/" $REPO_LIST`
			[[ -z "$repo" || "$repo" =~ ${DOWNLOAD_URL##*/} ]] && echo -e "${RED}No custom repository, exiting${NOCOLOR}" && exit 1
			listparams[1]="$repo"
		;;
		--repo=*)
			[[ -z ${param#*=} ]] && echo -e "${RED}Repository URL is required, exiting${NOCOLOR}" && exit 1
			listparams[1]="${param#*=}"
		;;
		-s|--stable)
			if [[ -z $STABLE_URL ]]; then
				listparams[0]="1"
			else
				get_image_from_url $STABLE_URL "Stable" || exit
			fi
		;;
		--beta)
			[[ -z $BETA_URL ]] && exit
			get_image_from_url $BETA_URL "Beta" || exit
		;;
		--download=*)
			[[ -z ${param#*=} ]] && echo -e "${RED}Download PATH is required, exiting${NOCOLOR}" && exit 1
			[[ ! -d ${param#*=} ]] && echo -e "${RED}Provided PATH does not exist, exiting${NOCOLOR}" && exit 1
			download_path="${param#*=}"
		;;
		--select)
			select_drive=1
		;;

		*)
			if [[ "$param" =~ ^$URL_PROTO://.+ ]]; then
			    if [[ $SKIP_CHECK -ne 0 || "$param" =~ $OS_BRAND ]]; then
					get_image_from_url "$param" "this" || exit
				else
					echo -e "${RED}Bad url for $OS_BRAND image: ${WHITE}$param${NOCOLOR}\n"
					exit
				fi
			elif [[ "$param" =~ $OS_REGEX$ ]]; then
				[[ -f "$DIR/$param" ]] && param="$DIR/$param"
				url=$( url_decode "$param" )
			else
				echo -e "${RED}Unknown param: ${WHITE}$param${NOCOLOR}\n" && usage 2
			fi
		;;
	esac
done


[[ $nfs -eq 1 && $smb -eq 1 ]] && echo -e "${YELLOW}Specify only one of the options: ${GREEN}--smb${NOCOLOR} or ${GREEN}--nfs${NOCOLOR}. Both are not allowed${NOCOLOR}\n" && usage 1
[[ ( $nfs -eq 1 || $smb -eq 1 ) && ( "$url" == *http* ||  "$url" == *ftp* ) ]] && echo -e "${YELLOW}--nfs or --smb and http or ftp - incompatible\n" && usage 1
[[ ! -z $farm_hash && ! -z $rig_conf ]] && echo -e "${YELLOW}--hash and --rigconf - incompatible\n" && usage 1


# only download in specified path
if [[ ! -z "$download_path" ]]; then
	[[ ! "$download_path" =~ /$ ]] && download_path+=/
	get_image_from_list -1 "$download_path"
	echo
	# list images from default repo
	if [[ -z "$url" || ! -z "${listparams[*]}" ]]; then
		get_image_from_list "${listparams[0]}" "${listparams[1]}" || exit
	fi
	# download new
	TMPDIR="${download_path}tmp"
	mkdir -p $TMPDIR || exit 1
	get_image
	exitcode=$?
	if [[ $exitcode -eq 0 ]]; then
		mv -f $TMPDIR/*$OS_BRAND* $download_path
		#get_image_from_list -1 "$download_path"
	fi
	cd $DIR
	exit $exitcode
fi


if [[ ! -z "${listparams[*]}" ]]; then
	get_image_from_list "${listparams[0]}" "${listparams[1]}" || exit
fi

start_or_continue_replace
