#!/bin/sh
#-------------------------------------------------------------------------------
# charon_menu_preferences
#-------------------------------------------------------------------------------
# Copyright (C) 2013-2022 STROMASYS.
# All rights reserved.
#
#set -x
VERSION=1.10

function The_End
{
  tput rmacs
  tput sgr0
  echo "$1"
  exit
}

trap 'echo;The_End "Aborted."' 1 2 9 14 15

. `dirname $0`/charon_common
. `dirname $0`/charon_common_menu
LOGFLIST="${CHARONDIR}/utils/charon_logchk.list"
BOOTLIST="${CHARONDIR}/utils/charon_gstart.boot"

#-----------------------------------------------------------------------------
# Functions
#-----------------------------------------------------------------------------
function set_preferences
{
  echo "CUIEDIT=${CUIEDIT}"                  >${PREFFILE}
  echo "GUIEDIT=${GUIEDIT}"                  >>${PREFFILE}
  echo "SELEDIT=${SELEDIT}"                  >>${PREFFILE}
  echo "LOGTAILST=${LOGTAILST}"              >>${PREFFILE}
  echo "LOGTAILCT=${LOGTAILCT}"              >>${PREFFILE}
  echo "OOMPRVPIDKILL=${OOMPRVPIDKILL}"      >>${PREFFILE}
  echo "SEMIGRAPH=${SEMIGRAPH}"              >>${PREFFILE}
  echo "LISTSEPAR=${LISTSEPAR}"              >>${PREFFILE}
  echo "GLOBALLOGMON=${GLOBALLOGMON}"        >>${PREFFILE}
  echo "SVCTIMOUTSTART=${SVCTIMOUTSTART}"    >>${PREFFILE}
  echo "SVCTIMOUTSTOP=${SVCTIMOUTSTOP}"      >>${PREFFILE}
  echo "AUTOSTOPLOGTAIL=${AUTOSTOPLOGTAIL}"  >>${PREFFILE}
  echo "ENABLESUDO=${ENABLESUDO}"            >>${PREFFILE}
  echo "CONSOLEMODE=${CONSOLEMODE}"          >>${PREFFILE}
  echo "DEFAULTBLUE=${DEFAULTBLUE}"          >>${PREFFILE}

  chmod u+x ${PREFFILE}
}


function set_default_editor
{
  echo
  echo "Please select the default editor for the [32m[1mcharacter[0m user interface (CUI)."
  echo "Selecting 'none' will force the utility to ask you the editor each time"
  echo "a file has to be edited."
  ED="none "
  test -x /bin/nano      && ED="${ED}nano "
  test -x /bin/vi        && ED="${ED}vi "
  test -x /usr/bin/vim   && ED="${ED}vim "
  echo "[1mAvailable options[0m: ${FGBLUE}${ED}[0m"
  while test 1
  do
    echo -n "${FGBLUEBOLD}Your choice [`basename ${CUIEDIT}`] (q to quit): [0m"
    read ANS
    ANS=`echo "${ANS}" | tr -d [:blank:]`
    test -z "${ANS}" && ANS=`basename ${CUIEDIT}`
    case "${ANS}"
    in
      q|Q)
        break
        ;;
      *)
        if test -n "`echo ${ED} | grep -w ${ANS}`"
        then
          CUIEDIT=${ANS}
          test "${ANS}" = "none" || CUIEDIT=`which ${ANS}`
          set_preferences
          break
        else
          tput cuu1;tput el
        fi
        ;;
    esac
  done

  echo
  echo "Please select the default editor for the [32m[1mgraphical[0m user interface (GUI)."
  echo "Selecting 'none' will force the default CUI editor (if not set to 'none')."
  ED="none "
  test -x /usr/bin/gedit && ED="${ED}gedit "
  test -x /usr/bin/emacs && ED="${ED}emacs "
  test -x /usr/bin/gvim  && ED="${ED}gvim "
  echo "[1mAvailable options[0m: ${FGBLUE}${ED}[0m"
  while test 1
  do 
    echo -n "${FGBLUEBOLD}Your choice [`basename ${GUIEDIT}`] (q to quit): [0m"
    read ANS
    ANS=`echo "${ANS}" | tr -d [:blank:]`
    test -z "${ANS}" && ANS=`basename ${GUIEDIT}`
    case "${ANS}"
    in
      q|Q)
        break
        ;;
      *)
        if test -n "`echo ${ED} | grep -w ${ANS}`"
        then
          GUIEDIT=${ANS}
          test "${ANS}" = "none" || GUIEDIT=`which ${ANS}`
          set_preferences
          break
        else
          tput cuu1;tput el
        fi
        ;;
    esac
  done

  if test "${CUIEDIT}" = "none" -a "${GUIEDIT}" = "none"
  then
    SELEDIT="N/A"
    set_preferences
  else
    echo
    echo "${FGBLUEBOLD}Available editor modes selection: [0m"
    echo "1 - always ask"
    echo "2 - automatic"
    SELEDITD="1"
    test "${SELEDIT}" = "auto" && SELEDITD="2"
    while test 1
    do 
      echo -n "${FGBLUEBOLD}Please select the mode [default is ${SELEDITD}] (q to quit): [0m"
      read ANS
      ANS=`echo "${ANS}" | tr -d [:blank:]`
      test -z "${ANS}" && ANS=${SELEDITD}
      case "${ANS}"
      in
        q|Q)
          break
          ;;
        1)
          SELEDIT="always_ask"
          set_preferences
          break
          ;;
        2)
          SELEDIT="auto"
          set_preferences
          break
          ;;
        *)
          tput cuu1;tput el
          ;;
      esac
    done
  fi
}

function log_tail_on_startstop
{
  cat <<EOF

When a guest (virtual machine) is started or stopped, its log file is displayed
continuously until CTRL-C is pressed. This feature can be disabled, the log
file can still be displayed using the 'logtail' or 'logview' commands.

(!) This is valid for RHEL 7.x and CentOS 7.x and above (not for RHEL 6.x)

EOF

  CH="enable"
  test "${LOGTAILST}" = "true" && CH="disable"
  while test 1
  do 
    echo -n "${FGBLUEBOLD}Do you want to ${CH} this feature (y/n)? [n] [0m"
    read ANS
    test -z "${ANS}" && ANS="n"
    case "${ANS}"
    in
      y|Y)
        if test "${LOGTAILST}" = "true"
        then
          LOGTAILST="false"
        else
          LOGTAILST="true"
        fi
        set_preferences
        break
        ;;
      n|N)
        break
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done

  cat <<EOF

A "Press CTRL-C" line can be displayed periodically as a reminder when a
continuous log view is running either started automatically or on demand,
using the 'logtail'command for example.

EOF
  CH="enable"
  test "${LOGTAILCT}" = "enabled" && CH="disable"
  while test 1
  do 
    echo -n "${FGBLUEBOLD}Do you want to ${CH} this feature (y/n)? [n] [0m"
    read ANS
    test -z "${ANS}" && ANS="n"
    case "${ANS}"
    in
      y|Y)
        if test "${LOGTAILCT}" = "enabled"
        then
          LOGTAILCT="disabled"
        else
          LOGTAILCT="enabled"
        fi
        set_preferences
        break
        ;;
      n|N)
        break
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done

  cat <<EOF

The continuous log view can be stopped automatically if either the "Started"
or "Stopped" message is found in the log file. This is the default behavior.

EOF
  CH="enable"
  test ${AUTOSTOPLOGTAIL:-1} = 1 && CH="disable"
  while test 1
  do 
    echo -n "${FGBLUEBOLD}Do you want to ${CH} this feature (y/n)? [n] [0m"
    read ANS
    test -z "${ANS}" && ANS="n"
    case "${ANS}"
    in
      y|Y)
        if test ${AUTOSTOPLOGTAIL:-1} = 1
        then
          AUTOSTOPLOGTAIL=0
        else
          AUTOSTOPLOGTAIL=1
        fi
        set_preferences
        break
        ;;
      n|N)
        break
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done
}

function update_sysctl
{
    VMOV=`/sbin/sysctl -n vm.overcommit_memory 2>/dev/null`
    VMPA=`/sbin/sysctl -n vm.panic_on_oom 2>/dev/null`
    cat <<EOSYSCTL >/etc/sysctl.d/charon.conf
#-- Updated on `date +"%d-%b-%Y %H:%M:%S"` --
vm.overcommit_memory=${VMOV}
vm.panic_on_oom=${VMPA}
EOSYSCTL
}

function oom_settings
{
  echo
  DEFANS="1"
  test "${OOMPRVPIDKILL}" = "disabled" && DEFANS="0"
  while test 1
  do
    echo -n "Charon VM process killing prevention (0=disabled, 1=enabled) [[36m${DEFANS}[0m] : "
    read ANS
    test -z "${ANS}" && ANS=${DEFANS}
    case "${ANS}"
    in
      0)
        OOMPRVPIDKILL="disabled"
        set_preferences
        echo
        echo "[31mCharon virtual machines will not be protected against OOM Killer.[0m"
        echo
        if test "${ANS}" != "${DEFANS}"
        then
          tput smso
          echo " Applying and verifying changes for running guests... "
          tput rmso
          display_guestslist
          Press_Enter
        fi
        break
        ;;
      1)
        OOMPRVPIDKILL="enabled"
        set_preferences
        echo
        echo "[32mCharon virtual machines will be protected against OOM Killer.[0m"
        echo
        if test "${ANS}" != "${DEFANS}"
        then
          tput smso
          echo " Applying and verifying changes for running guests... "
          tput rmso      
          display_guestslist
          Press_Enter
        fi
        break
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done

  echo
  while test 1
  do
    OVERCOMMIT=`/sbin/sysctl -n vm.overcommit_memory 2>/dev/null`
    PANICONOOM=`/sbin/sysctl -n vm.panic_on_oom 2>/dev/null`

    DEFANS=${OVERCOMMIT:-0}
    echo -n "VM overcommit memory (0, 1, 2 or ? for help) [[36m${DEFANS}[0m] : "
    read ANS
    test -z "${ANS}" && ANS=${DEFANS}
    case "${ANS}"
    in
      0|1|2)
        /sbin/sysctl -q vm.overcommit_memory=${ANS}
        update_sysctl 
        break
        ;;
      ?)
        cat <<OVRMEM

[1mThe Linux kernel supports the following overcommit handling modes[0m

0	-	Heuristic overcommit handling. Obvious overcommits of
		address space are refused. Used for a typical system. It
		ensures a seriously wild allocation fails while allowing
		overcommit to reduce swap usage.  root is allowed to 
		allocate slightly more memory in this mode. This is the 
		default.

1	-	Always overcommit. Appropriate for some scientific
		applications. Classic example is code using sparse arrays
		and just relying on the virtual memory consisting almost
		entirely of zero pages.

2	-	Don't overcommit. The total address space commit
		for the system is not permitted to exceed swap + a
		configurable amount (default is 50%) of physical RAM.
		Depending on the amount you use, in most situations
		this means a process will not be killed while accessing
		pages but will receive errors on memory allocation as
		appropriate.

		Useful for applications that want to guarantee their
		memory allocations will be available in the future
		without having to initialize every page.

OVRMEM
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done

  echo
  while test 1
  do
    OVERCOMMIT=`/sbin/sysctl -n vm.overcommit_memory 2>/dev/null`
    PANICONOOM=`/sbin/sysctl -n vm.panic_on_oom 2>/dev/null`

    DEFANS=${PANICONOOM:-0}
    echo -n "VM panic_on_oom (0, 1 or ? for help) [[36m${DEFANS}[0m] : "
    read ANS
    test -z "${ANS}" && ANS=${DEFANS}
    case "${ANS}"
    in
      0|1)
        /sbin/sysctl -q vm.panic_on_oom=${ANS}
        update_sysctl 
        break
        ;;
      ?)
        cat <<PANOOM

[1mThis enables or disables panic on out-of-memory feature.[0m

- If this is set to 1, the kernel panics when out-of-memory happens.
- If this is set to 0, the kernel will kill some rogue process, by calling
  oom_kill().

Usually, oom_killer can kill rogue processes and system will survive. If you
want to panic the system rather than killing rogue processes, set this to 1.

The default value is 0 (recommended)

PANOOM
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done
}

function semigraphics_settings
{
  if test "${SEMIGRAPH}" = "enabled"
  then
    SEMIGRAPH="disabled"
  else
    SEMIGRAPH="enabled"
  fi
  set_preferences
}

function global_logmon_settings
{
  echo
  tput bold
  echo "NOTE:"
  tput sgr0
  if test "${GLOBALLOGMON}" = "enabled"
  then
    GLOBALLOGMON="disabled"
    echo "If there are log monitoring services running, please stop them manually."
  else
    GLOBALLOGMON="enabled"
    echo "If there are existing virtual machines configured, please create and start"
    echo "the log monitoring services manually."
  fi
  set_preferences
  echo
  Press_Enter
}


function display_vm_separator
{
  echo
  while test 1
  do
    echo -n "Select 1=none, 2=blank line, 3=separation line, q=quit : "
    read ANS
    case "${ANS}"
    in
      1)
        LISTSEPAR="none"
        set_preferences
        break
        ;;
      2)
        LISTSEPAR="blank"
        set_preferences
        break
        ;;
      3)
        LISTSEPAR="line"
        set_preferences
        break
        ;;
      q)
        break
        ;;
      *)
        tput cuu1;tput el
        ;;
    esac
  done
}

function set_charonguestservice
{
  echo
  echo "Default start timeout = [36m${SVCTIMOUTSTART} minutes[0m"
  while test 1
  do
    echo -n "Enter default timeout for start in minutes (greater than 0): "
    read ANS
    if test -n "${ANS}"
    then
      if test -n "`echo ${ANS} | tr -d [:digit:]`"
      then
        echo "Must be numeric (integer)."
      else
        if test ${ANS} -eq 0
        then
          echo "Must be greater than 0."
        else
          SVCTIMOUTSTART=${ANS}
          set_preferences
          break
        fi
      fi
    else
      echo "Not changed."
      break
    fi
  done

  echo
  echo "Default stop timeout = [36m${SVCTIMOUTSTOP} minutes[0m"
  while test 1
  do
    echo -n "Enter default timeout for stop in minutes (greater than 0): "
    read ANS
    if test -n "${ANS}"
    then
      if test -n "`echo ${ANS} | tr -d [:digit:]`"
      then
        echo "Must be numeric (integer)."
      else
        if test ${ANS} -eq 0
        then
          echo "Must be greater than 0."
        else
          SVCTIMOUTSTOP=${ANS}
          set_preferences
          break
        fi
      fi
    else
      echo "Not changed." 
      break
    fi
  done
}

function set_sudo
{
  test ${ENABLESUDO:-0} = 0 && ENABLESUDO=1 || ENABLESUDO=0
  set_preferences
}

function console_mode
{
  cat <<EOCM

[7mSet console access mode to either:[0m
1 - "[36mAlways ask[0m" : if 'putty' and 'telnet' are installed and a DISPLAY is
                   defined, will ask for one of the other
2 - "[36mputty[0m"      : if 'putty' and 'telnet' are installed and a DISPLAY is
                   defined, will force to 'putty'. If no DISPLAY, will force
                   to 'telnet'
3 - "[36mtelnet[0m"     : if 'telnet' is installed, will force to 'telnet'

q - quit

EOCM

  case "${CONSOLEMODE}"
  in
    "putty")  DEFCMOD=2;;
    "telnet") DEFCMOD=3;;
    *)        DEFCMOD=1;;
  esac

  while test 1
  do
    echo -n "Console access mode [${DEFCMOD}] : "
    read ANS
    case "${ANS}"
    in
      1)
        CONSOLEMODE="always_ask"
        set_preferences
        break
        ;;
      2)
        if test -e /usr/bin/putty
        then
          CONSOLEMODE="putty"
          set_preferences
          break
        else
          tput bold
          echo "'putty' is not installed !"
          tput sgr0
          echo
        fi
        ;;
      3)
        if test -e /usr/bin/telnet
        then
          CONSOLEMODE="telnet"
          set_preferences
          break
        else
          tput bold
          echo "'telnet' is not installed !"
          tput sgr0
          echo
        fi
        ;;
      q)
        break
        ;;
      "")
        break
        ;;
      *)
        tput cuu1
        tput el
        ;;
    esac
  done
}

function default_blue
{
  test ${DEFAULTBLUE:-0} = 0 && DEFAULTBLUE=1 || DEFAULTBLUE=0
  set_preferences
}


#-----------------------------------------------------------------------------
# Main menu
#-----------------------------------------------------------------------------
while test 1
do
  display_header "Preferences"
  if test `id -u` -ne 0
  then
    echo
    tput bold
    echo "Must be root !"
    tput sgr0
    Press_Enter
    echo
    exit 1
  fi

  #--- get the user's preferences (function is in charon_common script)
  get_preferences

  #--- display the options
  echo "${FGBLUEBOLD} 1[0m - Default editor:"
  echo "       Character User Interface (CUI) = [36m`basename ${CUIEDIT}`[0m"
  echo "       Graphical User Interface (GUI) = [36m`basename ${GUIEDIT}`[0m"
  echo "       Selection mode = [36m${SELEDIT}[0m"

  echo "${FGBLUEBOLD} 2[0m - Continuous log view:"
  echo "       Automatically start with guest start: [36m${LOGTAILST}[0m"
  echo "       Press CTRL-C line display/reminder: [36m${LOGTAILCT}[0m"
  if test ${AUTOSTOPLOGTAIL:-1} = 1
  then
    echo "       Automatically stop continuous log view: [36mYes[0m"
  else
    echo "       Automatically stop continuous log view: No[0m"
  fi
  echo -n "       "
  if test "${SEMIGRAPH}" = "enabled"
  then
    tput smacs
    echo -n "m"
    tput rmacs
  else
    echo -n "+"
  fi
  echo " [90mwhen started interactively from the 'menu' or with 'vmstart'.[0m"

  echo "${FGBLUEBOLD} 3[0m - Out Of Memory (OOM) settings"
  echo -n "       Charon VM process killing prevention = "
  test "${OOMPRVPIDKILL}" = "enabled" && echo -n "[36m" || echo -n "[31m"
  echo "${OOMPRVPIDKILL}[0m"
  OVERCOMMIT=`/sbin/sysctl -n vm.overcommit_memory 2>/dev/null`
  typeset -i OV=${OVERCOMMIT}+1
  OVERCOMDIS=`echo "Heuristic overcommit handling [default],Always overcommit,Don't overcommit [recommended]" | cut -f${OV} -d','`
  echo "       VM overcommit_memory value = [36m${OVERCOMMIT} (${OVERCOMDIS})[0m"
  PANICONOOM=`/sbin/sysctl -n vm.panic_on_oom 2>/dev/null`
  echo -n "       VM panic_on_oom = [36m${PANICONOOM:-Unknown}"
  test ${PANICONOOM:-0} = 0 && echo " (disabled)[0m" || echo " (enabled)[0m"

  echo -n "${FGBLUEBOLD} 4[0m - Semi-graphics (drawing tables): "
  test "${SEMIGRAPH}" = "enabled" && echo -n "[36m" || echo -n "[31m"
  echo "${SEMIGRAPH}[0m"

  echo -n "${FGBLUEBOLD} 5[0m - Display guests separator:       "
  case "${LISTSEPAR}"
  in
    ""|"none") echo "None";;
    "blank")   echo "[36mBlank line[0m";;
    "line")    echo "[36mSeparation line[0m";;
  esac

  echo -n "${FGBLUEBOLD} 6[0m - Charon log monitoring (global): "
  test "${GLOBALLOGMON}" = "enabled" && echo -n "[36m" || echo -n "[31m"
  echo "${GLOBALLOGMON}[0m"

  echo "${FGBLUEBOLD} 7[0m - Charon VM service default timeout: Start=[36m${SVCTIMOUTSTART} minutes[0m / Stop=[36m${SVCTIMOUTSTOP} minutes[0m"

  echo -n "${FGBLUEBOLD} 8[0m - Access 'menu' using 'sudo': "
  test ${ENABLESUDO:-0} = 0 && echo "[31mDisabled[0m" || echo "[36mEnabled[0m"

  echo -n "${FGBLUEBOLD} 9[0m - Console access mode: "
  if test ! -e /usr/bin/putty
  then
    if test -e /usr/bin/telnet
    then
      echo "[31m'putty' not installed, using 'telnet'[0m"
      CONSOLEMODE="telnet"
      set_preferences
    else
      echo "[31mNor 'putty' nor 'telnet' are installed[0m"
      CONSOLEMODE="always_ask"
      set_preferences
    fi
  else
    case "${CONSOLEMODE}"
    in
      "always_ask")
        echo "[36mAlways ask[0m"
        ;;
      "telnet")
        echo "[36m'telnet' preferred[0m"
        ;;
      "putty")
        echo "[36m'putty' preferred when possible[0m"
        ;;
      *)
        echo "[36mAlways ask[0m"
        CONSOLEMODE="always_ask"
        set_preferences
        ;;
    esac
  fi

  echo -n "${FGBLUEBOLD}10[0m - Blue color adjust for white/black background: "
  if test ${DEFAULTBLUE:-0} = 0
  then
    echo "[38;5;27mNORMAL[0m - [38;5;32mBOLD[0m"
  else
    echo "${FGBLUE}NORMAL[0m - ${FGBLUEBOLD}BOLD[0m"
  fi

  echo -n "${FGBLUEBOLD}Enter your choice ('q' to quit): [0m"
  read ANS
  case "${ANS}"
  in
    1)
      #--- Default editor
      set_default_editor
      ;;
    2)
      #--- Log tail when a guest is started/stopped
      log_tail_on_startstop
      ;;
    3)
      #--- OOM settings
      oom_settings
      ;;
    4)
      #--- Semi-graphics
      semigraphics_settings
      ;;
    5)
      #--- Display VM separator
      display_vm_separator
      ;;
    6)
      #--- Global log monitoring
      global_logmon_settings
      ;;
    7)
      #--- Charon guest service
      set_charonguestservice
      ;;
    8)
      #--- Enable/disable 'sudo'
      set_sudo
      ;;
    9)
      #--- Console access mode
      console_mode
      ;;
    10)
      #--- Default blue color for white or black background
      default_blue
      ;;
    q|Q)
      break
      ;;
  esac
done

exit
