#!/bin/sh
# description: Services for CryptoPro CSP
# processname: N/A # kchansrv
# pidfile: N/A # /var/run/kchansrv.pid
# chkconfig: 345 50 60
### BEGIN INIT INFO
# Provides:		cprocsp
# Required-Start:	$network $syslog
# Required-Stop:	$network $syslog
# Default-Start:	2 3 4 5
# Default-Stop:		0 1 6
# Short-Description:	Start and stop CSP servers
# Description:		Start and stop CSP servers
#			
#			
### END INIT INFO

# disable any X11 bio_gui if it's installed
unset DISPLAY

old_path=$PATH
PATH=/usr/xpg4/bin:/usr/bin:/bin:/usr/sbin:/sbin

for SETLIMITS in /opt/cprocsp/sbin/amd64/set_hsm_ulimits.sh /opt/cprocsp/sbin/amd64/set_hsm_ulimits.sh /opt/cprocsp/sbin/ia32/set_hsm_ulimits.sh
do
      test "/set_hsm_ulimits.sh" = "$SETLIMITS" && continue
      test -f $SETLIMITS || continue
      . $SETLIMITS
done

lsb_sanity_check()
{
    test -f /lib/lsb/init-functions || return 1
    if ! test -r /etc/debian_version; then
      test -f /usr/bin/lsb_release || return 1
      test "`/usr/bin/lsb_release |sed 's/^.*core-\([[:digit:]]*\)\.[[:digit:]]*-.*$/\1/'`" -ge 3 || return 1   
      test -f /usr/lib/lsb/install_initd || return 1
      test -f /usr/lib/lsb/remove_initd || return 1
    fi
    return 0
}

if test -z ""; then
    if lsb_sanity_check
    then
	. /lib/lsb/init-functions

	daemon_status()
	{
	    my_pid=`pidofproc ${1+"$@"}`
	    if test -n "$my_pid";then
		echo "$1 is running (pid $my_pid)"
		return 0
	    else
		echo "$1 is stopped"
		return 1
	    fi
	}
    else
	if test -f /etc/init.d/functions
	then
	    . /etc/init.d/functions
	else
	    echo "Error: Unknown non-lsb linux"
	    exit 1
	fi

	if test -f /etc/altlinux-release; then
	    daemon_status()
	    {
		my_pid=`pidofproc ${1+"$@"}`
		if test -n "$my_pid";then
		    echo "$1 is running (pid $pid)"
		    return 0
		else
		    echo "$1 is stopped"
		    return 1
		fi
	    }
	else
	    daemon_status()
	    {
		status ${1+"$@"}
	    }

	    start_daemon()
	    {
		my_nice=
		my_force=
		while [ "$1" != "${1##[-+]}" ]; do
			case $1 in
			     -f)
				my_force="--force"
				shift
				;;
			     -n)
				my_nice=$2
				shift 2
				;;
			esac
		done
		LSB=LSB-1.1 daemon ${my_force:-} ${my_nice:-} $*
		return $?
	    }
	fi
    fi
fi

serv_list()
{
  test -f $1 && for i in `$1 -ini '\config\services' -enum section`; do
    $1 -ini \\config\\services\\$i\\StartService -view
  done
}
PID_FILE=/var/run/cprocsp.pid
SERVICE_LIST=""

#for sdir in /opt/cprocsp/sbin/amd64 /opt/cprocsp/sbin/amd64;do
for sdir in /opt/cprocsp/sbin/amd64 /opt/cprocsp/sbin/ia32;do
	test -f $sdir/cpconfig && for serv_to_start in `serv_list $sdir/cpconfig`
	do 
		server_to_start=$sdir/$serv_to_start
		if test -f $server_to_start && test x"`echo $SERVICE_LIST|fgrep $serv_to_start`" = x; then
			SERVICE_LIST="$SERVICE_LIST $serv_to_start" 
			eval SERVER_$serv_to_start=$server_to_start
		fi
	done
done

check_func() {
  check_stop=0
  trap "check_stop=1"  2 3 15
  for CPVERIFY in /opt/cprocsp/bin/amd64/cpverify /opt/cprocsp/bin/amd64/cpverify /opt/cprocsp/bin/ia32/cpverify
  do
      test "/cpverify" = "$CPVERIFY" && continue
      test -f $CPVERIFY || continue
      $CPVERIFY 1>/dev/null 2>&1 && break
  done

  echo $$ >$PID_FILE
  while test $check_stop = 0 && test -n "$*"
  do
    file=$1
    hash=$2
    shift 2
    $CPVERIFY $file $hash
    cpverify_ret=$?
    if test $cpverify_ret -ne 0
    then
      RET=3
      logger CryptoPro CSP: error while checking $file integrity. Expected hash: $hash. Got hash: `$CPVERIFY -mk $file`. Error code: $cpverify_ret.    
      mv -f $file $file.corrupted
    fi
  done
  rm $PID_FILE
  trap 2 3 15
  return $RET
}
test -f /opt/cprocsp/sbin/amd64/lcdfunctions && . /opt/cprocsp/sbin/amd64/lcdfunctions
test -f /opt/cprocsp/sbin/ia32/lcdfunctions && . /opt/cprocsp/sbin/ia32/lcdfunctions
test -f /opt/cprocsp/sbin/amd64/lcdfunctions && . /opt/cprocsp/sbin/amd64/lcdfunctions

pause_after_start() {
  if test -z ""; then
    # will set $my_pid:
    daemon_status $1 > /dev/null
    j=0
    max=10
    while test $j -lt $max; do
      j=`expr $j + 1`
      service_status=`ps -A -o stat,pid,user,time,args | grep $my_pid | grep -v grep | awk '{print $1}'`
      if echo $service_status | grep D > /dev/null; then
        sleep 1
      else
        break
      fi
    done
  else
    sleep 3
  fi
}

kill_service() {
  arg="$1"
  ret=0
 
  if daemon_status $arg >/dev/null; then
    j=0
    max=10
    echo
    while test $j -lt $max; do
      j=`expr $j + 1`
      killproc $arg
      ret=$?
      if test $ret -ne 0; then
        break
      fi
      if daemon_status $arg >/dev/null; then
        sleep 1
      else
        break
      fi
    done
   
    if test $j -eq $max; then
      ret=1
    fi
  fi
 
  return $ret
}

stop_check() {
   test -f $PID_FILE || return 0
   check_pid=`cat $PID_FILE`
   if test x$1 != xforce 
   then
      if kill -0 $check_pid 2>/dev/null
      then
        test x`find $PID_FILE -mtime 0` != x && return 1
      else
	rm $PID_FILE
	return 0
      fi
   fi
   kill $check_pid 2>/dev/null
   if test $? != 0
   then
	rm $PID_FILE
	return 0
   fi

   i=0
   while test $i -lt 180
   do
	kill -0 $check_pid 2>/dev/null || return 0
	sleep 1
	i=`expr $i + 1`
   done
   kill -9 $check_pid
   if ! kill -0 $check_pid 2>/dev/null; then
     rm $PID_FILE
   fi
   return 0
}

cpcsp_check() {
  stop_check
  ret=$?
  while [ $ret -ne 0 ] ; do
    echo "Other check process is running. Wait..."
    sleep 2
    stop_check
    ret=$?
  done
  list=${1:-`ls /opt/cprocsp/lib/hashes|sed 's%.*%/opt/cprocsp/lib/hashes/&%'`}
  test -n "$list" && check_func `cat $list`
  return $?
}


#start_daemon()
#{
#     sleep 1
##  /usr/sbin/daemon -f -c $1
# ( cd / ; nohup $1 </dev/null >/dev/null 2>&1 )
#  ret=$?
#  if test $ret -eq 0; then
#    printf ": ok\n"
#  else
#    printf ": error $ret\n"
#  fi
#  return $ret
#}

#killproc()
#{
#  PIDS=`ps -A -o comm,pid|awk "/$1 /{print \\$2}"`
#  if test -n "$PIDS"; then
#    kill $PIDS
#    ret=$?
#    if test $ret -eq 0; then
#      printf ": ok\n"
#    else
#      printf ": error\n"
#    fi
#  else
#    printf ": nothing to kill\n"
#  fi
#  # TODO: CPCSP-4142: return $ret
#  return 0
#}

#daemon_status()
#{
#  ps -A -o comm,pid|sed -ne "/^.*$1/{s/ \{1,\}/ /g
#P
#}"|awk '{print}END{exit NR==0;}' 
#}

cpcsp_locks_clean() {
  if type lsof > /dev/null 2>&1 ;
  then
    # get csp opened files
    lsof_list=`lsof -F n|grep "/var/opt/cprocsp/tmp"|sed -n 's#^n\(/var/opt/cprocsp.*\)#\1#p'`
    # delete 1-day-old tmp files that are not opened by anyone
    find "/var/opt/cprocsp/tmp" -type f -mtime +1 -name ".*" | while read tmp_file_path; do
      lsof_match_tmp=0
      echo "$lsof_list" | while read lsof_file_path; do
        if test "$lsof_file_path" = "$tmp_file_path"; then
           lsof_match_tmp=1
           break
        fi
      done
      if test $lsof_match_tmp -eq 0; then
        rm -f "$tmp_file_path"
      fi
    done
  else
    # delete 14-days-old files
    find "/var/opt/cprocsp/tmp" -type f -mtime +14 -name ".*" -exec rm -f "{}" \;
  fi
}

cpcsp_clean()
{
  cpcsp_locks_clean
  for mnt in /var/opt/cprocsp/mnt/* ; do
    if [ -d $mnt ] ; then
      LANG=C LC_ALL=C umount $mnt 2>&1 | \
	  grep -v 'not mounted' | \
	  grep -v 'not in mnttab' | \
	  grep -v 'not a file system root directory' 1>&2
    fi
  done
}
    
cpcsp_start() {
#  ulimit -d unlimited
  for i in $SERVICE_LIST; do
    test x$1 = xrestart && test x$i = xsrv_wrapper && continue  
    printf "Starting $i"
    # Precedence of 64-bit version over 32-bit one.
    eval start_daemon \$SERVER_$i
    pause_after_start $i
    RET=$?
  echo
  test $RET -eq 0 && test -d /var/lock/subsys && touch /var/lock/subsys/$i
    test $RETVAL -eq 0 && RETVAL=$RET
  done
}
#full copy of cpcsp_stop but not stoping srv_srapper. need it for call it from inside of srv_srapper
cpcsp_hsmstop() {
  for i in $SERVICE_LIST; do
    test x$i = xsrv_wrapper && continue  
    printf "Shutting down $i"
    kill_service $i
    RET=$?
    test $RET -eq 0 && rm -f /var/lock/subsys/$i
    test $RETVAL -eq 0 && RETVAL=$RET
    if test $RET -ne 0; then
      echo "Error stopping service"
      break
    fi
  done
  cpcsp_clean
}

cpcsp_stop() {
  for i in $SERVICE_LIST; do
    test x$1 = xrestart && test x$i = xsrv_wrapper && continue  
    printf "Shutting down $i"
    kill_service $i
    RET=$?  
    test $RET -eq 0 && rm -f /var/lock/subsys/$i
    test $RETVAL -eq 0 && RETVAL=$RET
    if test $RET -ne 0; then
      echo "Error stopping service"
      break
    fi
  done
  cpcsp_clean
}

repair_var() {
    if ! test -d /var/opt/cprocsp ;
    then
	mkdir -p /var/opt/cprocsp
	mkdir /var/opt/cprocsp/keys
	mkdir /var/opt/cprocsp/users
	mkdir /var/opt/cprocsp/tmp
	mkdir /var/opt/cprocsp/mnt

	chown -R root /var/opt/cprocsp

	chmod 775 /var/opt/cprocsp
	chmod 777 /var/opt/cprocsp/keys
	chmod 1777 /var/opt/cprocsp/users
	chmod 777 /var/opt/cprocsp/tmp
	chmod 775 /var/opt/cprocsp/mnt
    fi
}

RETVAL=0
case "$1" in
  start) test "x$2" = "xrestart" ||
#   repair_var; 
		cpcsp_check;
		RET=$?
		test $RETVAL -eq 0 && RETVAL=$RET
		cpcsp_clean;
		cpcsp_start $2;
		RET=$?
		test $RETVAL -eq 0 && RETVAL=$RET
		;;
  stop) cpcsp_stop $2;;
  hsmstop) cpcsp_hsmstop $2 ;;
  restart) cpcsp_stop restart; cpcsp_start restart;;
  status)
    for i in $SERVICE_LIST; do
      daemon_status $i
      RET=$?
      test $RETVAL -eq 0 && RETVAL=$RET
    done;;
  check)        shift;
                cpcsp_locks_clean;
                cpcsp_check $*;
                RET=$?
                test $RETVAL -eq 0 && RETVAL=$RET;;
  stop_check) shift; stop_check $*;RETVAL=$?;;
  *)
    echo "Usage: $0 {start|stop|restart|status|check|stop_check}"
    RETVAL=1;;
esac

PATH=$old_path
exit $RETVAL
