#!/bin/bash
################################################################################
# Name:
#   cloudbackup-updater.setup
# Description:
#   Detects the platform running the updater and invokes the appropriate modules
#   for the platform. If os.data is detected in the same folder, it is assumed
#   that this is running in tar distro mode; otherwise, it is assumed that this
#   is running in normal update mode. NOTE: ServerMill will call this script in
#   the tarball with --user and not --username.
# Requires parameters:
#   --help (h) -- prints this help text
#   --version (v) -- prints the version of this script
#   --shutdown (s) -- tries to find cloudbackup-updater and shut it down
#   --configure (c) --username (u) <username> --apikey (k) <apiKey> --flavor (f)
#     <flavor> --datacenter (t) <dataCenter> --apihost (a) <apiDrivesrvr>
#     --force (o)
# Requires environment variables:
#   TRACE - if defined turns on function tracing
# TODO: WARNING! THE --user PARAMETER PASSED TO THIS SCRIPT IS INCOMPATIBLE WITH --username PASSED TO LEGACY BINARY UPDATER!!!!!!! ADD --user TO LEGACY GOING FORWARD

################################################################################
# Description:
#   Logging for updater scripts.
# Requires parameters:
#   $1 - log message
#   $2 - line number
# Requires environment variables:
#   installlogname - log file name
# Sets environment variables:
#   theapikey - api key to scrub from all messages
# Returns:
#   Return code 0 or exit code 1
export installlogname=/var/log/cbu-installer.log
function logmsg
{
  linenumber=$1; [[ ! -z "${linenumber}" ]] && linenumber="(${linenumber})"
  logmessage=$2
  [[ ! -z "${theapikey}" ]] && [[ "${logmessage}" =~ "${theapikey}" ]] && logmessage=${logmessage/$theapikey/REDACTED}
  echo "$( date '+%F %H:%M:%S' ) [$$] ${thescriptname}${linenumber}: ${logmessage}" >> ${installlogname}
  [[ "${logmessage}" =~ "FATAL" ]] && echo "[PID: $$] EXITING: ${logmessage}" >&2 && exit 1
  rex='^function '; [[ "${logmessage}" =~ $rex ]] && echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [PID: $$] ${logmessage}${linenumber} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  return 0
}

################################################################################
# Description:
#   Print API key if found in these parameters
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   String API key or nothing
function parseapikey
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function parseapikey'
  echo $* | python -c 'import sys
for l in sys.stdin:
  a = l.split()
  for i in range(1,len(a)):
    if (a[i] == "--apikey"):
      print(a[i +1])
      sys.exit(0)'
}

################################################################################
# Description:
#   Install missing executable with current package manager.
# Requires parameters:
#   $1 - executable (uses "which" to check whether it is installed already)
#   $2 - yum package that installs this executable
#   $3 - apt package that installs this executable
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1
function installmissing
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installmissing'
  executable=$1
  [[ -z "$2" ]] && yumpackage=${executable} || yumpackage=$2
  [[ -z "$3" ]] && aptpackage=${yumpackage} || aptpackage=$3
  which ${executable} >/dev/null 2>&1 && return 0
  which yum >/dev/null 2>&1; if [ $? -eq 0 ]; then yum -y install ${yumpackage} >/dev/null 2>&1; return $?; fi
  which apt >/dev/null 2>&1; if [ $? -eq 0 ]; then apt -y install ${aptpackage} >/dev/null 2>&1; return $?; fi
  return 1
}

################################################################################
# Description:
#   Verify python exists and attempt to link it if it doesn't but python2/3 does.
# Requires parameters:
#   N/A
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1
function linkpython
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function linkpython'
  which python > /dev/null 2>&1 && return 0
  which python3 > /dev/null 2>&1 && cd /usr/bin && ln -s `which python3` python && return 0
  which python2 > /dev/null 2>&1 && cd /usr/bin && ln -s `which python2` python && return 0
  which python > /dev/null 2>&1 && return 0
  logmsg ${LINENO} 'WARNING! python is not on this server'
  return 1
}

################################################################################
# Description:
#   Install python if it doesn't already exist.
# Requires parameters:
#   N/A
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 1
function installpython
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installpython'
  linkpython && return 0
  installmissing python || logmsg ${LINENO} "WARNING: Failed to install python"
  linkpython && return 0
  installmissing python2 || logmsg ${LINENO} "WARNING: Failed to install python2"
  linkpython && return 0
  installmissing python3 || logmsg ${LINENO} "WARNING: Failed to install python3"
  linkpython
}

################################################################################
# Description:
#   Install any missing dependencies (missing tools like curl and bzip2).
# Requires parameters:
#   N/A
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 1
function installdependencies
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installdependencies'
  which yum >/dev/null 2>&1 && yum -y update >/dev/null 2>&1
  which apt >/dev/null 2>&1 && apt -y update >/dev/null 2>&1
  installpython || logmsg ${LINENO} 'FATAL ERROR! Failed to set up python on this server'
  installmissing curl || logmsg ${LINENO} 'FATAL ERROR! Failed to set up curl on this server'
  installmissing bzip2 || logmsg ${LINENO} 'FATAL ERROR! Failed to set up bzip2 on this server'
  installmissing sed || logmsg ${LINENO} 'FATAL ERROR! Failed to set up sed on this server'
}

################################################################################
# Description:
#   Checks the system and sets flavor, version, package manager, system manager,
#   etc.
# Requires parameters:
#   N/A
# Requires environment variables:
#   thebasefolder - the folder that contains this script
# Sets environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thesysmanager - system control manager
#   thepackagemgr - package manager
#   thearchitecture - binary architecture (v2/v3)
# Returns:
#   Return code 0 or exit code 1
function setostype
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function setostype'
  export theflavor=unknown
  export theversion=unknown
  export thepackagemgr=unknown
  export thesysmanager=unknown
  export thearchitecture=unknown
  export prettyname=`grep PRETTY_NAME /etc/os-release`
  [[ ! `pwd` = "${thebasefolder}" ]] && ( cd ${thebasefolder} || logmsg ${LINENO} "FATAL ERROR: Cannot access the base folder: ${thebasefolder}" )
  [[ ! -f os.data ]] && logmsg ${LINENO} "INFO: Running in non-registration mode" && return 0
  for osdata in `cat ${thebasefolder}/os.data`; do
    osflavor=`echo "${osdata}" | cut -d'+' -f1`
    [[ "${osdata}" =~ "${osflavor}" ]] || continue
    osversion=`echo "${osdata}" | cut -d'+' -f2`
    [[ "${osdata}" =~ "${osversion}" ]] || continue
    theflavor="${osflavor}"
    theversion="${osversion}"
    thepackagemgr=`echo "${osdata}" | cut -d'+' -f3`
    thesysmanager=`echo "${osdata}" | cut -d'+' -f4`
    thearchitecture=`echo "${osdata}" | cut -d'+' -f5`
  done
  logmsg ${LINENO} "OS type set: ${prettyname} ${theflavor} ${theversion} ${thepackagemgr} ${thesysmanager}"
}

################################################################################
# Description:
#   Run binary updater with all parameters and "forward" the return code to the
#   calling process. Used with legacy installs only. NOTE: As long as we use the
#   old parameter names, we don't have to convert "user" to "username".
# TODO: USE PYTHON TO CONVERT ' --username ' TO ' --user ' IN $*
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   thebasefolder - the folder that contains this script
# Sets environment variables:
#   N/A
# Returns:
#   Exit code 0/1
function runupdater
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function runupdater'
  cd ${thebasefolder} || logmsg ${LINENO} "FATAL ERROR: Cannot access the base folder: ${thebasefolder}"
  [[ -x cloudbackup-updater.a ]] && ( [[ -x cloudbackup-updater.setup ]] || mv -f cloudbackup-updater cloudbackup-updater.setup ) && mv -f cloudbackup-updater.a cloudbackup-updater
  ./cloudbackup-updater $* && exit 0
  logmsg ${LINENO} "FATAL ERROR: Legacy updater install failed."
}

################################################################################
# Description:
#   Get the current updater version and tar file and extract here.
# Requires parameters:
#   N/A
# Requires environment variables:
#   agentrepoaddr - the address of agent repository
# Sets environment variables:
#   updaterversion - current production version of updater
#   updatertarfile - file name of updater tar
#   updatertarfolder - folder where the tar is extracted
# Returns:
#   Return code 0 or exit code 1
function getupdaterpackage
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function getupdaterpackage'
  export updaterversion=`curl ${agentrepoaddr}/updater-version.txt`
  [[ -z "${updaterversion}" ]] && logmsg ${LINENO} "FATAL ERROR: Cannot access ${agentrepoaddr} updater version"
  export updatertarfile=cloudbackup-updater-${updaterversion}.tar.bz2
  curl -O ${agentrepoaddr}/updater/${updatertarfile}
  [[ $? -ne 0 ]] && logmsg ${LINENO} "FATAL ERROR: Failed download ${updatertarfile} updater tar file"
  tar jxvf ${updatertarfile}
  export updatertarfolder=cloudbackup-updater-${updaterversion}
  [[ ! -d ${updatertarfolder} ]] && logmsg ${LINENO} "FATAL ERROR: Failed to extract ${updatertarfile} updater tar file"
}

################################################################################
# Description:
#   Legacy installtion
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   thebasefolder - base folder where this script was executed from.
#   updatertarfolder - (set by getupdaterpackage) folder where the tar is extracted
# Sets environment variables:
#   N/A
# Returns:
#   Exit code 0/1
function installlegacy
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installlegacy'
logmsg ${LINENO} 'LEGACY INSTALL'; return 0
  # If cloudbackup-updater binary exists, call it with all the parameters $* and exit $?.
  [[ -x ${thebasefolder}/cloudbackup-updater ]] && ( runupdater $*; exit $? )
  # Otherwise download and run latest updater.
  getupdaterpackage
  cd ${updatertarfolder} || logmsg ${LINENO} "FATAL ERROR: Cannot access updater base folder: ${updatertarfolder}"
  ./cloudbackup-updater $*
  exitcode=$?
  [[ ${exitcode} -ne 0 ]] && logmsg ${LINENO} "FATAL ERROR: Updater install failure."
  logmsg ${LINENO} 'Finished legacy install'
  exit ${exitcode}
}

################################################################################
# Description:
#   Test whether a service exists. Used with installservice function.
# Requires parameters:
#   $1 - Name of service (without the .service extension)
# Requires environment variables:
#   installlogname - log file name
# Sets environment variables:
#   N/A
# Returns:
#   String value true or false
function serviceexists
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function serviceexists'
  systemctl list-units --full -all | grep -Fq "$1.service" >/dev/null 2>&1 && echo true || echo false
}

################################################################################
# Description:
#   Install a specified service. Assumes the service script for this service is
#   moved to /lib/systemd/system/. and that the matching service application is
#   in the proper place (e.g., /usr/bin or /usr/local/bin).
# Requires parameters:
#   $1 - Service installed status string: true or false
#   $2 - Name of service (with the .service extension)
# Requires environment variables:
#   installlogname - log file name
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 1
function installservice
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installservice'
  export serviceinstalled=$1
  export servicename=$2
  # Is the service already installed? If so, just reload and done.
  systemctl daemon-reload
  [[ ${serviceinstalled} = true ]] && return 0
  # Install/start the service.
  systemctl enable ${servicename}.service
  systemctl restart ${servicename}.service
  # Try for up to 30 seconds to wait for the service to start up.
  timeout=$( expr `date +%s` + 30 )
  while [ ! systemctl status ${servicename}.service >/dev/null 2>&1 -a $timeout -ge `date +%s`]; do sleep 2; done
  systemctl status ${servicename}.service >/dev/null 2>&1 || logmsg ${LINENO} "FATAL ERROR: Failed to start ${servicename} service"
}

################################################################################
# Description:
#   Install driveclient backup agent.
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
#   agentrepoaddr - agent repository URL
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1 or exit code 1
function installagent
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installagent'
return 0
  logmsg ${LINENO} "Agent installation: ${thearchitecture}: ${theflavor} ${theversion}"
  # Capture agent installation status.
  export agentinstalled=`serviceexists driveclient`
  # Compare local/production agent version and install-and-quit if local is stale.
  export localagentversion=unknown
  [[ -x /usr/local/bin/driveclient ]] && localagentversion=`/usr/local/bin/driveclient --version 2>/dev/null | head -1 | cut -d' ' -f2`
  export prodagentversion=`curl ${agentrepoaddr}/version.txt 2>/dev/null`
  [[ "${localagentversion}" = "${prodagentversion}" ]] && logmsg ${LINENO} "Agent already up-to-date: ${localagentversion}" && return 0
  logmsg ${LINENO} "Local agent version ${localagentversion} is stale (does not match production version ${prodagentversion})"
  export agenttarfile=driveclient-${prodagentversion}.tar.bz2
  curl -O ${agentrepoaddr}/tar/${agenttarfile} || logmsg ${LINENO} "FATAL ERROR: Failed download ${agenttarfile} agent tar file"
  tar jxvf ${agenttarfile}
  export agenttarfolder=driveclient-${prodagentversion}
  [[ ! -d ${agenttarfolder} ]] && logmsg ${LINENO} "FATAL ERROR: Failed to extract ${agenttarfile} agent tar file"
  # Move agent files to the proper places.
  [[ -d /etc/driveclient ]] || mkdir /etc/driveclient
  mv ${agenttarfolder}/driveclient /usr/local/bin/.
  mv ${agenttarfolder}/cacert.pem /etc/driveclient/.
  mv ${agenttarfolder}/driveclient.service.d.script /lib/systemd/system/driveclient.service
  # TODO: EVENTUALLY THE AGENT MAY INSTALL THE v4driveclient BINARY
  # Register driveclient.
  python -c "import os; os.system('/usr/local/bin/driveclient $*'.replace(' --user ',' --username '))"
  # Install driveclient as a service.
  installservice ${agentinstalled} driveclient
  logmsg ${LINENO} 'Finished agent install'
}

################################################################################
# Description:
#   Install updater for all Linux flavors that use systemctl.
# Requires parameters:
#   N/A
# Requires environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 1 (via called functions)
function installupdater
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installupdater'
return 0
  logmsg ${LINENO} "Updater installation: ${thearchitecture}: ${theflavor} ${theversion}"
  checkforupdates || return 0
  # Capture updater installation status.
  export updaterinstalled=`serviceexists cbu-updater`
  # Copy/move updater files to their places.
  # TODO: MUST FIX THIS WHEN WE CHANGE THE BINARY/SCRIPT UPDATER NAMES IN THE TARBALL
  cp ${thebasefolder}/cloudbackup-updater /usr/bin/. || logmsg ${LINENO} "FATAL ERROR: copy failed ${thebasefolder}/cloudbackup-updater to /usr/bin/."
  mv ${thebasefolder}/cbu-updater-service /usr/bin/. || logmsg ${LINENO} "FATAL ERROR: move failed ${thebasefolder}/cbu-updater-service to /usr/bin/."
  mv ${thebasefolder}/cloudbackup-updater-py.service.d.script /lib/systemd/system/cbu-updater.service || logmsg ${LINENO} "FATAL ERROR: move failed ${thebasefolder}/cloudbackup-updater-py.service.d.script to /lib/systemd/system/cbu-updater.service"
  installservice ${updaterinstalled} cbu-updater
  logmsg ${LINENO} 'Finished updater install'
}

################################################################################
# Description:
#   Install nscd for all Linux flavors that have the sssd bug.
# Requires parameters:
#   N/A
# Requires environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 1
function installnscd
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function installnscd'
return 0
  logmsg ${LINENO} "nscd installation: ${thearchitecture}: ${theflavor} ${theversion}"
  systemctl status nscd >/dev/null 2>&1 && logmsg ${LINENO} 'Package nscd found' && return 0
  apt -y update >/dev/null 2>&1
  apt -y install bzip2 nscd >/dev/null 2>&1
  systemctl enable nscd >/dev/null 2>&1
  systemctl start nscd >/dev/null 2>&1
  systemctl status nscd >/dev/null 2>&1 || logmsg ${LINENO} 'FATAL ERROR: Unable to install required package nscd'
  logmsg ${LINENO} 'Finished nscd install'
}

################################################################################
# Description:
#   Install from a tarball.
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1 or exit code 0/1 (via called functions)
function tarinstall
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function tarinstall'
  logmsg ${LINENO} "Install tar ${thearchitecture}"
  case ${thearchitecture} in
    v2) installagent $*; installupdater;;
    v3) installnscd; installagent $*; installupdater;;
    *)  logmsg ${LINENO} "WARNING: tar install on unidentified architecture: ${thearchitecture}: ${theflavor} ${theversion}"
        installlegacy $*;;
  esac
  logmsg ${LINENO} 'Finished tar install'
}

################################################################################
# Description:
#   Check for updater/agent updates. Compare local/production updater version
#   and indicate whether local is stale.
# Requires parameters:
#   N/A
# Requires environment variables:
#   agentrepoaddr - the address of agent repository
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1 indicating stale (0) or up-to-date (1)
function checkforupdates
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function checkforupdates'
  export localupdaterversion=unknown
  [[ -x /usr/bin/cloudbackup-updater ]] && localupdaterversion=`/usr/bin/cloudbackup-updater --version 2>/dev/null | head -1 | cut -d' ' -f2`
  export produpdaterversion=`curl ${agentrepoaddr}/updater-version.txt 2>/dev/null`
  [[ "${localupdaterversion}" = "${produpdaterversion}" ]] && logmsg ${LINENO} "Updater already up-to-date: ${localupdaterversion}" && return 1
  logmsg ${LINENO} "Local updater version ${localupdaterversion} is stale (does not match production version ${produpdaterversion})"
  return 0
}

################################################################################
# Description:
#   Check for updater/agent updates and install-and-quit if local is stale.
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0/1 or exit code 0/1 (depending on called functions)
function normalupdate
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function normalupdate'
return 0
  logmsg ${LINENO} "Normal update installation: ${thearchitecture}: ${theflavor} ${theversion}"
  installagent $*
  installupdater
}

################################################################################
# Description:
#   Installs updater on virgin server. If registration parameters are passed,
#   register the agent. When this is done, a new installation of both updater
#   and agent should be up and running. Downloads the tarballs to install each.
#   Note that the agent is installed and registered indirectly by calling the
#   setup script from the downloaded tarball.
# Requires parameters:
#   $* - Parameters passed to this script (typically either registration
#     parameters or nothing)
# Requires environment variables:
#   agentrepoaddr - the address of agent repository
#   theflavor - operating system flavor
#   theversion - operating system version
#   thearchitecture - binary architecture (v2/v3)
# Sets environment variables:
#   N/A
# Returns:
#   Exit code 0/1
function virgininstall
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function virgininstall'
  logmsg ${LINENO} "Updater fresh installation: ${thearchitecture}: ${theflavor} ${theversion}"
  # Download the current production updater, extract it, and launch the setup script.
  export produpdaterversion=`curl ${agentrepoaddr}/updater-version.txt 2>/dev/null`
  export updatertarfile=cloudbackup-updater-${produpdaterversion}.tar.bz2
  curl -O ${agentrepoaddr}/updater/${updatertarfile} || logmsg ${LINENO} "FATAL ERROR: Failed download ${updatertarfile} updater tar file"
  tar jxvf ${updatertarfile} >/dev/null 2>&1
  export updatertarfolder=cloudbackup-updater-${produpdaterversion}
  [[ ! -d ${updatertarfolder} ]] && logmsg ${LINENO} "FATAL ERROR: Failed to extract ${updatertarfile} updater tar file to ${updatertarfolder}"
  cd ${updatertarfolder} || logmsg ${LINENO} "FATAL ERROR: Failed to enter tar folder `realpath ${updatertarfolder}`: `pwd`"
# TODO: THIS cp COMMAND IS ONLY FOR TESTING PURPOSES; REMOVE IT
pwd
[[ ! -x cloudbackup-updater.a ]] && [[ -x cloudbackup-updater ]] && mv cloudbackup-updater cloudbackup-updater.a
[[ -x ~/cloudbackup-updater.setup ]] && ( cp -f ~/cloudbackup-updater.setup cloudbackup-updater || logmsg ${LINENO} "FATAL ERROR: copy failed ~/cloudbackup-updater.setup to `pwd`/cloudbackup-updater" )
echo "YOU ARE HERE: `pwd`"
ls -la
logmsg ${LINENO} 'ENTERING ANOTHER SCRIPT'
  ./cloudbackup-updater $* || logmsg ${LINENO} "FATAL ERROR: Failed to run ${updatertarfolder}/cloudbackup-updater"
  logmsg ${LINENO} 'Finished fresh installation.'
}

################################################################################
# Description:
#   Shut down a running updater service. If necessary, send a kill signal.
# Requires parameters:
#   $* - updater service name(s) to stop
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0
function sendkill
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function sendkill'
  for i in $*; do
    systemctl status $i >/dev/null 2>&1 && systemctl stop $i >/dev/null 2>&1 && return 0
  done
  for i in $*; do
    # Make sure updater service is running. If not, we're done.
    ps -ef | grep $i | grep python >/dev/null 2>&1 || return 0
    # Get the pid of the updater service.
    pidnum=`ps -ef | grep $i | grep python | awk '{ print $2 }'`
    # Try to kill the updater service.
    [[ ${pidnum} -gt 0 ]] && kill ${pidnum}
    # Wait for updater service to finish.
    timeout=$( expr `date +%s` + 30 )
    while [ ! ps -ef | grep $i | grep python >/dev/null 2>&1 -a $timeout -ge `date +%s`]; do sleep 2; done
    ps -ef | grep $i | grep python >/dev/null 2>&1 || return 0
    # If it still won't go away, do a sure-kill.
    pidnum=`ps -ef | grep $i | grep python | awk '{ print $2 }'`
    [[ ${pidnum} -gt 0 ]] && kill -9 ${pidnum}
  done
}

################################################################################
# Description:
#   Display help for this script.
# Requires parameters:
#   N/A
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0
function displayhelp
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function displayhelp'
  echo 'syntax:
  --help
  --version
  --shutdown
  --configure --username <username> --apikey <apiKey> --flavor <flavor> --datacenter <dataCenter> --apihost <apiDrivesrvr> --force
  ' >&2
}

################################################################################
# Description:
#   Print version information to stdout.
# Requires parameters:
#   N/A
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   string with version information
function printversioninfo
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function printversioninfo'
  echo 'Version: UPDATER-BUILD-VERSION (UPDATER-BUILD-HASH)'
  echo 'Build Date: UPDATER-BUILD-DATE (UPDATER-BUILD-TYPE)'
}

################################################################################
# Description:
#   Parse script args. Fail on bad argv[1]. Immediately execute --help,
#   --shutdown, and --version commands and exit. Return to caller for empty or
#   --configure args.
# Requires parameters:
#   $1 - first argument passed to the script
# Requires environment variables:
#   N/A
# Sets environment variables:
#   N/A
# Returns:
#   Return code 0 or exit code 0/1
function parseparams
{
  [[ -v TRACE ]] && logmsg ${LINENO} 'function parseparams'
  if [ -z "$1" ]; then return 0; fi
  case $1 in
    --help|-h) displayhelp; exit 0;;
    --version|-v) printversioninfo; exit 0;;
    --configure|-c) return 0;;
    --shutdown|-s) sendkill cloudbackup-updater cbu-updater-service; exit 0;;
    *) logmsg ${LINENO} "FATAL ERROR: Unexpected parameter: $1";;
  esac
}

################################################################################
################################################################################
##                                 MAIN CODE                                  ##
################################################################################
################################################################################

export installlogname=/var/log/cbu-installer.log
export agentrepoaddr=http://agentrepo.drivesrvr.com
export thescriptname=`basename $0`
export thebasefolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
export theapikey=`parseapikey $*`
export installmode=`[[ -f ${thebasefolder}/cloudbackup-updater-py.service.d.script ]] && echo tar || ( [[ "${thebasefolder}" = "/usr/bin" ]] && echo existing || echo virgin )`
export PATH=${PATH}:${thebasefolder}
logmsg ${LINENO} "DEVELOPMENT `for i in $(printversioninfo); do echo -n $i' '; done`"
logmsg ${LINENO} "Updater setup executed from this folder: ${thebasefolder} with these parameters: $*."
logmsg ${LINENO} "Initial values: agent repo: ${agentrepoaddr} installer log: ${installlogname} script: ${thescriptname} install mode: ${installmode}"
parseparams $*
installdependencies
setostype
case ${installmode} in
  tar) tarinstall $*;;
  virgin) virgininstall $*;;
  existing) normalupdate $*;;
  unknown) logmsg ${LINENO} 'FATAL ERROR: unknown install mode';;
esac
logmsg ${LINENO} 'Finished'

