#!/bin/sh
# Author: Vitaly Lipatov <lav@etersoft.ru>
# 2006, 2007, 2008, 2010 Public domain

# chkconfig: 345 70 60
# description: Hasp keys support
#
# modulename: aksparlnx
# processnames: winehasp, aksusbd, hasplm, usbdaemon, SntlKeysSrvrlnx
#
### BEGIN INIT INFO
# Provides: haspd
# Required-Start: $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Hasp keys support
# Description: loads the aksparlnx driver and starts aksusbd, winehasp ans hasplm processes
### END INIT INFO

RMMOD=/sbin/rmmod
MODPROBE=/sbin/modprobe
INSMOD=/sbin/insmod

export MODULENAME=aksparlnx
export MODULEVERSION=3.2
HASPLM_ARGS="-c /etc/haspd/hasplm.conf"
HASPLMD_ARGS="-s"

EXTMO=ko
[ "$(uname -r | cut -c1-3)" = "2.4" ] && EXTMO=o

# current module or manually built
test -n "$DEFMODULEPATH" || DEFMODULEPATH=/lib/modules/$(uname -r)/kernel/extra/$MODULENAME.$EXTMO
#MANMODULEPATH=/lib/modules/haspd/$MODULENAME.$EXTMO
# use manually build if exists
#[ -r "$MANMODULEPATH" ] && DEFMODULEPATH=$MANMODULEPATH


OUTFORMAT=/etc/init.d/outformat
[ -x $OUTFORMAT ] || OUTFORMAT=/etc/init.d/haspd.outformat

if which tput >/dev/null && test -x $OUTFORMAT ; then
	. $OUTFORMAT
else
	MOVE_TO_COL(){ :; }
	SETCOLOR_SUCCESS(){ :; }
	SETCOLOR_FAILURE(){ :; }
	SETCOLOR_WARNING(){ :; }
	SETCOLOR_NORMAL(){ :; }
fi

# TODO: use printf?
success()
{
	MOVE_TO_COL
	echo -n '[ '
	SETCOLOR_SUCCESS
	echo -n 'DONE'
	SETCOLOR_NORMAL
	echo ' ]'
}

failure()
{
	MOVE_TO_COL
	echo -n '['
	SETCOLOR_FAILURE
	echo -n 'FAILED'
	SETCOLOR_NORMAL
	echo ']'
}

passed()
{
	MOVE_TO_COL
	echo -n '['
	SETCOLOR_WARNING
	echo -n 'PASSED'
	SETCOLOR_NORMAL
	echo ']'
}

skipping()
{
	MOVE_TO_COL
	echo -n '['
	SETCOLOR_SUCCESS
	echo -n 'SKIPPING'
	SETCOLOR_NORMAL
	echo ']'
}

get_pid()
{
	# TODO: use pgrep
	PIDOF=/bin/pidof
	if [ -x $PIDOF ] ; then
		dpid=`$PIDOF $1`
	else
		dpid="$(ps axh | grep $1 | grep -v grep | sed -e 's/ *\(.*\)/\1/' -e 's/ \+/ /g' | grep -v " /bin/sh " | grep -v "^$$ " |  cut -f1 -d\  | head -1)"
	fi
	test -n "$dpid"
}

is_loaded()
{
    get_pid $1
    test -n "$dpid"
}

is_moduled()
{
    lsmod | grep $MODULENAME > /dev/null
}

# Get kernel version
get_vermagic()
{
    MODFILE=$1
    modinfo $MODFILE | grep vermagic | sed -e "s| \+| |g" | cut -d " " -f 3-
}

load_module()
{
    local i
    echo -n "Loading HASP LPT kernel module... "
    $MODPROBE lp
    if [ ! -e /dev/lp0 ] ; then
        echo -n " (/dev/lp0 device has not found) "
        passed
        return
    fi

    # FIXME: how we can detect missed port?
    #if ! cat /dev/lp0 2>/dev/null >/dev/null ; then
    #    echo -n " (LPT port has not found) "
    #    passed
    #    return
    #fi

    # What about two key?
    if [ ! -c /dev/Hardlock ]; then
        mknod /dev/Hardlock c 42 0
        chmod 660 /dev/Hardlock
    fi

    $MODPROBE parport_pc

    # try load module by modprobe
    $MODPROBE $MODULENAME 2>/dev/null && { echo ; echo -n "    modprobe $MODULENAME" ; success ; return ; }

    #if [ -r "$DEFMODULEPATH" ] ; then
    #        local INSMODF=
    #        [ "$EXTMO" = "o" ] && INSMODF="-f"
    #    $INSMOD $INSMODF $DEFMODULEPATH && { echo -n -e "\n\tinsmod $DEFMODULEPATH" ; success ; return ; }
    #	    #echo -n "Incorrect module. Your system: " ; uname -a ; dmesg | tail -n2
    #fi
    #echo -n -e "$DEFMODULEPATH is not found,\nyou can try compile it with 'service haspd build' command."
    if [ -r "$DEFMODULEPATH" ] ; then
        #echo "$MODULENAME is not loaded with errors..."
        #$MODPROBE $MODULENAME
        echo -n " (LPT port has not found) "
        passed
        return
    else
        echo "$MODULENAME is not found"
        echo -n "you can try compile it with 'service haspd build' command."
        failure
    fi
    echo "Note: This kernel module needed ONLY for LPT HASP keys"
    echo
}

check_usbfs()
{
    if [ ! -f /proc/bus/usb/devices ]; then
        echo -n "Check kernel for CONFIG_USB_DEVICEFS... "
	if [ ! -d /proc/bus/usb ] ; then
	        #failure
		#echo "You have to use kernel with CONFIG_USB_DEVICEFS enabled for support USB HASP"
		passed
		echo -n "Enable workaround for /proc/bus/usb (bind from /dev/bus/usb)"
		mount --bind /dev/bus /proc/bus
		ln -s /sys/kernel/debug/usb/devices /proc/bus/usb/devices && success
		# return 1
	else
		success
	        echo -n "Mounting usbdevfs to /proc/bus/usb (it can be insecure)... "
	        #echo "You have to mount usbfs (usbdevfs) filesystem into /proc/bus/usb, f.i.: mount -t usbfs none /proc/bus/usb"
		mount -t usbfs none /proc/bus/usb || { failure ; }
		success
	fi
    fi
    # for libusb: use modern way instead /proc/bus/usb
    test -d /dev/bus/usb && export USB_DEVFS_PATH=/dev/bus/usb
    return 0
}

start_inservice()
{
	SERVICE=$1
	shift
        echo -n "Running $SERVICE... "
        is_loaded $SERVICE && passed && return
	if which $SERVICE >/dev/null 2>/dev/null ; then
	        $SERVICE $@ || { failure ; exit 1 ; }
		success
	else
		skipping
	fi
}

start_sentinel()
{
	# Load Sentinel
	cd /usr/lib/sentinel 2>/dev/null || return
	export LD_LIBRARY_PATH=./
	export PATH=./:$PATH
	start_inservice usbsentinel
	start_inservice SntlKeysSrvrlnx
	cd - >/dev/null
}

start()
{
	load_module
	check_usbfs

	# start HASP always due possible LPT keys (undetected as USB)
	start_inservice aksusbd
	start_inservice winehasp
	start_inservice hasplm $HASPLM_ARGS
	start_inservice hasplmd $HASPLMD_ARGS

	for i in `usbkeytest --detect` ; do
		case $i in
			aladdin)
#				echo "HASP key present"
				;;
			eutron)
				start_inservice skeyd
				;;
			sentinel)
				start_sentinel
				;;
			*)
				echo "Unknown key $i"
				;;
		esac
	done

}

# kill specified process
stopping()
{
	is_loaded $1 || { passed ; return ; }
	# usual way
	kill $dpid
	for pau in 1 2 3 4 ; do
		is_loaded $1 || { success ; return ; }
		echo -n "."
		# 0.5 do not work only on Special Linux
		sleep 1
	done
	# kill immediately (brokes skeyd semget, FM: id get with fot)
	kill -KILL $dpid
	for pau in 1 2 3 ; do
		is_loaded $1 || { success ; return ; }
		echo -n "."
		# 0.5 do not work only on Special Linux
		sleep 1
	done
	failure
}

stop()
{
    for i in hasplmd hasplm winehasp aksusbd ; do
        echo -n "Stopping $i... "
	stopping $i
    done

    for i in skeyd usbsentinel SntlKeysSrvrlnx; do
        echo -n "Stopping $i... "
	stopping $i
    done

	if [ -L "/proc/bus/usb/devices" ] ; then
		echo -n "Stopping workaround for /proc/bus/usb"
		rm -f /proc/bus/usb/devices
		umount /proc/bus
		success
	fi

    echo -n "Unloading HASP LPT kernel module... "
    is_moduled || { passed ; return ; }
    $RMMOD aksparlnx || { failure ; return ; }
    success

}

status()
{
	echo "Hardware protection keys support bundle. Etersoft (c) 2008-2012"
	echo "HASPD package 3.2 with /dev/bus/usb support"
	echo "Aladdin HASP 4/HL/SRM driver status:"
	is_moduled && echo "    kernel module aksparlnx is loaded" || echo "    kernel module aksparlnx is not loaded (WARNING: HASP LPT keys support is disabled! Run service haspd build if needed.)"
	
	for i in aksusbd winehasp hasplm hasplmd; do
		is_loaded $i && echo "    $i is running" || echo "    $i is stopped"
	done
	is_loaded aksusbd && aksusbd -v
	[ -L "/proc/bus/usb/devices" ] && echo "    /proc/bus/usb workaround is enabled"
	echo "Smartkey 3 USB/LPT driver status:"
	for i in skeyd ; do
		is_loaded $i && echo "    $i is running" || echo "    $i is stopped"
	done
	is_loaded skeyd && skeymon
	echo "SafeNet Sentinel status:"
	for i in usbsentinel SntlKeysSrvrlnx ; do
		is_loaded $i && echo "    $i is running" || echo "    $i is stopped"
	done
	echo
	echo
	echo "Use \$ eterkeytest [--hasp] [--sentinel] [--eutron] for test key presence"
}

restart()
{
    stop
    start
}

case "$1" in
    start)
        start
        ;;
    condstop|stop)
        stop
        ;;
    restart)
        restart
        ;;
    build)
        # remove manual built module
	rm -f $DEFMODULEPATH
        cd /usr/src/$MODULENAME-$MODULEVERSION
	MODDEST=`dirname $DEFMODULEPATH` sh build.sh -i -v
	depmod -a
        ;;
    status)
        status
        ;;
    condrestart)
        # remove manual built module
	rm -f $MANMODULEPATH
        # only restart if it is already running
	# TODO: more correctly
	is_loaded aksusbd && restart
        ;;
    *)
        echo "Usage: haspd {start|stop|restart|build|condrestart|condstop|status}"
esac

