#!/bin/bash

#
# PrimeMiner install script. Currently tested on Debian Wheezy.
# https://nooblet.org/blog/2014/primeminer
# @stalksta

### BEGIN INIT INFO
# Provides:          xolominer
# Required-Start:    $local_fs $network $remote_fs
# Required-Stop:     $local_fs $network $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: xolominer
# Description:       PrimeCoin Miner
### END INIT INFO

. /lib/lsb/init-functions

NAME=xolominer
DESC="PrimeCoin Miner"
INSTALLDIR=/usr/local/share/xolominer
ADMINMAIL=root
RUNASUSER=miner
RUNASGROUP=miner
LOGPATH=/var/log/xolominer

if [ -r /etc/default/xolominer ]; then
	. /etc/default/xolominer
fi

DAEMONNAME=xolominer
DAEMON="${INSTALLDIR}/${DAEMONNAME}"
CONFIG=/etc/${NAME}/${NAME}.conf
PIDPATH=/var/run/${NAME}
LOGFILE=${LOGPATH}/${DAEMONNAME}.log
PIDFILE=${PIDPATH}/${DAEMONNAME}.pid
RUNUSER=${RUNAS%:*}
PRIMECOIND_OPTS="-exitondisc=1"
NUMTHREADS=$(grep -c ^processor /proc/cpuinfo)
COMPILEOPT="USE_UPNP="

# Remove the old PID is its stale
cleanpid() {
	# Check for stale PIDFILE
	if [ -e ${PIDFILE} ]; then
		if ! kill -0 $(cat ${PIDFILE}) > /dev/null 2>&1; then
			rm -f $PIDFILE
		fi
	fi
}

#  Create needed directories
do_init() {
	# Only if we have a working config, else exit.
	([ -x ${DAEMON} ] && [ -r ${CONFIG} ]) || exit 1
	if ! grep -q ^_run ${CONFIG}; then exit 1; fi

	# Create directories
	for dir in ${PIDPATH} ${LOGPATH}; do
		if [ ! -e ${dir} ]; then
			mkdir -p ${dir}; chown ${RUNUSER}:root ${dir}; chmod 0750 ${dir};
		fi
	done
}

# Lets mine!
do_start() {
	do_init
	cleanpid
	log_daemon_msg "Starting ${DESC}" "${NAME}"
        start-stop-daemon --background -c $RUNAS --start --make-pidfile --pidfile $PIDFILE --exec $0 -- run
	log_end_msg $?
}

# Kill PID and its children
do_stop() {
	log_daemon_msg "Stopping ${DESC}" "${NAME}"
	exitcode=1
	if [ -e ${PIDFILE} ]; then
		ppid=$(cat ${PIDFILE});
		if [ ! -z "${ppid}" ]; then
			kill $(echo -n "${ppid} "; pgrep -P ${ppid}) > /dev/null 2>&1
			try=0
			while :; do
				if kill -0 ${ppid} > /dev/null 2>&1; then
					sleep 0.1
				else
					exitcode=0
					rm -f ${PIDFILE}
					break
				fi
				try=$((${try} +1))
				if [ $try -gt 20 ]; then break; fi
			done
		fi
	fi
	log_end_msg ${exitcode}
}

# Check if running
_getstatus() {
	do_init()
	if [ ! -e ${PIDFILE} ]; then echo "Missing PIDFILE: ${PIDFILE}" 1>&2; exit 1; fi
	ppid=$(cat ${PIDFILE})
	if [ -z "${ppid}" ]; then echo "Empty PIDFILE: ${PIDFILE}" 1>&2; exit 1; fi
	if ! kill -0 ${ppid} > /dev/null 2>&1; then echo "Not running." 1>&2; exit 1; fi
	return 0
}

# Return miner info to stdout
do_status() {
	do_init
	if _getstatus; then
		pool=$(cat /var/run/${NAME}/${DAEMONNAME}.pool)
		cpd=$(tail -100 /var/log/${NAME}/${DAEMONNAME}.log|awk '/STATS.*chains/ {print $11}'|tail -1)
		if [ -z "${cpd}" ]; then cpd=0; fi
		echo ${pool} ${cpd}
	fi
	exit 0
}

# truncate logs, gzip others
do_rotate() {
        rm -f ${LOGFILE}.5.gz
        for i in 4 3 2 1; do
                [ -e ${LOGFILE}.${i}.gz ] && mv ${LOGFILE}.${i}.gz ${LOGFILE}.$((${i} +1)).gz
        done
        [ -e ${LOGFILE} ] && cp ${LOGFILE} ${LOGFILE}.1 && truncate ${LOGFILE} --size 0 && gzip ${LOGFILE}.1
		ls ${LOGFILE}.*.gz 2>&1 > /dev/null && chown miner:miner ${LOGFILE}.*.gz
}

# installer question/answer
_ask() {
	varname=$1
	shift
	var=
	spacer="                                                                                                 ."
	string="$* [$(eval echo \$${varname})]: "
	read -r -p "${spacer:0:$((70 - ${#string}))}${string}" var
	if [ ! -z "${var}" ]; then
		eval ${varname}="${var}"
	fi
}

lastlog=
outputlog=

# create "[date]"
_iprefix() {
	echo "    [$(date +'%Y.%m.%d %H:%M.%S')]"
}

# write to logfile
_ilog() {
	if [ -e "${tmpdir}/exit" ]; then exit 1; fi
	lastlog="$(_iprefix) ${*}"
	echo "${lastlog}" >> ${outputlog}
}

# write to stdout
_iecho() {
	if [ -e "${tmpdir}/exit" ]; then exit 1; fi
	echo -e "$(_iprefix) ${*}" | tee --append ${outputlog}
}

# damn, its broken
_iexit() {
	echo; echo
	echo " !! Uh oh. Something went wrong. Check install log at ${outputlog}"
	echo
	if [ -e "${tmpdir}/exit" ]; then exit 1; fi
	if [ -e "${tmpdir}" ]; then touch "${tmpdir}/exit"; fi
	exit 1
}

# Awesome spinning ascii art
_iprogress() {
	if [ -e "${tmpdir}/exit" ]; then if [ "$1" = "0" ]; then _iexit; else exit 1; fi; fi
	if [ "$1" = "0" ]; then echo -e "\r${lastlog} .. done"; return; fi
 	icount=$((${icount} +1));
 	s=${progressString:$((${icount} % 8)):1};
	echo -ne "\r${lastlog} .. ${s}"
}

# Install miner
do_install() {
	echo "Installing ${DESC} ..

This will install ${NAME} from github ready for use and overwrite any current installation (your configs in /etc/${NAME} are safe, however)"
	echo
	echo "Press ENTER to use default."
	echo
	# set defaults
	installdir="/usr/local/share/${NAME}"
	githubaddr="https://github.com/thbaumbach/primecoin"
	prereq="git build-essential cmake libboost-all-dev libssl-dev libdb-dev libdb++-dev libglib2.0-dev libgmp-dev gzip"
	user="miner"
	group="miner"
	adminmail="root"
	logpath=/var/log/${NAME}
	config=1
	var=""

	_ask githubaddr "GitHUB address"
	_ask installdir "Install directory"
	_ask logpath "Log path"
	_ask user "Run as user"
	_ask group "Run as group"
	_ask adminmail "Admin mail"

	echo
	echo -n "Install to ${installdir}? [yN]: "; read var;
	if [ "${var}" != "Y" ] && [ "${var}" != "y" ]; then echo "Abort."; exit 1; fi
	echo

	outputlog="/tmp/${NAME}-install_$(date +%Y%m%d%H%M%S).log"
	progressString="/-\|/-\|";
	icount=0

	echo "Logging installer debug output to ${outputlog}"; echo

	_iecho "Stop ${NAME}"
	$0 stop 2>&1 > ${outputlog}

	_ilog "Updating package manager"; while read l; do _iprogress; done < <(apt-get update 2>&1 | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;

	_iecho "Installing pre-requisites"
	for i in ${prereq}; do
		_ilog "  - ${i}"; while read l; do _iprogress; done < <(apt-get -y install ${i} 2>&1 | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;
	done

	_iecho "Create temp directory"
	tmpdir=$(mktemp -d 2>>${outputlog}) || _iexit

	_iecho "Backup install script"
	cat ${0} > ${tmpdir}/${NAME}-script 2>> ${outputlog} || _iexit

	_ilog "Clone git repository from ${githubaddr}"
	cd ${tmpdir} 2>>${outputlog} || _iexit
	while read l; do _iprogress; done < <(git clone -q -v --depth 1 ${githubaddr} ${NAME} 2>&1 | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;
	cd ${tmpdir}/${NAME}/ 2>>${outputlog} || _iexit

	_ilog "Generating build structure with cmake"
	mkdir bin 2>>${outputlog} || _iexit
	cd bin 2>>${outputlog} || _iexit
	while read l; do _iprogress; done < <(cmake .. 2>&1 | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;

	_iecho "Determine threads for compiling"
	memfree=$(awk '/^MemFree:/ {print $2}' /proc/meminfo)
	membuffers=$(awk '/^Buffers:/ {print $2}' /proc/meminfo)
	memcache=$(awk '/^Cached:/ {print $2}' /proc/meminfo)
	totalfree=$(( ( (${memfree} + ${membuffers} + ${memcache}) * 800 ) / 1000))
	cthread=$(($totalfree / 200000))
	if [ "${NUMTHREADS}" -lt "${cthread}" ]; then cthread=${NUMTHREADS}; fi
	if [ "${cthread}" -lt 2 ]; then cthread=1; fi
	_iecho "Compiling from source (kick back, relax, this may take a while)"
	_ilog "   - make -j ${cthread}"
	export CXXFLAGS="-Ofast  -march=native -fomit-frame-pointer -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter"
	while read l; do _iprogress; done < <(make -j ${cthread} VERBOSE=1 2>&1  | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;

	if [ ! -x ./${DAEMONNAME} ]; then echo "Binary ${DAEMONNAME} does not exist. Compile failed?" >> ${outputlog}; _iexit; fi

	if ! grep -q "^${group}:" /etc/group; then
		_iecho "Create group: ${group}"
		groupadd ${group} 2>>${outputlog} || _iexit
	fi
	if ! grep -q "^${user}:" /etc/passwd; then
		_iecho "Create user: ${user}"
		useradd -M -d ${installdir} -s /bin/bash --gid ${user} ${group} 2>>${outputlog} || _iexit
	fi

	_iecho "Prepare install directory"
	rm -rfv ${installdir} >> ${outputlog} 2>&1 || _iexit
	mkdir -pv ${installdir} >> ${outputlog} 2>&1 || _iexit

	_iecho "Copy binary"
	mv -v ./${DAEMONNAME} ${installdir} >> ${outputlog} 2>&1 || _iexit

	_iecho "Copy script"
	mv -v ${tmpdir}/${NAME}-script ${installdir} >> ${outputlog} 2>&1 || _iexit
	rm -fv /etc/init.d/${NAME} >> ${outputlog} 2>&1 || _iexit
	ln -sv ${installdir}/${NAME}-script /etc/init.d/${NAME} >> ${outputlog} 2>&1 || _iexit
	chmod -c +x ${installdir}/${NAME}-script >> ${outputlog} 2>&1 || _iexit

	_iecho "Set ${NAME} to run at boot .."
	insserv -v ${NAME} >> ${outputlog} 2>&1 || _iexit

	if [ ! -d /etc/${NAME} ]; then
		_iecho "Creating config directory"
		mkdir -pv /etc/${NAME} >> ${outputlog} 2>&1 || _iexit
		chown -c ${user}:root /etc/${NAME} >> ${outputlog} 2>&1 || _iexit
		chmod -c 0700 /etc/${NAME} >> ${outputlog} 2>&1 || _iexit
	fi

	if [ ! -e /etc/${NAME}/${NAME}.conf ]; then
		config=0
		_iecho "Generating sample config"
		echo -e "# _run <address> <minerid> <poolfee> <poolip> <poolport>\n\n## example\n# _run Aaaabbbcccddd111222333 10 3 176.34.128.129 1337" > /etc/${NAME}/${NAME}.conf 2>> ${outputlog} || _iexit
		chown -c ${user}:root /etc/${NAME}/${NAME}.conf >> ${outputlog} 2>&1
		chmod -c 0600 /etc/${NAME}/${NAME}.conf >> ${outputlog} 2>&1
	elif ! grep -q ^_run /etc/${NAME}/${NAME}.conf; then
		config=0
	fi

	_iecho "Generating defaults file"
	echo "INSTALLDIR=\"${installdir}\"" > /etc/default/${NAME} 2>> ${outputlog}
	echo "RUNAS=${user}:${group}" >> /etc/default/${NAME} 2>> ${outputlog}
	echo "LOGPATH=${logpath}" >> /etc/default/${NAME} 2>> ${outputlog}
	echo "ADMINMAIL=${adminmail}" >> /etc/default/${NAME} 2>> ${outputlog}
	chmod -c 0644 /etc/default/${NAME} 2>> ${outputlog}

	_iecho "Generating crontab file (auto-restart & rotate logs)"
	cat << EOF > /etc/cron.d/${NAME} || _iexit
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

*/5 *   * * *   root    /etc/init.d/${NAME} status > /dev/null || /etc/init.d/${NAME} restart
@daily          root    /etc/init.d/${NAME} rotate

# EOF
EOF

	_ilog "Purge temporary install directory"
	while read l; do _iprogress; done < <(rm -rfv ${tmpdir} 2>&1 | tee --append ${outputlog}; [ ${PIPESTATUS[0]} -eq 0 ] || _iexit); _iprogress 0;

	if [ "${config}" -eq 0 ]; then
		echo
		echo " !! You should edit the config at /etc/${NAME}/${NAME}.conf"
	fi

	echo;
	echo "Complete. Start ${NAME} with: /etc/init.d/${NAME} start"

	# Please don't change/remove this. I spent hours making this script.
	echo -e "\nDid this installer save you time? Why not tip the author?\n\tBTC: 1HHNJLssA5vhJjnrb7XYadJ9nxdFGFvcfc\n\tLTC: LfHqQRbqq5pS89fYZV8NAFqPCFzbodAX8U\n\tXPM: AaoDKf9VC4b9RpZ23mwyzfAxXdZSarzgqi\n"

}

# Run miner with given pool settings
_run() {

	address=$1
	minerid=$2
	poolfee=$3
	poolip=$4
	poolport=$5
	poolshare=$6
	genproclimit=${NUMTHREADS}

	PARAMS=""
	if [ ! -z "$address" ] && [ "$address" != "null" ]; then PARAMS="${PARAMS} -pooluser=${address}"; fi
	if [ ! -z "$minerid" ] && [ "$minerid" != "null" ]; then PARAMS="${PARAMS} -minerid=${minerid}"; fi
	if [ ! -z "$poolfee" ] && [ "$poolfee" != "null" ]; then PARAMS="${PARAMS} -poolfee=${poolfee}"; fi
	if [ ! -z "$poolip" ] && [ "$poolip" != "null" ]; then PARAMS="${PARAMS} -poolip=${poolip}"; fi
	if [ ! -z "$poolport" ] && [ "$poolport" != "null" ]; then PARAMS="${PARAMS} -poolport=${poolport}"; fi
	if [ ! -z "$poolshare" ] && [ "$poolshare" != "null" ]; then PARAMS="${PARAMS} -poolshare=${poolshare}"; fi
#	if [ ! -z $address ] && [ "$address" != "null" ]; then PARAMS="${PARAMS} -pooluser=${address}

	tail -25 ${LOGFILE}|mail -s "${NAME} / ${HOSTNAME} / ${address}@${poolip}:${poolport}" ${ADMINMAIL}
	if [ "$FIRST" -eq 0 ]; then do_rotate; fi
	FIRST=0
	echo "============ ${address}@${poolip}:${poolport} ============" > ${LOGFILE}
	echo ${address}@${poolip}:${poolport} > ${PIDPATH}/${DAEMONNAME}.pool

	#${DAEMON} -pooluser=${address} -minerid=${minerid} -poolfee=${poolfee} -poolip=${poolip} -poolport=${poolport} -genproclimit=${genproclimit} ${OPT} >> ${LOGFILE} 2>&1
	${DAEMON} ${PARAMS} -genproclimit=${genproclimit} ${OPT} >> ${LOGFILE} 2>&1
}

# loop through config pools
do_run() {
	[ -x "${DAEMON}" ] || exit 1
	[ -r "${CONFIG}" ] || exit 2
	[ -w "${LOGPATH}" ] || exit 3

	do_rotate
	echo "No logs, just started." > ${LOGFILE}

	FIRST=1

	while :; do
		. ${CONFIG}
	done
}

# remove all but configs
do_uninstall() {
	echo " Uninstalling ${NAME} .."
	echo
	echo " !! Warning: Uninstall shall remove the following files/directories:"
	filelist="${INSTALLDIR}
${PIDPATH}
${LOGPATH}
/etc/init.d/${NAME}
/etc/default/${NAME}
/etc/cron.d/${NAME}"
	while read f; do echo "   - ${f}"; done << EOF
${filelist}
EOF
	echo
	echo -n "Continue with uninstall? [yN]: "; read var;
	if [ "${var}" != "Y" ] && [ "${var}" != "y" ]; then echo "Abort."; exit 1; fi

	echo
	echo " ====== Stopping ${NAME} .."
	$0 stop > /dev/null 2>&1

	echo " ====== Removing from startup .."
	insserv -rv ${NAME}
	echo " ====== Removing files .."
	while read f; do rm -rfv ${f}; done << EOF
${filelist}
EOF
echo
echo Uninstall complete.
}


case "$1" in
  start)
	do_start
        ;;
  stop)
	do_stop
        ;;

  restart|force-reload)
	do_stop;
	do_start;
        ;;
  status)
	do_status;
	;;
  rotate)
    do_init;
	do_rotate;
	echo "$(date): Logfile rotated" >> ${LOGFILE}
	;;
  install)
	do_install;
	;;
  run)
	do_run;
	;;
  uninstall)
	do_uninstall;
	;;
  *)
        echo "Usage: $0 {start|stop|restart|force-reload|status|install|uninstall}" >&2
        exit 1
        ;;
esac

exit 0

