#!/bin/sh
#
# chkconfig: 345 10 90
# description: Atempo Live Navigator driver startup script
#
### BEGIN INIT INFO
# Provides:          hndriver
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Atempo Live Navigator driver startup script
# Description: Endpoint Data Protection for Remote Offices, Desktops, Laptops and File Servers
### END INIT INFO

# Name of the daemon
# MUST NOT be the same name as the script: the
# stop command would kill the script too
MODULES_TITLE="CDP modules"
MODULENAME1=redirfs
MODULENAME2=hnfsflt
DEPMOD_MARKER=/lib/modules/`uname -r`/extra/.hndepmod
DKMS_REBUILD_MARKER=/lib/modules/`uname -r`/extra/.hnbuild
BLACKLIST_MARKER=/lib/modules/`uname -r`/extra/.hnblacklisted
REDIRFS_FILTER_PATH=/sys/fs/redirfs/filters/hnfsflt
SYS_BLACKLIST_CONF=/etc/modprobe.d/blacklist.conf 
SYS_BLACKLIST_CONF_HEADER="# ALN LiveNavigator: prevent loading of CDP modules"
AGENT_BIN=/etc/init.d/hnagent
AGENT_STATUS=0  #  not running
subsys=hndriver

# These are lists of supported RHEL7/CentOS7 kernel versions.
# Add new version into appropriate list.
SUPPORTED_LIST_RHEL="3.10.0-123 3.10.0-123.20.1 3.10.0-229.1.2 3.10.0-229.4.2 3.10.0-229.20.1 3.10.0-327.4.5 3.10.0-327.13.1 3.10.0-327.18.2 3.10.0-327.36.3 3.10.0-514 3.10.0-514.10 3.10.0-514.10.2 3.10.0-514.26.2 3.10.0-693 3.10.0-693.11.1 3.10.0-693.2.1 3.10.0-693.5.2 3.10.0-862 3.10.0-862.3.2"
SUPPORTED_LIST_CENTOS="3.10.0-123.20.1 3.10.0-229.20.1 3.10.0-693.11.1 3.10.0-693 3.10.0-693.2.1 3.10.0-693.5.2 3.10.0-862 3.10.0-862.3.2"
SUPPORTED_LIST_FEDORA="4.5.2-302 4.5.5-300 4.6.3-300 4.6.4-301 4.8.6-300 4.11.3-202 4.13.16-100 4.11.8-300 4.14.4-200 4.13.9-300"


# On FreeBSD 7, the following lines enable the startup script. If these lines are deleted, it won't work.
# PROVIDE: Atempo Live Navigator
# REQUIRE: NETWORKING

if echo "\c" | grep "c">/dev/null ; then
    ECHOMODE=Bsd
else
    ECHOMODE=Sys5
fi

echo_no_cr() {
    if [ "$ECHOMODE" = Bsd ] ; then
        echo -n "$*"
    else
        echo "$*\c"
    fi
}

ISREDHATLIKE=1
# Source function library.
if [ -f /etc/init.d/functions ] ; then
    . /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ] ; then
    . /etc/rc.d/init.d/functions
else
    ISREDHATLIKE=0
fi

ISSUSE=1
if [ -f /etc/rc.status ] ; then
    . /etc/rc.status
else
    ISSUSE=0
fi

get_locale_of_keyword()
{
    LOC=`locale | grep "${1}=" | cut -d= -f2 | sed 's/"//g'`
    if [ "$LOC" ]; then
        echo `expr substr ${LOC} 1 3`
    fi
}

set_locale()
{
    # LC_ALL - Overrides individual LC_* settings: if LC_ALL is set, none of the below LC_* have any effect.
    LOCALE3=$(get_locale_of_keyword "LC_ALL")
    if [ "fr_" = "${LOCALE3}" ]; then
        locale=fr
        return
    fi

    # LC_IDENTIFICATION - Metadata about the locale information.
    LOCALE3=$(get_locale_of_keyword "LC_IDENTIFICATION")
    if [ "fr_" = "${LOCALE3}" ]; then
        locale=fr
        return
    fi

    # LC_MESSAGES - What language should be used for system messages.
    LOCALE3=$(get_locale_of_keyword "LC_MESSAGES")
    if [ "fr_" = "${LOCALE3}" ]; then
        locale=fr
        return
    fi
}


load_modules()
{
    set_modules_blacklisted
    find /lib/modules/`uname -r` -name ${MODULENAME1}.ko | grep "weak-updates"
    if [ $? -eq 0 ]; then
        # This is CentOS/RHEL system which uses symlinks now instead of real files.
        # Get rid of using these symlinks. 
        # http://lists.us.dell.com/pipermail/dkms-devel/2012-June/001090.html
        rm -rf $(find /lib/modules/*/ -name weak-updates | xargs)
        echo "Removed weak-updates."
        /sbin/depmod -a > /dev/null 2>&1
        # And now rebuild modules for current kernel version.
        mkdir -p $(dirname "$DKMS_REBUILD_MARKER")
        touch $DKMS_REBUILD_MARKER
    fi

    #  Check the system version and find whether CDP modules are supported for this system.
    #  If CDP modules are not supported - add them to blacklist, so, they never be loaded in the kernel.
    check_modules_permitted # >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        return
    fi
    unset_modules_blacklisted

    if [ -f $DKMS_REBUILD_MARKER ]; then
        rm -f $DKMS_REBUILD_MARKER
        rebuild_dkms_modules
    fi

    if [ -f $DEPMOD_MARKER ]; then
        /sbin/depmod -a > /dev/null 2>&1
        rm -f $DEPMOD_MARKER
    fi

    #  Check modules are ready for loading, i.e. whether sources have been built and .ko files have been installed under /lib/modules/<kernel>/ directory.
    check_modules_installed >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        mkdir -p $(dirname "$DEPMOD_MARKER")
        touch $DEPMOD_MARKER  #  still required for this kernel version
        touch $DKMS_REBUILD_MARKER  #  still required for this kernel version
        build_dkms_modules
    fi

    check_modules_loaded >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "Done."
        return
    fi

    if [ "$locale" = "fr" ]; then
        echo_no_cr "Chargement de $MODULES_TITLE"
    else
        echo_no_cr "Loading $MODULES_TITLE"
    fi

    modprobe --syslog  ${MODULENAME2} > /dev/null 2>&1

    if [ $ISREDHATLIKE -eq 1 ]; then
        echo_success
        echo
    elif [ $ISSUSE -eq 1 ]; then
        rc_status -v
    else
        echo "Done."
    fi
    echo
    return
}

unload_modules()
{
    if [ "$locale" = "fr" ]; then
        echo_no_cr "Déchargement de $MODULES_TITLE"
    else
        echo_no_cr "Unloading $MODULES_TITLE"
    fi

    check_modules_loaded >/dev/null 2>&1
    if [ $? -eq 0 ]; then
    #  Unload 'hnfsflt' module from the kernel.
    #  'redirfs' module can't be unloaded from the kernel.
    if [ -d  ${REDIRFS_FILTER_PATH} ]; then
        if [ -x ${AGENT_BIN} ]; then
            ${AGENT_BIN} status|grep "running"
            if [ $? -eq 0 ]; then
                AGENT_STATUS=1  #  running
                ${AGENT_BIN} stop
            fi
        fi
        #  a) Deactivate filter
        echo '0' > ${REDIRFS_FILTER_PATH}/active
        #  b) Clear paths
        echo 'c' > ${REDIRFS_FILTER_PATH}/paths
        #  c) Unregister filter
        echo '1' > ${REDIRFS_FILTER_PATH}/unregister
        #  Unload module
        /sbin/rmmod ${MODULENAME2}
        #  Restore the Agent's status
        if [ -x ${AGENT_BIN} ]; then
            if [ ${AGENT_STATUS} -eq 1 ]; then
                ${AGENT_BIN} start
            fi
        fi
    fi
    fi

    if [ $ISREDHATLIKE -eq 1 ]; then
        echo_success
        echo
    elif [ $ISSUSE -eq 1 ]; then
        rc_status -v
    else
        echo "Done."
    fi
}

check_modules_installed()
{
    /sbin/modinfo ${MODULENAME1}  >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        /sbin/modinfo ${MODULENAME2}  >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            if [ "$locale" = "fr" ]; then
                echo_no_cr "$MODULES_TITLE installé."
            else
                echo_no_cr "$MODULES_TITLE installed."
            fi
            return 0
        fi
    fi

    if [ "$locale" = "fr" ]; then
        echo_no_cr "$MODULES_TITLE ne sont pas installés."
    else
        echo_no_cr "$MODULES_TITLE are not installed."
    fi

    return 1
}

set_modules_blacklisted()
{
    grep -e "^install ${MODULENAME1} /bin/false" ${SYS_BLACKLIST_CONF} >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo ""                                  >> ${SYS_BLACKLIST_CONF}
        echo ${SYS_BLACKLIST_CONF_HEADER}        >> ${SYS_BLACKLIST_CONF}        
        echo "install ${MODULENAME1} /bin/false" >> ${SYS_BLACKLIST_CONF}
    fi

    grep -e "^install ${MODULENAME2} /bin/false" ${SYS_BLACKLIST_CONF} >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "install ${MODULENAME2} /bin/false" >>  ${SYS_BLACKLIST_CONF}
    fi

    mkdir -p $(dirname "$BLACKLIST_MARKER")
    touch "$BLACKLIST_MARKER"
}

unset_modules_blacklisted()
{
    grep -e "^install ${MODULENAME1} /bin/false" ${SYS_BLACKLIST_CONF} >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        sed --in-place -e "/${SYS_BLACKLIST_CONF_HEADER}/d"  -e "/install ${MODULENAME1} \/bin\/false/d"  -e "/install ${MODULENAME2} \/bin\/false/d" ${SYS_BLACKLIST_CONF} >/dev/null 2>&1
    fi
    rm -f "$BLACKLIST_MARKER"  >/dev/null 2>&1
}

rebuild_dkms_modules()
{
    if [ -f $BLACKLIST_MARKER ]; then
        set_modules_blacklisted # >/dev/null 2>&1
        return
    fi

    echo "Rebuilding DKMS modules for ALN LiveNavigator:"

    NAME=livenavigatormodule
    PACKAGE_NAME=$NAME
    CVERSION=""
    ARCH=""
    is_deb_based_system
    if [ $? -eq 0 ]; then
        PACKAGE_NAME=$NAME-dkms
        DEB_NAME=$(echo $PACKAGE_NAME | sed 's,_,-,')
        CVERSION=$(dpkg-query -W -f='${Version}' $DEB_NAME | awk -F "-" '{print $1}' | cut -d\: -f2)
        ARCH=$(dpkg --print-architecture)
    else
        CVERSION=$(rpm -q --queryformat "%{VERSION}\n" ${PACKAGE_NAME} | sort -g | tail --lines=1 | tr -d '\n')
    fi

    echo COMMAND: /usr/share/$PACKAGE_NAME/postinst "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" 
    /usr/share/$PACKAGE_NAME/postinst "$NAME" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" >/dev/null 2>&1
}

build_dkms_modules()
{
    #  Check the system version and find whether CDP modules are supported for this system.
    #  If CDP modules are not supported - add them to blacklist, so, they never be loaded in the kernel.
    check_modules_permitted # >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        set_modules_blacklisted # >/dev/null 2>&1
        return
    fi
    unset_modules_blacklisted

    #  Check modules are ready for loading, i.e. whether sources have been built and .ko files have been installed under /lib/modules/<kernel>/ directory.
    check_modules_installed >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        rebuild_dkms_modules
    fi
    rm -f $DKMS_REBUILD_MARKER
}

is_deb_based_system()
{
    if [ -f "/etc/debian_version" ]; then
        return 0
    else
        return 1
    fi
}

check_modules_permitted()
{
    HN_SYS_ARCH=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/')  # 32 or 64

    #  Novell SuSE    /etc/SuSE-release
    #  OpenSuSE       /etc/SuSE-release, /etc/os-release
    #  Red Hat,CentOS /etc/redhat-release, /etc/redhat_version
    #  Fedora         /etc/fedora-release, /etc/redhat-release, /etc/os-release
    #  Slackware      /etc/slackware-release, /etc/slackware-version
    #  Debian         /etc/debian_release, /etc/debian_version
    #  Ubuntu         /etc/debian_version
    #  Mandrake       /etc/mandrake-release
    #  Yellow dog     /etc/yellowdog-release
    #  Sun JDS        /etc/sun-release 
    #  Solaris/Sparc  /etc/release 
    #  Gentoo         /etc/gentoo-release
    #  Amazon Linux   /etc/system-release
    #  PLD Linux      /etc/pld-release, /etc/os-release
    #  ArchLinux      /etc/arch-release, /etc/os-release
    if [ -f /etc/lsb-release ]; then
        . /etc/lsb-release
        if [ -n "$DISTRIB_ID" ] && [ -n "$DISTRIB_RELEASE" ]; then
            HN_SYS_OS=$DISTRIB_ID
            HN_SYS_VER=$DISTRIB_RELEASE
        fi
    fi

    if [ -z "$HN_SYS_OS" ] || [ -z "$HN_SYS_VER" ]; then
      if [ -f /etc/SuSE-release ]; then
        HN_SYS_OS="suse"
        HN_SYS_VER=$(cat /etc/SuSE-release | grep 'VERSION ='| sed 's/VERSION =//' | tr -d '[[:space:]]')
      elif  [ -f /etc/fedora-release ] && [ -f /etc/os-release ]; then
        . /etc/os-release
        HN_SYS_OS=$ID
        HN_SYS_VER=$VERSION_ID
      elif [ -f /etc/debian_version ]; then
        if [ -f /etc/os-release ]; then
            . /etc/os-release
            HN_SYS_OS=$ID
            HN_SYS_VER=$VERSION_ID
        else       
            HN_SYS_OS=Debian
            HN_SYS_VER=$(cat /etc/debian_version)
        fi
      elif [ -f /etc/centos-release ] && [ -f /etc/os-release ]; then
        . /etc/os-release
        HN_SYS_OS=$ID
        HN_SYS_VER=$VERSION_ID
      elif [ -f /etc/redhat-release ]; then
        read -r RELEASE_DATA < /etc/redhat-release
        if [[ "$RELEASE_DATA" =~ "Red Hat" ]]; then
            HN_SYS_OS="redhat"
            RELEASE_STRING=`grep -e 'Red Hat.*release [0-9.]\+' /etc/redhat-release`
        elif [[ "$RELEASE_DATA" =~ "Fedora" ]]; then
            HN_SYS_OS="fedora"
            RELEASE_STRING=`grep -e 'Fedora.*release [0-9.]\+' /etc/redhat-release`
        elif [[ "$RELEASE_DATA" =~ "CentOS" ]]; then
            HN_SYS_OS="centos"
            RELEASE_STRING=`grep -e 'CentOS.*release [0-9.]\+' /etc/redhat-release`
        fi
        HN_SYS_VER=$(echo ${RELEASE_STRING} | sed 's/^[^0-9]*\([0-9.]\+\)[^0-9]*$/\1/')
      else
        HN_SYS_OS=$(uname -s)
        HN_SYS_VER=$(uname -r)
      fi
    fi

    HN_SYS_OS=$(echo ${HN_SYS_OS} | tr '[:upper:]' '[:lower:]')

    echo ${HN_SYS_VER} | grep "\." >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        HN_SYS_VER=$(echo ${HN_SYS_VER} | sed 's/^\([0-9]*\)\..*$/\1/')
    fi

    if [ "$HN_SYS_OS" = "centos" ]; then
        if [ ${HN_SYS_VER} -eq 7 ]; then
            INSTALLED_KERNEL=$(uname -r)
            INSTALLED_KERNEL_VERSION=$(echo ${INSTALLED_KERNEL} | sed 's/^\([0-9.-]*\)\..*$/\1/')

            for ITEM in $SUPPORTED_LIST_CENTOS
            do
                if [ "$INSTALLED_KERNEL_VERSION" = "$ITEM" ]; then
                    #  Installed version is in the list of supported
                    return 0
                fi
            done

            # Installed version is not supported
            return 1
        fi
    fi

    
    if [ "$HN_SYS_OS" = "redhat" ]; then
        if [ ${HN_SYS_VER} -eq 7 ]; then
            INSTALLED_KERNEL=$(uname -r)
            INSTALLED_KERNEL_VERSION=$(echo ${INSTALLED_KERNEL} | sed 's/^\([0-9.-]*\)\..*$/\1/')

            for ITEM in $SUPPORTED_LIST_RHEL
            do
                if [ "$INSTALLED_KERNEL_VERSION" = "$ITEM" ]; then
                    #  Installed version is in the list of supported
                    return 0
                fi
            done

            # Installed version is not supported
            return 1
        fi
    fi


    if [ "$HN_SYS_OS" = "suse" ] || [ "$HN_SYS_OS" = "opensuse" ]; then
        if [ ${HN_SYS_VER} -ge 11 ]; then
            cat /etc/modprobe.d/unsupported-modules | grep -e "^allow_unsupported_modules 1" >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                echo "allow_unsupported_modules 1" > /etc/modprobe.d/unsupported-modules
            fi
        fi

        #if [ "openSUSE" = `head --bytes=8 /etc/SuSE-release` ]; then
            # There is a lot of kernel flavours like:
            #    kernel-debug
            #    kernel-default
            #    kernel-desktop
            #    kernel-ec2
            #    kernel-pae
            #    kernel-trace
            #    kernel-vanilla
            #    kernel-xen
            KERNEL_FLAVOR=$(uname -r | sed 's/^.*-\([a-z0-9]*\)$/\1/')
            CVERSION_CURRENT=$(uname -r | sed "s/-${KERNEL_FLAVOR}//") # get rid of flavor suffix
            KERNEL_ARCH=$(uname -m)
            KERNEL_DEVEL_CAP="kernel-${KERNEL_FLAVOR}-devel.${KERNEL_ARCH}=${CVERSION_CURRENT}"

            echo COMMAND: zypper --non-interactive --no-gpg-checks install -C "${KERNEL_DEVEL_CAP}"
            zypper --non-interactive --no-gpg-checks install -C "${KERNEL_DEVEL_CAP}"
            if [ $? -ne 0 ]; then
                echo "===================================================="
                echo "Please, do following steps (according documentation)"
                echo " 1. update the system with command:"
                echo "       zypper update"
                echo " 2. reboot your system (to boot from updated kernel)"
                echo " 3. try to install the package again."
                echo "===================================================="
            fi
        #fi
    fi


    if [ "$HN_SYS_OS" = "fedora" ]; then
        # Installed on the current system:
        #    kernel-PAE-4.2.6-200.fc22.i686.rpm
        # Presents on remote repo:
        #    kernel-PAE-4.2.8-200.fc22.i686.rpm
        #    kernel-PAE-devel-4.2.8-200.fc22.i686.rpm
        # The problem is: the package
        #           kernel-PAE-devel-4.2.6-200.fc22.i686.rpm
        # is absent in repo. So, "devel" package won't be installed. And current system can't build CDP module until it updates to version 8.
        if [ ${HN_SYS_ARCH} -eq 32 ]; then
            uname -r | grep "PAE" >/dev/null 2>&1
            if [ $? -eq 0 ]; then
                #  fix that ugly thing with "+PAE"
                uname -r | grep "PAEdebug" >/dev/null 2>&1
                if [ $? -eq 0 ]; then
                    CVERSION_CURRENT=$(uname -r | sed 's/+PAEdebug//') # get rid of "+PAEdebug" suffix
                    KERNEL_DEVEL_PACKAGE="kernel-PAEdebug-devel-${CVERSION_CURRENT}"
                else
                    CVERSION_CURRENT=$(uname -r | sed 's/+PAE//') # get rid of "+PAE" suffix
                    KERNEL_DEVEL_PACKAGE="kernel-PAE-devel-${CVERSION_CURRENT}"
                fi
            else
                uname -r | grep "debug" >/dev/null 2>&1
                if [ $? -eq 0 ]; then
                    CVERSION_CURRENT=$(uname -r | sed 's/+debug//') # get rid of "+debug" suffix
                    KERNEL_DEVEL_PACKAGE="kernel-debug-devel-${CVERSION_CURRENT}"
                else
                    CVERSION_CURRENT=$(uname -r)
                    KERNEL_DEVEL_PACKAGE="kernel-devel-${CVERSION_CURRENT}"
                fi
            fi

            echo COMMAND: dnf --assumeyes install "${KERNEL_DEVEL_PACKAGE}"
            dnf --assumeyes install "${KERNEL_DEVEL_PACKAGE}"
            if [ $? -ne 0 ]; then
                echo "===================================================="
                echo "Please, do following steps (according documentation)"
                echo " 1. update the system with command:"
                echo "     dnf update"
                echo " 2. reboot your system (to boot from updated kernel)"
                echo " 3. try to install the package again."
                echo "===================================================="
            fi
        fi

        INSTALLED_KERNEL=$(uname -r)
        INSTALLED_KERNEL_VERSION=$(echo ${INSTALLED_KERNEL} | sed 's/^\([0-9.-]*\)\..*$/\1/')

        for ITEM in $SUPPORTED_LIST_FEDORA
        do
            if [ "$INSTALLED_KERNEL_VERSION" = "$ITEM" ]; then
                #  Installed version is in the list of supported
                return 0
            fi
        done

        # Installed version is not supported
        return 1
    fi

    return 0
}

check_modules_loaded()
{
    lsmod | grep "${MODULENAME2}"  >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        if [ "$locale" = "fr" ]; then
               echo "$MODULES_TITLE statut: Chargé."
           else
               echo "$MODULES_TITLE status: Loaded."
           fi
        return 0
    fi

    if [ "$locale" = "fr" ]; then
        echo "$MODULES_TITLE statut: Non chargée."
    else
        echo "$MODULES_TITLE status: Not loaded."
    fi
    return 1
}

locale=C # POSIX is default value
set_locale
if [ -f "${SYS_BLACKLIST_CONF}.bak" ]; then
    rm "${SYS_BLACKLIST_CONF}.bak"
fi


case "$1" in
  load)
    load_modules
    ;;
  start)
    #  on systems with `systemd` it is launched one time in the beginning
    load_modules
    [ -d /var/lock/subsys ] || mkdir -p /var/lock/subsys
    touch /var/lock/subsys/"$subsys"
    if [ -x ${AGENT_BIN} ]; then
        ${AGENT_BIN} restart
    fi
    ;;
  stop)
    unload_modules
    rm -f /var/lock/subsys/"$subsys"
    ;;
  restart)
    unload_modules
    load_modules
    if [ -x ${AGENT_BIN} ]; then
        ${AGENT_BIN} restart
    fi
    ;;
  status)
    check_modules_loaded
    ;;
  build)
    build_dkms_modules
    load_modules
    if [ -x ${AGENT_BIN} ]; then
        ${AGENT_BIN} restart
    fi
    ;;
  clean)
    unload_modules
    unset_modules_blacklisted
    ;;
  *)
    echo "Usage: $0 {load|start|stop|restart|status|build|clean}"
    exit 1
    ;;
esac

exit 0

