#!/bin/bash

#####################################################################
# Проверка/запуск/остановка драйверов для PCI и USB модулей LCARD.
# Линки устройств создаются автоматически, предварительно
# надо скопировать lcard.rules в папку /etc/udev/rules.d
# чтобы заработал udev. Нумерация слотов сквозная....ldev0, ldev1....
# Параметер howmany задает количество создаваемых линков (max 128).
# Пакетные зависимости: lcomp-dkms liblcomp1 liblcomp1-dev
#####################################################################

readonly scriptfile="${BASH_SOURCE[0]}";               # script file name
readonly scriptname="$(basename $scriptfile)";         # base name of script
readonly scripthome="$(dirname  $scriptfile)";         # directory of script
readonly scriptFILE="$(realpath $scriptfile)";         # real path name of script
readonly scriptHOME="$(dirname  $scriptFILE)";         # real directory of script

readonly lcomp_web_site="http://download.opensuse.org/repositories/home:/l-card/";
readonly lcomp_deb_list='lcomp-dkms liblcomp1 liblcomp1-dev'; # deb dependencies
readonly lcomp_lib_dkms="/var/lib/dkms/lcomp"; # directory to seach drivers in

readonly numdevices="10";                              # max number of devices 1..128
readonly rmodlist="ldevusb ldevpci ldevpcibm ldevice"; # remove  modules
readonly imodlist="ldevice ldevpci ldevpcibm ldevusb"; # install modules
declare -i errors=0;                                   # error counter
declare -i hastty=0;                                   # terminal mode

#############################################################################################################################
# https://stackoverflow.com/questions/1763891/is-it-possible-to-make-stdout-and-stderr-output-be-of-different-colors-in-xterm
#############################################################################################################################
function colorize_norm()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[31m&\e[m,'   >&2 ) 3>&1 | sed $'s,.*,\e[32m&\e[m,'   );
function colorize_bold()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[1;31m&\e[m,' >&2 ) 3>&1 | sed $'s,.*,\e[1;32m&\e[m,' );
function colorize_head()( set -o pipefail; ( "$@" 2>&1>&3 | sed $'s,.*,\e[1;35m&\e[m,' >&2 ) 3>&1 | sed $'s,.*,\e[1;37m&\e[m,' );
function colorize_none()( "$@"; );

###########################
# print $1 to stdout/stderr
###########################
function print_stdout(){      echo "$1"; };
function print_stderr(){ 1>&2 echo "$1"; };
function print_log(){ if [ $hastty -eq 1 ]; then colorize_bold print_stdout "$1"; else print_stdout "$1"; fi; };
function error_log(){ if [ $hastty -eq 1 ]; then colorize_bold print_stderr "$1"; else print_stderr "$1"; fi; };
function title_log(){ if [ $hastty -eq 1 ]; then colorize_head print_stdout "$1"; else print_stdout "$1"; fi; };

####################
# check user is root
####################
function check_root(){
 if [ $(id -u) -ne 0 ]; then
  error_log "Please run this script as root or use sudo!";
  let errors++;
  exit 1;
 fi;
};

###########################
# list kernel modules names
###########################
function list_mod(){
 if [ -e /proc/modules ]; then
  cat /proc/modules  | cut -d " " -f 1;
  return;
 fi;
 if which lsmod >/dev/null 2>&1; then
  lsmod | tail -n +2 | cut -d " " -f 1;
  return;
 fi;
 return 1;
};

########################
# check kernel module $1
########################
function has_mod(){
 local mod="$(list_mod | grep "$1")";
 if [ -n "$mod" ]; then return 0; else return 1; fi;
};

#######################
# options for module $1
#######################
function opt_mod(){
 if [ "_$1" = "_ldevice" ]; then
  echo -n "howmany=$numdevices";
 fi;
};

################################
# print status of deb package $1
# expected: install ok installed
################################
function print_deb_status(){
 local deb="$1"; if [ -z "$deb" ]; then return 1; fi;
 env LANG=en dpkg -s $deb 2>/dev/null | grep 'Status:' | sed 's/Status://' | xargs;
};

#################################
# check status of deb packages $*
#################################
function check_deb_installed(){
 local missed="";
 local expect="install ok installed";
 while [ -n "$1" ]; do
  if [ "_$(print_deb_status "$1")" != "_$expect" ]; then missed+=" $1"; fi;
  shift;
 done;
 if [ -n "$missed" ]; then
  error_log "Package not installed:$missed";
  let errors++;
  return $1;
 fi;
 return 0;
};

########################
# list kernel modules ko
########################
function list_drivers(){
 find $lcomp_lib_dkms/ -type f -name 'ldev*.ko' | grep $(uname -r);
};

####################
# find kernel driver
####################
function find_driver(){
 if [ -n "$1" ]; then list_drivers | grep -P "\b$1\b" | tail -n 1; fi;
};

###################
# remove modules $*
###################
function rem_mods(){
 for mod in $*; do
  if has_mod $mod; then
   if rmmod $mod.ko; then
    print_log "Succeed stop  $mod";
   else
    error_log "Failure stop  $mod";
    let errors++;
   fi;
  else
   print_log "Already stop  $mod";
  fi;
 done;
};

####################
# install modules $*
####################
function ins_mods(){
 if [ $(list_drivers | wc -l) -ge 4 ]; then
  for mod in $*; do
   if [ -f "$(find_driver "$mod")" ]; then
    if has_mod $mod; then
     print_log "Already start $mod";
    else
     if insmod "$(find_driver "$mod")" $(opt_mod $mod); then
      print_log "Succeed start $mod";
     else
      error_log "Failure start $mod";
      let errors++;
     fi;
    fi;
   else
    error_log "Not found     $mod.ko";
    let errors++;
   fi;
  done;
 else
  error_log "Drivers not found";
  let errors++;
 fi;
};

###################
# print ldev status
###################
function ldev_status(){
 check_deb_installed $lcomp_deb_list;
 if [ $(list_drivers | wc -l) -ge 4 ]; then
  local mod="$(list_mod | grep ldev | xargs)";
  if [ -n "$mod" ]; then
   print_log "ldev status: STARTED - $mod";
   return 0;
  else
   error_log "ldev status: STOPPED";
   let errors++;
  fi;
 else
  error_log "ldev status: drivers not found";
  let errors++;
 fi;
 return 1;
};

declare -i opt_i=0;
declare -i opt_r=0;

######
# MAIN
######
function main(){
 if [ -t 1 ] && [ -t 2 ]; then let hastty=1; fi;
 case $1 in
  stop)    opt_r=1; opt_i=0; ;;
  start)   opt_r=0; opt_i=1; ;;
  restart) opt_r=1; opt_i=1; ;;
  drivers) list_drivers; exit $?; ;;
  status)  if ldev_status; then exit 0; else exit 1; fi; ;;
  *)       title_log "usage: $scriptname start|restart|stop|status|drivers"; exit 0; ;;
 esac;
 check_root;
 title_log "Exec $1";
 if [ $opt_r -eq 1 ]; then rem_mods $rmodlist; fi;
 if [ $opt_i -eq 1 ]; then ins_mods $imodlist; fi;
 title_log "Done $1";
 title_log "";
 if [ $errors -eq 0 ]; then exit 0; else exit 1; fi;
};

main "$@";

#############
# END OF FILE
#############
