summaryrefslogtreecommitdiff
path: root/functions
diff options
context:
space:
mode:
Diffstat (limited to 'functions')
-rw-r--r--functions341
1 files changed, 240 insertions, 101 deletions
diff --git a/functions b/functions
index d9e6f89..2cbf01e 100644
--- a/functions
+++ b/functions
@@ -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: