#!/bin/bash

# The original version of this file was taken from the CentOS5 
# initscripts-8.45.30-2.el5.x86_64 package and as this package is licensensed
# under GPLv2 and GPLv2+ this entire file is provided under those licenses.

# As the CentOS / RedHat version has severe bugs (see for example
# https://bugzilla.redhat.com/show_bug.cgi?id=703426
# we (the BeeGFS team) cannot rely on it and modified the original
# version therefore
#
# 2011/05/10 Bernd Schubert <bernd.schubert@itwm.fraunhofer.de>

# -*-Shell-script-*-
#
# functions	This file contains functions to be used by most or all
#		shell scripts in the /etc/init.d directory.
#

TEXTDOMAIN=initscripts

# Make sure umask is sane
umask 022

# Set up a default search path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH

# Get a sane screen width
[ -z "${COLUMNS:-}" ] && COLUMNS=80

if [ -z "${CONSOLETYPE:-}" -a -x "/sbin/consoletype" ]; then
	CONSOLETYPE="`/sbin/consoletype`"
fi

if [ -f /etc/sysconfig/i18n -a -z "${NOLOCALE:-}" ] ; then
  . /etc/profile.d/lang.sh
fi

# Read in our configuration
if [ -z "${BOOTUP:-}" ]; then
  if [ -f /etc/sysconfig/init ]; then
      . /etc/sysconfig/init
  else
    # This all seem confusing? Look in /etc/sysconfig/init,
    # or in /usr/doc/initscripts-*/sysconfig.txt
    BOOTUP=color
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \\033[0;39m"
    LOGLEVEL=1
  fi
  if [ "$CONSOLETYPE" = "serial" ]; then
      BOOTUP=serial
      MOVE_TO_COL=
      SETCOLOR_SUCCESS=
      SETCOLOR_FAILURE=
      SETCOLOR_WARNING=
      SETCOLOR_NORMAL=
  fi
fi

if [ "${BOOTUP:-}" != "verbose" ]; then
   INITLOG_ARGS="-q"
else
   INITLOG_ARGS=
fi

# Interpret escape sequences in an fstab entry
fstab_decode_str() {
	fstab-decode echo "$1"
}

# Check if $pid (could be plural) are running
checkpid() {
	local base=$1
	shift

	local i
	local RUNNING_PIDS=`pidof $base`

	# pidof told us the daemon is not running, so we do not need to 
	# do further check
	[ -n "$RUNNING_PIDS" ] || return 1

	for pid in $* ; do
		[ -d "/proc/$pid" ] || continue

		for rp in $RUNNING_PIDS; do
			# check if `pidof` and provided pid to checkpid() match
			# if so we found a running pid with the correct name
			[ $rp -eq $pid ] && return 0
		done
	done
	return 1
}

__readlink() {
    ls -bl "$@" 2>/dev/null| awk '{ print $NF }'
}

# __umount_loop awk_program fstab_file first_msg retry_msg umount_args
# awk_program should process fstab_file and return a list of fstab-encoded
# paths; it doesn't have to handle comments in fstab_file.
__umount_loop() {
	local remaining sig=
	local retry=3

	remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
	while [ -n "$remaining" -a "$retry" -gt 0 ]; do
		if [ "$retry" -eq 3 ]; then
			action "$3" fstab-decode umount $5 $remaining
		else
			action "$4" fstab-decode umount $5 $remaining
		fi
		sleep 2
		remaining=$(LC_ALL=C awk "/^#/ {next} $1" "$2" | sort -r)
		[ -z "$remaining" ] && break
		fstab-decode /sbin/fuser -k -m $sig $remaining >/dev/null
		sleep 5
		retry=$(($retry -1))
		sig=-9
	done
}

# Similar to __umount loop above, specialized for loopback devices
__umount_loopback_loop() {
	local remaining devremaining sig=
	local retry=3

	remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
	devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
	while [ -n "$remaining" -a "$retry" -gt 0 ]; do
		if [ "$retry" -eq 3 ]; then
			action $"Unmounting loopback filesystems: " \
				fstab-decode umount $remaining
		else
			action $"Unmounting loopback filesystems (retry):" \
				fstab-decode umount $remaining
		fi
		for dev in $devremaining ; do
			losetup $dev > /dev/null 2>&1 && \
				action $"Detaching loopback device $dev: " \
				losetup -d $dev
		done
		remaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $2}' /proc/mounts)
		devremaining=$(awk '$1 ~ /^\/dev\/loop/ && $2 != "/" {print $1}' /proc/mounts)
		[ -z "$remaining" ] && break
		fstab-decode /sbin/fuser -k -m $sig $remaining >/dev/null
		sleep 5
		retry=$(($retry -1))
		sig=-9
	done
}

# __proc_pids {program} [pidfile]
# Set $pid to pids from /var/run* for {program}.  $pid should be declared
# local in the caller.
# Returns LSB exit code for the 'status' action.
__pids_var_run_running() {
	local base=${1##*/}
	local pid_file=${2:-/var/run/$base.pid}

	# checkpid already sets $pid globally, so we can't re-use it for now
	local pids=
	if [ -f "$pid_file" ]; then
		local line=`cat $pid_file | tr '\n' ' '`
		for entry in $line; do
			checkpid $base $entry
			[ $? -eq 0 ] || continue
			
			# found a matching pid
			pids="$pids $entry"			
		done < "$pid_file"

	        if [ -n "$pids" ]; then
			pid=$pids # globally we need $pid
	                return 0
	        fi
		return 1 # "Program is dead and /var/run pid file exists"
	fi
	return 3 # "Program is not running"
}

# Output PIDs of matching processes, found using pidof
__pids_pidof() {
	pidof -c -o $$ -o $PPID -o %PPID -x "$1" || \
		pidof -c -o $$ -o $PPID -o %PPID -x "${1##*/}"
}


# A function to start a program.
daemon() {
	# Test syntax.
	local gotbase= force= nicelevel corelimit
	local pid base= user= nice= bg= pid_file=
	nicelevel=0
	while [ "$1" != "${1##[-+]}" ]; do
	  case $1 in
	    '')    echo $"$0: Usage: daemon [+/-nicelevel] {program}"
	           return 1;;
	    --check)
		   base=$2
		   gotbase="yes"
		   shift 2
		   ;;
	    --check=?*)
	    	   base=${1#--check=}
		   gotbase="yes"
		   shift
		   ;;
	    --user)
		   user=$2
		   shift 2
		   ;;
	    --user=?*)
	           user=${1#--user=}
		   shift
		   ;;
	    --pidfile)
		   pid_file=$2
		   shift 2
		   ;;
	    --pidfile=?*)
		   pid_file=${1#--pidfile=}
		   shift
		   ;;
	    --force)
	    	   force="force"
		   shift
		   ;;
	    [-+][0-9]*)
	    	   nice="nice -n $1"
	           shift
		   ;;
	    *)     echo $"$0: Usage: daemon [+/-nicelevel] {program}"
	           return 1;;
	  esac
	done

        # Save basename.
        [ -z "$gotbase" ] && base=${1##*/}

        # See if it's already running. Look *only* at the pid file.
	__pids_var_run_running "$base" "$pid_file"

	[ -n "$pid" -a -z "$force" ] && return

	# make sure it doesn't core dump anywhere unless requested
	corelimit="ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}"
	
	# if they set NICELEVEL in /etc/sysconfig/foo, honor it
	[ -n "${NICELEVEL:-}" ] && nice="nice -n $NICELEVEL"
	
	# Echo daemon
        [ "${BOOTUP:-}" = "verbose" -a -z "${LSB:-}" ] && echo -n " $base"

	# And start it up.
	if [ -z "$user" ]; then
	   $nice /bin/bash -c "$corelimit >/dev/null 2>&1 ; $*"
	else
	   $nice runuser -s /bin/bash - $user -c "$corelimit >/dev/null 2>&1 ; $*"
	fi
	[ "$?" -eq 0 ] && success $"$base startup" || failure $"$base startup"
}

# reall kill here, return 0 if kill succeeded, 1 if not
do_killproc()
{
	level=$1
	time=$2

	kill -${level} $pid >/dev/null 2>&1
	RC=0
	count_time=0
	while [ $RC -eq 0 -a $count_time -lt $time ]; do
		checkpid $base $pid
		if [ $? -ne 0 ]; then
			return 0
		fi
		sleep 1
		count=$(($count_time + 1))
	done

	return 1
}

remove_pidfile()
{
        # Remove pid file if any.
	if [ -z "$killlevel" ]; then
            rm -f "${pid_file:-/var/run/$base.pid}"
	fi
}

# A function to stop a program.
killproc() {
	local RC killlevel= base pid pid_file= delay
	local pidfile_only=0

	RC=0; delay=3
	# Test syntax.
	if [ "$#" -eq 0 ]; then
		echo $"Usage: killproc [-p pidfile] [ -d delay] {program} [-signal]"
		return 1
	fi
	if [ "$1" = "-p" ]; then
		pid_file=$2
		shift 2
	fi
	if [ "$1" = "-d" ]; then
		delay=$2
		shift 2
	fi
	
        
	# check for second arg to be kill level
	[ -n "${2:-}" ] && killlevel=$2

        # Save basename.
        base=${1##*/}

        # Find pid.
	__pids_var_run_running "$1" "$pid_file"
	if [ -z "$pid_file" -a -z "$pid" ]; then
		pid="$(__pids_pidof "$1")"
	fi

	if [ -z "$pid" ]; then
		if [ -n "${LSB:-}" -a -n "$killlevel" ]; then
			RC=7 # Program is not running
		else
			failure $"$base shutdown"
			RC=0
		fi

		remove_pidfile
		return $RC
	fi

        # Kill it.
	[ "$BOOTUP" = "verbose" -a -z "${LSB:-}" ] && echo -n "$base "
	if [ -z "$killlevel" ] ; then
		# TERM first, then KILL if not dead
		# use specified level only
		do_killproc TERM 30
		[ $? -ne 0 ] || do_killproc KILL 5

	else
               	do_killproc $killlevel 30 >/dev/null 2>&1
	fi

	# determine the exit code here after kill (depends on if kill succeeded)
	checkpid $base $pid
	RC=$?
	[ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"
	RC=$((! $RC))

	remove_pidfile
	return $RC
}

# A function to find the pid of a program. Looks *only* at the pidfile
pidfileofproc() {
	local pid

	# Test syntax.
	if [ "$#" = 0 ] ; then
		echo $"Usage: pidfileofproc {program}"
		return 1
	fi

	__pids_var_run_running "$1"
	[ -n "$pid" ] && echo $pid
	return 0
}

# A function to find the pid of a program.
pidofproc() {
	local RC pid pid_file=

	# Test syntax.
	if [ "$#" = 0 ]; then
		echo $"Usage: pidofproc [-p pidfile] {program}"
		return 1
	fi
	if [ "$1" = "-p" ]; then
		pid_file=$2
		shift 2
	fi
	fail_code=3 # "Program is not running"

	# First try "/var/run/*.pid" files
	__pids_var_run_running "$1" "$pid_file"
	RC=$?
	if [ -n "$pid" ]; then
		echo $pid
		return 0
	fi

	[ -n "$pid_file" ] && return $RC
	__pids_pidof "$1" || return $RC
}

status() {
	local base pid pid_file=

	# Test syntax.
	if [ "$#" = 0 ] ; then
		echo $"Usage: status [-p pidfile] {program}"
		return 1
	fi
	if [ "$1" = "-p" ]; then
		pid_file=$2
		shift 2
	fi
	base=${1##*/}

	# First try "pidof"
	__pids_var_run_running "$1" "$pid_file"
	RC=$?
	if [ -z "$pid_file" -a -z "$pid" ]; then
		pid="$(__pids_pidof "$1")"
	fi
	if [ -n "$pid" ]; then
	        echo $"${base} (pid $pid) is running..."
	        return 0
	fi

	case "$RC" in
		0)
			echo $"${base} (pid $pid) is running..."
			return 0
			;;
		1)
	                echo $"${base} dead but pid file exists"
	                return 1
			;;
	esac
	# See if /var/lock/subsys/${base} exists
	if [ -f /var/lock/subsys/${base} ]; then
		echo $"${base} dead but subsys locked"
		return 2
	fi
	echo $"${base} is stopped"
	return 3
}

status_multi() {
	local base pid pid_file=

	# Test syntax.
	if [ "$#" = 0 ] ; then
		echo $"Usage: status [-p pidfile] {program}"
		return 1
	fi
	if [ "$1" = "-p" ]; then
		pid_file=$2
		shift 2
	fi
	base=${1##*/}

	# First try "pidof"
	__pids_var_run_running "$1" "$pid_file"
	RC=$?
	if [ -z "$pid_file" -a -z "$pid" ]; then
		pid="$(__pids_pidof "$1")"
	fi
	if [ -n "$pid" ]; then
	        echo $"${base} (pid $pid) is running..."
	        return 0
	fi

	case "$RC" in
		0)
			echo $"${base} (pid $pid) is running..."
			return 0
			;;
		1)
	                echo $"${base} dead but pid file exists"
	                return 1
			;;
	esac
	# See if /var/lock/subsys/${base}-$CONFIG exists
	if [ -f /var/lock/subsys/${base}-$CONFIG ]; then
		echo $"${base} dead but subsys locked"
		return 2
	fi
	echo $"${base} is stopped"
	return 3
}

echo_success() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
  echo -n $"  OK  "
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 0
}

echo_failure() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo -n $"FAILED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

echo_passed() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"PASSED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

echo_warning() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"WARNING"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

# Inform the graphical boot of our current state
update_boot_stage() {
  if [ "$GRAPHICAL" = "yes" -a -x /usr/bin/rhgb-client ]; then
    /usr/bin/rhgb-client --update="$1"
  fi
  return 0
}

# Log that something succeeded
success() {
  #if [ -z "${IN_INITLOG:-}" ]; then
  #   initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
  #fi
  [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_success
  return 0
}

# Log that something failed
failure() {
  local rc=$?
  #if [ -z "${IN_INITLOG:-}" ]; then
  #   initlog $INITLOG_ARGS -n $0 -s "$1" -e 2
  #fi
  [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_failure
  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
  return $rc
}

# Log that something passed, but may have had errors. Useful for fsck
passed() {
  local rc=$?
  #if [ -z "${IN_INITLOG:-}" ]; then
  #   initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
  #fi
  [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_passed
  return $rc
}  

# Log a warning
warning() {
  local rc=$?
  #if [ -z "${IN_INITLOG:-}" ]; then
  #   initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
  #fi
  [ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_warning
  return $rc
}  

# Run some action. Log its output.
action() {
  local STRING rc

  STRING=$1
  echo -n "$STRING "
  if [ "${RHGB_STARTED:-}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
      echo -n "$STRING " > /etc/rhgb/temp/rhgb-console
  fi
  shift
  "$@" && success $"$STRING" || failure $"$STRING"
  rc=$?
  echo
  if [ "${RHGB_STARTED:-}" != "" -a -w /etc/rhgb/temp/rhgb-console ]; then
      if [ "$rc" = "0" ]; then
      	echo_success > /etc/rhgb/temp/rhgb-console
      else
        echo_failure > /etc/rhgb/temp/rhgb-console
	[ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
      fi
      echo > /etc/rhgb/temp/rhgb-console
  fi
  return $rc
}

# returns OK if $1 contains $2
strstr() {
  [ "${1#*$2*}" = "$1" ] && return 1
  return 0
}

# Confirm whether we really want to run this service
confirm() {
  [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=yes
  while : ; do 
      echo -n $"Start service $1 (Y)es/(N)o/(C)ontinue? [Y] "
      read answer
      if strstr $"yY" "$answer" || [ "$answer" = "" ] ; then
         return 0
      elif strstr $"cC" "$answer" ; then
	 rm -f /var/run/confirm
	 [ -x /usr/bin/rhgb-client ] && /usr/bin/rhgb-client --details=no
         return 2
      elif strstr $"nN" "$answer" ; then
         return 1
      fi
  done
}

# resolve a device node to its major:minor numbers in decimal or hex
get_numeric_dev() {
(
    fmt="%d:%d"
    if [ "$1" == "hex" ]; then
        fmt="%x:%x"
    fi
    ls -lH "$2" | awk '{ sub(/,/, "", $5); printf("'"$fmt"'", $5, $6); }'
) 2>/dev/null
}

# find the working name for a running dm device with the same table as one
# that dmraid would create
resolve_dm_name() {
(
    name="$1"

    line=$(/sbin/dmraid -ay -t --ignorelocking | \
        egrep -iv "no block devices found|No RAID disks" | \
        awk -F ':' "{ if (\$1 ~ /^$name$/) { print \$2; }}")
    for x in $line ; do
        if [[ "$x" =~ "^/dev/" ]] ; then
            majmin=$(get_numeric_dev dec $x)
            line=$(echo "$line" | sed -e "s,$x\( \|$\),$majmin\1,g")
        fi
    done
    line=$(echo "$line" | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' \
               -e 's/ core [12] [[:digit:]]\+ / core [12] [[:digit:]]\\+ /')
    /sbin/dmsetup table | \
        sed -n -e "s/.*\(no block devices found\|No devices found\).*//" \
               -e "s/\(^[^:]\+\): $line\( \+$\|$\)/\1/p"
) 2>/dev/null
}

# Check whether file $1 is a backup or rpm-generated file and should be ignored
is_ignored_file() {
    case "$1" in
	*~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave)
	    return 0
	    ;;
    esac
    return 1
}
# A sed expression to filter out the files that is_ignored_file recognizes
__sed_discard_ignored_files='/\(~\|\.bak\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'

