File qserv of Package systemd-qserv

#!/usr/bin/env bash
#: Title           : qserv 
#: Sypnosis        : qserv [options]
#: Date Created    : Thu Feb 18 10:45:54 PHT 2012
#: Last Edit       : Tue Sep 10 07:03:56 PHT 2013  
#: License         : GPL-2+0
#: Version         : 1.0
#: Author          : Jason V. Ferrer '<jetchisel@opensuse.org>'
#: Description     : A simple interactive script that handles systemd services for OpenSUSE.
#: Options         : [ -h  --help ][ -? ][ -a  --about][ -v  --version ]
#: Note            : This is just a front end to systemd's systemctl and a not replacement.
# NOTE             : 
#                  : 
# TODO             : 
# Only root can deal with systemctl, as a normal user you need to enter the roots password. or use your favorite sudo utility.
###############################################################################################################################
# The menu still needs some (professional) redesigning but overall functionality was tested and seems to be working as expected.

shopt -s extglob
shopt -s checkwinsize 

COLUMNS=$(tput cols)
LINES=$(tput lines)

trap 'COLUMNS=$(tput cols) LINES=$(tput lines)' WINCH

## The colors
if [[ -t 1 ]]; then
  red=$(tput setaf 1)
  bold=$(tput bold)
  normal=$(tput sgr0)
  gb=$(tput setaf 2 && tput bold)  #"$green$bold"
  rb=$(tput setaf 1 && tput bold)
fi

half=$(($COLUMNS / 2))
barso=
Heading() { "$@";}
samp() { "$@"; }

if [[ $DISPLAY ]]; then ## the trap for COLUMNS is still buggy!
  barso=$(for ((j=0;j<=$(($half + 2));j++)); do printf "%s" '='; done)
  Heading() { printf "%s\n %$(($half - 4))s  \n%s\n\n" "$Barso" "$Title" "$Barso"; }
  samp() { printf "%s\n  %$(($half))s  \n%s\n\n" "$Barso" "$Example $Sample" "$Barso" ; }
 else 
   barso=$(for ((j=0;j<$COLUMNS;j++)); do printf "%s" '='; done)
   Heading() { printf "%s\n  %$(($half + 26))s  \n%s\n\n" "$Barso" "$Title" "$Barso" ;}
   samp() { printf "%s\n  %$(($half + 48))s  \n%s\n\n" "$Barso" "$Example $Sample" "$Barso" ; }
fi

version_() { version='Systemd-qserv 1.0'; printf "\n%s\n\n" "$version"; }

printf -v Barso "%s$barso%s" "$gb" "$normal"
printf -v Title "%sWelcome to qserv press the H key for help%s" "$bold" "$normal" ##
## This is the menu where you can choose from. You only need to press the number or letter from the choices the -n1 from read does the magic
Menu() { 
  action_=(Start Stop Restart Reload Enable Disable Query List Sysmode 'Man qserv' Help About Quit)
  all_=({1..9} M H A Q)
  
  for i in "${!all_[@]}"; do 
    printf -v all "%s[${all_[i]}]%s" "$gb" "$normal"
    printf -v action "%s${action_[i]}%s" "$bold" "$normal"
    printf "%s\n" "$all $action" 
  done
  echo
}

_foos=("list_" "quit" "Man_" "Return_")
_bars=("List" "Quit" "Man" "Return")

for i in "${!_foos[@]}"
  do printf -v "${_foos[$i]}" "%s${_bars[$i]}%s" "$gb" "$normal"
done

notes() {
  sample=(apache2 sshd mysql nfs cifs cups vboxdrv)
  printf -v Sample "%s${sample[*]}%s" "$gb" "$normal"
  printf -v Example "%sservices are:%s"
  samp
  printf "%s\n" "$Return_: Return to main menu." "$list_: List services." "$quit: Exit ${0##*/}"
}

sysnote() {
  printf -v key "%sJust key in the arguments to systemctl%s" "$bold" "$normal"
  printf "%s\n  %$(($half - 4))s  \n%s\n\n" "$Barso" "$key" "$Barso" 
   
  cat  <<-EOF
$Man_ : Read systemctl's man page.
$list_: List services.
$quit: Exit ${0##*/}
$Return_: Return to main menu.
EOF
}

About() { 
  foos_=("float" "MainDev" "Bman")
  bars_=("1.0" "MAINTAINER AND DEVELOPER:" "INITIAL PACKAGER FOR openSUSE:")
  for i in "${!foos_[@]}"
    do printf -v "${foos_[$i]}" "%s${bars_[$i]}%s" "$bold" "$normal"
  done
  
  less <<-EOF
You are using  version $float

Systemd-qserv is just a front end to systemctl and not a replacement for it.
It was written in the hope that user's will not have a hard time switching 
to systemd. It's goal is to make one's life easier when  dealing with systemd's
units (*.services.) This program only scratches the surface about what can be 
done. OpenSUSE has a  nice tool called yast/yast2 to deal with such advance task!

This program is free software you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

       $MainDev
            Jason V. Ferrer  'Jetchisel <jetchisel@opensuse.org>'
 
       $Bman
            Boris Manojlovic 'bmanojlovic <boris@steki.net>'     

Some detailed information you can find in this site.
            http://jason.ferrer.com.ph/2012/03/systemd-qserv.html
EOF
clear
}

usage() {
   cat <<-EOF
Usage: ${0##*/} [ -h  --help ][ -? ][ -a  --about][ -v  --version ]
EOF
}

Help() {
  foos=("interactive" "looks" "author")
  bars=("INTERACTIVE" "SEE ALSO" "AUTHOR")
  for i in "${!foos[@]}"
    do printf -v "${foos[$i]}" "%s${bars[$i]}%s" "$bold" "$normal"
  done

  less <<-EOF                           
Usage: ${0##*/} [ -h  --help ][ -? ][ -a  --about][ -v  --version ]

To use the $interactive menu just run ${0##*/} without any option.
         
Press 1 to start service(s):
Press 2 to stop service(s):
Press 3 to restart services(s):
Press 4 to reload service(s):
Press 5 to enable service(s):
Press 6 to disable service(s):
Press 7 to check the status of a specific service(s):
Press 8 to list available services:
Press 9 systemctl mode:
Press M qserv man page:
Press Q to quit this menu:
                               
You can put one or more service at a time and it can be without a '*.service' ie sshd apache2 mysql
or with a '*.service' extension ie 'sshd.service apache2.service mysql.service' or  a mix of both!
The only limitation in systemctl mode is using a command that it does not recognize! Press the return
key during the systemctl mode to acquire a more detailed info about it's units.                                    

    $looks
      systemctl(1)

    $author
       Jason V. Ferrer  'Jetchisel   <jetchisel@opensuse.org>'    
EOF
clear
}  

Solution() {
  line=()
   while read -ra _line; do
     [[ "${_line[0]}" != *.service ]] && continue 
     line+=("${_line[0]}")
   done < <(systemctl list-units --all)

   printf -v output "%s|" "@(${line[@]%.service})"
   output=${output%%|}
   
   temp=("${serv[@]%.service}")  ## remove the extension if there is any. no extension is not affected.
                                 ## so mixing a service with or without extension is allowed. 
   combined=()
   tmps=() ## This creates an array which only is listed in systemctl list-units --all.
   for serve in "${temp[@]}"; do
     [[ $serve != $output ]] && continue
     tmps+=("$serve")
   done
  
   tmps_=() ## This creates an array which is not listed in systemctl list-units --all.
   for serve_ in "${temp[@]}"; do
     [[ $serve_ != $output ]] || continue
     tmps_+=("$serve_")
   done  
   combined+=("${tmps[@]}" "${tmps_[@]}") ## combined tmps_ and tmps
   "$@"
 }

colored() { ## colored output of error and 'active (running)'
  old='error'
  old_='active (running)' ## 
  printf -v new "%s$old%s" "$rb" "$normal"
  printf -v new_ "%s$old_%s" "$gb" "$normal"
  
      while IFS= read -u8 -r one; do
        one=${one//$old/$new}  ## A simple search and replace using PE.
        printf "%s\n" "${one//$old_/$new_}"
      done 8< <(systemctl status "${temp[@]/%/.service}") | less 
    
}

paused() {
  echo
  printf -v prompt "%sDo you want to see the status? Y\N %s" "$gb" "$normal"
  read -r -e -p "$prompt" -n1 button
    case "$button" in
      [Yy]) colored ;;
      [Nn]) return ;;
      *) printf "%s\n\n" "Invalid answer!"
         paused
    esac
}

list() { ## We only need the services.
  Old=failed
  old=error
  final=()

  printf -v new "%s$old%s" "$rb" "$normal"
  printf -v New "%s$Old%s" "$rb" "$normal"

  mapfile -t lines < <(systemctl list-units --all)

  for i in  "${!lines[@]}"; do
    [[ ${lines[i]%% *} != *.service ]] && continue
    final+=("${lines[i]//$old/$new}")
  done

  printf "%s\n" "${final[@]//$Old/$New}" | less
}

## the empty variable we define global.
printf -v empty "%sPlease enter a service!%s" "$bold" "$normal" 

Progress() { ## A simple progress meter :-)
  echo       ## we only need the echo to have an additional blank space.
  i=0
  while ((i <= 100)); do
     printf "\r%1d%% complete..." $i 
     ((i += RANDOM%5+2))
  ## Will accept all arguments in systemctl. So you can run "Progress systemctl blah...blah" :-)
  done
  echo
}

forced() {
## Some service is not listed but that does not mean they dont exist, most probably they are disabled.
  printf "\n%s$rb${tmps_[*]} $normal is not listed as a service (probably disabled) trying..!\n" >&2 
}

start_() {
## check if input is both listed and not listed in systemctl list-units --all.
## the variable "$output" is the list that has the listed services.
  if ((${#tmps[@]})) && ((${#tmps_[@]})); then  
## Some service is not listed but that does not mean they dont exist, most probably they are disabled.
    forced
## Process them both with systemctl and let the pause function handle the errors.
## 2>/dev/null also discards the Progress function's error printing to stder.
    Progress < <(systemctl start "${combined[@]/%/.service}" 2>/dev/null)  && printf "\n%s\n" "$gb${tmps[*]}$normal has been started. (or at least tried)"
    paused
## Check if input is ONLY listed in systemctl list-units --all. The variable "$output" holds it.
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then 
## Process it directly with systemctl.
    Progress < <(systemctl start "${tmps[@]/%/.service}" 2>/dev/null) &&  printf "\n%s\n" "$gb${tmps[*]}$normal has been started. (or at least tried)"
    paused
  else 
## return to menu if all the input is not valid.
    forced
    Progress < <(systemctl start "${tmps_[@]/%/.service}" 2>/dev/null) 
    paused
  fi 
}

start() {          ## We use the  'clear' external program to clear the cluttered screen.
  while :; do      ## Again a while loop so we will not exit the session without the q button.
    clear
    notes
    printf -v prompt "\n%s(Enter the service(s) to start) ==> %s" "$gb" "$normal" 
      read -r -e -p "$prompt" -a serv  
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;; ## not allowed using the empty variable at line 250.
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;            ## some false positive testing :D
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0 ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service)  Solution start_  ;; ## check for extension and without extension
        esac                                     
  done
}

stop_() {
  if ((${#tmps[@]})) && ((${#tmps_[@]}));then
    forced
    Progress < <(systemctl stop "${combined[@]/%/.service}" 2>/dev/null) &&  printf "\n%s\n" "$gb${tmps[*]}$normal has been stopped. (or at least tried)"
    paused
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then
    Progress < <(systemctl stop "${tmps[@]/%/.service}" 2>/dev/null) &&  printf "\n%s\n" "$gb${tmps[*]}$normal has been stopped. (or at least tried)"
    paused
  else 
    forced
    Progress < <(systemctl stop "${tmps_[@]/%/.service}" 2>/dev/null)
    paused
  fi 
}

stop() {
  while :; do
    clear
    notes 
    printf -v prompt "\n%s(Enter the service(s) to stop) ==> %s" "$gb" "$normal"      
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0 ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) Solution stop_ ;;
        esac                     
  done
}

    
restart_() {
  if ((${#tmps[@]})) && ((${#tmps_[@]}));then
    forced
    Progress < <(systemctl restart "${combined[@]/%/.service}" 2>/dev/null) &&  printf "\n%s\n" "$gb${tmps[*]}$normal has been restarted. (or at least tried)"
    paused
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then
    Progress < <(systemctl restart "${tmps[@]/%/.service}" 2>/dev/null) &&  printf "\n%s\n" "$gb${tmps[*]}$normal has been restarted. (or at least tried)"
  paused
  else
    forced
    Progress < <(systemctl restart "${tmps_[@]/%/.service}" 2>/dev/null)
    paused    
  fi
}

restart() { 
  while :; do
    clear
    notes
    printf -v prompt "\n%s(Enter the service(s) to restart) ==> %s" "$gb" "$normal"
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0 ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) Solution restart_ ;;
        esac                          
   done 
}

reload_() {
   if ((${#tmps[@]})) && ((${#tmps_[@]}));then
     forced
     Progress < <(systemctl reload "${combined[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been reloaded. (or at least tried)"
     paused
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then
     Progress < <(systemctl reload "${tmps[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been reloaded. (or at least tried)"
     paused
  else 
     forced
     Progress < <(systemctl reload "${tmps_[@]/%/.service}" 2>/dev/null) 
     paused    
  fi
}

reload() {
  while :; do 
    clear
    notes
    printf -v prompt "\n%s(Enter the service(s) to reload) ==> %s" "$gb" "$normal"
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0  ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) Solution reload_;;
        esac               
  done
}

Enable_() {
   if ((${#tmps[@]})) && ((${#tmps_[@]}));then
     forced
      Progress < <(systemctl enable "${combined[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been enabled. (or at least tried)"
     paused
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then
     Progress < <(systemctl enable "${tmps[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been enabled. (or at least tried)"
     paused
  else 
     forced
     Progress < <(systemctl enable "${tmps_[@]/%/.service}" 2>/dev/null)
     paused    
  fi
}

Enable() {
  while :; do
    clear
    notes
    printf -v prompt "\n%s(Enter the service(s) to enable) ==> %s" "$gb" "$normal"
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0  ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) Solution Enable_ ;;  
        esac                        
  done
}

disable_() {
   if ((${#tmps[@]})) && ((${#tmps_[@]}));then
     forced
     Progress < <(systemctl disable "${combined[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been disabled. (or at least tried)"
     paused
  elif ((${#tmps[@]})) && ((! ${#tmps_[@]})); then
     Progress < <(systemctl disable "${tmps[@]/%/.service}" 2>/dev/null) && printf "\n%s\n" "$gb${tmps[*]}$normal has been disabled. (or at least tried)"
     paused
  else 
     forced
     Progress < <(systemctl disable "${tmps_[@]/%/.service}" 2>/dev/null)
     paused    
  fi   
}

disable() { 
  while :; do            
    clear
    notes 
    printf -v prompt "\n%s(Enter the service(s) to disable) ==> %s" "$gb" "$normal"
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0  ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) Solution disable_ ;;
        esac             
  done 
}

query() {
  while :; do
    clear
    notes
    printf -v prompt "\n%s(Enter the service(s) to query) ==> %s" "$gb" "$normal"
      read -r -e -p "$prompt"  -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          "") printf "\n%s$empty" 2>&1; sleep 1 ;;
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Qq]|[Qq][Uu][Ii][Tt]) clear; exit 0  ;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          !(*.service)|*.service) temp=("${serv[@]%.service}")
                                  colored ;;
        esac                                   
  done
}

##Systemctl mode you can do things like '--system daemon-reload'.
Systemctl() {
  while :; do 
    clear
    sysnote
    printf -v prompt "\n%ssystemctl:~>%s " "$rb" "$normal"
      read -r -e -p "$prompt" -a  serv
        [[ ${serv[@]} ]] && history -s "${serv[@]}"
        case "${serv[@]}" in
          [Ll]|[Ll][Ii][Ss][Tt]) list ;;
          [Mm]|[Mm][Aa][Nn]) man systemctl ;;
          [Qq]|[Qq][Uu][Ii][Tt])  clear; exit 0;;
          [Rr]|[Rr][Ee][Tt][Uu][Rr][Nn]) clear; break ;;
          *) systemctl "${serv[@]}"; sleep 3;;
        esac                
  done
}

choice() {
  printf -v prompt "%s(Enter your choice) ==>%s "  "$gb" "$normal" ##
  read -r -e -p "$prompt"  -n1 serv 
}

Quit() {
  clear
  exit 0 
}

Unknown () {
  single=(H help)
  var=(H_ help_)
  for n in "${!single[@]}"; do
    printf -v "${var[$n]}" "%s${single[$n]}%s" "$gb" "$normal"
  done
  echo
  printf "%s" "Unknown option press the $H_ key for  $help_"!
  sleep 2   
}

## This is where it all started :-). 
MainScript() {
  while :; do
    clear
    Heading
    Menu
    choice
      case $serv in                      
        1) start     ;; 
        2) stop      ;;
        3) restart   ;;
        4) reload    ;;
        5) Enable    ;;
        6) disable   ;;   
        7) query     ;;
        8) list      ;;
        9) Systemctl ;;
        [Aa]) About      ;;
        [Qq]) Quit      ;;  ## Exit when the Q or q button is pressed.       
        [Hh]) Help      ;;   
        [Mm]) man qserv ;;  ## Read qserv man page.
        *) Unknown   ;;
     esac
    clear
  done
}

## parsing options
while :; do
  case "$1" in
    -h | --help | -\?) Help; exit 0 ;;   
    -a | --about) About; exit 0 ;;                                                                                                                                                                       
    -v | --version) version_; exit 0 ;;
    --) shift; break ;;
    -*) echo "WARN: Unknown option (ignored): $1" >&2
        usage
        exit 1 ;;
    '')  MainScript ;; # no more options. start MainScript
     *) usage ; exit 1 
  esac
done
## Penito la musica!  
openSUSE Build Service is sponsored by