#!/bin/bash # initscripts functions # # width: STAT_COL=80 if [[ ! -t 1 ]]; then USECOLOR="" elif [[ -t 0 ]]; then # stty will fail when stdin isn't a terminal STAT_COL="$(/bin/stty size)" # stty gives "rows cols"; strip the rows number, we just want columns STAT_COL="${STAT_COL##* }" elif /bin/tput cols &>/dev/null; then # is /usr/share/terminfo already mounted, and TERM recognized? STAT_COL=$(/bin/tput cols) fi if ((STAT_COL==0)); then # if output was 0 (serial console), set default width to 80 STAT_COL=80 USECOLOR="" fi # we use 13 characters for our own stuff STAT_COL=$(($STAT_COL - 13)) # disable colors on broken terminals TERM_COLORS="$(/bin/tput colors 2>/dev/null)" if (($? != 3)); then case $TERM_COLORS in *[!0-9]*) USECOLOR="";; [0-7]) USECOLOR="";; '') USECOLOR="";; esac fi unset TERM_COLORS # clear the TZ envvar, so daemons always respect /etc/localtime unset TZ # sanitize the locale settins unset LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY \ LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE \ LC_MEASUREMENT LC_IDENTIFICATION LC_ALL if [[ $DAEMON_LOCALE =~ yes|YES && -n $LOCALE ]]; then export LANG="${LOCALE}" else export LANG=C fi # set colors if [[ $USECOLOR =~ yes|YES ]]; then if /bin/tput setaf 0 &>/dev/null; then C_CLEAR="$(tput sgr0)" # clear text C_MAIN="${C_CLEAR}$(/bin/tput bold)" # main text C_OTHER="${C_MAIN}$(/bin/tput setaf 4)" # prefix & brackets C_SEPARATOR="${C_MAIN}$(/bin/tput setaf 0)" # separator C_BUSY="${C_CLEAR}$(/bin/tput setaf 6)" # busy C_FAIL="${C_MAIN}$(/bin/tput setaf 1)" # failed C_DONE="${C_MAIN}" # completed C_BKGD="${C_MAIN}$(/bin/tput setaf 5)" # backgrounded C_H1="${C_MAIN}" # highlight text 1 C_H2="${C_MAIN}$(/bin/tput setaf 6)" # highlight text 2 else C_CLEAR="\e[m" # clear text C_MAIN="\e[;1m" # main text C_OTHER="\e[1;34m" # prefix & brackets C_SEPARATOR="\e[1;30m" # separator C_BUSY="\e[;36m" # busy C_FAIL="\e[1;31m" # failed C_DONE="${C_MAIN}" # completed C_BKGD="\e[1;35m" # backgrounded C_H1="${C_MAIN}" # highlight text 1 C_H2="\e[1;36m" # highlight text 2 fi fi if [[ -t 1 ]]; then SAVE_POSITION="\e[s" RESTORE_POSITION="\e[u" DEL_TEXT="\e[$(($STAT_COL+4))G" else SAVE_POSITION="" RESTORE_POSITION="" DEL_TEXT="" fi # prefixes: PREFIX_REG="::" PREFIX_HL=" >" # functions: deltext() { printf "${DEL_TEXT}" } printhl() { printf "${C_OTHER}${PREFIX_HL} ${C_H1}${1}${C_CLEAR} \n" } printsep() { printf "\n${C_SEPARATOR} ------------------------------\n" } stat_bkgd() { printf "${C_OTHER}${PREFIX_REG} ${C_MAIN}${1}${C_CLEAR} " deltext printf " ${C_OTHER}[${C_BKGD}BKGD${C_OTHER}]${C_CLEAR} " } stat_busy() { printf "${C_OTHER}${PREFIX_REG} ${C_MAIN}${1}${C_CLEAR} " printf "${SAVE_POSITION}" deltext printf " ${C_OTHER}[${C_BUSY}BUSY${C_OTHER}]${C_CLEAR} " } stat_append() { printf "${RESTORE_POSITION}" printf -- "${C_MAIN}${1}${C_CLEAR}" printf "${SAVE_POSITION}" } stat_done() { deltext printf " ${C_OTHER}[${C_DONE}DONE${C_OTHER}]${C_CLEAR} \n" } stat_fail() { deltext printf " ${C_OTHER}[${C_FAIL}FAIL${C_OTHER}]${C_CLEAR} \n" } stat_die() { stat_fail exit ${1:-1} } status() { stat_busy "$1" shift if "$@" >/dev/null 2>&1; then stat_done return 0 fi stat_fail return 1 } # usage : in_array( $needle, $haystack ) # return : 0 - found # 1 - not found # Copied from makepkg in_array() { [[ $2 ]] || return 1 local needle=$1; shift local item for item in "$@"; do [[ ${item#@} = $needle ]] && return 0 done return 1 # Not Found } # daemons: add_daemon() { [[ -d /run/daemons ]] || /bin/mkdir -p /run/daemons > /run/daemons/"$1" } rm_daemon() { /bin/rm -f /run/daemons/"$1" } ck_daemon() { [[ ! -f /run/daemons/$1 ]] } # Check if $1 is a valid daemon name have_daemon() { [[ -f /etc/rc.d/$1 && -x /etc/rc.d/$1 ]] } # Check if $1 is started at boot ck_autostart() { local d for d in "${DAEMONS[@]}"; do [[ "$1" = ${d#@} ]] && return 1 done return 0 } start_daemon() { have_daemon "$1" && /etc/rc.d/"$1" start } ck_depends() { for daemon in "$@"; do ck_daemon "$daemon" && start_daemon "$daemon" done } start_daemon_bkgd() { stat_bkgd "Starting $1" have_daemon "$1" && (start_daemon "$1") &>/dev/null & } stop_daemon() { have_daemon "$1" && /etc/rc.d/"$1" stop } # Status functions status_started() { deltext echo -ne "$C_OTHER[${C_STRT}STARTED$C_OTHER]$C_CLEAR " } status_stopped() { deltext echo -ne "$C_OTHER[${C_STRT}STOPPED$C_OTHER]$C_CLEAR " } ck_status() { if ! ck_daemon "$1"; then status_started else status_stopped fi } # PIDs to be omitted by killall5 declare -a omit_pids add_omit_pids() { omit_pids+=( $@ ) } kill_everything() { # $1 = where we are being called from. # This is used to determine which hooks to run. # Find daemons NOT in the DAEMONS array. Shut these down first for daemon in /run/daemons/*; do [[ -f $daemon ]] || continue daemon=${daemon##*/} in_array "$daemon" "${DAEMONS[@]}" || stop_daemon "$daemon" done # Shutdown daemons in reverse order for ((i=${#DAEMONS[@]}-1; i>=0; i--)); do [[ ${DAEMONS[$i]:0:1} = '!' ]] && continue ck_daemon ${DAEMONS[$i]#@} || stop_daemon ${DAEMONS[$i]#@} done # Terminate all processes stat_busy "Sending SIGTERM To Processes" run_hook "$1_prekillall" local pid k5args="" for pid in ${omit_pids[@]}; do k5args+=" -o $pid" done /sbin/killall5 -15 $k5args &> /dev/null /bin/sleep 5 stat_done stat_busy "Sending SIGKILL To Processes" /sbin/killall5 -9 $k5args &> /dev/null /bin/sleep 1 stat_done run_hook "$1_postkillall" } activate_vgs() { [[ $USELVM =~ yes|YES && -x /sbin/lvm && -d /sys/block ]] || return # Kernel 2.6.x, LVM2 groups /sbin/modprobe -q dm-mod 2>/dev/null stat_busy "Activating LVM2 groups" if /sbin/vgchange --sysinit -a y >/dev/null; then stat_done else stat_fail fi } # Arch cryptsetup packages traditionally contained the binaries # /usr/sbin/cryptsetup # /sbin/cryptsetup.static # By default, initscripts used the /sbin/cryptsetup.static. # Newer packages will only have /sbin/cryptsetup and no static binary # This ensures maximal compatibility with the old and new layout for CS in /sbin/cryptsetup /usr/sbin/cryptsetup \ /sbin/cryptsetup.static ''; do [[ -x $CS ]] && break done read_crypttab() { # $1 = function to call with the split out line from the crypttab local line nspo failed=0 while read line; do [[ $line && ${line:0:1} != '#' ]] || continue eval nspo=("${line%#*}") if $1 "${nspo[0]}" "${nspo[1]}" "${nspo[2]}" "${nspo[*]:3}"; then crypto_unlocked=1 else failed=1 fi done < /etc/crypttab return $failed } ############################### # Custom hooks in initscripts # ############################### # Hooks can be used to include custom code in various places in the rc.* scripts # # Define a hook function in a functions.d file using: # function_name() { # ... # } # add_hook hook_name function_name # It is allowed to register several hook functions for the same hook # Is is also allowed to register the same hook function for several hooks # # Currently, the following hooks exist: # sysinit_start: at the beginning of rc.sysinit # multi_start: at the beginning of rc.multi # single_start: at the beginning of rc.single # shutdown_start: at the beginning of rc.shutdown # sysinit_end: at the end of rc.sysinit # multi_end: at the end of rc.multi # single_end: at the end of rc.single # sysinit_udevlaunched: after udev has been launched in rc.sysinit # single_udevlaunched: after udev has been launched in rc.single # sysinit_udevsettled: after uevents have settled in rc.sysinit # single_udevsettled: after uevents have settled in rc.single # sysinit_premount: before local filesystems are mounted, but after root is mounted read-write in rc.sysinit # shutdown_prekillall: before all processes are being killed in rc.shutdown # single_prekillall: before all processes are being killed in rc.single # shutdown_postkillall: after all processes have been killed in rc.shutdown # single_postkillall: after all processes have been killed in rc.single # shutdown_poweroff: directly before powering off in rc.shutdown # # Declare add_hook and run_hook as read-only to prevent overwriting them. # Too bad we cannot do the same thing with hook_funcs if [[ $RC_FUNCTIONS_HOOK_FUNCS_DEFINED -ne 1 ]]; then declare -A hook_funcs add_hook() { [[ $1 && $2 ]] || return 1 hook_funcs["$1"]+=" $2" } run_hook() { [[ $1 ]] || return 1 local func for func in ${hook_funcs["$1"]}; do "${func}" done } declare -fr add_hook run_hook declare -r RC_FUNCTIONS_HOOK_FUNCS_DEFINED=1 fi # Function for setting console font if required set_consolefont() { [[ $CONSOLEFONT ]] || return 0 stat_busy "Loading Console Font: $CONSOLEFONT" #CONSOLEMAP in UTF-8 shouldn't be used [[ $CONSOLEMAP && ${LOCALE,,} =~ utf ]] && CONSOLEMAP="" for i in /dev/tty[0-9]*; do /usr/bin/setfont ${CONSOLEMAP:+-m ${CONSOLEMAP}} \ $CONSOLEFONT -C ${i} >/dev/null 2>&1 done if (($? != 0)); then stat_fail elif [[ $CONSOLEMAP ]]; then cat <<"EOF" >>/etc/profile.d/locale.sh if [ "$CONSOLE" = "" -a "$TERM" = "linux" -a -t 1 ]; then printf "\033(K"; fi EOF stat_done else stat_done fi } # Source additional functions at the end to allow overrides for f in /etc/rc.d/functions.d/*; do [[ -e $f ]] && . "$f" done # End of file # vim: set ts=2 sw=2 noet: