#!/bin/bash
# vim: ai ts=4 sw=4 expandtab

set -e

SERVICE_NAME="CPFS Client"

SYSCONFIG_FILE=/etc/cpfs/cpfs-client.conf
CPFS_MOUNT_CONFIG="/etc/cpfs/cpfs-mounts.conf"
CPFS_OPTIONS_CONFIG="/etc/cpfs/cpfs-options.conf"
FORCE_AUTO_BUILD="/var/lib/cpfs/client/force-auto-build"
SUBSYS=/var/lock/subsys/cpfs-client

CLIENT_MOD=lustre

POSTSTART_LOG="/opt/cpfs/log/post-start.log"
POSTSTOP_LOG="/opt/cpfs/log/post-stop.log"
POSTSTART="/etc/cpfs/cpfs-post-start.sh"
POSTSTOP="/etc/cpfs/cpfs-post-stop.sh"
PRESTART="/etc/cpfs/cpfs-pre-start.sh"
PRESTART_LOG="/opt/cpfs/log/pre-start.log"
PRESTOP="/etc/cpfs/cpfs-pre-stop.sh"
PRESTOP_LOG="/opt/cpfs/log/pre-stop.log"

DEFAULT_FS_TYPE="lustre"
DEFAULT_BUILD_ARGS="-j4"

handle_selinux()
{
    selinuxenabled 2>/dev/null || return

    echo
    echo "WARNING: SELINUX IS ENABLED. CPFS might not work!"
    echo "         Please try to disable selinux (Usually in /etc/selinux/config)"
    echo
}

build_cpfs()
{
    if [[ -z "$(dkms status cpfs-client)" ]]; then
        echo "ERROR: please firstly install cpfs-client-dkms package"
        return
    else
        kernel_ver=`uname -r`
        installed_ver=`dkms status cpfs-client | grep $kernel_ver | cut -f2 -d',' | sed -e 's/^[ \t]*//'`
        if [[ -z "$installed_ver" ]]; then
            echo "ERROR: cpfs-client-dkms is not correctly installed"
            return
        fi
        echo "Rebuilding cpfs-client $installed_ver, $kernel_ver"
        dkms build cpfs-client/$installed_ver && dkms install cpfs-client/$installed_ver
    fi
}

# Invoke start and stop plugin 
invoke_plugin()
{
    set +e
    op=$1
    op_log=$2
    if [ -e "$op" ]; then
        sh $op $op_log
        if [ $? -ne 0 ]; then
            echo "$op failed, check $op_log for details"
            return 1
        fi
    fi
    set -e
}

RETVAL=0
case "$1" in
    start)
        #Prestart
        res=`invoke_plugin $PRESTART $PRESTART_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }

        #Start
        set +e
        handle_selinux
        set -e

        echo "Starting ${SERVICE_NAME}: "
        modprobe $CLIENT_MOD

        echo "- Mounting directories from $CPFS_MOUNT_CONFIG"
        mkdir -p `dirname $SUBSYS`
        touch $SUBSYS

        OLDIFS="$IFS"
        IFS=$'\n'
        file=`tr -d '\r' < $CPFS_MOUNT_CONFIG`
        [ -z "$file" ] && { echo "$CPFS_MOUNT_CONFIG is empty, please configure it"; exit 1; }
        for raw_line in $file; do
            line=`echo $raw_line | sed -e 's/^[ \t]*//'`
            if [[ -z "$line" ]] || [[ "$line" =~ ^#.* ]]; then
                continue # ignore empty line
            fi
       
            mntpnt=`echo $line | awk '{print $1}'`
            mntdir=`echo $line | awk '{print $2}'`
            mntopt=`echo $line | awk '{print $3}'`
            fstype=`echo $line | awk '{print $4}'`
 
            if [ -z "$mntpnt" ]; then
                echo "Invalid config line: \"$line\""
                continue
            fi
 
            if [ -z "$fstype" ]; then
                fstype=${DEFAULT_FS_TYPE}
            fi
 
            set +e
            mount -l | grep "${mntdir} " >/dev/null 2>&1
            dir_mounted=$?
            mount -t ${fstype} | grep "${mntdir} " >/dev/null 2>&1
            dir_lustre_mounted=$?
            if [ $dir_mounted -eq 0 ]; then
                if [ $dir_lustre_mounted -eq 0 ]; then
                    # already mounted
                    echo ">> ${mntpnt} ${mntdir} already mounted."
                    set -e
                    continue
                else
                    # mounted by other, we can't override, report error
                    echo ">> ${mntdir} mounted by other fs."
                    set -e
                    continue
                fi
            fi
            set -e
 
            # Make sure mount dir exists.
            if [ ! -e ${mntdir} ]; then
                mkdir -p ${mntdir}
            fi
 
            if [ ! -z "$mntopt" ]; then
                echo "mount -t ${fstype} ${mntpnt} ${mntdir} -o ${mntopt}"
                mount -t ${fstype} ${mntpnt} ${mntdir} -o ${mntopt}
            else
                echo "mount -t ${fstype} ${mntpnt} ${mntdir}"
                mount -t ${fstype} ${mntpnt} ${mntdir}
            fi
        done
        RETVAL=$?

        # Poststart
        set +e
        if [ $RETVAL -eq 0 ]; then
           res=`invoke_plugin $POSTSTART $POSTSTART_LOG`
           [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }
        fi
        set -e
        IFS="$OLDIFS"
        ;;
    stop)
        echo "Shutting down ${SERVICE_NAME}: "
        # Prestop
        set +e
        res=`invoke_plugin $PRESTOP $PRESTOP_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }
        set -e

        # Stop
        RETVAL=$?
        echo "- Unmounting directories from $CPFS_MOUNT_CONFIG"
        OLDIFS="$IFS"
        IFS=$'\n'
        file=`tac $CPFS_MOUNT_CONFIG` # we have to read all lines at once
        for raw_line in $file; do
            line=`echo $raw_line | sed -e 's/^[ \t]*//'`
            if [[ -z "$line" ]] || [[ "$line" =~ ^#.* ]]; then
                continue # ignore empty line
            fi
 
            mntdir=`echo $line | awk '{print $2}'`
            fstype=`echo $line | awk '{print $4}'`
            if [ -z "$mntdir" ]; then
                echo "Invalid config line: \"$line\""
                continue
            fi
            if [ -z "$fstype" ]; then
                fstype=${DEFAULT_FS_TYPE}
            fi

            set +e
            echo "umount ${mntdir}"
            mount -t ${fstype} | grep "${mntdir} " >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                # not lustre mounted
                echo ">> ${mntdir} is not CPFS mounted, skip..."
                set -e
                continue
            fi
            res=`umount ${mntdir} 2>&1`
            if [ $? -ne 0 ]; then
                # umount failed, ignore the failure if not mounted at all
                echo $res | grep "not mounted" >/dev/null 2>&1
                if [ $? -ne 0 ]; then
                    # Is mounted, abort.
                    echo "umount failed: $res"
                    exit 1
                fi
            fi
            set -e
        done
        IFS="$OLDIFS"

        echo "- Unloading modules"
        set +e
        res=`lustre_rmmod`
        if [ $? -ne 0 ]; then
            # rmmod failed, ignore it if the module is not loaded at all
            echo $res | grep "does not exist in" >/dev/null 2>&1
            if [ $? -ne 0 ]; then
                # Is loaded, check if a CPFS is still mounted (all from the list are unmounted, so 
                # it must be a CPFS, which was manually mounted)
                STILL_MOUNTED=$(mount -t lustre | wc -l)
                if [ ${STILL_MOUNTED} -eq 0 ]; then
                    # no more CPFS instances, no reason why rmmod should be failing, abort
                    echo "rmmod failed: $res"
                    exit 1 
                else
                    # CPFS instances mounted, so failure to rmmod is normal
                    echo "WARNING: Unloading CPFS modules failed. There are still mounted CPFS instances."
                fi
            fi
        fi
        RETVAL=$?
        set -e

        if [ $RETVAL -eq 0 ]; then rm -f $SUBSYS; fi

        # Poststop
        set +e
        if [ $RETVAL -eq 0 ]; then
          res=`invoke_plugin $POSTSTOP $POSTSTOP_LOG`
          [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }  
        fi
        set -e
        ;;
    restart)
        $0 stop
        $0 start
        RETVAL=$?
        ;;
    rebuild)
        # rebuild against current kernel
        build_cpfs
        ;;
    reconfigure)
        # reconfigure all config
        set +e
        res=`invoke_plugin $PRESTOP $PRESTOP_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }

        res=`invoke_plugin $POSTSTOP $POSTSTOP_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }

        res=`invoke_plugin $PRESTART $PRESTART_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }

        res=`invoke_plugin $POSTSTART $POSTSTART_LOG`
        [ $? -eq 0 ] || { RETVAL=$?; echo >&2 "$res"; }

        echo "Reconfigure $SERVICE_NAME completed."
        set -e
        ;;
    status)
        # Return value is slightly different for the status command:
        # 0 - service up and running
        # 3 - service not running (unused)
        # 4 - service status unknown :-(
        set +e
        echo -n "Checking for service $SERVICE_NAME: "
        lsmod | grep $CLIENT_MOD >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo "is running..."
            mount -t lustre | grep lustre >/dev/null 2>&1
            if [ $? -eq 0 ]; then
                mount -t lustre | cut "-d " -f1-3
                echo
                RETVAL=0
            else
                echo ">> No active CPFS mounts detected."
                echo
                RETVAL=4
            fi
        else
            echo "is stopped."
            echo
            RETVAL=3
        fi
        set -e
        ;;
    *)
        echo "Usage: $0 {start|stop|status|restart|rebuild|reconfigure}"
        exit 3
        ;;
    esac
exit $RETVAL
