xref: /freebsd/libexec/rc/hooks.sh (revision 6c05f3a74f30934ee60919cc97e16ec69b542b06)
1:
2# SPDX-License-Identifier: BSD-2-Clause
3
4# NAME:
5#	hooks.sh - provide hooks for customization
6#
7# SYNOPSIS:
8#	hooks_add_all HOOKS [--first] func [...]
9#	hooks_add_once HOOKS [--first] func [...]
10#	hooks_add_default_set {all,once}
11#	hooks_add HOOKS func [...]
12#	hooks_get [--lifo] HOOKS
13#	hooks_run [--lifo] HOOKS ["args"]
14#	hooks_run_all [--lifo] HOOKS ["args"]
15#	hooks_has HOOKS func
16#
17#	add_hooks HOOKS [--first] func [...]
18#	run_hooks HOOKS [LIFO] ["args"]
19#	run_hooks_all HOOKS [LIFO] ["args"]
20#
21# DESCRIPTION:
22#	The functions add_hooks and run_hooks are retained for
23#	backwards compatability.  They are aliases for hooks_add and
24#	hooks_run.
25#
26#	hooks_add_all simply adds the "func"s to the list "HOOKS".
27#
28#	If the first arg is '--first' "func"s are added to the start
29#	of the list.
30#
31#	hooks_add_once does the same but only if "func" is not in "HOOKS".
32#	hooks_add uses one of the above based on "option", '--all' (default)
33#	or '--once'.
34#
35#	hooks_add_default_set sets the default behavior of hooks_add
36#
37#	hooks_get simply returns the named list of functions.
38#
39#	hooks_has indicates whether "func" in in "HOOKS".
40#
41#	hooks_run runs each "func" in $HOOKS and stops if any of them
42#	return a bad status.
43#
44#	hooks_run_all does the same but does not stop on error.
45#
46#	If run_hooks or run_hooks_all is given a flag of '--lifo' or
47#	2nd argument of LIFO the hooks are run in the reverse order of
48#	calls to hooks_add.
49#	Any "args" specified are passed to each hook function.
50#
51
52# RCSid:
53#	$Id: hooks.sh,v 1.24 2024/12/13 03:55:52 sjg Exp $
54#
55#	@(#)Copyright (c) 2000-2024 Simon J. Gerraty
56#
57#	This file is provided in the hope that it will
58#	be of use.  There is absolutely NO WARRANTY.
59#	Permission to copy, redistribute or otherwise
60#	use this file is hereby granted provided that
61#	the above copyright notice and this notice are
62#	left intact.
63
64# avoid multiple inclusion
65_HOOKS_SH=:
66
67# does local *actually* work?
68local_works() {
69    local _fu
70}
71
72if local_works > /dev/null 2>&1; then
73    _local=local
74else
75    _local=:
76fi
77# for backwards compatability
78local=$_local
79
80
81##
82# hooks_add_all list func ...
83#
84# add "func"s to "list" regardless
85#
86hooks_add_all() {
87    eval $_local __h
88    __h=$1; shift
89    case "$1" in
90    --first)
91        shift
92        eval "$__h=\"$* \$$__h\""
93        ;;
94    *)  eval "$__h=\"\$$__h $*\"";;
95    esac
96}
97
98##
99# hooks_add_once list func ...
100#
101# add "func"s to "list" if not already there
102#
103hooks_add_once() {
104    eval $_local __h __hh __first
105    __h=$1; shift
106    case "$1" in
107    --first) shift; __first=:;;
108    *) __first=;;
109    esac
110    eval "__hh=\$$__h"
111    while [ $# -gt 0 ]
112    do
113        : __hh="$__hh" 1="$1"
114        case "$__first $__hh " in
115        *" $1 "*) ;;    # dupe
116        :*) __hh="$1 $__hh";;
117        *) __hh="$__hh $1";;
118        esac
119        shift
120    done
121    eval "$__h=\"$__hh\""
122}
123
124##
125# hooks_add_default_set [--]{all,once}
126#
127# change the default method of hooks_add
128#
129hooks_add_default_set() {
130    case "$1" in
131    once|--once) HOOKS_ADD_DEFAULT=once;;
132    *) HOOKS_ADD_DEFAULT=all;;
133    esac
134}
135
136##
137# hooks_add [--{all,once}] list func ...
138#
139# add "func"s to "list"
140#
141# If '--once' use hooks_add_once,
142# default is hooks_add_all.
143#
144hooks_add() {
145    case "$1" in
146    --all) shift; hooks_add_all "$@";;
147    --once) shift; hooks_add_once "$@";;
148    *) hooks_add_${HOOKS_ADD_DEFAULT:-all} "$@";;
149    esac
150}
151
152##
153# hooks_get [--lifo] list [LIFO]
154#
155# return $list
156#
157hooks_get() {
158    eval $_local __h __h2 e __l
159    case "$1" in
160    --lifo) __l=LIFO; shift;;
161    esac
162    eval "__h=\$$1"
163    case "$__l$2" in
164    LIFO*)
165        __h2="$__h"
166        __h=
167        for e in $__h2
168        do
169            __h="$e $__h"
170        done
171        ;;
172    esac
173    echo "$__h"
174}
175
176##
177# hooks_has list func
178#
179# is func in $list ?
180#
181hooks_has() {
182    eval $_local __h
183    eval "__h=\$$1"
184    case " $__h " in
185    *" $1 "*) return 0;;
186    esac
187    return 1
188}
189
190##
191# hooks_run [--all] [--lifo] list [LIFO] [args]
192#
193# pass "args" to each function in "list"
194# Without '--all'; if any return non-zero return that immediately
195#
196hooks_run() {
197    eval $_local __a e __h __hl __h2 __l
198    __a=return
199    __l=
200
201    while :
202    do
203        case "$1" in
204        --all) __a=:; shift;;
205        --lifo) __l=$1; shift;;
206        *) break;;
207        esac
208    done
209    __hl=$1; shift
210    case "$1" in
211    LIFO) __l=--lifo; shift;;
212    esac
213    __h=`hooks_get $__l $__hl`
214    for e in $__h
215    do
216        $e "$@" || $__a $?
217    done
218}
219
220##
221# hooks_run_all [--lifo] list [LIFO] [args]
222#
223# pass "args" to each function in "list"
224#
225hooks_run_all() {
226    hooks_run --all "$@"
227}
228
229##
230# add_hooks,run_hooks[_all] aliases
231#
232add_hooks() {
233    hooks_add "$@"
234}
235
236run_hooks() {
237    hooks_run "$@"
238}
239
240run_hooks_all() {
241    hooks_run --all "$@"
242}
243
244
245case /$0 in
246*/hooks.sh)
247    # simple unit-test
248    list=HOOKS
249    flags=
250    while :
251    do
252        : 1=$1
253        case "$1" in
254        HOOKS|*hooks) list=$1; shift;;
255        --*) flags="$flags $1"; shift;;
256        *) break;;
257        esac
258    done
259    for f in "$@"
260    do
261        : f=$f
262        case "$f" in
263        LIFO) ;;
264        false|true) ;;
265        *) eval "$f() { echo This is $f; }";;
266        esac
267    done
268    echo hooks_add $flags $list "$@"
269    hooks_add $flags $list "$@"
270    echo hooks_run $list
271    hooks_run $list
272    echo hooks_run --all --lifo $list
273    hooks_run --all --lifo $list
274    echo hooks_run $list LIFO
275    hooks_run $list LIFO
276    ;;
277esac
278