mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-28 22:57:37 +00:00
537 lines
14 KiB
Bash
537 lines
14 KiB
Bash
#!/bin/bash
|
|
# initscripts functions
|
|
#
|
|
|
|
# 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"
|
|
|
|
if [[ $1 == "start" ]]; then
|
|
if [[ $STARTING ]]; then
|
|
echo "A daemon is starting another daemon, this is unlikely to work as intended.\n"
|
|
else
|
|
export STARTING=1
|
|
fi
|
|
fi
|
|
|
|
# width:
|
|
calc_columns () {
|
|
STAT_COL=80
|
|
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 ))
|
|
|
|
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=$(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 = [yY][eE][sS] && $LOCALE ]]; then
|
|
export LANG="${LOCALE}"
|
|
else
|
|
export LANG=C
|
|
fi
|
|
|
|
# set colors
|
|
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 4) # 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
|
|
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
|
|
|
|
# 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
|
|
"$@" &>/dev/null
|
|
local ret=$?
|
|
(( ret == 0 )) && stat_done || stat_fail
|
|
return $ret
|
|
}
|
|
|
|
# usage : in_array( $needle, $haystack )
|
|
# return : 0 - found
|
|
# 1 - not found
|
|
in_array() {
|
|
local needle=$1; shift
|
|
local item
|
|
for item; do
|
|
[[ $item = "${needle}" ]] && return 0
|
|
done
|
|
return 1 # Not Found
|
|
}
|
|
|
|
# daemons:
|
|
|
|
add_daemon() {
|
|
[[ -d /run/daemons ]] || mkdir -p /run/daemons
|
|
>| /run/daemons/"$1"
|
|
}
|
|
|
|
rm_daemon() {
|
|
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 daemon
|
|
for daemon in "${DAEMONS[@]}"; do
|
|
[[ $1 = "${daemon#@}" ]] && return 1
|
|
done
|
|
return 0
|
|
}
|
|
|
|
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() {
|
|
local daemon
|
|
for daemon; 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() {
|
|
! 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
|
|
declare -a omit_pids
|
|
|
|
add_omit_pids() {
|
|
omit_pids+=( $@ )
|
|
}
|
|
|
|
# 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##*/}
|
|
ck_autostart "$daemon" && stop_daemon "$daemon"
|
|
done
|
|
|
|
# Shutdown daemons in reverse order
|
|
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"
|
|
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"
|
|
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_udevsettled"
|
|
|
|
# in case loading a module changed the display mode
|
|
calc_columns
|
|
}
|
|
|
|
activate_vgs() {
|
|
[[ $USELVM = [yY][eE][sS] && -x $(type -P lvm) && -d /sys/block ]] || return 0
|
|
# Kernel 2.6.x, LVM2 groups
|
|
stat_busy "Activating LVM2 groups"
|
|
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
|
|
# /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 != '#'* ]] || 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
|
|
}
|
|
|
|
# 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/\^\[(\[151|%)G//g' /var/log/boot
|
|
}
|
|
|
|
###############################
|
|
# 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
|
|
# 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 != 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=""
|
|
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
|
|
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
|
|
|
|
# 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:
|