USE_SYSTEMD=0
_use_systemd=$(command -v systemctl 2>&1 >/dev/null && systemctl is-system-running)
case "$_use_systemd" in
  offline|unknown)
    USE_SYSTEMD=0
    ;;
  "")
    USE_SYSTEMD=0
    ;;
  *)
    USE_SYSTEMD=1
    ;;
esac

use_systemd()
{
  test $USE_SYSTEMD = 1
}

#!/bin/sh

PREFIX=/var/cfengine

package_type()
{
  echo depot
}

os_type()
{
  echo hpux
}

rc_d_path()
{
  echo "/sbin"
}

rc_start_level()
{
  echo S970
}

rc_kill_level()
{
  echo K050
}

platform_service()
{
  /sbin/init.d/"$1" "$2"
}

native_is_upgrade()
{
  test -f "$PREFIX/bin/cf-agent"
}
PKG_TYPE=depot
SCRIPT_TYPE=preremove
PROJECT_TYPE=cfengine-nova
BUILT_ON_OS=hpux
BUILT_ON_OS_VERSION=
# postgresql docs, https://www.postgresql.org/docs/current/locale.html, recommend using C locale unless otherwise needed
export LC_ALL=C # overrides all other env vars: https://www.gnu.org/software/libc/manual/html_node/Locale-Categories.html
# Upgrade detection is a mess. It is often difficult to tell, especially from
# the postinstall script, so we use the package-upgrade.txt file to remember.
case "$PKG_TYPE" in
  depot|deb|bff)
    case "$SCRIPT_TYPE" in
      preinstall|preremove)
        if native_is_upgrade; then
          mkdir -p "$PREFIX"
          echo "File used by CFEngine during package upgrade. Can be safely deleted." > "$PREFIX/package-upgrade.txt"
        else
          rm -f "$PREFIX/package-upgrade.txt"
        fi
        alias is_upgrade='native_is_upgrade'
        ;;
      postremove|postinstall)
        if [ -f "$PREFIX/package-upgrade.txt" ]; then
          if [ "$SCRIPT_TYPE" = "postinstall" ]; then
            rm -f "$PREFIX/package-upgrade.txt"
          fi
          alias is_upgrade='true'
        else
          alias is_upgrade='false'
        fi
        ;;
    esac
    ;;
esac

get_cfengine_state() {
    if use_systemd; then
        systemctl list-units -l | sed -r -e '/^\s*(cf-[-a-z]+|cfengine3)\.service/!d' -e 's/\s*(cf-[-a-z]+|cfengine3)\.service.*/\1/'
    else
        platform_service cfengine3 status | awk '/is running/ { print $1 }'
    fi
}

restore_cfengine_state() {
    # $1 -- file where the state to restore is saved (see get_cfengine_state())

    if use_systemd; then
        for service in `cat "$1"`; do
            definition=`systemctl cat "$service"` || continue
            # only try to start service that are defined/exist (some may be gone
            # in the new version)
            if [ -n "$definition" ]; then
                systemctl start "$service" || echo "Failed to start service $service"
            fi
        done
    else
        CALLED_FROM_STATE_RESTORE=1
        if [ -f ${PREFIX}/bin/cfengine3-nova-hub-init-d.sh ]; then
            . ${PREFIX}/bin/cfengine3-nova-hub-init-d.sh
            if grep postgres "$1" >/dev/null; then
                start_postgres >/dev/null || echo "Failed to start PostgreSQL"
            fi
            if grep httpd "$1" >/dev/null; then
                start_httpd >/dev/null || echo "Failed to start Apache"
            fi
        fi

        for d in `grep 'cf-' "$1"`; do
            if [ -f ${PREFIX}/bin/${d} ]; then
                ${PREFIX}/bin/${d} || echo "Failed to start $d"
            fi
        done
    fi
}

wait_for_cf_postgres() {
    # wait for CFEngine Postgresql service to be available, up to 60 sec.
    # Returns 0 is psql command succeeds,
    # Returns non-0 otherwise (1 if exited by timeout)
    for i in $(seq 1 60); do
        true "checking if Postgresql is available..."
        if cd /tmp && su cfpostgres -c "$PREFIX/bin/psql -l" >/dev/null 2>&1; then
            true "Postgresql is available, moving on"
            return 0
        fi
        true "waiting 1 sec for Postgresql to become available..."
        sleep 1
    done
    # Note: it is important that this is the last command of this function.
    # Return code of `psql` is the return code of whole function.
    cd /tmp && su cfpostgres -c "$PREFIX/bin/psql -l" >/dev/null 2>&1
}

wait_for_cf_postgres_down() {
    # wait for CFEngine Postgresql service to be shutdown, up to 60 sec.
    # Returns 0 if postgresql service is not running
    # Returns non-0 otherwise (1 if exited by timeout)
    for i in $(seq 1 60); do
        true "checking if Postgresql is shutdown..."
        if cd /tmp && ! su cfpostgres -c "$PREFIX/bin/psql -l" >/dev/null 2>&1; then
            true "Postgresql is shutdown, moving on"
            return 0
        fi
        true "waiting 1 sec for Postgresql to shutdown..."
        sleep 1
    done
    # Note: it is important that this is the last command of this function.
    # Return code of `psql` is the return code of whole function.
    cd /tmp && ! su cfpostgres -c "$PREFIX/bin/psql -l" >/dev/null 2>&1
}

cf_agent_pids() {
    # Prints the PIDs of running cf-agent processes, except our own ancestors
    # (cf-agent may be running this package upgrade) and, where /proc tells
    # us, processes in other mount namespaces (containers).
    _ancestors=" "
    _pid=$$
    while [ -n "$_pid" ] && [ "$_pid" -gt 1 ]; do
        _ancestors="$_ancestors$_pid "
        _pid=$(ps -o ppid= -p "$_pid" 2>/dev/null | tr -d ' ')
    done
    _ns=$(readlink /proc/self/ns/mnt 2>/dev/null || true)
    for _pid in $(pgrep -x cf-agent); do
        case "$_ancestors" in
            *" $_pid "*) continue ;;
        esac
        if [ -z "$_ns" ] || [ "$(readlink /proc/$_pid/ns/mnt 2>/dev/null)" = "$_ns" ]; then
            echo "$_pid"
        fi
    done
}

terminate_cf_agents() {
    # Call after stopping cf-execd. Stopping cf-execd doesn't stop an agent it
    # started (systemd KillMode=process), and that agent can keep changing
    # things, like permissions under state/pg (ENT-14899). Gives running agents
    # up to 600s to finish, then kills them. Fails if it can't check for agents
    # or can't kill them.
    if ! command -v pgrep >/dev/null; then
        cf_console echo "Error: pgrep not found, can't check for running cf-agent"
        return 1
    fi
    _pids=$(cf_agent_pids)
    if [ -z "$_pids" ]; then
        return 0
    fi
    _timeout=600
    cf_console echo "Waiting up to ${_timeout}s for cf-agent to finish:"
    cf_console ps -o pid,etime,args -p "$(echo $_pids | tr ' ' ',')" || true
    _waited=0
    while [ -n "$(cf_agent_pids)" ] && [ "$_waited" -lt "$_timeout" ]; do
        sleep 5
        _waited=$((_waited + 5))
    done
    # Killing an agent can let the shell cf-execd started it from run the next
    # one (update.cf, then promises.cf), so check a few times.
    for _try in 1 2 3; do
        _pids=$(cf_agent_pids)
        if [ -z "$_pids" ]; then
            return 0
        fi
        cf_console echo "Warning: killing cf-agent(s) still running after ${_timeout}s:"
        cf_console ps -o pid,etime,args -p "$(echo $_pids | tr ' ' ',')" || true
        kill -KILL $_pids 2>/dev/null || true
        sleep 1
    done
    _pids=$(cf_agent_pids)
    if [ -n "$_pids" ]; then
        cf_console echo "Error: cf-agent(s) still running after being killed:"
        cf_console ps -o pid,etime,args -p "$(echo $_pids | tr ' ' ',')" || true
        return 1
    fi
}

safe_cp() {
    # "safe" alternative to `cp`. Tries `cp -al` first, and if it fails - `cp -a`.
    # Deletes partially-copied files if copy operation fails.
    # Args:
    #   * dir you're copying stuff from
    #   * name of stuff you're copying (one arg!)
    #   * dir you're copying stuff to
    # Example: instead of
    #   cp "$PREFIX/state/pg/data" "$BACKUP_DIR"
    # use
    #   safe_cp "$PREFIX/state/pg" data "$BACKUP_DIR"
    test "$#" -eq 3 || return 2
    from="$1"
    name="$2"
    to="$3"
    # First, try copying files creating hardlinks
    # Do not print errors - we'll do it another way
    if cp -al "$from/$name" "$to" 2>/dev/null; then
        # Copy succeeded
        return 0
    fi
    echo "Copy creating hardlinks failed, removing partially-copied data and trying simple copy"
    rm -rf "$to/$name"
    if cp -a "$from/$name" "$to"; then
        # Copy succeeded
        return 0
    fi
    echo "Copy failed, so removing partially-copied data and aborting"
    rm -rf "$to/$name"
    return 1
}

safe_cp_nolink() {
    # Like `safe_cp`, but never creates hardlinks, so the copy does not share
    # mode and owner with the source. Args are same as in safe_cp.
    test "$#" -eq 3 || return 2
    from="$1"
    name="$2"
    to="$3"
    if cp -a "$from/$name" "$to"; then
        return 0
    fi
    echo "Copy failed, so removing partially-copied data and aborting"
    rm -rf "$to/$name"
    return 1
}

safe_mv() {
    # "safe" alternative to `mv`. Executes `safe_cp` and deletes source dir if
    # that succeeds.
    # Args are same as in safe_cp
    # Exampe: instead of
    #   mv "$PREFIX/state/pg/data" "$BACKUP_DIR"
    # use
    #   safe_mv "$PREFIX/state/pg" data "$BACKUP_DIR"
    test "$#" -eq 3 || return 2
    from="$1"
    name="$2"
    to="$3"
    if safe_cp "$from" "$name" "$to"; then
        # Copy succeeded - so we can delete old dir
        rm -rf "$from/$name"
        return 0
    else
        # Copy failed (partially-copied data is removed by safe_cp)
        return 1
    fi
}

on_files() {
    # perform operation $1 on each file in $2 with optional extra argument $3
    # Examples:
    # to copy only files:
    #   on_files cp "$PREFIX/lib" "$BACKUP_DIR/lib"
    # to move only files:
    #   on_files mv "$PREFIX/lib" "$PREFIX/lib.new"
    # to remove only files:
    #   on_files rm "$PREFIX/lib"
    test "$#" -ge 2 || return 2
    # Split on newlines, not on spaces.
    IFS='
'
    for file in $(ls -a1 "$2"); do
        if [ -f "$2/$file" ]; then
            $1 "$2/$file" $3
        fi
    done
    # Restore normal splitting semantics.
    unset IFS
}


dir_is_empty() {
    # Returns 0 if directory $1 has no entries at all, hidden ones included.
    # Args:
    #   * directory to inspect
    test "$#" -eq 1 || return 2
    test -z "$(ls -A "$1" 2>/dev/null)"
}

dir_has_only_empty_dirs() {
    # Returns 0 if every entry in directory $1 is itself an empty directory.
    # After reset_dir() this is what nested mount points look like: their
    # contents were removed but the directories themselves survive.
    # Args:
    #   * directory to inspect
    test "$#" -eq 1 || return 2
    for entry in "$1"/* "$1"/.[!.]* "$1"/..?*; do
        test -e "$entry" || test -L "$entry" || continue
        test -d "$entry" || return 1
        dir_is_empty "$entry" || return 1
    done
    return 0
}

reset_dir() {
    # Empty a directory and make sure it exists afterwards.
    # The exit status of `rm -rf` is deliberately ignored: when the directory is
    # a mount point its contents are removed but the directory itself cannot be
    # (EBUSY). That is expected and harmless, so test the postcondition instead
    # of trusting the exit status.
    # Args:
    #   * directory to empty
    # Returns 0 if the directory exists and is empty afterwards, 1 otherwise.
    test "$#" -eq 1 || return 2
    rm -rf "$1" 2>/dev/null || true
    mkdir -p "$1" || return 1
    dir_is_empty "$1"
}
case `package_type` in
  rpm|deb)
    if is_upgrade; then
      # We want to skip removal scripts on upgrade.
      # However, non-rpm and non-deb package systems don't run removal scripts
      # on upgrade, so don't do it there (they would not detect upgrade
      # correctly in this situation anyway).
      exit 0
    fi
    ;;
esac
if [ -f "$PREFIX/CFENGINE_TEST_PACKAGE_SCRIPT.txt" ]; then
  # Special mode during testing. Dump some info for verification.
  (
    echo "new_script----"
    echo "script_type=$SCRIPT_TYPE"
    if is_upgrade; then
      echo "is_upgrade=1"
    else
      echo "is_upgrade=0"
    fi
  ) >> "$PREFIX/CFENGINE_TEST_PACKAGE_SCRIPT.log"
fi

is_community()
{
  test "$PROJECT_TYPE" = "cfengine-community"
}

is_nova()
{
  test "$PROJECT_TYPE" = "cfengine-nova" || test "$PROJECT_TYPE" = "cfengine-nova-hub"
}

case "`os_type`" in
    aix)
        INSTLOGGROUP="system"
        ;;
    *)
        INSTLOGGROUP="root"
        ;;
esac

INSTLOG="/var/log/CFEngine-Install-$(date '+%Y-%m-%d_%H:%M:%S_%Z').log"
mkdir -p "$(dirname "$INSTLOG")"
touch "$INSTLOG"
rm -f /var/log/CFEngineHub-Install.log
rm -f /var/log/CFEngine-Install.log
ln -s "$INSTLOG" /var/log/CFEngine-Install.log
chown root:$INSTLOGGROUP "$INSTLOG"
chmod 600 "$INSTLOG"
CONSOLE=7
# Redirect most output to log file, but keep console around for custom output.
case "$SCRIPT_TYPE" in
  pre*)
    eval "exec $CONSOLE>&1 > $INSTLOG 2>&1"
    ;;
  *)
    eval "exec $CONSOLE>&1 >> $INSTLOG 2>&1"
    ;;
esac
echo "$SCRIPT_TYPE:"

# Output directly to console, bypassing log.
cf_console()
{
  # Use subshell to prevent "set +x" from leaking out into the rest of the
  # execution.
  (
    set +x
    "$@" 1>&$CONSOLE 2>&$CONSOLE
  )
}

set -x
cf_console platform_service cfengine3 stop

case `os_type` in
  redhat)
    #
    # Unregister CFEngine initscript on uninstallation.
    #
    test -x /sbin/chkconfig && test -f /etc/init.d/cfengine3 && chkconfig --del cfengine3

    #
    # systemd support
    #
    use_systemd && systemctl disable cfengine3.service > /dev/null 2>&1

    #
    # Clean lock files created by initscript, if any
    #
    for i in cf-execd cf-serverd cf-monitord cf-hub cf-reactor; do
      rm -f /var/lock/$i /var/lock/subsys/$i
    done
    ;;

  solaris|hpux)
    rm -f `rc_d_path`/rc3.d/`rc_start_level`cfengine3 \
          `rc_d_path`/rc0.d/`rc_kill_level`cfengine3 \
          `rc_d_path`/rc1.d/`rc_kill_level`cfengine3 \
          `rc_d_path`/rc2.d/`rc_kill_level`cfengine3 \
          `rc_d_path`/rcS.d/`rc_kill_level`cfengine3
    ;;

  aix)
    /usr/bin/rm -f /etc/rc.d/rc2.d/K05cfengine3 /etc/rc.d/rc2.d/S97cfengine3
    ;;
esac

exit 0
