diff options
Diffstat (limited to 'functions')
-rw-r--r-- | functions | 341 |
1 files changed, 240 insertions, 101 deletions
@@ -2,32 +2,56 @@ # initscripts functions # -# width: +# sanitize PATH (will be overridden later when /etc/profile is sourced, but is useful for UDev) +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -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) +if [[ $1 == "start" ]]; then + if [[ $STARTING ]]; then + echo "A daemon is starting another daemon, this is unlikely to work as intended." + else + export STARTING=1 + fi fi -if ((STAT_COL==0)); then - # if output was 0 (serial console), set default width to 80 + +# width: +calc_columns () { STAT_COL=80 - USECOLOR="" -fi + if [[ ! -t 1 ]]; then + USECOLOR="" + elif [[ -t 0 ]]; then + # stty will fail when stdin isn't a terminal + STAT_COL=$(stty size) + # stty gives "rows cols"; strip the rows number, we just want columns + STAT_COL=${STAT_COL##* } + elif tput cols &>/dev/null; then + # is /usr/share/terminfo already mounted, and TERM recognized? + STAT_COL=$(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)) + # we use 13 characters for our own stuff + STAT_COL=$(( STAT_COL - 13 )) + + 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 +} + +calc_columns # disable colors on broken terminals -TERM_COLORS="$(/bin/tput colors 2>/dev/null)" -if (($? != 3)); then +TERM_COLORS=$(tput colors 2>/dev/null) +if (( $? != 3 )); then case $TERM_COLORS in *[!0-9]*) USECOLOR="";; [0-7]) USECOLOR="";; @@ -43,25 +67,25 @@ unset TZ 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 +if [[ $DAEMON_LOCALE = [yY][eE][sS] && $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 5)" # 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 +if [[ $USECOLOR = [yY][eE][sS] ]]; then + if tput setaf 0 &>/dev/null; then + C_CLEAR=$(tput sgr0) # clear text + C_MAIN=${C_CLEAR}$(tput bold) # main text + C_OTHER=${C_MAIN}$(tput setaf 5) # prefix & brackets + C_SEPARATOR=${C_MAIN}$(tput setaf 0) # separator + C_BUSY=${C_CLEAR}$(tput setaf 6) # busy + C_FAIL=${C_MAIN}$(tput setaf 1) # failed + C_DONE=${C_MAIN} # completed + C_BKGD=${C_MAIN}$(tput setaf 5) # backgrounded + C_H1=${C_MAIN} # highlight text 1 + C_H2=${C_MAIN}$(tput setaf 6) # highlight text 2 else C_CLEAR="\e[m" # clear text C_MAIN="\e[;1m" # main text @@ -69,23 +93,13 @@ if [[ $USECOLOR =~ yes|YES ]]; then C_SEPARATOR="\e[1;30m" # separator C_BUSY="\e[;36m" # busy C_FAIL="\e[1;31m" # failed - C_DONE="${C_MAIN}" # completed + C_DONE=${C_MAIN} # completed C_BKGD="\e[1;35m" # backgrounded - C_H1="${C_MAIN}" # highlight text 1 + 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="::" @@ -142,24 +156,20 @@ stat_die() { status() { stat_busy "$1" shift - if "$@" >/dev/null 2>&1; then - stat_done - return 0 - fi - stat_fail - return 1 + "$@" &>/dev/null + local ret=$? + (( ret == 0 )) && stat_done || stat_fail + return $ret } # 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 + for item; do + [[ $item = "${needle}" ]] && return 0 done return 1 # Not Found } @@ -167,12 +177,12 @@ in_array() { # daemons: add_daemon() { - [[ -d /run/daemons ]] || /bin/mkdir -p /run/daemons - > /run/daemons/"$1" + [[ -d /run/daemons ]] || mkdir -p /run/daemons + >| /run/daemons/"$1" } rm_daemon() { - /bin/rm -f /run/daemons/"$1" + rm -f /run/daemons/"$1" } ck_daemon() { @@ -186,9 +196,9 @@ have_daemon() { # Check if $1 is started at boot ck_autostart() { - local d - for d in "${DAEMONS[@]}"; do - [[ "$1" = ${d#@} ]] && return 1 + local daemon + for daemon in "${DAEMONS[@]}"; do + [[ $1 = "${daemon#@}" ]] && return 1 done return 0 } @@ -197,8 +207,11 @@ start_daemon() { have_daemon "$1" && /etc/rc.d/"$1" start } +# Never use this function, it causes daemons to be stoped in the wrong order. +# The only way to start a daemon at boot is to add it to the DAEMONS array. ck_depends() { - for daemon in "$@"; do + local daemon + for daemon; do ck_daemon "$daemon" && start_daemon "$daemon" done } @@ -224,11 +237,23 @@ status_stopped() { } ck_status() { - if ! ck_daemon "$1"; then - status_started - else - status_stopped + ! ck_daemon "$1" && status_started || status_stopped +} + +# Return PID of $1 +get_pid() { + pidof -o %PPID $1 || return 1 +} + +# Check if PID-file $1 is still the active PID-file for command $2 +ck_pidfile() { + if [[ -f $1 ]]; then + local fpid ppid + read -r fpid <"$1" + ppid=$(get_pid "$2") + [[ $fpid = "${ppid}" ]] && return 0 fi + return 1 } # PIDs to be omitted by killall5 @@ -238,52 +263,84 @@ add_omit_pids() { omit_pids+=( $@ ) } - -kill_everything() { - # $1 = where we are being called from. - # This is used to determine which hooks to run. +# Stop all daemons +# This function should *never* ever perform any other actions beside calling stop_daemon()! +# It might be used by a splash system etc. to get a list of daemons to be stopped. +stop_all_daemons() { # Find daemons NOT in the DAEMONS array. Shut these down first + local daemon for daemon in /run/daemons/*; do [[ -f $daemon ]] || continue daemon=${daemon##*/} - in_array "$daemon" "${DAEMONS[@]}" || stop_daemon "$daemon" + ck_autostart "$daemon" && 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]#@} + local i daemon + for (( i=${#DAEMONS[@]}-1; i>=0; i-- )); do + [[ ${DAEMONS[i]} = '!'* ]] && continue + daemon=${DAEMONS[i]#@} + ck_daemon "$daemon" || stop_daemon "$daemon" done +} +kill_all() { # Terminate all processes + # and wait until killall5 reports all done or timeout + # Unfortunately killall5 does not support the 0 signal, so just + # use SIGCONT for checking (which should be ignored). 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 + local i + killall5 -15 ${omit_pids[@]/#/-o } &>/dev/null + for (( i=0; i<20 && $?!=2; i++ )); do + sleep .25 # 1/4 second + killall5 -18 ${omit_pids[@]/#/-o } &>/dev/null + done stat_done stat_busy "Sending SIGKILL To Processes" - /sbin/killall5 -9 $k5args &> /dev/null - /bin/sleep 1 + local i + killall5 -9 ${omit_pids[@]/#/-o } &>/dev/null + for (( i=0; i<4 && $?!=2; i++ )); do + sleep .25 # 1/4 second + killall5 -18 ${omit_pids[@]/#/-o } &>/dev/null + done stat_done +} + +# Start/trigger UDev, load MODULES and settle UDev +udevd_modprobe() { + # $1 = where we are being called from. + # This is used to determine which hooks to run. + status "Starting UDev Daemon" udevd --daemon + + run_hook "$1_udevlaunched" + + stat_busy "Triggering UDev uevents" + udevadm trigger --action=add --type=subsystems + udevadm trigger --action=add --type=devices + stat_done + + # Load modules from the MODULES array defined in rc.conf + [[ -f /proc/modules ]] && (( ${#MODULES[*]} )) && + status "Loading Modules" modprobe -ab "${MODULES[@]}" + + status "Waiting for UDev uevents to be processed" \ + udevadm settle --timeout=${UDEV_TIMEOUT:-30} - run_hook "$1_postkillall" + run_hook "$1_udevsettled" + + # in case loading a module changed the display mode + calc_columns } activate_vgs() { - [[ $USELVM =~ yes|YES && -x /sbin/lvm && -d /sys/block ]] || return + [[ $USELVM = [yY][eE][sS] && -x $(type -P lvm) && -d /sys/block ]] || return 0 # 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 + modprobe -q dm-mod 2>/dev/null + vgchange --sysinit -a y >/dev/null + (( $? == 0 )) && stat_done || stat_fail } # Arch cryptsetup packages traditionally contained the binaries @@ -301,7 +358,7 @@ 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 + [[ $line && $line != '#'* ]] || continue eval nspo=("${line%#*}") if $1 "${nspo[0]}" "${nspo[1]}" "${nspo[2]}" "${nspo[*]:3}"; then crypto_unlocked=1 @@ -312,6 +369,75 @@ read_crypttab() { return $failed } +# Filesystem functions +# These can be overridden/reused for customizations like shutdown/loop-fsck. +NETFS="nfs,nfs4,smbfs,cifs,codafs,ncpfs,shfs,fuse,fuseblk,glusterfs,davfs,fuse.glusterfs" + +# Check local filesystems +fsck_all() { + fsck -A -T -C"$FSCK_FD" -a -t "no${NETFS//,/,no},noopts=_netdev" $FORCEFSCK + return $? +} + +# Single-user login and/or automatic reboot after fsck (if needed) +fsck_reboot() { + # $1 = exit code returned by fsck + # Ignore conditions 'FS errors corrected' and 'Cancelled by the user' + (( ($1 | 33) == 33 )) && return 0 + if (( $1 & 2 )); then + echo + echo "********************** REBOOT REQUIRED *********************" + echo "* *" + echo "* The system will be rebooted automatically in 15 seconds. *" + echo "* *" + echo "************************************************************" + echo + sleep 15 + else + echo + echo "***************** FILESYSTEM CHECK FAILED ****************" + echo "* *" + echo "* Please repair manually and reboot. Note that the root *" + echo "* file system is currently mounted read-only. To remount *" + echo "* it read-write type: mount -n -o remount,rw / *" + echo "* When you exit the maintenance shell the system will *" + echo "* reboot automatically. *" + echo "* *" + echo "************************************************************" + echo + sulogin -p + fi + echo "Automatic reboot in progress..." + umount -a + mount -n -o remount,ro / + reboot -f + exit 0 +} + +mount_all() { + mount -a -t "nosysfs,no${NETFS//,/,no}" -O no_netdev +} + +remove_leftover() { + stat_busy "Removing Leftover Files" + # handle this separately until we declare the non-symlinks obsoleted + [[ ! -L /var/lock ]] && rm -rf /var/lock/* + if [[ ! -L /var/run && -d /var/run ]]; then + find /var/run/ \! -type d -delete + ln -s /run/daemons /var/run/daemons + fi + /usr/lib/initscripts/arch-tmpfiles --create --remove && stat_done || stat_fail +} + +bootlogd_stop() { + [[ -f /run/bootlogd.pid ]] || return 0 + touch /var/log/boot + kill $(< /run/bootlogd.pid) + rm -f /run/bootlogd.pid + sed -i -r -e 's/\^\[\[[0-9]?;?[0-9]?[0-9]?;?[0-9]?[0-9]?[ms]//g' \ + -e 's/\^\[(\[1[0-9]1|%)G//g' -e 's/\^\[\[0;1//g' /var/log/boot +} + ############################### # Custom hooks in initscripts # ############################### @@ -338,21 +464,23 @@ read_crypttab() { # 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 +# sysinit_postmount: after local filesystems are mounted # 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_postumount: after filesystems are unmounted # 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 +if (( RC_FUNCTIONS_HOOK_FUNCS_DEFINED != 1 )); then declare -A hook_funcs add_hook() { [[ $1 && $2 ]] || return 1 - hook_funcs["$1"]+=" $2" + hook_funcs[$1]+=" $2" } run_hook() { @@ -371,13 +499,14 @@ fi 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 + #CONSOLEMAP in UTF-8 shouldn't be used + [[ $CONSOLEMAP && ${LOCALE,,} =~ utf ]] && CONSOLEMAP="" + local i + for i in /dev/tty[0-9]*; do + setfont ${CONSOLEMAP:+-m "${CONSOLEMAP}"} \ + "$CONSOLEFONT" -C ${i} &>/dev/null + done + if (( $? )); then stat_fail elif [[ $CONSOLEMAP ]]; then cat <<"EOF" >>/etc/profile.d/locale.sh @@ -394,5 +523,15 @@ for f in /etc/rc.d/functions.d/*; do [[ -e $f ]] && . "$f" done +# Exit current shell if user is not root +need_root() { + (( EUID )) && printf 'You need to be root.\n' && exit 1 +} + +# Quit script if it's not running by root +# This can be disabled in scripts sourcing functions by setting NEED_ROOT=0 +# A local call to need_root can be done to ensure part of script need root privilege +(( ${NEED_ROOT:-0} == 1 )) && need_root + # End of file # vim: set ts=2 sw=2 noet: |