D.2. /etc/rc.d/init.d/functions


#!/bin/sh

########################################################################

# Begin $rc_base/init.d/functions

#

# Description : Run Level Control Functions

#

# Authors     : Gerard Beekmans - gerard@linuxfromscratch.org

#

# Version     : 00.00

#

# Notes       : With code based on Matthias Benkmann's simpleinit-msb

#        http://winterdrache.de/linux/newboot/index.html

#

########################################################################



## Environmental setup

# Setup default values for environment

umask 022

export PATH="/bin:/usr/bin:/sbin:/usr/sbin"



# Signal sent to running processes to refresh their configuration

RELOADSIG="HUP"



# Number of seconds between STOPSIG and FALLBACK when stopping processes

KILLDELAY="3"



## Screen Dimensions

# Find current screen size

if [ -z "${COLUMNS}" ]; then

    COLUMNS=$(stty size)

    COLUMNS=${COLUMNS##* }

fi



# When using remote connections, such as a serial port, stty size returns 0

if [ "${COLUMNS}" = "0" ]; then 

    COLUMNS=80

fi



## Measurements for positioning result messages

COL=$((${COLUMNS} - 8))

WCOL=$((${COL} - 2))



## Provide an echo that supports -e and -n

# If formatting is needed, $ECHO should be used

case "`echo -e -n test`" in

    -[en]*)

        ECHO=/bin/echo

        ;;

    *)

        ECHO=echo

        ;;

esac



## Set Cursor Position Commands, used via $ECHO

SET_COL="\\033[${COL}G"      # at the $COL char

SET_WCOL="\\033[${WCOL}G"    # at the $WCOL char

CURS_UP="\\033[1A\\033[0G"   # Up one line, at the 0'th char



## Set color commands, used via $ECHO

# Please consult `man console_codes for more information

# under the "ECMA-48 Set Graphics Rendition" section

#

# Warning: when switching from a 8bit to a 9bit font,

# the linux console will reinterpret the bold (1;) to

# the top 256 glyphs of the 9bit font.  This does

# not affect framebuffer consoles

NORMAL="\\033[0;39m"         # Standard console grey

SUCCESS="\\033[1;32m"        # Success is green

WARNING="\\033[1;33m"        # Warnings are yellow

FAILURE="\\033[1;31m"        # Failures are red

INFO="\\033[1;36m"           # Information is light cyan

BRACKET="\\033[1;34m"        # Brackets are blue



STRING_LENGTH="0"   # the length of the current message



#*******************************************************************************

# Function - boot_mesg()

#

# Purpose:      Sending information from bootup scripts to the console

#

# Inputs:       $1 is the message

#               $2 is the colorcode for the console

#

# Outputs:      Standard Output

#

# Dependencies: - sed for parsing strings.

#            - grep for counting string length.

#               

# Todo:         

#*******************************************************************************

boot_mesg()

{

    local ECHOPARM=""



    while true

    do

        case "${1}" in

            -n)

                ECHOPARM=" -n "

                shift 1

                ;;

            -*)

                echo "Unknown Option: ${1}"

                return 1

                ;;

            *)

                break

                ;;

        esac

    done



    ## Figure out the length of what is to be printed to be used

    ## for warning messages. 

    STRING_LENGTH=$((${#1} + 1))



    # Print the message to the screen

    ${ECHO} ${ECHOPARM} -e "${2}${1}"

    

}



boot_mesg_flush()

{

    # Reset STRING_LENGTH for next message

    STRING_LENGTH="0"

}



boot_log()

{

    # Left in for backwards compatibility

    :

}



echo_ok()

{

    ${ECHO} -n -e "${CURS_UP}${SET_COL}${BRACKET}[${SUCCESS}  OK  ${BRACKET}]"

    ${ECHO} -e "${NORMAL}"

        boot_mesg_flush

}



echo_failure()

{

    ${ECHO} -n -e "${CURS_UP}${SET_COL}${BRACKET}[${FAILURE} FAIL ${BRACKET}]"

    ${ECHO} -e "${NORMAL}"

        boot_mesg_flush

}



echo_warning()

{

    ${ECHO} -n -e "${CURS_UP}${SET_COL}${BRACKET}[${WARNING} WARN ${BRACKET}]"

    ${ECHO} -e "${NORMAL}"

        boot_mesg_flush

}



print_error_msg()

{

    echo_failure

    # $i is inherited by the rc script

    boot_mesg -n "FAILURE:\n\nYou should not be reading this error message.\n\n" ${FAILURE}

    boot_mesg -n " It means that an unforeseen error took"

    boot_mesg -n " place in ${i}, which exited with a return value of"

    boot_mesg " ${error_value}.\n"

    boot_mesg_flush

    boot_mesg -n "If you're able to track this"

    boot_mesg -n " error down to a bug in one of the files provided by"

    boot_mesg -n " the LFS book, please be so kind to inform us at"

    boot_mesg " lfs-dev@linuxfromscratch.org.\n"

    boot_mesg_flush

    boot_mesg -n "Press Enter to continue..." ${INFO}

    boot_mesg "" ${NORMAL}

    read ENTER

}



check_script_status()

{

    # $i is inherited by the rc script

    if [ ! -f ${i} ]; then

        boot_mesg "${i} is not a valid symlink." ${WARNING}

        echo_warning

        continue

    fi



    if [ ! -x ${i} ]; then

        boot_mesg "${i} is not executable, skipping." ${WARNING}

        echo_warning

        continue

    fi

}



evaluate_retval()

{

    error_value="${?}"



    if [ ${error_value} = 0 ]; then

        echo_ok

    else

        echo_failure

    fi



    # This prevents the 'An Unexpected Error Has Occurred' from trivial

    # errors.

    return 0

}



print_status()

{

    if [ "${#}" = "0" ]; then

        echo "Usage: ${0} {success|warning|failure}"

        return 1

    fi



    case "${1}" in



        success)

            echo_ok

            ;;



        warning)

            # Leave this extra case in because old scripts

            # may call it this way.

            case "${2}" in

                running)

                    ${ECHO} -e -n "${CURS_UP}"

                    ${ECHO} -e -n "\\033[${STRING_LENGTH}G   "

                    boot_mesg "Already running." ${WARNING}

                    echo_warning

                    ;;

                not_running)

                    ${ECHO} -e -n "${CURS_UP}"

                    ${ECHO} -e -n "\\033[${STRING_LENGTH}G   "

                    boot_mesg "Not running." ${WARNING}

                    echo_warning

                    ;;

                not_available)

                    ${ECHO} -e -n "${CURS_UP}"

                    ${ECHO} -e -n "\\033[${STRING_LENGTH}G   "

                    boot_mesg "Not available." ${WARNING}

                    echo_warning

                    ;;

                *)

                    # This is how it is supposed to

                    # be called

                    echo_warning

                    ;;

            esac

        ;;



        failure)

            echo_failure

        ;;



    esac



}



reloadproc()

{

    local pidfile=""

    local failure=0



    while true

    do

        case "${1}" in

            -p)

                pidfile="${2}"

                shift 2

                ;;

            -*)

                log_failure_msg "Unknown Option: ${1}"

                return 2

                ;;

            *)

                break

                ;;

        esac

    done



    if [ "${#}" -lt "1" ]; then

        log_failure_msg "Usage: reloadproc [-p pidfile] pathname"

        return 2

    fi



    # This will ensure compatibility with previous LFS Bootscripts

    if [ -n "${PIDFILE}" ];    then

        pidfile="${PIDFILE}"

    fi



    # Is the process running?

    if [ -z "${pidfile}" ];    then

        pidofproc -s "${1}"

    else

        pidofproc -s -p "${pidfile}" "${1}"

    fi



    # Warn about stale pid file

    if [ "$?" = 1 ]; then

        boot_mesg -n "Removing stale pid file: ${pidfile}. " ${WARNING}

        rm -f "${pidfile}"

    fi



    if [ -n "${pidlist}" ];    then

        for pid in ${pidlist}

        do

            kill -"${RELOADSIG}" "${pid}" || failure="1"

        done



        (exit ${failure})

        evaluate_retval



    else

        boot_mesg "Process ${1} not running." ${WARNING}

        echo_warning

    fi

}



statusproc()

{

    local pidfile=""

    local base=""

    local ret=""



    while true

    do

        case "${1}" in

            -p)

                pidfile="${2}"

                shift 2

                ;;

            -*)

                log_failure_msg "Unknown Option: ${1}"

                return 2

                ;;

            *)

                break

                ;;

        esac

    done



    if [ "${#}" != "1" ]; then

        shift 1

        log_failure_msg "Usage: statusproc [-p pidfile] pathname"

        return 2

    fi



    # Get the process basename

    base="${1##*/}"



    # This will ensure compatibility with previous LFS Bootscripts

    if [ -n "${PIDFILE}" ];    then

        pidfile="${PIDFILE}"

    fi



    # Is the process running?

    if [ -z "${pidfile}" ];    then

        pidofproc -s "${1}"

    else

        pidofproc -s -p "${pidfile}" "${1}"

    fi



    # Store the return status

    ret=$?



    if [ -n "${pidlist}" ];    then

        ${ECHO} -e "${INFO}${base} is running with Process"\

            "ID(s) ${pidlist}.${NORMAL}"

    else

        if [ -n "${base}" -a -e "/var/run/${base}.pid" ]; then

            ${ECHO} -e "${WARNING}${1} is not running but"\

                "/var/run/${base}.pid exists.${NORMAL}"

        else

            if [ -n "${pidfile}" -a -e "${pidfile}" ]; then

                ${ECHO} -e "${WARNING}${1} is not running"\

                    "but ${pidfile} exists.${NORMAL}"

            else

                ${ECHO} -e "${INFO}${1} is not running.${NORMAL}"

            fi

        fi

    fi



    # Return the status from pidofproc

    return $ret

}



# The below functions are documented in the LSB-generic 2.1.0



#*******************************************************************************

# Function - pidofproc [-s] [-p pidfile] pathname

#

# Purpose: This function returns one or more pid(s) for a particular daemon

#

# Inputs: -p pidfile, use the specified pidfile instead of pidof

#         pathname, path to the specified program

#

# Outputs: return 0 - Success, pid's in stdout

#          return 1 - Program is dead, pidfile exists

#          return 2 - Invalid or excessive number of arguments, 

#                     warning in stdout

#          return 3 - Program is not running

#

# Dependencies: pidof, echo, head

#

# Todo: Remove dependency on head

#       This depreciates getpids

#       Test changes to pidof

#

#*******************************************************************************

pidofproc()

{

    local pidfile=""

    local lpids=""

    local silent=""

    pidlist=""

    while true

    do

        case "${1}" in

            -p)

                pidfile="${2}"

                shift 2

                ;;



            -s)

                # Added for legacy opperation of getpids

                # eliminates several '> /dev/null'

                silent="1"

                shift 1

                ;;

            -*)

                log_failure_msg "Unknown Option: ${1}"

                return 2

                ;;

            *)

                break

                ;;

        esac

    done



    if [ "${#}" != "1" ]; then

        shift 1

        log_failure_msg "Usage: pidofproc [-s] [-p pidfile] pathname"

        return 2

    fi



    if [ -n "${pidfile}" ]; then

        if [ ! -r "${pidfile}" ]; then

            return 3 # Program is not running

        fi



        lpids=`head -n 1 ${pidfile}`

        for pid in ${lpids}

        do

            if [ "${pid}" -ne "$$" -a "${pid}" -ne "${PPID}" ]; then

                kill -0 "${pid}" 2>/dev/null &&

                pidlist="${pidlist} ${pid}"

            fi

            

            if [ "${silent}" != "1" ]; then

                echo "${pidlist}"

            fi



            test -z "${pidlist}" && 

            # Program is dead, pidfile exists

            return 1

            # else

            return 0

        done



    else

        pidlist=`pidof -o $$ -o $PPID -x "$1"`

        if [ "${silent}" != "1" ]; then

            echo "${pidlist}"

        fi



        # Get provide correct running status

        if [ -n "${pidlist}" ]; then

            return 0

        else

            return 3

        fi



    fi



    if [ "$?" != "0" ]; then

        return 3 # Program is not running

    fi

}



# This will ensure compatibility with previous LFS Bootscripts

getpids()

{

    if [ -z "${PIDFILE}" ]; then

        pidofproc -s -p "${PIDFILE}" $@

    else

        pidofproc -s $@

    fi

    base="${1##*/}"

}



#*******************************************************************************

# Function - loadproc [-f] [-n nicelevel] [-p pidfile] pathname [args]

#

# Purpose: This runs the specified program as a daemon

#

# Inputs: -f, run the program even if it is already running

#         -n nicelevel, specifies a nice level. See nice(1).

#         -p pidfile, uses the specified pidfile

#         pathname, pathname to the specified program

#         args, arguments to pass to specified program

#

# Outputs: return 0 - Success

#          return 2 - Invalid of excessive number of arguments, 

#                     warning in stdout

#          return 4 - Program or service status is unknown

#

# Dependencies: nice, rm

#

# Todo: LSB says this should be called start_daemon

#       LSB does not say that it should call evaluate_retval

#       It checks for PIDFILE, which is deprecated.

#         Will be removed after BLFS 6.0

#       loadproc returns 0 if program is already running, not LSB compliant

#

#*******************************************************************************

loadproc()

{

    local pidfile=""

    local forcestart=""

    local nicelevel="10"



# This will ensure compatibility with previous LFS Bootscripts

    if [ -n "${PIDFILE}" ];    then

        pidfile="${PIDFILE}"

    fi



  while true

    do

        case "${1}" in

            -f)

                forcestart="1"

                shift 1

                ;;

            -n)

                nicelevel="${2}"

                shift 2

                ;;

            -p)

                pidfile="${2}"

                shift 2

                ;;

            -*)

                log_failure_msg "Unknown Option: ${1}"

                return 2 #invalid or excess argument(s)

                ;;

            *)

                break

                ;;

        esac

    done



    if [ "${#}" = "0" ]; then

        log_failure_msg "Usage: loadproc [-f] [-n nicelevel] [-p pidfile] pathname [args]"

        return 2 #invalid or excess argument(s)

    fi



    if [ -z "${forcestart}" ]; then

        if [ -z "${pidfile}" ];    then

            pidofproc -s "${1}"

        else

            pidofproc -s -p "${pidfile}" "${1}"

        fi



        case "${?}" in

            0)

                log_warning_msg "Unable to continue: ${1} is running"

                return 0 # 4

                ;;

            1)

                boot_mesg "Removing stale pid file: ${pidfile}" ${WARNING}

                rm -f "${pidfile}"

                ;;

            3)

                ;;

            *)

                log_failure_msg "Unknown error code from pidofproc: ${?}"

                return 4

                ;;

        esac

    fi



    nice -n "${nicelevel}" "${@}"

    evaluate_retval # This is "Probably" not LSB compliant, but required to be compatible with older bootscripts

    return 0

}



#*******************************************************************************

# Function - killproc  [-p pidfile] pathname [signal]

#

# Purpose:

#

# Inputs: -p pidfile, uses the specified pidfile

#         pathname, pathname to the specified program

#         signal, send this signal to pathname

#

# Outputs: return 0 - Success

#          return 2 - Invalid of excessive number of arguments, 

#                     warning in stdout

#          return 4 - Unknown Status

#

# Dependencies: kill, rm

#

# Todo: LSB does not say that it should call evaluate_retval

#       It checks for PIDFILE, which is deprecated.

#         Will be removed after BLFS 6.0

#

#*******************************************************************************

killproc()

{

    local pidfile=""

    local killsig=TERM # default signal is SIGTERM

    pidlist=""



    # This will ensure compatibility with previous LFS Bootscripts

    if [ -n "${PIDFILE}" ];    then

        pidfile="${PIDFILE}"

    fi



    while true

    do

        case "${1}" in

            -p)

                pidfile="${2}"

                shift 2

                ;;

            -*)

                log_failure_msg "Unknown Option: ${1}"

                return 2

                ;;

            *)

                 break

                ;;

        esac

    done



    if [ "${#}" = "2" ]; then

        killsig="${2}"

    elif [ "${#}" != "1" ];    then

        shift 2

        log_failure_msg "Usage: killproc  [-p pidfile] pathname [signal]"

        return 2

    fi



    # Is the process running?

    if [ -z "${pidfile}" ];    then

        pidofproc -s "${1}"

    else

        pidofproc -s -p "${pidfile}" "${1}"

    fi



    # Remove stale pidfile

    if [ "$?" = 1 ]; then

        boot_mesg "Removing stale pid file: ${pidfile}." ${WARNING}

        rm -f "${pidfile}"

    fi



    # If running, send the signal

    if [ -n "${pidlist}" ]; then

    for pid in ${pidlist}

    do

        kill -${killsig} ${pid} 2>/dev/null



        # Wait up to 3 seconds, for ${pid} to terminate

        case "${killsig}" in

        TERM|SIGTERM|KILL|SIGKILL)

            # sleep in 1/10ths of seconds and

            # multiply KILLDELAY by 10

            local dtime="${KILLDELAY}0"

            while [ "${dtime}" != "0" ]

            do

                kill -0 ${pid} 2>/dev/null || break

                sleep 0.1

                dtime=$(( ${dtime} - 1))

            done

            # If ${pid} is still running, kill it

            kill -0 ${pid} 2>/dev/null && kill -KILL ${pid} 2>/dev/null

            ;;

        esac

    done



    # Check if the process is still running if we tried to stop it

    case "${killsig}" in

    TERM|SIGTERM|KILL|SIGKILL)

        if [ -z "${pidfile}" ];    then

            pidofproc -s "${1}"

        else

            pidofproc -s -p "${pidfile}" "${1}"

        fi



        # Program was terminated

        if [ "$?" != "0" ]; then

            # Remove the pidfile if necessary

            if [ -f "${pidfile}" ];    then

                rm -f "${pidfile}"

            fi

            echo_ok

            return 0

        else # Program is still running

            echo_failure

            return 4 # Unknown Status

        fi

        ;;

    *)

        # Just see if the kill returned successfully

        evaluate_retval

        ;;

    esac

    else # process not running

    print_status warning not_running

    fi

}





#*******************************************************************************

# Function - log_success_msg "message"

#

# Purpose: Print a success message

#

# Inputs: $@ - Message

#

# Outputs: Text output to screen

#

# Dependencies: echo

#

# Todo: logging

#

#*******************************************************************************

log_success_msg()

{

    ${ECHO} -n -e "${BOOTMESG_PREFIX}${@}"

    ${ECHO} -e "${SET_COL}""${BRACKET}""[""${SUCCESS}""  OK  ""${BRACKET}""]""${NORMAL}"

    return 0

}



#*******************************************************************************

# Function - log_failure_msg "message"

#

# Purpose: Print a failure message

#

# Inputs: $@ - Message

#

# Outputs: Text output to screen

#

# Dependencies: echo

#

# Todo: logging

#

#*******************************************************************************

log_failure_msg() {

    ${ECHO} -n -e "${BOOTMESG_PREFIX}${@}"

    ${ECHO} -e "${SET_COL}""${BRACKET}""[""${FAILURE}"" FAIL ""${BRACKET}""]""${NORMAL}"

    return 0

}



#*******************************************************************************

# Function - log_warning_msg "message"

#

# Purpose: print a warning message

#

# Inputs: $@ - Message

#

# Outputs: Text output to screen

#

# Dependencies: echo

#

# Todo: logging

#

#*******************************************************************************

log_warning_msg() {

    ${ECHO} -n -e "${BOOTMESG_PREFIX}${@}"

    ${ECHO} -e "${SET_COL}""${BRACKET}""[""${WARNING}"" WARN ""${BRACKET}""]""${NORMAL}"

    return 0

}



# End $rc_base/init.d/functions


Host by Alair