xref: /freebsd/libexec/rc/hooks.sh (revision 7e1c014a9e3a632099efd1fa34a583b627b71bb3)
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.21 2024/09/06 16:53:45 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# We want to use local if we can
68# if isposix-shell.sh has been sourced isPOSIX_SHELL will be set
69# as will local
70case "$local" in
71local|:) ;;
72*)  if (echo ${PATH%:*}) > /dev/null 2>&1; then
73        local=local
74    else
75        local=:
76    fi
77    ;;
78esac
79
80##
81# hooks_add_all list func ...
82#
83# add "func"s to "list" regardless
84#
85hooks_add_all() {
86    eval $local __h
87    __h=$1; shift
88    case "$1" in
89    --first)
90        shift
91        eval "$__h=\"$* \$$__h\""
92        ;;
93    *)  eval "$__h=\"\$$__h $*\"";;
94    esac
95}
96
97##
98# hooks_add_once list func ...
99#
100# add "func"s to "list" if not already there
101#
102hooks_add_once() {
103    eval $local __h __hh __first
104    __h=$1; shift
105    case "$1" in
106    --first) shift; __first=:;;
107    *) __first=;;
108    esac
109    eval "__hh=\$$__h"
110    while [ $# -gt 0 ]
111    do
112        : __hh="$__hh" 1="$1"
113        case "$__first $__hh " in
114        *" $1 "*) ;;    # dupe
115        :*) __hh="$1 $__hh";;
116        *) __hh="$__hh $1";;
117        esac
118        shift
119    done
120    eval "$__h=\"$__hh\""
121}
122
123##
124# hooks_add_default_set [--]{all,once}
125#
126# change the default method of hooks_add
127#
128hooks_add_default_set() {
129    case "$1" in
130    once|--once) HOOKS_ADD_DEFAULT=once;;
131    *) HOOKS_ADD_DEFAULT=all;;
132    esac
133}
134
135##
136# hooks_add [--{all,once}] list func ...
137#
138# add "func"s to "list"
139#
140# If '--once' use hooks_add_once,
141# default is hooks_add_all.
142#
143hooks_add() {
144    case "$1" in
145    --all) shift; hooks_add_all "$@";;
146    --once) shift; hooks_add_once "$@";;
147    *) hooks_add_${HOOKS_ADD_DEFAULT:-all} "$@";;
148    esac
149}
150
151##
152# hooks_get [--lifo] list [LIFO]
153#
154# return $list
155#
156hooks_get() {
157    eval $local __h __h2 e __l
158    case "$1" in
159    --lifo) __l=LIFO; shift;;
160    esac
161    eval "__h=\$$1"
162    case "$__l$2" in
163    LIFO*)
164        __h2="$__h"
165        __h=
166        for e in $__h2
167        do
168            __h="$e $__h"
169        done
170        ;;
171    esac
172    echo "$__h"
173}
174
175##
176# hooks_has list func
177#
178# is func in $list ?
179#
180hooks_has() {
181    eval $local __h
182    eval "__h=\$$1"
183    case " $__h " in
184    *" $1 "*) return 0;;
185    esac
186    return 1
187}
188
189##
190# hooks_run [--all] [--lifo] list [LIFO] [args]
191#
192# pass "args" to each function in "list"
193# Without '--all'; if any return non-zero return that immediately
194#
195hooks_run() {
196    eval $local __a e __h __hl __h2 __l
197    __a=return
198    __l=
199
200    while :
201    do
202        case "$1" in
203        --all) __a=:; shift;;
204        --lifo) __l=$1; shift;;
205        *) break;;
206        esac
207    done
208    __hl=$1; shift
209    case "$1" in
210    LIFO) __l=--lifo; shift;;
211    esac
212    __h=`hooks_get $__l $__hl`
213    for e in $__h
214    do
215        $e "$@" || $__a $?
216    done
217}
218
219##
220# hooks_run_all [--lifo] list [LIFO] [args]
221#
222# pass "args" to each function in "list"
223#
224hooks_run_all() {
225    hooks_run --all "$@"
226}
227
228##
229# add_hooks,run_hooks[_all] aliases
230#
231add_hooks() {
232    hooks_add "$@"
233}
234
235run_hooks() {
236    hooks_run "$@"
237}
238
239run_hooks_all() {
240    hooks_run --all "$@"
241}
242
243
244case /$0 in
245*/hooks.sh)
246    # simple unit-test
247    list=HOOKS
248    flags=
249    while :
250    do
251        : 1=$1
252        case "$1" in
253        HOOKS|*hooks) list=$1; shift;;
254        --*) flags="$flags $1"; shift;;
255        *) break;;
256        esac
257    done
258    for f in "$@"
259    do
260        : f=$f
261        case "$f" in
262        LIFO) ;;
263        false|true) ;;
264        *) eval "$f() { echo This is $f; }";;
265        esac
266    done
267    echo hooks_add $flags $list "$@"
268    hooks_add $flags $list "$@"
269    echo hooks_run $list
270    hooks_run $list
271    echo hooks_run --all --lifo $list
272    hooks_run --all --lifo $list
273    echo hooks_run $list LIFO
274    hooks_run $list LIFO
275    ;;
276esac
277