#!/bin/sh

# This program is Copyright (c) 2018 VividCortex, Inc. All rights reserved.

# This is a placeholder that is populated with the service version that the
# script is deployed with. It is here for information purposes only - DO NOT USE
VERSION=unknown

# Placeholder that is populated with the base URI for the download server - DO NOT USE
baseuri="https://static-download.vividcortex.com"

serviceName="security-gateway" # files, dirs
txtServiceName="Security Gateway"
fullTxtServiceName="VividCortex ${txtServiceName}"

# To-do: using '-' in unit/file names is probably a bad idea, at least for FreeBSD

# To-do: support non-root installs

# To-do: ability to install SG as read-only / write-only.

set -u
POSIXLY_CORRECT=1
export POSIXLY_CORRECT
TERM=dumb
export TERM

unalias -a >/dev/null 2>&1 || true

configFilename="${serviceName}.conf"
defaultconfdir="/etc/vividcortex/${serviceName}"
confdir="${defaultconfdir}"
logdir="/var/log/vividcortex/${serviceName}"
runvdir="/var/run/vividcortex/${serviceName}"
servicePidFile="${runvdir}/${serviceName}.pid"
tempdir=""
socks5=""
SKIPCERTS=""
LOADCERTS=""
LISTEN_URI=""
LISTEN_ISHTTPS=""
LISTEN_CRT=""
LISTEN_KEY=""
LISTEN_PWD=""
DB_DSN=""
DB_SCHEMA="vividcortex"
HASH_SALT=""

EXISTS="command -v"
${EXISTS} ls >/dev/null 2>&1 || EXISTS=which
if ! ${EXISTS} ls >/dev/null 2>&1 ; then
	echo "command/which failed" >&2
	exit 1
fi

# testing
test "${baseuri}" = "unknown" && baseuri="https://static-download.vividcortex.com"

###############################################################################

initscript_systemd() {
	nl='
'
	while IFS="${nl}" read -r line; do
		echo "${line}"
	done <<\HEREDOC
# This program is Copyright (c) 2018 VividCortex, Inc. All rights reserved.

[Unit]
Description=VividCortex Security Gateway
After=local-fs.target syslog.target network.target time-sync.target nss-lookup.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/security-gateway
ProtectSystem=strict
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=x86-64
NoNewPrivileges=true
Restart=on-abort
RestartPreventExitStatus=1
RestartSec=1
KillMode=control-group
KillSignal=SIGTERM
TimeoutStopSec=3

[Install]
WantedBy=multi-user.target
HEREDOC
}

###############################################################################

initscript_Redhat() {
	nl='
'
	while IFS="${nl}" read -r line; do
		echo "${line}"
	done <<\HEREDOC
#!/bin/bash

# This program is Copyright (c) 2018 VividCortex, Inc. All rights reserved.

VERSION=unknown

### BEGIN INIT INFO
# Provides:          security-gateway
# Required-Start:    $remote_fs $local_fs
# Required-Stop:     $remote_fs $local_fs
# Should-Start:      $syslog $network $named $time $all
# Should-Stop:       $syslog $network $named $time
# Default-Start:     3 4 5
# Default-Stop:      0 1 2 6
# Short-Description: VividCortex Security Gateway
# Description:       VividCortex Security Gateway
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin

unalias -a >/dev/null 2>&1 || true

serviceName="security-gateway"
runvdir="/var/run/vividcortex/${serviceName}"

DESC="VividCortex Security Gateway"
NAME="${serviceName}"
SERVICE="${serviceName}"
VCPIDFILE="${runvdir}/${NAME}.pid"
VCLOCKFILE="/var/lock/subsys/${SERVICE}"
BIN_PATH=/usr/local/bin
DAEMON="${BIN_PATH}/${NAME}"
SERVICE_ARGS=""
set_conf_file=0
if [ "${set_conf_file}" != "0" ]; then
	SERVICE_ARGS="-config-file=/etc/vividcortex/security-gateway/security-gateway.conf"
fi

# Exit if the package is not installed
[ -x "${DAEMON}" ] || exit 0

# Read optional config file
[ -r "/etc/sysconfig/${SERVICE}" ] && . "/etc/sysconfig/${SERVICE}"

# Source function library.
. /etc/rc.d/init.d/functions

# Set HOME in case it isn't or points to a user dir (sudo)
HOME=~root
test -d "${HOME}" || HOME=/root
test -d "${HOME}" || HOME=
export HOME

RETVAL=0

start() {
	echo -n $"Starting ${NAME}: "
	if [ -f "${VCLOCKFILE}" ]; then
		if [ -s "${VCPIDFILE}" ]; then
			PID=$(cat "${VCPIDFILE}")
			NAME15=$(echo ${NAME} | cut -c1-15) # ps-compatible processname
			if ps --pid="${PID}" | grep "${NAME15}" >/dev/null 2>&1 ; then
				echo "already running (pid ${PID})"
				return 0
			fi
		fi
	fi
	rm -f "${VCLOCKFILE}" "${VCPIDFILE}"
	daemon --user=root --pidfile="${VCPIDFILE}" "nohup ${DAEMON} ${SERVICE_ARGS} >/dev/null 2>&1 &"
	RETVAL=$?
	if [ "${RETVAL}" -eq 0 ]; then
		sleep 3
		pid=$(ps -AF | grep "${DAEMON}\$" | grep -v grep | tr -s ' ' | cut -d' ' -f2)
		if [ -n "${pid}" ]; then
			mkdir -p "${runvdir}" 2>/dev/null || true
			echo "${pid}" > "${VCPIDFILE}"
			touch "${VCLOCKFILE}"
		else
			RETVAL=1
		fi
	fi
	echo
	return "${RETVAL}"
}


stop() {
	# Return
	#   0 if daemon has been stopped
	#   7 if daemon was already stopped
	#   other if a failure occurred

	# Kill service, return if that cannot be done. (If it wasn't running, that's OK.)
	echo -n "Stopping ${NAME}: "
	rm -f "${VCLOCKFILE}"
	killproc "${DAEMON}"
	RETVAL=$?
	[ "${RETVAL}" -ne 0 -a "${RETVAL}" -ne 7 ] && return "${RETVAL}"
	rm -f "${VCPIDFILE}" "${VCLOCKFILE}" "/var/lock/vividcortex/${SERVICE}"
	echo
	return 0
}

restart() {
	stop
	start
}


case "$1" in
start)
	start
	;;
stop)
	stop
	;;
restart|force-reload)
	restart
	;;
reload)
	RETVAL=3
	;;
status)
	status "${NAME}"
	RETVAL=$?
	;;
*)
	echo $"Usage: $0 {start|stop|restart|force-reload|status}"
	RETVAL=2
	;;
esac

exit ${RETVAL}
HEREDOC
}

###############################################################################

initscript_Debian() {
	nl='
'
	while IFS="${nl}" read -r line; do
		echo "${line}"
	done <<\HEREDOC
#!/bin/sh

# This program is Copyright (c) 2018 VividCortex, Inc. All rights reserved.

VERSION=1.0.40

### BEGIN INIT INFO
# Provides:          security-gateway
# Required-Start:    $remote_fs $local_fs
# Required-Stop:     $remote_fs $local_fs
# Should-Start:      $syslog $network $named $time $all
# Should-Stop:       $syslog $network $named $time
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: VividCortex Security Gateway
# Description:       VividCortex Security Gateway
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin

unalias -a >/dev/null 2>&1 || true

serviceName="security-gateway"
runvdir="/var/run/vividcortex/${serviceName}"

DESC="VividCortex Security Gateway"
NAME="${serviceName}"
SERVICE="${serviceName}"
VCPIDFILE="${runvdir}/${NAME}.pid"
VCLOCKFILE="/var/lock/vividcortex/${SERVICE}"
BIN_PATH=/usr/local/bin
DAEMON="${BIN_PATH}/${NAME}"
SERVICE_ARGS=""
set_conf_file=0
if [ "${set_conf_file}" != "0" ]; then
	SERVICE_ARGS="-config-file=/etc/vividcortex/security-gateway/security-gateway.conf"
fi

# Exit if the package is not installed
[ -x "${DAEMON}" ] || exit 0

# Read optional config file
[ -r "/etc/default/${SERVICE}" ] && . "/etc/default/${SERVICE}"

# For old distros: tiny implementations, to be replaced by LSB functions
log_daemon_msg() {
	test -z "${2:-}" && echo -n "$1:" || echo -n "$1: $2"
}
log_end_msg() {
	test $1 -eq 0 && echo "." || echo " failed!"
	return $1
}
status_of_proc() {
	local status
	status="0"
	pidofproc $1 >/dev/null || status="$?"
	if [ "$status" = "0" ]; then
		echo "$2 is running"
	elif [ "$status" = "4" ]; then
		echo "could not access PID file for $2"
	else
		echo "$2 is not running"
	fi
	return $status
}

# Load required variables and functions (LSB)
[ -r /lib/init/vars.sh ] && . /lib/init/vars.sh
. /lib/lsb/init-functions

# Set HOME in case it isn't (boot) or points to a user dir (sudo)
HOME=~root
test -d "${HOME}" || HOME=/root
test -d "${HOME}" || HOME=
export HOME

# Are we dealing with an ancient start-stop-daemon?
start-stop-daemon --help | grep -q retry && SSD_LEGACY=0 || SSD_LEGACY=1

do_start() {
	# Return
	#   0 if daemon has been started
	#   1 if daemon was already running
	#   2 if daemon could not be started
	start-stop-daemon --start --quiet --exec=${DAEMON} --background --pidfile=${VCPIDFILE} --make-pidfile --test > /dev/null || return 1
	start-stop-daemon --start --quiet --exec=${DAEMON} --background --pidfile=${VCPIDFILE} --make-pidfile -- $SERVICE_ARGS || return 2
	# should be running
	sleep 3
	start-stop-daemon --start --quiet --exec=${DAEMON} --background --pidfile=${VCPIDFILE} --make-pidfile --test > /dev/null && return 2	
}

do_stop() {
	# Return
	#   0 if daemon has been stopped
	#   1 if daemon was already stopped
	#   2 if daemon could not be stopped
	#   other if a failure occurred

	# Kill service, return if that cannot be done. (If it wasn't running, that's OK.)
    if [ ${SSD_LEGACY} -eq 0 ]; then
		start-stop-daemon --stop --quiet --oknodo --retry=TERM/5/KILL/5 --exec=${DAEMON} --pidfile=${VCPIDFILE} --remove-pidfile --user=root
		RETVAL="$?"
    else
		start-stop-daemon --stop --quiet --oknodo --name=${NAME} --pidfile=${VCPIDFILE} --remove-pidfile --user=root
		RETVAL="$?"
    fi
	[ "${RETVAL}" -ne 0 ] && return "${RETVAL}"
	rm -f "${VCPIDFILE}" "${VCLOCKFILE}" "/var/lock/subsys/${serviceName}"
	return 0
}

case "$1" in
	start)
		pidofproc "$DAEMON" >/dev/null && exit 0
		[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
		do_start
		case "$?" in
			0|1)
				[ "$VERBOSE" != no ] && log_end_msg 0
				exit 0
				;;
			*)  [ "$VERBOSE" != no ] && log_end_msg 1
				exit 1
				;;
		esac
		;;

	stop)
		[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
		do_stop
		case "$?" in
			0|1)
				[ "$VERBOSE" != no ] && log_end_msg 0
				exit 0
				;;
			*)
				[ "$VERBOSE" != no ] && log_end_msg 1
				exit 1
				;;
		esac
		;;

	status)
		status_of_proc "$DAEMON" "$NAME"
		exit $?
		;;

	restart|force-reload)
		log_daemon_msg "Restarting $DESC" "$NAME"
		do_stop
		case "$?" in
			0|1)
				do_start
				case "$?" in
					0)
						log_end_msg 0
						exit 0
						;;
					*)
						log_end_msg 1 # 1 old process is still running, other: failed to start
						exit 1
						;;
				esac
				;;
			*)
				log_end_msg 1 # Failed to stop
				exit 1
				;;
		esac
		;;

	reload)
		exit 3
		;;

	*)
		echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
		exit 2
		;;
esac

exit 1 # should not reach here; 1 = generic or unspecified error
HEREDOC
}

###############################################################################

check_config()
{
	test "${LISTEN_URI}" = "" && abort "--listen-uri required.  Use install --help to see a list of supported options"
	test -n "${LISTEN_ISHTTPS}" && test "${LISTEN_KEY}" = "" && abort "--tls-key-file required for https"
	test -n "${LISTEN_ISHTTPS}" && test "${LISTEN_CRT}" = "" && abort "--tls-crt-file required for https"
	test "${HASH_SALT}" = "" && abort "--hash-salt required"
	test "${DB_DSN}" = "" && abort "--db-dsn required"
	test "${VCTOKEN}" = "" && abort "--token required"
}


###############################################################################

reset_tempdir()
{
	test -n "${tempdir}" && test -d "${tempdir}" && rm -Rf "${tempdir}" >/dev/null 2>&1
	tempdir=""
}

abort()
{
	if [ $# -gt 0 ]; then
		echo >&2
		echo "$1" >&2
		echo >&2
	fi
	reset_tempdir
	exit 1
}

create_tempdir()
{
	tempdir=$(mktemp -d "/tmp/vividcortex.${serviceName}.XXXXXX" 2>/dev/null)
	if [ $? -ne 0 ] || [ -z "${tempdir}" ] || [ ! -d "${tempdir}" ]; then
		tempdir=""
		abort "Unable to create temp folder under /tmp"
	fi
}

###############################################################################

createdir()
{
	mkdir -p "$1" 2>/dev/null || abort "Unable to create directory $1"
}

###############################################################################

getfile()
{
	failed=0
	if ${EXISTS} curl >/dev/null 2>&1 ; then
		if [ -z "${socks5}" ]; then
			curl -f -s "$1" > "$2" 2>/dev/null && return 0
			test -n "${SKIPCERTS}" && curl -f -s -k "$1" > "$2" 2>/dev/null && return 0
		else
			curl -f -s --socks5-hostname "${socks5}" "$1" > "$2" 2>/dev/null && return 0
			curl -f -s --socks5 "${socks5}" "$1" > "$2" 2>/dev/null && return 0
			curl -f -s -x "socks5://${socks5}" "$1" > "$2" 2>/dev/null && return 0
			test -n "${SKIPCERTS}" && curl -f -s -k --socks5-hostname "${socks5}" "$1" > "$2" 2>/dev/null && return 0
			test -n "${SKIPCERTS}" && curl -f -s -k --socks5 "${socks5}" "$1" > "$2" 2>/dev/null && return 0
			test -n "${SKIPCERTS}" && curl -f -s -k -x "socks5://${socks5}" "$1" > "$2" 2>/dev/null && return 0
		fi
		failed=1
	fi
	if ${EXISTS} wget >/dev/null 2>&1 ; then
		# depending on version, uses env vars
		wget -q -O - "$1" > "$2" 2>/dev/null && return 0
		test -n "${SKIPCERTS}" && wget -q --no-check-certificate -O - "$1" > "$2" 2>/dev/null && return 0
		failed=1
	fi
	if ${EXISTS} fetch >/dev/null 2>&1 ; then
		# fetch uses env vars and does not support socks5
		fetch -q -o - "$1" > "$2" 2>/dev/null && return 0
		test -n "${SKIPCERTS}" && fetch -q --no-verify-peer -o - "$1" > "$2" 2>/dev/null && return 0
		failed=1
	fi

	test "${failed}" = "0" && abort "No suitable tool for file download found"

	test "$#" -gt 2 && test "$3" = "IGNORE" && return 1

	dlHelp="Unable to retrieve $1

Please verify proxy/firewall and install or update CA Root Certificates"

	case "${initver}" in
		FreeBSD)
			abort "${dlHelp} - e.g. pkg install security/ca_root_nss"
			;;
		Redhat)
			if [ "${distro}" = "Slackware" ]; then
				abort "${dlHelp} - e.g. update-ca-certificates"
			else
				abort "${dlHelp} - e.g. yum update ca-certificates"
			fi
			;;
		Debian|OpenRC|systemd)
			if [ "${distro}" = "SuSE" ]; then
				abort "${dlHelp} - e.g. zypper install ca-certificates ; update-ca-certificates"
			else
				abort "${dlHelp} - e.g. update-ca-certificates"
			fi
			;;
		*)
			abort "${dlHelp}."
			;;
	esac
}

###############################################################################

usage()
{
	abort "Usage: install [options]  ...

Full list of options:

  --help               Display this help information
  --autostart          Configure system to start the ${txtServiceName} at boot
  --no-autostart       Do not configure system to start the ${txtServiceName} at boot
  --start-now          Start the ${txtServiceName} after installation
  --db-dsn 'DSN'       The Data Source Name for the samples database
  --db-schema 'SCHEMA' The schema to connect to in the target database. Defaults to 'vividcortex'
  --hash-salt 'SALT'   The salt to use when hashing samples to produce an id
                       Changing the salt invalidates your samples ids.
  --listen-uri 'URI'   HTTP(S) endpoint for ${txtServiceName} E.g. 'https://[::]:1237'
  --tls-crt-file 'FQN' HTTPS crt [certificate] filename, in PEM, DER or PFX/P12 format
  --tls-key-file 'FQN' HTTPS key [private key] filename, in PEM, DER or PFX/P12 format
  --tls-key-pass 'PWD' Optional passphrase for PEM/PFX/P12 files
  --token 'TOKEN'      Configure VividCortex API token for the desired environment.
                       Users must be authenticated with the environment chosen to see the samples.
  --cdn-uri 'URI'      Use custom CDN endpoint 'URI'
  --proxy 'URI/auto/dyn/no' Configure HTTP/HTTPS or SOCKS5 proxy to 'URI',
      'auto' [default] sets whatever proxy (or no proxy) is detected in environment vars,
      'dyn' makes ${txtServiceName} detect proxies on startup.
  --no-proxy           Do not configure a proxy, alias of --proxy=no
  --bin-dir 'DIR'      Use custom install directory 'DIR'
  --cfg-dir 'DIR'      Use custom configuration files directory 'DIR'
  --uninstall          Stop & uninstall the ${txtServiceName}
  --upgrade            Stop & upgrade the ${txtServiceName} with the latest version, then restart.
                       Upgrade will use existing configuration files, optionally specified with --cfg-dir flag.
  --batch              Non-interactive mode, suppresses prompts
  --init 'INIT'        Linux only. Override init detection and use the
                       specified init setup [Debian, None, OpenRC, Redhat].
  --version 'TAG'      Install ${txtServiceName} version 'TAG' (latest otherwise)"
}

###############################################################################

if [ "$(id -u)" -ne 0 ]; then
	abort "This script must be run as root"
fi

test -d /usr || abort "/usr not mounted"

# Note that I am using the external getopt(1) here rather than the bash-
# internal getopts() because /bin/sh on some operating systems (e.g. FreeBSD)
# is not bash.
(getopt -T) >/dev/null 2>&1
exitcode=$?
if [ ${exitcode} -eq 4 ]; then
	# GNU version, supports long options
	GETARGS=$(getopt -o "" -l "help,autostart,no-autostart,start-now,load-certs,skip-certs,batch,uninstall,upgrade,debug,no-proxy,proxy:,version:,init:,cdn-uri:,bin-dir:,cfg-dir:,db-dsn:,db-schema:,hash-salt:,listen-uri:,tls-crt-file:,tls-key-file:,tls-key-pass:,token:" -n "$0" -- "$@") 2>/dev/null
	test $? -eq 0 || usage
	eval set -- "${GETARGS}"
else
	# BSD, cannot validate
	eval set -- "$*"
fi

AUTOSTART=""
BATCH=""
UNINSTALL=""
UPGRADE=""
DEBUG=""
NOPROXY=""
PROXY="auto"
STARTNOW=""
VCTOKEN=""
FORCE_INIT=""
INSTALL_VERSION=current
defaultvcbindir="/usr/local/bin"
vcbindir="${defaultvcbindir}"

if [ -n "${SSL_NO_VERIFY_PEER:-}" ]; then
	SKIPCERTS=1
	LOADCERTS=1
fi

ORIG_ARGS="$@"

while [ $# -ne 0 ]; do
	case "$1" in
		--autostart)
			shift
			AUTOSTART=1
			;;
		--no-autostart)
			shift
			AUTOSTART=0
			;;
		--batch)
			shift
			BATCH=1
			;;
		--start-now)
			shift
			STARTNOW=1
			;;
		--load-certs)
			shift
			LOADCERTS=1
			;;
		--skip-certs)
			shift
			SKIPCERTS=1
			LOADCERTS=1
			;;
		--no-proxy)
			shift
			NOPROXY=1
			PROXY=""
			;;
		--proxy)
			shift
			if [ -n "$1" ]; then
				NOPROXY=""
				PROXY="$1"
				shift
				if [ "${PROXY}" = "no" ] || [ "${PROXY}" = "none" ] || [ "${PROXY}" = "false" ] || [ "${PROXY}" = "off" ]; then
					NOPROXY=1
					PROXY=""
				fi
			fi
			;;
		--init)
			shift
			FORCE_INIT="$1"
			if [ "${FORCE_INIT}" != "Debian" ] && [ "${FORCE_INIT}" != "None" ] && [ "${FORCE_INIT}" != "OpenRC" ] && [ "${FORCE_INIT}" != "Redhat" ]; then
				abort "init must be Debian, None, OpenRC or Redhat"
			fi
			shift
			;;
		--debug)
			shift
			DEBUG="${DEBUG}1"
			;;
		--cdn-uri)
			shift
			test -z "$1" && abort "--cdn-uri requires a value"
			baseuri="$1"
			echo "${baseuri}" | grep '^http' >/dev/null 2>&1 || abort "--cdn-uri must be http or https"
			shift
			;;
		--bin-dir)
			shift
			test -z "$1" && abort "--bin-dir requires a value"
			vcbindir="$1"
			echo "${vcbindir}" | grep '^/[^ ]\+[^/]$' >/dev/null 2>&1 || abort "invalid directory: ${vcbindir}"
			test -d "${vcbindir}" || abort "${vcbindir} is not a directory"
			shift
			;;
		--listen-uri)
			shift
			test -z "$1" && abort "--listen-uri requires a value"
			LISTEN_URI="$1"
			echo "${LISTEN_URI}" | grep '^http\(s\|\)://' >/dev/null 2>&1 || abort "--listen-uri scheme must be http or https"
			echo "${LISTEN_URI}" | grep '^https://' >/dev/null 2>&1 && LISTEN_ISHTTPS="1"
			shift
			;;
		--tls-crt-file)
			shift
			test -z "$1" && abort "--tls-crt-file requires a value"
			LISTEN_CRT="$1"
			shift
			;;
		--tls-key-file)
			shift
			test -z "$1" && abort "--tls-key-file requires a value"
			LISTEN_KEY="$1"
			shift
			;;
		--tls-key-pass)
			shift
			test -z "$1" && abort "--tls-key-pass requires a value"
			LISTEN_PWD="$1"
			shift
			;;
		--cfg-dir)
			shift
			test -z "$1" && abort "--cfg-dir requires a value"
			confdir="$1"
			echo "${confdir}" | grep '^/[^ ]\+[^/]$' >/dev/null 2>&1 || abort "invalid directory: ${confdir}"
			test -d "${confdir}" || abort "${confdir} is not a directory"
			shift
			;;
		--token)
			shift
			test -z "$1" && abort "--token requires a value"
			VCTOKEN="$1"
			shift
			;;
		--uninstall)
			shift
			UNINSTALL=1
			;;
		--upgrade)
			shift
			UPGRADE=1
			;;
		--version)
			shift
			if [ -n "$1" ]; then
				INSTALL_VERSION="$1"
				shift
			fi
			;;
		--db-dsn)
			shift
			test -z "$1" && abort "--db-dsn requires a value"
			DB_DSN="$1"
			shift
			;;
		--db-schema)
			shift
			test -z "$1" && abort "--db-schema requires a value"
			DB_SCHEMA="$1"
			shift
			;;
		--hash-salt)
			shift
			test -z "$1" && abort "--hash-salt requires a value"
			HASH_SALT="$1"
			shift
			;;
		--help)
			shift
			usage
			;;
		--)
			shift
			break
			;;
		*)
			shift
			usage
			;;
	esac
done

if [ "${DEBUG}" = "1" ]; then # cmdline includes a single --debug
	# find ourselves
	SELF=$(readlink -f "$0" 2>/dev/null)
	test -n "${SELF}" && head "${SELF}" | grep 'VividCortex' >/dev/null 2>&1 || abort "cannot find script"
	# create a temp install script patched with verbose flags
	create_tempdir
	sed 's/>\/dev\/null 2>&1//' "${SELF}" |
		sed 's/2>\/dev\/null//' |
		sed 's/curl -f -s/curl -f -v/' |
		sed 's/wget -q/wget -v/' |
		sed 's/fetch -q/fetch -v/' > "${tempdir}/vcinstall"
	# run it in trace mode
	echo
	echo -n "running install in batch mode, please wait..."
	/bin/sh -x "${tempdir}/vcinstall" --batch --debug ${ORIG_ARGS} >"${tempdir}/vcoutput" 2>&1
	cat "${tempdir}/vcoutput" | tr -s '\r' '\n' >/tmp/vividcortex.log
	reset_tempdir
	echo
	echo
	echo "Install trace copied to /tmp/vividcortex.log"
	echo
	exit 0
elif [ -n "${DEBUG}" ]; then
	# dump diagnostics
	uname -a
	sestatus
	getenforce
	cat /etc/lsb-release
	cat /etc/redhat-release
	cat /etc/debian_version
	cat /etc/gentoo-release
	cat /etc/SuSE-release
	cat /etc/os-release
	set | grep -i '\(proxy\|socks\)'
	ls -l "${logdir}/"
	tail -n 30 "${logdir}/${serviceName}.log"
fi

platform=$(uname -s | tr A-Z a-z)
distro=""
arch=""
initver=""
initdir=""
initname="${serviceName}"
initperm=755
startcmd=""
stopcmd=""
preinstallcmd="true"
installcmd=""
uninstallcmd="true"

longbit=$(getconf LONG_BIT 2>/dev/null)
if [ -z "${longbit}" ]; then
	if [ -x /usr/bin/file ] && [ -x /bin/cat ]; then
		if /usr/bin/file /bin/cat | grep 64.bit >/dev/null 2>&1 ; then
			longbit=64
		fi
	else
		if uname -a | grep "\(amd\|x86_\)64" >/dev/null 2>&1 ; then
			longbit=64
		fi
	fi
fi

case "${longbit}" in
	64)
		arch="amd64"
		;;
	32)
		abort "${fullTxtServiceName} isn't supported on 32-bit systems"
		;;
	*)
		abort "Could not determine system configuration.
Please contact VividCortex for installation support.
Additional information: $(uname -a)"
		;;
esac

# aborts or sets (distro) or (distro,initdir,initver)
case "${platform}" in
	linux)
		initdir="/etc/init.d"

		if [ -n "${FORCE_INIT}" ]; then
			initver="${FORCE_INIT}"
			if [ "${initver}" = "None" ]; then
				initdir="/tmp"
				initname=""
			else
				test -d "${initdir}" || initdir="/etc/rc.d"
				test -d "${initdir}" || abort "Cannot find directory for init scripts"
			fi
			distro="Unknown-${FORCE_INIT}"
		elif grep -i ubuntu /etc/*-release >/dev/null 2>&1 ; then
			distro="Ubuntu"
			initver="Debian"
		elif grep -i debian /etc/*-release >/dev/null 2>&1 ; then
			distro="Debian"
			initver="Debian"
		elif grep -i amazon /etc/*-release >/dev/null 2>&1 ; then
			distro="Amazon"
			initver="Redhat"
		elif grep -i centos /etc/*-release >/dev/null 2>&1 ; then
			distro="CentOS"
			initver="Redhat"
		elif grep -i red.hat.enterprise /etc/*-release >/dev/null 2>&1 ; then
			distro="RHEL"
			initver="Redhat"
		elif grep -i fedora /etc/*-release >/dev/null 2>&1 ; then
			distro="Fedora"
			initver="Redhat"
		elif grep 'ID=coreos' /etc/os-release >/dev/null 2>&1 ; then
			distro="CoreOS"
			#systemd
		elif grep 'ID=alpine' /etc/os-release >/dev/null 2>&1 ; then
			distro="Alpine"
			if ${EXISTS} rc-update >/dev/null 2>&1; then
				# host
				initver="OpenRC"
			else
				# container
				initdir="/tmp"
				initver="None"
				initname=""
				SKIPCERTS=1
				LOADCERTS=1
			fi
		elif grep 'ID=slackware' /etc/os-release >/dev/null 2>&1 ; then
			distro="Slackware"
			initdir="/etc/rc.d"
			initver="Redhat"
		elif grep 'ID=rancheros' /etc/os-release >/dev/null 2>&1 ; then
			distro="RancherOS"
			initdir="/tmp"
			initver="None"
			initname=""
		elif grep 'ID=arch' /etc/os-release >/dev/null 2>&1 ; then
			distro="Arch"
			#systemd
		elif grep 'ID=devuan' /etc/os-release >/dev/null 2>&1 ; then
			distro="Devuan"
			initver="Debian"
		elif [ -e /etc/redhat-release ]; then
			distro="Redhat"
			initver="Redhat"
		elif [ -e /etc/debian_version ]; then
			distro="Debian"
			initver="Debian"
		elif [ -e /etc/gentoo-release ]; then
			distro="Gentoo"
			initver="OpenRC"
		elif [ -e /etc/SuSE-release ]; then
			distro="SuSE"
			initver="Debian"
		else
			distro="Unknown"
			# don't abort, it may be an unknown systemd-based distro
		fi
		;;
	freebsd)
		initdir="/etc/rc.d"
		test -d /usr/local/etc/rc.d && grep '/usr/local/etc/rc.d' /etc/defaults/rc.conf >/dev/null 2>&1 && initdir="/usr/local/etc/rc.d"
		test -d /usr/local/etc && test "${confdir}" = "${defaultconfdir}" && confdir="/usr/local/etc/vividcortex/${serviceName}"
		distro="FreeBSD"
		initver="FreeBSD"
		;;
	*)
		abort "Sorry, this install script doesn't support the '${platform}' platform.
Please contact VividCortex for installation support.
Additional information: $(uname -a)"
		;;
esac

if [ "${UNINSTALL}" = "" ] && [ "${UPGRADE}" = "" ]; then
	check_config
fi

# linux: do we need to use systemd instead of legacy initver?
if [ "${platform}" = "linux" ] && [ "${FORCE_INIT}" = "" ]; then
	if [ -d /etc/systemd/system ]; then
		if ${EXISTS} systemctl >/dev/null 2>&1 ; then
			# installed; enabled?
			export SYSTEMD_PAGER=
			if systemctl --version >/dev/null 2>&1 ; then
				# enabled; in use?
				if systemctl | grep -q "\.service" ; then
					initver="systemd"
					# CoreOS mounts /usr read-only. Use /vividcortex/* unless user overrides it.
					test "${distro}" = "CoreOS" && test "${vcbindir}" = "${defaultvcbindir}" && vcbindir="/vividcortex/${serviceName}"
				fi
			fi
		fi
	fi
fi

# verify initver dependencies and set startcmd/stopcmd/installcmd
case "${initver}" in
	Redhat)
		startcmd="${initdir}/${serviceName} start"
		stopcmd="${initdir}/${serviceName} stop"
		if [ "${distro}" = "Slackware" ]; then
			installcmd="ln -s -f ${initdir}/${serviceName} /etc/rc.d/rc3.d/S${serviceName}"
			uninstallcmd="rm -f /etc/rc.d/rc?.d/?${serviceName} && rm -f ${initdir}/${serviceName}"
		else
			installcmd="/sbin/chkconfig --add ${serviceName}"
			uninstallcmd="/sbin/chkconfig --del ${serviceName}"
			${EXISTS} /sbin/chkconfig >/dev/null 2>&1 || initver=""
		fi
		;;
	Debian)
		if ${EXISTS} update-rc.d >/dev/null 2>&1 ; then
			startcmd="${initdir}/${serviceName} start"
			stopcmd="${initdir}/${serviceName} stop"
			installcmd="update-rc.d ${serviceName} defaults"
			uninstallcmd="rm -f ${initdir}/${serviceName} && update-rc.d ${serviceName} remove"
		elif ${EXISTS} /sbin/chkconfig >/dev/null 2>&1 ; then
			startcmd="${initdir}/${serviceName} start"
			stopcmd="${initdir}/${serviceName} stop"
			installcmd="/sbin/chkconfig --add ${serviceName}"
			uninstallcmd="/sbin/chkconfig --del ${serviceName}"
		else
			initver=""
		fi
		;;
	OpenRC)
		startcmd="rc-service ${serviceName} start"
		stopcmd="rc-service ${serviceName} stop"
		installcmd="rc-update add ${serviceName}"
		uninstallcmd="rc-update delete ${serviceName}"
		${EXISTS} rc-update >/dev/null 2>&1 || initver=""
		${EXISTS} rc-service >/dev/null 2>&1 || initver=""
		;;
	systemd)
		servicePidFile=""
		startcmd="systemctl start ${serviceName}.service"
		stopcmd="systemctl stop ${serviceName}.service"
		preinstallcmd="systemctl daemon-reload"
		installcmd="systemctl enable ${serviceName}.service"
		uninstallcmd="systemctl disable ${serviceName}.service"
		initdir="/etc/systemd/system"
		initname="${serviceName}.service"
		initperm=644
		;;
	FreeBSD)
		startcmd="${initdir}/${serviceName} onestart"
		stopcmd="${initdir}/${serviceName} stop"
		installcmd="true"
		if [ "${UNINSTALL}" = "" ]; then
			srvEnabled=""
			grep '^[[:space:]]*'${serviceName}'_enable="\?\(FALSE\|false\|NO\|no\|0\)' /etc/rc.conf >/dev/null 2>&1 && srvEnabled=0
			grep '^[[:space:]]*'${serviceName}'_enable="\?\(TRUE\|true\|YES\|yes\|1\)' /etc/rc.conf >/dev/null 2>&1 && srvEnabled=1
			if [ "${AUTOSTART}" = "0" ]; then
				test "${srvEnabled}" = "1" && abort "Please change ${serviceName}_enable to FALSE in /etc/rc.conf"
				test "${srvEnabled}" = "0" || abort "Please add ${serviceName}_enable=FALSE to /etc/rc.conf"
			elif [ "${AUTOSTART}" = "1" ]; then
				# compatibility: init script starts by default when ${serviceName}_enable not present
				test "${srvEnabled}" = "0" && abort "${serviceName}_enable=FALSE found in /etc/rc.conf, change it to TRUE to autostart"
			elif [ "${srvEnabled}" = "0" ]; then
				AUTOSTART=0
			elif [ "${srvEnabled}" = "1" ]; then
				AUTOSTART=1
			else
				abort "Please set ${serviceName}_enable to FALSE or TRUE in /etc/rc.conf"
			fi
		fi
		;;
	None)
		startcmd="${vcbindir}/${serviceName}"
		test "${confdir}" = "${defaultconfdir}" || startcmd="${startcmd} -config-file=${confdir}/${configFilename}"
		stopcmd="test -f ${servicePidFile} && kill \$(cat ${servicePidFile}) || rm -f ${servicePidFile}"
		test "${AUTOSTART}" = "1" && abort "Autostarting unsupported, please remove option --autostart"
		AUTOSTART=0
		;;
	*)
		initver=""
		;;
esac

###############################################################################

delete_binary()
{
	test $# -ne 1 && abort "delete_binary: expected 1 arg, got $#"
	srvBinDir="$1"
	echo "${srvBinDir}" | grep '^/[^?*" ]\+[^/?*" .]$' >/dev/null 2>&1 || abort "delete_binary: invalid dir ${srvBinDir}"
	delspec="${srvBinDir}/${serviceName}"
	for f in ${delspec}; do
		test -f "${f}" && grep -i 'Copyright (c) [0-9-]\+ VividCortex, Inc' "${f}" >/dev/null 2>&1 && rm -f "${f}" && echo "deleted $f"
	done
}

###############################################################################

stop_service()
{
	echo -n "Stopping ${fullTxtServiceName}... "
	# stop - assumes running service use current init system
	if [ -n "${stopcmd}" ]; then
		${stopcmd} >/dev/null 2>&1
	fi
	# stop - generic linux/freebsd
	${EXISTS} service >/dev/null 2>&1 && service ${serviceName} stop >/dev/null 2>&1
	${EXISTS} rc-service >/dev/null 2>&1 && rc-service ${serviceName} stop >/dev/null 2>&1
	${EXISTS} systemctl >/dev/null 2>&1 && systemctl stop ${serviceName}.service >/dev/null 2>&1
	test -x /etc/init.d/${serviceName} && /etc/init.d/${serviceName} stop >/dev/null 2>&1
	test -x /etc/rc.d/${serviceName} && /etc/rc.d/${serviceName} stop >/dev/null 2>&1
	test -x /usr/local/etc/rc.d/${serviceName} && /usr/local/etc/rc.d/${serviceName} stop >/dev/null 2>&1
	if [ -f "${servicePidFile}" ]; then
		# ${stopcmd} fails on BusyBox's ash
		sleep 7
		if [ -f "${servicePidFile}" ]; then
			kill $(cat "${servicePidFile}")
			rm -f "${servicePidFile}" >/dev/null 2>&1
		fi
	fi
	rm -f "/var/lock/subsys/${serviceName}" >/dev/null 2>&1
	echo "OK"
}

###############################################################################

delete_init()
{
	echo -n "Removing ${txtServiceName} init script... "
	# assumes running service use current init system
	${uninstallcmd} >/dev/null 2>&1
	# generic linux/freebsd
	/sbin/chkconfig --del ${serviceName} >/dev/null 2>&1
	${EXISTS} systemctl >/dev/null 2>&1 && systemctl disable ${serviceName}.service >/dev/null 2>&1
	${EXISTS} rc-update >/dev/null 2>&1 && rc-update delete ${serviceName} >/dev/null 2>&1
	rm -f /etc/init.d/${serviceName} >/dev/null 2>&1
	${EXISTS} update-rc.d >/dev/null 2>&1 && update-rc.d ${serviceName} remove >/dev/null 2>&1 # after deleting init.d script
	rm -f /etc/rc.d/${serviceName} >/dev/null 2>&1
	rm -f /etc/rc.d/rc?.d/?${serviceName} /etc/rc.d/rc?.d/?[0-9]${serviceName} /etc/rc.d/rc?.d/?[0-9][0-9]${serviceName} >/dev/null 2>&1
	rm -f /usr/local/etc/rc.d/${serviceName} >/dev/null 2>&1
	rm -f /etc/systemd/system/${serviceName}.service >/dev/null 2>&1
	rm -f /etc/systemd/system/*/${serviceName}.service >/dev/null 2>&1
	echo "OK"
}

###############################################################################

get_init()
{
	if [ -n "${initname}" ]; then
		"initscript_${initver}" >"${tempdir}/initscript" 2>/dev/null
		test -s "${tempdir}/initscript" || abort "${initver} not yet supported, please contact VividCortex.

Additional information: $(uname -a)"

		if [ "${vcbindir}" != "${defaultvcbindir}" ]; then
			escFrom=`echo "${defaultvcbindir}" | sed 's/\//\\\&/g'`
			escTo=`echo "${vcbindir}" | sed 's/\//\\\&/g'`
			sed "s/${escFrom}/${escTo}/g" "${tempdir}/initscript" >"${tempdir}/initscript.new" || abort "Failed to replace vcbindir in init script"
			mv -f "${tempdir}/initscript.new" "${tempdir}/initscript" || abort "Failed to move file after replacing vcbindir in init script"
		fi
		if [ "${confdir}" != "${defaultconfdir}" ]; then
			escFrom=`echo "${defaultconfdir}" | sed 's/\//\\\&/g'`
			escTo=`echo "${confdir}" | sed 's/\//\\\&/g'`
			sed "s/${escFrom}/${escTo}/g" "${tempdir}/initscript" >"${tempdir}/initscript.new" || abort "Failed to replace confdir in init script"
			sed "s/set_conf_file=0/set_conf_file=1/" "${tempdir}/initscript.new" >"${tempdir}/initscript" || abort "Failed to replace set_conf_file in init script"
			if [ "${initver}" = "systemd" ]; then
				mv -f "${tempdir}/initscript" "${tempdir}/initscript.new" || abort "Unable to move init script"
				sed "s/\(^ExecStart=.\+$\)/\1 -config-file=${escTo}\/${configFilename}/" "${tempdir}/initscript.new" > "${tempdir}/initscript" || abort "Failed to patch ExecStart in init script"
			fi
			rm -f "${tempdir}/initscript.new"
		fi
	fi
}

###############################################################################

install_init()
{
	if [ -n "${initname}" ]; then
		mv -f "${tempdir}/initscript" "${initdir}/${initname}" || abort "Unable to install ${txtServiceName} init script"
		chmod ${initperm} "${initdir}/${initname}" || abort "Unable to set ${initdir}/${initname} permissions"
	fi
}

###############################################################################

set_proxy()
{
	# detect proxy
	detProxy=${HTTPS_PROXY:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${https_proxy:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${HTTP_PROXY:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${http_proxy:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${SOCKS_SERVER:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="socks5://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${ALL_PROXY:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="socks5://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=${all_proxy:-''}
	test -n "${detProxy}" && echo "${detProxy}" | grep -v '://' >/dev/null 2>&1 && detProxy="socks5://${detProxy}"
	echo "${detProxy}" | grep '://' >/dev/null 2>&1 || detProxy=""

	unset ALL_PROXY all_proxy HTTP_PROXY http_proxy HTTP_PROXY_AUTH HTTPS_PROXY https_proxy SOCKS_SERVER SOCKS_VERSION SSL_NO_VERIFY_PEER

	# scheme-less proxy, detect
	if echo "${detProxy}" | grep "^://" >/dev/null 2>&1 ; then
		export HTTP_PROXY="http${detProxy}"
		export http_proxy="http${detProxy}"
		export HTTPS_PROXY="http${detProxy}"
		export https_proxy="http${detProxy}"
		if getfile "${baseuri}/install" "/dev/null" IGNORE ; then
			detProxy="http${detProxy}"
		else
			export HTTP_PROXY="https${detProxy}"
			export http_proxy="https${detProxy}"
			export HTTPS_PROXY="https${detProxy}"
			export https_proxy="https${detProxy}"
			if getfile "${baseuri}/install" "/dev/null" IGNORE ; then
				detProxy="https${detProxy}"
			else
				detProxy=""
			fi
		fi
		unset HTTP_PROXY http_proxy HTTPS_PROXY https_proxy
	fi

	proxy=""
	dynmsg=""

	if [ -n "${NOPROXY}" ]; then
		test -n "${detProxy}" && dynmsg=" because of --no-proxy. If install fails, consider removing
that option as ${detProxy} may be a valid proxy."
	elif [ "${PROXY}" = "auto" ]; then
		proxy="${detProxy}"
		dynmsg="  (auto-detected)"
	elif [ "${PROXY}" = "dyn" ]; then
		proxy="${detProxy}"
		dynmsg="  (will re-detect every time the service starts)"
	elif [ -n "${PROXY}" ]; then
		proxy="${PROXY}"
	elif [ "${BATCH}" = "1" ]; then
		test -n "${detProxy}" && dynmsg=" because of --batch and lack of --proxy. If install fails,
consider --proxy=auto as ${detProxy} may be a valid proxy."
	else
		resp=""
		echo
		echo -n "Do you need to set up a proxy? [y/N] "
		if read -r resp && [ "${resp}" = "Y" ] || [ "${resp}" = "y" ]; then
			if [ -n "${detProxy}" ]; then
				echo
				echo "Environment vars suggest this may be a valid proxy: ${detProxy}"
			fi
			echo
			echo -n "Please input your proxy URI: "
			read -r proxy
			test -z "${proxy}" && abort "Blank proxy; retry install"
		fi
	fi

	if [ -n "${proxy}" ]; then
		if echo "${proxy}" | grep "^\(socks5\|socks\)://" >/dev/null 2>&1 ; then
			# socks5 proxy
			socks5=$(echo "${proxy}" | sed 's/[^:]\+:\/\///')
			export SOCKS_SERVER="${socks5}"
			export SOCKS_VERSION=5
			export ALL_PROXY="${proxy}"
			export all_proxy="${proxy}"
		elif echo "${proxy}" | grep "^\(https\|http\)://" >/dev/null 2>&1 ; then
			# https/http proxy
			export HTTP_PROXY="${proxy}"
			export http_proxy="${proxy}"
			export HTTPS_PROXY="${proxy}"
			export https_proxy="${proxy}"
		else
			abort "Unsupported proxy URI: ${proxy}
Proxy URI must begin with 'https://', 'http://', 'socks5://' or 'socks://'.
E.g.: socks5://user:pass@127.0.0.1:1080"
		fi
		echo
		echo "Using proxy: ${proxy}${dynmsg}"
	else
		# try harder to not use a proxy
		export NO_PROXY="$(echo "${baseuri}" | sed 's/.*:\/\///' | sed 's/\/.*$//')"
		export no_proxy="${NO_PROXY}"
		echo
		echo "Not using a proxy${dynmsg}"
	fi
	test "${PROXY}" = "dyn" && proxy="auto"
}

###############################################################################

create_config()
{
	rm -f "${globalconf}.tmp" >/dev/null 2>&1
	test -e "${globalconf}.tmp" && abort "Unable to remove ${globalconf}.tmp"

	cat - > "${globalconf}.tmp" <<EOF
{
    EXTRA_CONFIG
EOF

	# testing
	grep 'EXTRA_' "${globalconf}.tmp" >/dev/null 2>&1 && echo '{' > "${globalconf}.tmp"

	if [ -n "${LOADCERTS}" ]; then
		cat - >> "${globalconf}.tmp" <<EOF
    "override-os-certs": "true",
EOF
	fi

	if [ -n "${SKIPCERTS}" ]; then
		cat - >> "${globalconf}.tmp" <<EOF
    "skip-certs": "true",
EOF
	fi

	if [ -n "${LISTEN_ISHTTPS}" ]; then
		if [ -n "${LISTEN_PWD}" ]; then
			cat - >> "${globalconf}.tmp" <<EOF
    "tls-key-pass": "${LISTEN_PWD}",
EOF
		fi
		cat - >> "${globalconf}.tmp" <<EOF
    "tls-crt-file": "${LISTEN_CRT}",
    "tls-key-file": "${LISTEN_KEY}",
EOF
	fi

	cat - >> "${globalconf}.tmp" <<EOF
    "db-dsn": "${DB_DSN}",
    "db-schema": "${DB_SCHEMA}",
    "hash-salt": "${HASH_SALT}",
    "binding": "${LISTEN_URI}",
    "jwt-public-key": "$(echo "${JWT_PEM}" | tr '\n' '_' | sed 's:_:\\n:g')",
    "env-id": "${VCENV}",
    "log-type": "file",
    "proxy-uri": "${proxy}"
}
EOF

	mv -f "${globalconf}.tmp" "${globalconf}" >/dev/null 2>&1 || abort "Unable to move ${globalconf}.tmp to ${globalconf}"
	test -s "${globalconf}" || abort "Creation of ${globalconf} failed"
	chmod 600 "${globalconf}" >/dev/null 2>&1 || abort "Unable to chmod ${globalconf}"
}

start_service()
{
	resp=""
	if [ -z "${AUTOSTART}" ] && [ "${BATCH}" != "1" ] && [ "${installcmd}" != "" ]; then
		echo -n "Would you like to schedule automatic service startup? [Y/n] "
		read -r resp
		echo
		test -z "${resp}" && resp="Y"
	fi

	${preinstallcmd} >/dev/null 2>&1 || abort "Running pre-install action '${preinstallcmd}' failed"

	if [ "${resp}" = "Y" ] || [ "${resp}" = "y" ] || [ "${AUTOSTART}" = "1" ]; then
		if [ "${installcmd}" = "" ]; then
			abort "Sorry, don't know how to enable init scripts for '${initver}'.
Please enable the '${serviceName}' init script manually.
Please also tell VividCortex how to improve this script to do that."
		else
			${installcmd} >/dev/null 2>&1 || abort "Unable to install init script using '${installcmd}'"
			AUTOSTART=1
		fi
		echo "${txtServiceName} init script scheduled for automatic start/stop"
	else
		echo "${txtServiceName} init script is NOT scheduled for automatic start/stop"
	fi

	echo

	if [ "${STARTNOW}" = "1" ]; then
		echo "Starting ${fullTxtServiceName}"
		started=0
		if [ "${servicePidFile}" = "" ]; then
			${startcmd} >/dev/null 2>&1 && started=1
		else
			rm -f "${servicePidFile}" >/dev/null 2>&1
			if ${startcmd} >/dev/null 2>&1 ; then
				sleep 3
				test -f "${servicePidFile}" && started=1
			fi
		fi

		if [ "${started}" != "1" ]; then
			abort "${fullTxtServiceName} service startup may have failed.

It can be started by running:

    ${startcmd}

and stopped by running:

    ${stopcmd}"
		elif [ "${AUTOSTART}" != "1" ]; then
			echo
			echo "Started successfully.  ${txtServiceName} is NOT configured to start at boot because"
			echo "install was run without --autostart.  It can be started by running:"
			echo
			echo "    ${startcmd}"
			echo
			echo "and stopped by running:"
			echo
			echo "    ${stopcmd}"
		fi
	else
		echo "${txtServiceName} can be started by running:"
		echo
		echo "    ${startcmd}"
		echo
		echo "and stopped by running:"
		echo
		echo "    ${stopcmd}"
	fi
}

###############################################################################

cleanup_service()
{
	rm -Rf "${runvdir}" >/dev/null 2>&1
	rm -Rf "/var/lock/vividcortex/${serviceName}" >/dev/null 2>&1
	delete_binary "${defaultvcbindir}"
	delete_binary "${vcbindir}"
	if [ -d "${logdir}" ]; then
		echo "OK, deleted everything except logs at ${logdir}"
	else
		echo "OK"
	fi
}

###############################################################################

globalconf="${confdir}/${configFilename}"

if [ "${UNINSTALL}" = "1" ]; then
	if [ "${UPGRADE}" = "1" ]; then
		abort "Sorry, you can't --upgrade and --uninstall at the same time."
	fi
	echo
	if [ "${BATCH}" != "1" ]; then
		echo -n "Are you sure you want to uninstall ${fullTxtServiceName}? [y/N] "
		read -r resp
		test "${resp}" != "y" && test "${resp}" != "Y" && abort "Uninstall aborted."
		echo
	fi

	stop_service
	delete_init
	echo -n "Cleaning up... "
	# clean-up, starting with configuration files
	rm -Rf "/etc/vividcortex/${serviceName}" >/dev/null 2>&1
	rm -Rf "/usr/local/etc/vividcortex/${serviceName}" >/dev/null 2>&1
	cleanup_service
	echo
	exit 0
fi

if [ "${UPGRADE}" = "1" ]; then
	echo
	if [ "${BATCH}" != "1" ]; then
		echo -n "Are you sure you want to upgrade ${fullTxtServiceName}? [y/N] "
		read -r resp
		test "${resp}" != "y" && test "${resp}" != "Y" && abort "Upgrade aborted."
		echo
	fi

	test -e "${globalconf}" || abort "Error: Could not find global configuration file. You must have an existing installation in order to upgrade."

	stop_service
	delete_init
	echo -n "Cleaning up... "
	# clean-up. Leave config files
	cleanup_service
	echo
fi

###############################################################################

if [ "${initver}" = "" ] || [ "${initdir}" = "" ] || [ ! -d "${initdir}" ]; then
	abort "Sorry, install does not yet support your version or flavor of ${platform}/${distro}.

Additional information: $(uname -a)

Please contact VividCortex for installation support."
fi

# Download to temp folder in case we need to abort
create_tempdir

if [ -e "${globalconf}" ] && [ "${UPGRADE}" = "" ]; then
	abort "${globalconf} exists; stopping.
Remove and re-run if you want to replace an existing install."
fi

# agents are installed in ${vcbindir}; make sure it exists
if [ ! -d "${vcbindir}" ]; then
	if [ "${vcbindir}" = "/usr/local/bin" ] && [ ! -d /usr/local ]; then
		mkdir /usr/local >/dev/null 2>&1
		chmod 755 /usr/local >/dev/null 2>&1
	fi
	mkdir "${vcbindir}" >/dev/null 2>&1
	chmod 755 "${vcbindir}" >/dev/null 2>&1
	test -d "${vcbindir}" || abort "Cannot create ${vcbindir}"
fi

# customer consented a reinstall by removing globalconf; make sure service isn't running
if [ -z "${initname}" ] || [ -e "${initdir}/${initname}" ]; then
	stop_service >/dev/null
	sleep 1
	${uninstallcmd} >/dev/null 2>&1
fi

# remove service file
test -n "${initname}" && rm -f "${initdir}/${initname}"

echo
echo "Installing ${txtServiceName} for ${platform} ${distro} ${arch}."

if [ "${LISTEN_ISHTTPS}" = "" ] && [ "${BATCH}" != "1" ]; then
	echo
	echo -n "Using HTTP will expose samples to eavesdroppers. Are you sure? [y/N] "
	read -r resp
	test "${resp}" = "Y" || test "${resp}" = "y" || abort "${fullTxtServiceName} installation aborted"
fi

set_proxy

if [ "${INSTALL_VERSION}" != "current" ]; then
	echo
	echo "Installing ${txtServiceName} version: ${INSTALL_VERSION}"
fi

echo
echo "Using static IP: make sure to allow connections to TCP port 443 of static-app.vividcortex.com and static-download.vividcortex.com"

getfile "${baseuri}/public-keys/jwt.pem" "${tempdir}/jwt.pem"
JWT_PEM=$(cat "${tempdir}/jwt.pem")

getfile "${baseuri}/${serviceName}/${platform}/${arch}/${INSTALL_VERSION}/${serviceName}" "${tempdir}/${serviceName}"
chmod 700 "${tempdir}/${serviceName}"

EXTRA_ARG=""
if [ -n "${LOADCERTS}" ]; then
	EXTRA_ARG="${EXTRA_ARG} -override-os-certs"
fi
if [ -n "${SKIPCERTS}" ]; then
	EXTRA_ARG="${EXTRA_ARG} -skip-certs"
fi

# Run self-test
if [ "${UPGRADE}" = "1" ]; then
	{ "${tempdir}/${serviceName}" -config-file="${globalconf}" -self-test -create-db-objects -log-type=stderr ${EXTRA_ARG} ; } >"${tempdir}/${serviceName}.log" 2>&1
else
	{ "${tempdir}/${serviceName}" -config-file="" -self-test -api-token="${VCTOKEN}" -proxy-uri="${proxy}" -binding="${LISTEN_URI}" -tls-crt-file="${LISTEN_CRT}" -tls-key-file="${LISTEN_KEY}" -tls-key-pass="${LISTEN_PWD}" -create-db-objects -db-dsn="${DB_DSN}" -db-schema="${DB_SCHEMA}" -hash-salt="${HASH_SALT}" -log-type=stderr -jwt-public-key="${JWT_PEM}" ${EXTRA_ARG} ; } >"${tempdir}/${serviceName}.log" 2>&1
fi
exitcode=$?
# 0 exitSuccess
if [ ${exitcode} -ne 0 ]; then
	abort "Installation failed. Please retry and, if the problem persists, contact VividCortex.

Self-test log:
$(cat "${tempdir}/${serviceName}.log")

Additional information: ${distro}/${arch} (exitcode=${exitcode}) $(uname -a)"
fi

if [ "${UPGRADE}" = "" ]; then
# parse "VividCortex Env=N"
	VCENV="$(grep 'VividCortex Env=[0-9]\+$' "${tempdir}/${serviceName}.log" 2>/dev/null | sed 's/.\+VividCortex Env=//')"
	test -z "${VCENV}" && abort "Installation failed. Can't find a valid environment number in Selt-test log:

$(cat "${tempdir}/${serviceName}.log")

Additional information: ${distro}/${arch} $(uname -a)"
fi

mv -f "${tempdir}/${serviceName}" "${vcbindir}/" >/dev/null 2>&1 || abort "Unable to install ${serviceName}"
chmod 700 "${vcbindir}/${serviceName}" >/dev/null 2>&1 || abort "Unable to set ${vcbindir}/${serviceName} permissions"

get_init

createdir "${confdir}"
createdir "${logdir}"
createdir "${runvdir}"

install_init
reset_tempdir
if [ "${UPGRADE}" = "" ]; then
	create_config
fi

echo
echo "${fullTxtServiceName} successfully installed"
echo

start_service

echo
exit 0
