#!/bin/bash # General shell functions # Return codes definitions EXIT_CODE_SUCCESS=0 EXIT_CODE_FAILURE=1 EXIT_CODE_WARNING=2 # Setup default values for environment umask 022 export PATH="/tools/bin:/tools/sbin:/bin:/sbin" ## Screen Dimensions # Find current screen size if [ -z "${COLUMNS}" ]; then COLUMNS=$(stty size < /dev/console) COLUMNS=${COLUMNS##* } fi # When using remote connections, such as a serial port, stty size returns 0 if [ "${COLUMNS}" = "0" ]; then COLUMNS=80 fi # The starting position for displaying the "X" sign inside the check box [ ] CHECK_POSITION=2 SET_CHECK_POSITION="echo -en \\033[${CHECK_POSITION}G" # NORMAL prints text in normal color NORMAL="\\033[0;39m" # SUCCESS prints text in a green colour SUCCESS="echo -en \\033[1;32m" # WARNING prints text in a yellow colour WARNING="echo -en \\033[1;33m" # FAILURE prints text in a red colour FAILURE="echo -en \\033[1;31m" # Brackets are blue BRACKET="\\033[1;34m" # Set the console_loglevel to display only error messages (0,1,2 and 3) # KERN_EMERG "<0>" /* system is unusable */ # KERN_ALERT "<1>" /* action must be taken immediately */ # KERN_CRIT "<2>" /* critical conditions */ # KERN_ERR "<3>" /* error conditions */ # KERN_WARNING "<4>" /* warning conditions */ # KERN_NOTICE "<5>" /* normal but significant condition */ # KERN_INFO "<6>" /* informational */ # KERN_DEBUG "<7>" /* debug-level messages */ # Examples: # LOGLEVEL="1" --> Prevents all messages, expect panic messages, from # appearing on the console. # LOGLEVEL="8" --> Allow all messages to appear on the console. LOGLEVEL="3" # Timezone export TZ="America/Montreal" INIT_LOG_PATH="/var/log/hvinit" INIT_LOG_FILE="$INIT_LOG_PATH/init.log" # Arguments: Message string(s) to display display_checkbox_msg() { local LABEL="${*}" echo -en "${BRACKET}[ ${BRACKET}]${NORMAL} ${LABEL} " } # The print_status prints a coloured "X" letter inside the checkbox to the left # of the screen (the checkbox is displayed with the cmd_run_log_box function). print_status() { if [ ${#} = 0 ]; then # If no parameters are given, print usage information. echo "Usage: print_status {success|warning|failure}" return ${EXIT_CODE_FAILURE} fi case "$1" in success) ${SUCCESS} ;; warning) ${WARNING} ;; failure) ${FAILURE} ;; *) echo "Usage: print_status {success|warning|failure}" return ${EXIT_CODE_FAILURE} ;; esac echo -n "X" echo -en "${NORMAL}" echo } # Argument #1: message d'erreur boot_failure() { $FAILURE echo echo $1 echo echo "sulogin will now be started. When you logout, the system" echo "will reboot." echo echo -en "${NORMAL}" /sbin/sulogin /sbin/reboot -f } # Write a message to the log file. msg_log() { echo "<$*>" >> ${INIT_LOG_FILE} return ${EXIT_CODE_SUCCESS} } # Display a message with an orange warning box [X] msg_box_nolog() { STRING=$1 display_checkbox_msg "${STRING}" ${SET_CHECK_POSITION} print_status warning } # Write the command and it's arguments to the log file, without running the command. log_script_name() { echo ">>> Script: $* <<<" >> ${INIT_LOG_FILE} return ${EXIT_CODE_SUCCESS} } # Write the command and it's arguments to the log file, and run the command. cmd_run_log() { echo "[$*]" >> ${INIT_LOG_FILE} ${*} 1>> ${INIT_LOG_FILE} 2>&1 return ${?} } # Display the action name, run a command, log its output and display it's # status # First argument: action name (string) # Remaining arguments: command name with it's options cmd_run_log_box() { STRING=$1 display_checkbox_msg "${STRING}" shift ${SET_CHECK_POSITION} $* 1>> ${INIT_LOG_FILE} 2>&1 ERROR_CODE=${?} if [ $ERROR_CODE = 0 ]; then print_status success else print_status failure fi return $ERROR_CODE } # Display the action name, run a command, log its output and display it's # status # First argument: action name (string) # Remaining arguments: command name with it's options # Error codes returned by the command: # 0 = success # 1 = warning # 2 = failure cmd_run_log_box_warn() { STRING=$1 display_checkbox_msg "${STRING}" shift ${SET_CHECK_POSITION} $* 1>> ${INIT_LOG_FILE} 2>&1 ERROR_CODE=${?} if [ $ERROR_CODE = ${EXIT_CODE_SUCCESS} ]; then print_status success elif [ $ERROR_CODE = ${EXIT_CODE_WARNING} ]; then print_status warning else print_status failure fi return $ERROR_CODE } # Display the action name, run a command, log its output and display it's # status # If something went wrong during the checks of one of the partitions, # fsck will exit with a return value greater than 1 # First argument: action name (string) # Remaining arguments: command name with it's options # Error codes returned by the command: # 0 = success # 1 = warning # >1 = failure cmd_run_log_box_warn_checkfs() { STRING=$1 display_checkbox_msg "${STRING}" shift ${SET_CHECK_POSITION} $* 1>> ${INIT_LOG_FILE} 2>&1 ERROR_CODE=${?} if [ $ERROR_CODE = ${EXIT_CODE_SUCCESS} ]; then print_status success elif [ $ERROR_CODE = 1 ]; then print_status warning ERROR_CODE=${EXIT_CODE_WARNING} else print_status failure ERROR_CODE=${EXIT_CODE_FAILURE} fi return $ERROR_CODE } # Display the action name, run a command and display it's status (no log). # First argument: action name (string) # Remaining arguments: command name with it's options cmd_run_nolog_box() { STRING=$1 display_checkbox_msg "${STRING}" shift ${SET_CHECK_POSITION} $* 1>> /dev/null 2>&1 ERROR_CODE=${?} if [ $ERROR_CODE = 0 ]; then print_status success else print_status failure fi return $ERROR_CODE } # loadproc() starts a process (often a daemon) with proper error checking loadproc() { # If no parameters are given, print usage information. if [ ${#} = 0 ]; then msg_log "Usage: loadproc {program}" return ${EXIT_CODE_FAILURE} fi # Find the basename of the first parameter (the daemon's name without the # path that was provided so /usr/sbin/syslogd becomes plain 'syslogd' after # basename ran). base=$(/usr/bin/basename ${1}) # the pidlist variable will contain the output of the pidof command. pidof # will try to find the PID's that belong to a certain string; $base in # this case. pidlist=$(pidof -o $$ -o $PPID -o %PPID -x ${base}) pid="" for apid in ${pidlist}; do if [ -d /proc/${apid} ]; then pid="${pid} ${apid}" fi done # If the $pid variable contains anything (from the previous for loop) it # means the daemon is already running. if [ ! -n "${pid}" ]; then # Empty $pid variable means it's not running, so we run "$@" (all # parameters given to this function from the script) and then check # the return value. "$@" if [ ${?} -ne 0 ]; then return ${EXIT_CODE_FAILURE} else return ${EXIT_CODE_SUCCESS} fi else # The variable $pid was not empty, meaning it was already running. msg_log "Already running" return ${EXIT_CODE_WARNING} fi } # killproc() kills a process with proper error checking # Arg. #1: Name of process to kill # Arg. #2: Optional signal to kill the process with (like -HUP, -TERM, -KILL, etc) killproc() { # If no parameters are given, print usage information. if [ $# -lt 1 ]; then msg_log "Usage: killproc {program} [signal]" return ${EXIT_CODE_FAILURE} fi killproc_path ${1} /var/run ${2} return ${?} } # killproc_path() kills a process with proper error checking # Arg. #1: Name of process to kill # Arg. #2: Base directory containing PID file # Arg. #3: Optional signal to kill the process with (like -HUP, -TERM, -KILL, etc) killproc_path() { # If no parameters are given, print usage information. if [ $# -lt 2 ]; then msg_log "Usage: killproc_path {program} {pid-directory} [signal]" return ${EXIT_CODE_FAILURE} fi # Find the basename of the first parameter (the daemon's name without the # path). base=$(/usr/bin/basename ${1}) piddir=${2} # Check if we gave a signal to kill the process with (like -HUP, -TERM, # -KILL, etc) to this function (the third parameter). if [ "${3}" != "" ]; then killlevel=-${3} else nolevel=1 fi # The pidlist variable will contains the output of the pidof command. pidof # will try to find the PID's that belong to a certain string; $base in this # case. pidlist=$(pidof -o $$ -o $PPID -o %PPID -x ${base}) pid="" for apid in ${pidlist} do if [ -d /proc/${apid} ]; then pid="${pid} ${apid}" fi done # If $pid contains something from the previous for loop it means one or # more PID's were found that belongs to the processes to be killed. if [ -n "${pid}" ]; then # If no kill level was specified we'll try -TERM first and then sleep # for 2 seconds to allow the kill to be completed. if [ "${nolevel}" = 1 ]; then cmd_run_log kill -TERM ${pid} # If after -TERM the PID still exists we'll wait 2 seconds before # trying to kill it with -KILL. If the PID still exist after that, # wait two more seconds. If the PIDs still exist by then it's safe # to assume that we cannot kill these PIDs. if /bin/ps h ${pid} >/dev/null 2>&1; then cmd_run_log sleep 2 if /bin/ps h ${pid} > /dev/null 2>&1; then cmd_run_log kill -KILL ${pid} if /bin/ps h ${pid} > /dev/null 2>&1; then cmd_run_log sleep 2 fi fi fi /bin/ps h ${pid} >/dev/null 2>&1 if [ ${?} = 0 ]; then # If after the -KILL it still exists it can't be killed for # some reason. return ${EXIT_CODE_FAILURE} else # It was killed, remove possible stale PID file in ${piddir}. /bin/rm -f ${piddir}/${base}.pid return ${EXIT_CODE_SUCCESS} fi else # A kill level was provided. Kill with the provided kill level and # wait for 2 seconds to allow the kill to be completed. /bin/kill ${killlevel} ${pid} if /bin/ps h ${pid} > /dev/null 2>&1; then cmd_run_log sleep 2 fi /bin/ps h ${pid} >/dev/null 2>&1 if [ ${?} = 0 ]; then # If ps' return value is 0 it means it ran ok which indicates # that the PID still exists. This means the process wasn't # killed properly with the signal provided. return ${EXIT_CODE_FAILURE} else # If the return value was 1 or higher it means the PID didn't # exist anymore which means it was killed successfully. Remove # possible stale PID file. /bin/rm -f ${piddir}/${base}.pid return ${EXIT_CODE_SUCCESS} fi fi else # The PID didn't exist so we can't attempt to kill it. msg_log "Not running" return ${EXIT_CODE_WARNING} fi } # reloadproc() sends a signal to a daemon telling it to reload it's # configuration file. This is almost identical to the killproc function with # the exception that it won't try to kill it with a -KILL signal (aka -9). # Arg. #1: Name of process to reload # Arg. #2: Optional signal to reload the process with (like -HUP) reloadproc() { # If no parameters are given, print usage information. if [ ${#} = 0 ]; then msg_log "Usage: reloadproc {program} [signal]" return ${EXIT_CODE_FAILURE} fi # Find the basename of the first parameter (the daemon's name without # the path that was provided so /usr/sbin/syslogd becomes plain 'syslogd' # after basename ran). base=$(/usr/bin/basename ${1}) # Check if we gave a signal to send to the process (like -HUP) to this # function (the second parameter). If no second parameter was provided set # the nolevel variable. Else set the killlevel variable to the value of $2 # (the second parameter). if [ -n "${2}" ]; then killlevel="-${2}" else killlevel="-SIGHUP" fi # The pidlist variable will contains the output of the pidof command. pidof # will try to find the PID's that belong to a certain string; $base in this # case. pidlist=$(pidof -o $$ -o $PPID -o %PPID -x ${base}) pid="" for apid in ${pidlist} do if [ -d /proc/${apid} ]; then pid="${pid} ${apid}" fi done # If $pid contains something from the previous for loop it means one or # more PID's were found that belongs to the processes to be reloaded. if [ -n "${pid}" ]; then /bin/kill ${killlevel} ${pid} if [ ${?} -ne 0 ]; then sleep 2 if statusproc ${base} | grep -q "stopped"; then return ${EXIT_CODE_FAILURE} fi fi else # If $pid is empty no PID's have been found that belong to the process. msg_log "Not running" return ${EXIT_CODE_WARNING} fi return ${EXIT_CODE_SUCCESS} } # statusproc_path() will try to find out if a process is running or not. # Arg. #1: Name of process to check statusproc() { # If no parameters are given, print usage information. if [ $# -lt 1 ]; then msg_log "Usage: statusproc {program}" return ${EXIT_CODE_FAILURE} fi statusproc_path ${1} /var/run return ${?} } # statusproc_path() will try to find out if a process is running or not. # Arg. #1: Name of process to check # Arg. #2: Base directory containing PID file statusproc_path() { # If no parameters are given, print usage information. if [ $# -lt 2 ]; then msg_log "Usage: status {program} {pid-directory}" return ${EXIT_CODE_FAILURE} fi # Find the basename of the first parameter (the daemon's name without the # path). base=$(/usr/bin/basename ${1}) piddir=${2} # $pid will contain a list of PID's that belong to a process. pid=$(pidof -o $$ -o $PPID -o %PPID -x ${base}) if [ -n "${pid}" ]; then # If $pid contains something, the process is running, print the content # of the $pid variable. echo "${base} running with Process ID ${pid}" return ${EXIT_CODE_SUCCESS} fi # If $pid doesn't contain it check if a PID file exists and inform the # user about this stale file. if [ -f ${piddir}/${base}.pid ]; then pid=$(head -1 ${piddir}/${base}.pid) if [ -n "${pid}" ]; then echo "${base} stopped but ${piddir}/${base}.pid exists" return ${EXIT_CODE_FAILURE} fi fi echo "${base} is stopped" return ${EXIT_CODE_FAILURE} }