#!/bin/bash

# Display functions
print_welcome() {
    echo " 👋 Welcome to the Ferron 2.x installer for GNU/Linux!"
}

print_task() {
    echo -n "    $1"
}

print_task_success() {
    printf "\r"
    echo -n " ✅"
    printf "\n"
}

print_task_fail() {
    printf "\r"
    echo -n " 💥"
    printf "\n"
}

print_error() {
    echo " 😨 Error:"
    echo "$1" | awk '{print "      " $0}'
}

print_installation_failed() {
    echo " 😞 Installation failed. You might check the error message above."
}

print_installation_success() {
    echo " 🥳 Ferron is installed successfully! You can now access your newly-installed web server."
}

do_task() {
    print_task "$1"
    shift
    local TASK_OUTPUT_FILE
    local TASK_OUTPUT
    TASK_OUTPUT_FILE=$(mktemp /tmp/ferron-installer.XXXXXX)
    "$@" > "$TASK_OUTPUT_FILE" 2>&1
    TASK_EXIT_CODE=$?
    TASK_OUTPUT=$(cat "$TASK_OUTPUT_FILE")
    rm "$TASK_OUTPUT_FILE"
    if [ $TASK_EXIT_CODE -eq 0 ]; then
        print_task_success
    else
        print_task_fail
        print_error "$TASK_OUTPUT"
        print_installation_failed
        exit 1
    fi
}

read_input() {
   echo -n " ❓ $1: "
   read $2
}

# Tasks
update_package_lists() {
    case "$DISTRO" in
        "debian") DEBIAN_FRONTEND=noninteractive apt update;;
        "rhel") yum -y makecache;;
        "suse") zypper refresh;;
        "arch") pacman --noconfirm -Sy;;
        "alpine") apk update;;
        "freebsd") ASSUME_ALWAYS_YES=yes pkg update;;
        *) true
    esac
}

install_unzip() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y unzip;;
    "rhel") yum -y install unzip;;
    "suse") zypper install -y unzip;;
    "arch") pacman --noconfirm -S unzip;;
    "alpine") apk add --no-interactive unzip;;
    "freebsd") ASSUME_ALWAYS_YES=yes pkg install unzip;;
    *) echo "You need to install unzip manually" >&2
  esac
}

install_setcap() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y libcap2-bin;;
    "rhel") yum -y install libcap;;
    "suse") zypper install -y libcap-progs;;
    "arch") pacman --noconfirm -S libcap;;
    "alpine") apk add --no-interactive libcap-setcap;;
    "freebsd") echo "Your OS doesn't support setcap" >&2;;
    *) echo "You need to install setcap manually" >&2
  esac
}

install_curl() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y curl;;
    "rhel") yum -y install curl;;
    "suse") zypper install -y curl;;
    "arch") pacman --noconfirm -S curl;;
    "alpine") apk add --no-interactive curl;;
    "freebsd") ASSUME_ALWAYS_YES=yes pkg install curl;;
    *) echo "You need to install curl manually" >&2
  esac
}

install_runuser() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y util-linux;;
    "rhel") yum -y install util-linux;;
    "suse") zypper install -y util-linux;;
    "arch") pacman --noconfirm -S util-linux;;
    "alpine") apk add --no-interactive runuser;;
    "freebsd") echo "Your OS might not support runuser" >&2;;
    *) echo "You need to install runuser manually" >&2
  esac
}

determine_distro() {
    local OS="$(uname -s)"
    if [ "$OS" == "Linux" ]; then
      if [ -f /etc/redhat-release ] ; then
        DISTRO=rhel
      elif [ -f /etc/SuSE-release ] ; then
        DISTRO=suse
      elif [ -f /etc/debian_version ] ; then
        DISTRO=debian
      elif [ -f /etc/arch-release ] ; then
        DISTRO=arch
      elif [ -f /etc/alpine-release ] ; then
        DISTRO=alpine
      else
        DISTRO=other
      fi
    elif [ "$OS" == "FreeBSD" ]; then
      DISTRO=freebsd
    else
      DISTRO=other
    fi
}

check_prerequisities() {
    if [ "$(id -u)" != "0" ]; then
      echo 'You need to have root privileges to install Ferron' >&2
      return 1
    fi
    determine_distro
    local UPDATED_LISTS
    if type curl > /dev/null 2>/dev/null; then
        USE_CURL=1
    elif type wget > /dev/null 2>/dev/null; then
        USE_WGET=1
    else
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_curl
        if type curl > /dev/null 2>/dev/null; then
            USE_CURL=1
        elif type wget > /dev/null 2>/dev/null; then
            USE_WGET=1
        else
            echo "Neither curl nor wget is installed. You might install one of them using your package manager." >&2
            return 1
        fi
    fi
    if ! type unzip > /dev/null 2>/dev/null; then
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_unzip
        if ! type unzip > /dev/null 2>/dev/null; then
          echo "unzip is not installed. You might install unzip using your package manager." >&2
          return 1
        fi
    fi
    if (! type systemctl > /dev/null 2>/dev/null) && (! type setcap > /dev/null 2>/dev/null); then
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_setcap
        if (! type systemctl > /dev/null 2>/dev/null) && (! type setcap > /dev/null 2>/dev/null); then
            echo "setcap is not installed, but it's required for non-systemd systems. You might install setcap using your package manager." >&2
            return 1
        fi
    fi
    if (! type systemctl > /dev/null 2>/dev/null) && (! type runuser > /dev/null 2>/dev/null); then
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_runuser
        if (! type systemctl > /dev/null 2>/dev/null) && (! type runuser > /dev/null 2>/dev/null); then
            echo "runuser is not installed, but it's required for non-systemd systems. You might install runuser using your package manager." >&2
            return 1
        fi
    fi
    return 0
}

download_ferron_zip() {
        # Detect the machine architecture
        local ARCH
        ARCH=$(uname -m)

        # Normalize architecture name
        case "$ARCH" in
            x86_64) ARCH="x86_64" ;;
            i386 | i486 | i586 | i686) ARCH="i686" ;;
            armv7*) ARCH="armv7" ;;
            aarch64) ARCH="aarch64" ;;
            riscv64) ARCH="riscv64gc" ;;
            s390x) ARCH="s390x" ;;
            ppc64le) ARCH="powerpc64le" ;;
            *) echo "Unknown architecture: $ARCH" &>2; return 1 ;;
        esac

        # Detect the operating system
        local OS
        OS=$(uname -s)

        case "$OS" in
            Linux) OS="linux" ;;
            FreeBSD) OS="freebsd" ;;
            *) echo "Unknown OS: $OS" &>2; return 1 ;;
        esac

        # Detect the C library
        local LIBC
        if [ "$OS" = "linux" ]; then
            if ldd --version 2>&1 | grep -q "musl"; then
                LIBC="musl"
            else
                LIBC="gnu"
            fi
        else
            LIBC=""
        fi

        # Detect the ABI
        local ABI
        if [ "$ARCH" = "armv7" ]; then
            ABI="eabihf"
        else
            ABI=""
        fi

        # Construct the target triple
        local TARGET_TRIPLE
        if [ -n "$LIBC" ]; then
          TARGET_TRIPLE="${ARCH}-unknown-${OS}-${LIBC}${ABI}"
        elif [ -n "$ABI" ]; then
          TARGET_TRIPLE="${ARCH}-unknown-${OS}-${ABI}"
        else
          TARGET_TRIPLE="${ARCH}-unknown-${OS}"
        fi

        local FERRON_DOWNLOAD_COMMAND_AND_PARAMS
        if [ "$USE_WGET" = "1" ]; then
          FERRON_VERSION="$(wget -qO- https://dl.ferron.sh/latest2.ferron)"
          FERRON_DOWNLOAD_COMMAND_AND_PARAMS="wget -O-"
        elif [ "$USE_CURL" = "1" ]; then
          FERRON_VERSION="$(curl -fsL https://dl.ferron.sh/latest2.ferron)"
          FERRON_DOWNLOAD_COMMAND_AND_PARAMS="curl -fsSL"
        fi
        if [ "$FERRON_VERSION" = "" ]; then
          echo 'There was a problem while determining latest Ferron version!' >&2
          return 1
        fi
        FERRON_ZIP_ARCHIVE="$(mktemp /tmp/ferron.XXXXXX)"
        mv "$FERRON_ZIP_ARCHIVE" "$FERRON_ZIP_ARCHIVE.zip"
        FERRON_ZIP_ARCHIVE="$FERRON_ZIP_ARCHIVE.zip"
        if ! $FERRON_DOWNLOAD_COMMAND_AND_PARAMS "https://dl.ferron.sh/$FERRON_VERSION/ferron-$FERRON_VERSION-$TARGET_TRIPLE.zip" > $FERRON_ZIP_ARCHIVE; then
          echo 'There was a problem while downloading latest Ferron version!' >&2
          return 1
        fi
}

invalid_installation_type() {
  echo 'Invalid Ferron installation type.' >&2
  return 1
}

copy_ferron_files() {
    FERRON_EXTRACTION_DIRECTORY="$(mktemp -d /tmp/ferron.XXXXXX)"
    echo $INSTALLATION_CHANNEL > /etc/.ferron-installer.prop || return 1
    if [ "$FERRON_VERSION" != "" ]; then
      echo "$FERRON_VERSION" > /etc/.ferron-installer.version || return 1
    fi
    unzip $FERRON_ZIP_ARCHIVE -d $FERRON_EXTRACTION_DIRECTORY || return 1
    if [ "$INSTALLATION_CHANNEL" != "manual" ]; then
      rm -f $FERRON_ZIP_ARCHIVE  || return 1
    fi
    mkdir -p /var/log/ferron || return 1
    mkdir -p /var/lib/ferron || return 1
    mkdir -p /var/www || return 1
    if ! [ -d /var/www/ferron ]; then
      mv $FERRON_EXTRACTION_DIRECTORY/wwwroot /var/www/ferron || return 1
    fi
    mv $FERRON_EXTRACTION_DIRECTORY/ferron{,-*} /usr/sbin || return 1
    chown root:root /usr/sbin/ferron{,-*} || return 1
    chmod a+rx /usr/sbin/ferron{,-*} || return 1
    rm -rf $FERRON_EXTRACTION_DIRECTORY || return 1
    return 0
}

create_ferron_configuration() {
    (cat > /etc/ferron.kdl << 'EOF'
// See https://v2.ferronweb.org/docs/configuration-kdl for the configuration reference
* {
  // Set implicit HTTP port, and disable HTTPS
  default_http_port 80
  default_https_port #null

  // Webroot, from where static files are served
  root "/var/www/ferron"

  // Server logs
  log "/var/log/ferron/access.log"
  error_log "/var/log/ferron/error.log"
}
EOF
    ) || return 1
    chmod a+r /etc/ferron.kdl || return 1
}

create_ferron_user() {
    if type useradd &>/dev/null; then
        useradd -d /var/lib/ferron -m -s /usr/sbin/nologin ferron || return 1
    else
        # useradd is not available for instance on Alpine Linux
        adduser --home /var/lib/ferron --shell /usr/sbin/nologin --disabled-password ferron || return 1
    fi
    chown -hR ferron:ferron /var/log/ferron || return 1
    chown -hR ferron:ferron /var/lib/ferron || return 1
    chown -hR ferron:ferron /var/www/ferron || return 1
    find /var/log/ferron -type d -exec chmod 755 {} \; || return 1
    find /var/log/ferron -type f -exec chmod 644 {} \; || return 1
    find /var/www/ferron -type d -exec chmod 755 {} \; || return 1
    find /var/www/ferron -type f -exec chmod 644 {} \; || return 1
}

install_updater() {
  (cat > /usr/bin/ferron-updater << 'EOF'
# Display functions
print_welcome() {
    echo " 👋 Welcome to the Ferron 2.x updater for GNU/Linux!"
}

print_task() {
    echo -n "    $1"
}

print_task_success() {
    printf "\r"
    echo -n " ✅"
    printf "\n"
}

print_task_fail() {
    printf "\r"
    echo -n " 💥"
    printf "\n"
}

print_error() {
    echo " 😨 Error:"
    echo "$1" | awk '{print "      " $0}'
}

print_update_failed() {
    echo " 😞 Update failed. You might check the error message above."
}

print_update_success() {
    echo " 🥳 Ferron is updated successfully!"
}

print_update_latest() {
    echo " 🥳 Ferron is already up to date!"
}

do_task() {
    print_task "$1"
    shift
    local TASK_OUTPUT_FILE
    local TASK_OUTPUT
    TASK_OUTPUT_FILE=$(mktemp /tmp/ferron-installer.XXXXXX)
    $* > "$TASK_OUTPUT_FILE" 2>&1
    TASK_EXIT_CODE=$?
    TASK_OUTPUT=$(cat "$TASK_OUTPUT_FILE")
    rm "$TASK_OUTPUT_FILE"
    if [ $TASK_EXIT_CODE -eq 0 ]; then
        print_task_success
    else
        print_task_fail
        print_error "$TASK_OUTPUT"
        print_update_failed
        exit 1
    fi
}

read_input() {
   echo -n " ❓ $1: "
   read $2
}

# Tasks
update_package_lists() {
    case "$DISTRO" in
        "debian") DEBIAN_FRONTEND=noninteractive apt update;;
        "rhel") yum -y makecache;;
        "suse") zypper refresh;;
        "arch") pacman --noconfirm -Sy;;
        "alpine") apk update;;
        "freebsd") ASSUME_ALWAYS_YES=yes pkg update;;
        *) true
    esac
}

install_unzip() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y unzip;;
    "rhel") yum -y install unzip;;
    "suse") zypper install -y unzip;;
    "arch") pacman --noconfirm -S unzip;;
    "alpine") apk add --no-interactive unzip;;
    "freebsd") ASSUME_ALWAYS_YES=yes pkg install unzip;;
    *) echo "You need to install unzip manually" >&2
  esac
}

install_curl() {
  case "$DISTRO" in
    "debian") DEBIAN_FRONTEND=noninteractive apt install -y curl;;
    "rhel") yum -y install curl;;
    "suse") zypper install -y curl;;
    "arch") pacman --noconfirm -S curl;;
    "alpine") apk add --no-interactive curl;;
    "freebsd") ASSUME_ALWAYS_YES=yes pkg install curl;;
    *) echo "You need to install curl manually" >&2
  esac
}

check_prerequisities() {
    if [ "$(id -u)" != "0" ]; then
      echo 'You need to have root privileges to update Ferron' >&2
      return 1
    fi
    if ! [ -f /usr/sbin/ferron ]; then
      echo 'Ferron isn'"'"'t installed (or it'"'"'s installed without using Ferron installer)!' >&2
      return 1
    fi
    determine_distro
    local UPDATED_LISTS
    if type curl > /dev/null 2>/dev/null; then
        USE_CURL=1
    elif type wget > /dev/null 2>/dev/null; then
        USE_WGET=1
    else
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_curl
        if type curl > /dev/null 2>/dev/null; then
            USE_CURL=1
        elif type wget > /dev/null 2>/dev/null; then
            USE_WGET=1
        else
            echo "Neither curl nor wget is installed. You might install one of them using your package manager." >&2
            return 1
        fi
    fi
    if ! type unzip > /dev/null 2>/dev/null; then
        if [ "$UPDATED_LISTS" != "1" ]; then
          update_package_lists
          UPDATED_LISTS=1
        fi
        install_unzip
        if ! type unzip > /dev/null 2>/dev/null; then
          echo "unzip is not installed. You might install unzip using your package manager." >&2
          return 1
        fi
    fi

    if ! [ -f /etc/.ferron-installer.prop ]; then
      echo manual > /etc/.ferron-installer.prop;
    fi

    INSTALLATION_CHANNEL="$(cat /etc/.ferron-installer.prop)"

    return 0
}

download_ferron_zip() {
        # Detect the machine architecture
        local ARCH
        ARCH=$(uname -m)

        # Normalize architecture name
        case "$ARCH" in
            x86_64) ARCH="x86_64" ;;
            i386 | i486 | i586 | i686) ARCH="i686" ;;
            armv7*) ARCH="armv7" ;;
            aarch64) ARCH="aarch64" ;;
            riscv64) ARCH="riscv64gc" ;;
            s390x) ARCH="s390x" ;;
            ppc64le) ARCH="powerpc64le" ;;
            *) echo "Unknown architecture: $ARCH" &>2; return 1 ;;
        esac

        # Detect the operating system
        local OS
        OS=$(uname -s)

        case "$OS" in
            Linux) OS="linux" ;;
            FreeBSD) OS="freebsd" ;;
            *) echo "Unknown OS: $OS" &>2; return 1 ;;
        esac

        # Detect the C library
        local LIBC
        if [ "$OS" = "linux" ]; then
            if ldd --version 2>&1 | grep -q "musl"; then
                LIBC="musl"
            else
                LIBC="gnu"
            fi
        else
            LIBC=""
        fi

        # Detect the ABI
        local ABI
        if [ "$ARCH" = "armv7" ]; then
            ABI="eabihf"
        else
            ABI=""
        fi

        # Construct the target triple
        local TARGET_TRIPLE
        if [ -n "$LIBC" ]; then
          TARGET_TRIPLE="${ARCH}-unknown-${OS}-${LIBC}${ABI}"
        elif [ -n "$ABI" ]; then
          TARGET_TRIPLE="${ARCH}-unknown-${OS}-${ABI}"
        else
          TARGET_TRIPLE="${ARCH}-unknown-${OS}"
        fi

        local FERRON_DOWNLOAD_COMMAND_AND_PARAMS
        if [ "$USE_WGET" = "1" ]; then
          FERRON_VERSION="$(wget -qO- https://dl.ferron.sh/latest2.ferron)"
          FERRON_DOWNLOAD_COMMAND_AND_PARAMS="wget -O-"
        elif [ "$USE_CURL" = "1" ]; then
          FERRON_VERSION="$(curl -fsL https://dl.ferron.sh/latest2.ferron)"
          FERRON_DOWNLOAD_COMMAND_AND_PARAMS="curl -fsSL"
        fi
        if [ "$FERRON_VERSION" = "" ]; then
          echo 'There was a problem while determining latest Ferron version!' >&2
          return 1
        fi
        FERRON_ZIP_ARCHIVE="$(mktemp /tmp/ferron.XXXXXX)"
        mv "$FERRON_ZIP_ARCHIVE" "$FERRON_ZIP_ARCHIVE.zip"
        FERRON_ZIP_ARCHIVE="$FERRON_ZIP_ARCHIVE.zip"
        if ! $FERRON_DOWNLOAD_COMMAND_AND_PARAMS "https://dl.ferron.sh/$FERRON_VERSION/ferron-$FERRON_VERSION-$TARGET_TRIPLE.zip" > $FERRON_ZIP_ARCHIVE; then
          echo 'There was a problem while downloading latest Ferron version!' >&2
          return 1
        fi
}

invalid_installation_type() {
  echo 'Invalid Ferron installation type.' >&2
  return 1
}

copy_ferron_files() {
    FERRON_EXTRACTION_DIRECTORY="$(mktemp -d /tmp/ferron.XXXXXX)"
    echo $INSTALLATION_CHANNEL > /etc/.ferron-installer.prop || return 1
    if [ "$FERRON_VERSION" != "" ]; then
      echo "$FERRON_VERSION" > /etc/.ferron-installer.version || return 1
    fi
    unzip $FERRON_ZIP_ARCHIVE -d $FERRON_EXTRACTION_DIRECTORY || return 1
    if [ "$INSTALLATION_CHANNEL" != "manual" ]; then
      rm -f $FERRON_ZIP_ARCHIVE  || return 1
    fi
    mv $FERRON_EXTRACTION_DIRECTORY/ferron{,-*} /usr/sbin || return 1
    chown root:root /usr/sbin/ferron{,-*} || return 1
    chmod a+rx /usr/sbin/ferron{,-*} || return 1
    rm -rf $FERRON_EXTRACTION_DIRECTORY || return 1
    return 0
}

fix_selinux_context() {
    restorecon -r /usr/sbin/ferron{,-*} /usr/bin/ferron-updater /etc/ferron.kdl /var/www/ferron /var/log/ferron /var/lib/ferron || return 1
}

stop_ferron() {
    if ! type systemctl > /dev/null 2>&1; then
      /etc/init.d/ferron stop || return 1
    else
      systemctl stop ferron || return 1
    fi
}

restart_ferron() {
    if ! type systemctl > /dev/null 2>&1; then
      /etc/init.d/ferron start || return 1
    else
      systemctl start ferron || return 1
    fi
}

# Welcome message
print_welcome

# Execute tasks
do_task 'Checking prerequisites and installing required packages' check_prerequisities
if [ "$INSTALLATION_CHANNEL" = "stable" ]; then
  do_task 'Downloading Ferron ZIP archive' download_ferron_zip
  FERRON_CURRENT_VERSION="$(cat /etc/.ferron-installer.version)"
  if [ "$FERRON_CURRENT_VERSION" = "$FERRON_VERSION" ]; then
    rm -f $FERRON_ZIP_ARCHIVE
    print_update_latest
    exit 0
  fi
elif [ "$INSTALLATION_CHANNEL" = "manual" ]; then
  read_input 'Path to the Ferron ZIP archive' FERRON_ZIP_ARCHIVE
else
  do_task 'Refusing to install on invalid installation type' invalid_installation_type
fi
do_task 'Stopping Ferron' stop_ferron
do_task 'Copying Ferron files' copy_ferron_files
if type restorecon >/dev/null 2>&1; then
  do_task 'Fixing SELinux context' fix_selinux_context
fi
do_task 'Restarting Ferron' restart_ferron

# Ferron is updated successfully
print_update_success
EOF
    ) || return 1
    chmod a+rx /usr/bin/ferron-updater || return 1
}

fix_selinux_context() {
    restorecon -r /usr/sbin/ferron{,-*} /usr/bin/ferron-updater /etc/ferron.kdl /var/www/ferron /var/log/ferron /var/lib/ferron || return 1
}

install_service() {
    (cat > /etc/init.d/ferron << 'EOF'
#!/bin/bash
### BEGIN INIT INFO
# Provides:          ferron
# Required-Start:    $local_fs $remote_fs $network $syslog $named
# Required-Stop:     $local_fs $remote_fs $network $syslog $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# X-Interactive:     true
# Short-Description: Ferron web server
# Description:       Start the web server
#  This script will start the Ferron web server.
### END INIT INFO

server="/usr/sbin/ferron"
serverargs="-c /etc/ferron.kdl"
servicename="Ferron web server"

user="ferron"

script="$(basename $0)"
lockfile="/var/lock/$script"

. /etc/rc.d/init.d/functions 2>/dev/null || . /etc/rc.status 2>/dev/null || . /lib/lsb/init-functions 2>/dev/null

ulimit -n 12000 2>/dev/null
RETVAL=0

privilege_check()
{
  if [ "$(id -u)" != "0" ]; then
    echo 'You need to have root privileges to manage Ferron service'
    exit 1
  fi
}

do_start()
{
    if [ ! -f "$lockfile" ] ; then
        echo -n $"Starting $servicename: "
        setcap 'cap_net_bind_service=+ep' $server
        (runuser -u $user -- $server $serverargs > /dev/null &) && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch "$lockfile"
    else
        echo "$servicename is locked."
        RETVAL=1
    fi
}

echo_failure() {
    echo -n "fail"
}

echo_success() {
    echo -n "success"
}

echo_warning() {
    echo -n "warning"
}

do_stop()
{
    echo -n $"Stopping $servicename: "
    if type ps > /dev/null 2>&1; then
      pid=`ps -aef | grep "$server $serverargs" | grep -v " grep " | awk '{print $2}' | xargs`
    else
      pid=`pidof $server | xargs`
    fi
    kill -9 $pid > /dev/null 2>&1 && echo_success || echo_failure
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f "$lockfile"

    if [ "$pid" = "" -a -f "$lockfile" ]; then
        rm -f "$lockfile"
        echo "Removed lockfile ( $lockfile )"
    fi
}

do_reload()
{
    echo -n $"Reloading $servicename: "
    if type ps > /dev/null 2>&1; then
      pid=`ps -aef | grep "$server $serverargs" | grep -v " grep " | awk '{print $2}' | xargs`
    else
      pid=`pidof $server | xargs`
    fi
    kill -1 $pid > /dev/null 2>&1 && echo_success || echo_failure
    echo
}

do_status()
{
   if type ps > /dev/null 2>&1; then
     pid=`ps -aef | grep "$server $serverargs" | grep -v " grep " | awk '{print $2}' | head -n 1`
   else
     pid=`pidof -s $server`
   fi
   if [ "$pid" != "" ]; then
     echo "$servicename (pid $pid) is running..."
   else
     echo "$servicename is stopped"
   fi
}

case "$1" in
    start)
        privilege_check
        do_start
        ;;
    stop)
        privilege_check
        do_stop
        ;;
    status)
        do_status
        ;;
    restart)
        privilege_check
        do_stop
        do_start
        RETVAL=$?
        ;;
    reload)
        privilege_check
        do_reload
        ;;
    *)
        echo "Usage: $0 {start|stop|status|restart|reload}"
        RETVAL=1
esac

exit $RETVAL
EOF
  ) || return 1
  chmod a+rx /etc/init.d/ferron || return 1
if ! type systemctl > /dev/null 2>&1; then
  if type update-rc.d > /dev/null 2>&1; then
    update-rc.d ferron defaults || return 1
  else
    rc-update add ferron default || return 1
  fi
  /etc/init.d/ferron start || return 1
else
  (cat > /etc/systemd/system/ferron.service << 'EOF'
[Unit]
Description=Ferron web server
After=network.target

[Service]
Type=simple
User=ferron
ExecStart=/usr/sbin/ferron -c /etc/ferron.kdl
ExecReload=kill -HUP $MAINPID
Restart=on-failure
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target
EOF
  ) || return 1
  systemctl enable ferron || return 1
  systemctl start ferron || return 1
fi
}

# Welcome message
print_welcome

# Execute tasks
do_task 'Checking prerequisites and installing required packages' check_prerequisities
read_input 'Installation channel (`stable` for stable, `manual` for manual installation from a ZIP archive)' INSTALLATION_CHANNEL
if [ "$INSTALLATION_CHANNEL" = "stable" ]; then
  do_task 'Downloading Ferron ZIP archive' download_ferron_zip
elif [ "$INSTALLATION_CHANNEL" = "manual" ]; then
  read_input 'Path to the Ferron ZIP archive' FERRON_ZIP_ARCHIVE
else
  do_task 'Refusing to install on invalid installation type' invalid_installation_type
fi
do_task 'Copying Ferron files' copy_ferron_files
do_task 'Creating Ferron configuration' create_ferron_configuration
do_task 'Installing Ferron updater' install_updater
do_task 'Creating Ferron user' create_ferron_user
if type restorecon >/dev/null 2>&1; then
  do_task 'Fixing SELinux context' fix_selinux_context
fi
do_task 'Installing Ferron service' install_service

# Ferron is installed successfully
print_installation_success
