From cfabb85924f35c636550609b332d088aaae9941f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20B=C3=A4chler?= Date: Tue, 25 Aug 2009 12:57:02 +0200 Subject: Implement a hook-system that allows to add custom code to the initscripts at certain places A function add_hook can be called from functions.d to register a hook function. The existing hooks are based on suggestions from Michael Towers (larch) and on the implementation of initscripts-extras-fbsplash which currently uses the strings passed to stat_busy and stat_done for this. More hooks can be added if requested. The implementation uses associative arrays and will thus only work with bash 4 or later --- functions | 46 +++++++++++++++++++++++++++++++++++++++++++++- rc.multi | 4 ++++ rc.shutdown | 8 ++++++++ rc.single | 12 ++++++++++++ rc.sysinit | 9 +++++++++ 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/functions b/functions index 8745a38..56b78be 100644 --- a/functions +++ b/functions @@ -229,8 +229,52 @@ ck_status() { fi } +############################### +# 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's allowed to register several hook functions for the same hook +# +# The function takes the filename of the script that launched it as an argument +# +# Currently, the following hooks exist: +# start: at the beginning of rc.{multi,shutdown,single,sysinit} +# end: at the end of rc.{multi,single,sysinit} +# udevlaunched: after udev has been launched in rc.sysinit and rc.single +# udevsettled: after uevents have settled in rc.sysinit and rc.single +# premount: before local filesystems are mounted, but after root is mounted read-write in rc.sysinit +# prekillall: before all processes are being killed in rc.shutdown and rc.single +# postkillall: after all processes have been killed in rc.shutdown and rc.single +# poweroff: directly before powering off in rc.shutdown +# +# Make sure to never override the add_hook and run_hook functions via functions.d + +declare -A hook_funcs +for hook in start end udevlaunched udevsettled premount prekillall postkillall poweroff; do + hook_funcs["${hook}"]="" +done + +add_hook() { + [ -z "$1" -o -z "$2" ] && return 1 + hook_funcs["$1"]="${hook_funcs["$1"]} $2" +} + +run_hook() { + local func + + [ -z "$1" ] && return 1 + for func in ${hook_funcs["$1"]}; do + ${func} "$2" + done +} -#Source additional functions at the end to allow overrides +# Source additional functions at the end to allow overrides for f in /etc/rc.d/functions.d/*; do if [ -e $f ]; then . $f diff --git a/rc.multi b/rc.multi index 731e48e..0cddd1d 100755 --- a/rc.multi +++ b/rc.multi @@ -6,6 +6,8 @@ . /etc/rc.conf . /etc/rc.d/functions +run_hook start rc.multi + # Load sysctl variables if sysctl.conf is present [ -r /etc/sysctl.conf ] && /sbin/sysctl -q -p &>/dev/null @@ -24,4 +26,6 @@ if [ -x /etc/rc.local ]; then /etc/rc.local fi +run_hook end rc.multi + # vim: set ts=2 noet: diff --git a/rc.shutdown b/rc.shutdown index e2a4a84..5921e1c 100755 --- a/rc.shutdown +++ b/rc.shutdown @@ -6,6 +6,8 @@ . /etc/rc.conf . /etc/rc.d/functions +run_hook start rc.shutdown + # avoid staircase effect /bin/stty onlcr @@ -41,6 +43,8 @@ if [ "$PREVLEVEL" = "3" -o "$PREVLEVEL" = "5" ]; then done fi +run_hook prekillall rc.shutdown + # Terminate all processes stat_busy "Sending SIGTERM To Processes" /sbin/killall5 -15 &> /dev/null @@ -52,6 +56,8 @@ stat_busy "Sending SIGKILL To Processes" /bin/sleep 1 stat_done +run_hook postkillall rc.shutdown + stat_busy "Saving Random Seed" RANDOM_SEED=/var/lib/misc/random-seed [ -d $(dirname $RANDOM_SEED) ] || mkdir -p $(dirname $RANDOM_SEED) @@ -132,6 +138,8 @@ stat_busy "Remounting Root Filesystem Read-only" /bin/mount -n -o remount,ro / stat_done +run_hook poweroff rc.shutdown + # Power off or reboot if [ "$RUNLEVEL" = "0" ]; then printsep diff --git a/rc.single b/rc.single index 50b7cfb..d72e95b 100755 --- a/rc.single +++ b/rc.single @@ -6,6 +6,8 @@ . /etc/rc.conf . /etc/rc.d/functions +run_hook start rc.single + if [ "$PREVLEVEL" = "3" -o "$PREVLEVEL" = "5" ]; then # Find daemons NOT in the DAEMONS array. Shut these down first if [ -d /var/run/daemons ]; then @@ -26,6 +28,8 @@ if [ "$PREVLEVEL" = "3" -o "$PREVLEVEL" = "5" ]; then fi if [ "$PREVLEVEL" != "N" ]; then + run_hook prekillall rc.single + # Terminate all processes stat_busy "Sending SIGTERM To Processes" /sbin/killall5 -15 &> /dev/null @@ -37,10 +41,14 @@ if [ "$PREVLEVEL" != "N" ]; then /bin/sleep 1 stat_done + run_hook postkillall rc.single + stat_busy "Starting UDev Daemon" /sbin/udevd --daemon stat_done + run_hook udevlaunched rc.single + # Trigger udev uevents if /bin/pidof -o %PPID /sbin/udevd >/dev/null; then stat_busy "Triggering UDev uevents" @@ -55,6 +63,8 @@ if [ "$PREVLEVEL" != "N" ]; then stat_done fi + run_hook udevsettled rc.single + # try syslog-NG first, then fall back to good ol' syslogd if [ -x /etc/rc.d/syslog-ng ]; then /etc/rc.d/syslog-ng start @@ -64,6 +74,8 @@ if [ "$PREVLEVEL" != "N" ]; then fi fi +run_hook end rc.single + if [ "$RUNLEVEL" = "1" ]; then printsep printhl "Entering single-user mode..." diff --git a/rc.sysinit b/rc.sysinit index f6463cc..60dcbef 100755 --- a/rc.sysinit +++ b/rc.sysinit @@ -14,6 +14,8 @@ printhl "Copyright 2007-2009 Aaron Griffin" printhl "Distributed under the GNU General Public License (GPL)" printsep +run_hook start rc.sysinit + # mount /proc, /sys and our RAM /dev /bin/mount -n -t tmpfs udev /dev -o mode=0755,size=10M,nosuid /bin/mount -n -t proc none /proc @@ -63,6 +65,8 @@ stat_busy "Starting UDev Daemon" /sbin/udevd --daemon stat_done +run_hook udevlaunched rc.sysinit + # Trigger udev uevents if /bin/pidof -o %PPID /sbin/udevd >/dev/null; then stat_busy "Triggering UDev uevents" @@ -108,6 +112,8 @@ if /bin/pidof -o %PPID /sbin/udevd >/dev/null; then stat_done fi +run_hook udevsettled rc.sysinit + # bring up the loopback interface if [ -d /sys/class/net/lo ]; then stat_busy "Bringing up loopback interface" @@ -282,6 +288,7 @@ stat_busy "Mounting Local Filesystems" if [ -e /proc/mounts ]; then /bin/grep -e "/proc " -e "/sys " -e "/dev " /proc/mounts >> /etc/mtab fi +run_hook premount rc.sysinit # now mount all the local filesystems /bin/mount -a -t $NETFS -O no_netdev stat_done @@ -412,5 +419,7 @@ fi /bin/dmesg >| /var/log/dmesg.log +run_hook end rc.sysinit + # End of file # vim: set ts=2 noet: -- cgit v1.2.3