diff --git a/libexec/rc/debug.sh b/libexec/rc/debug.sh index db9ed8c94b6c..b379297a4183 100755 --- a/libexec/rc/debug.sh +++ b/libexec/rc/debug.sh @@ -1,440 +1,458 @@ : # SPDX-License-Identifier: BSD-2-Clause # NAME: # debug.sh - selectively debug scripts # # SYNOPSIS: # $_DEBUG_SH . debug.sh # DebugOn [-eo] "tag" ... # DebugOff [-eo] [rc="rc"] "tag" ... # Debugging # DebugAdd "tag" # DebugEcho ... # DebugLog ... # DebugShell "tag" ... # DebugTrace ... # Debug "tag" ... # # $DEBUG_SKIP echo skipped when Debug "tag" is true. # $DEBUG_DO echo only done when Debug "tag" is true. # # DESCRIPTION: # debug.sh provides the following functions to facilitate # flexible run-time tracing of complicated shell scripts. # # DebugOn turns tracing on if any "tag" is found in "DEBUG_SH". # It turns tracing off if "!tag" is found in "DEBUG_SH". # It also sets "DEBUG_ON" to the "tag" that caused tracing to be # enabled, or "DEBUG_OFF" if we matched "!tag". # If '-e' option given returns 1 if no "tag" matched. # If the '-o' flag is given, tracing is turned off unless there # was a matched "tag", useful for functions too noisy to tace. # # Further; when we set "DEBUG_ON" if we find # "$DEBUG_ON:debug_add:tag" in "DEBUG_SH" we will # add the new "tag" to "DEBUG_SH" so it only has effect after that # point. # # DebugOff turns tracing on if any "tag" matches "DEBUG_OFF" or # off if any "tag" matches "DEBUG_ON". This allows nested # functions to not interfere with each other. # # DebugOff accepts but ignores the '-e' and '-o' options. # The optional "rc" value will be returned rather than the # default of 0. Thus if DebugOff is the last operation in a # function, "rc" will be the return code of that function. # # DebugAdd allows adding a "tag" to "DEBUG_SH" to influence # later events, possibly in a child process. # # DebugEcho is just shorthand for: #.nf # $DEBUG_DO echo "$@" #.fi # # Debugging returns true if tracing is enabled. # It is useful for bounding complex debug actions, rather than # using lots of "DEBUG_DO" lines. # # DebugShell runs an interactive shell if any "tag" is found in # "DEBUG_INTERACTIVE", and there is a tty available. # The shell used is defined by "DEBUG_SHELL" or "SHELL" and # defaults to '/bin/sh'. # # Debug calls DebugOn and if that does not turn tracing on, it # calls DebugOff to turn it off. # # The variables "DEBUG_SKIP" and "DEBUG_DO" are set so as to # enable/disable code that should be skipped/run when debugging # is turned on. "DEBUGGING" is the same as "DEBUG_SKIP" for # backwards compatability. # # The use of $_DEBUG_SH is to prevent multiple inclusion, though # it does no harm in this case. # # BUGS: # Does not work with some versions of ksh. # If a function turns tracing on, ksh turns it off when the # function returns - useless. # PD ksh works ok ;-) # # AUTHOR: # Simon J. Gerraty # RCSid: -# $Id: debug.sh,v 1.42 2024/10/30 18:23:19 sjg Exp $ +# $Id: debug.sh,v 1.46 2024/12/13 03:55:52 sjg Exp $ # # @(#) Copyright (c) 1994-2024 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redistribute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # # Please send copies of changes and bug-fixes to: # sjg@crufty.net # _DEBUG_SH=: Myname=${Myname:-`basename $0 .sh`} DEBUGGING= DEBUG_DO=: DEBUG_SKIP= export DEBUGGING DEBUG_DO DEBUG_SKIP -case "$isPOSIX_SHELL,$local" in -:,:|:,local|false,:) ;; # sane -*) # this is the bulk of isposix-shell.sh +# have is handy +if test -z "$_HAVE_SH"; then + _HAVE_SH=: + + ## + # have that does not rely on return code of type + # + have() { + case `(type "$1") 2>&1` in + *" found") return 1;; + esac + return 0 + } +fi + +# does local *actually* work? +local_works() { + local _fu +} + +if local_works > /dev/null 2>&1; then + _local=local +else + _local=: +fi +# for backwards compatability +local=$_local + +if test -z "$isPOSIX_SHELL"; then if (echo ${PATH%:*}) > /dev/null 2>&1; then # true should be a builtin, : certainly is isPOSIX_SHELL=: - # you need to eval $local var - local=local - : KSH_VERSION=$KSH_VERSION - case "$KSH_VERSION" in - Version*) local=: ;; # broken - esac else isPOSIX_SHELL=false - local=: false() { return 1 } fi - ;; -esac +fi is_posix_shell() { $isPOSIX_SHELL return } ## # _debugAdd match # # Called from _debugOn when $match also appears in $DEBUG_SH with # a suffix of :debug_add:tag we will add tag to DEBUG_SH # _debugAdd() { - eval $local tag + eval $_local tag for tag in `IFS=,; echo $DEBUG_SH` do : tag=$tag case "$tag" in $1:debug_add:*) if is_posix_shell; then tag=${tag#$1:debug_add:} else tag=`expr $tag : '.*:debug_add:\(.*\)'` fi case ",$DEBUG_SH," in *,$tag,*) ;; *) set -x : _debugAdd $1 DEBUG_SH=$DEBUG_SH,$tag set +x ;; esac ;; esac done export DEBUG_SH } ## # _debugOn match first # # Actually turn on tracing, set $DEBUG_ON=$match # # Check if $DEBUG_SH contains $match:debug_add:* and call _debugAdd # to add the suffix to DEBUG_SH. This useful when we only want # to trace some script when run under specific circumstances. # # If we have included hooks.sh $_HOOKS_SH will be set # and if $first (the first arg to DebugOn) is suitable as a variable # name we will run ${first}_debugOn_hooks. # # We disable tracing for hooks_run itself but functions can trace # if they want based on DEBUG_DO # _debugOn() { DEBUG_OFF= DEBUG_DO= DEBUG_SKIP=: DEBUG_X=-x # do this firt to reduce noise case ",$DEBUG_SH," in *,$1:debug_add:*) _debugAdd $1;; *,$2:debug_add:*) _debugAdd $2;; esac set -x DEBUG_ON=$1 case "$_HOOKS_SH,$2" in ,*|:,|:,*[${CASE_CLASS_NEG:-!}A-Za-z0-9_]*) ;; *) # avoid noise from hooks_run set +x hooks_run ${2}_debugOn_hooks set -x ;; esac } ## # _debugOff match $DEBUG_ON $first # # Actually turn off tracing, set $DEBUG_OFF=$match # # If we have included hooks.sh $_HOOKS_SH will be set # and if $first (the first arg to DebugOff) is suitable as a variable # name we will run ${first}_debugOff_hooks. # # We do hooks_run after turning off tracing, but before resetting # DEBUG_DO so functions can trace if they want # _debugOff() { DEBUG_OFF=$1 set +x case "$_HOOKS_SH,$3" in ,*|:,|:,*[${CASE_CLASS_NEG:-!}A-Za-z0-9_]*) ;; *) hooks_run ${3}_debugOff_hooks;; esac set +x # just to be sure DEBUG_ON=$2 DEBUG_DO=: DEBUG_SKIP= DEBUG_X= } ## # DebugAdd tag # # Add tag to DEBUG_SH # DebugAdd() { DEBUG_SH=${DEBUG_SH:+$DEBUG_SH,}$1 export DEBUG_SH } ## # DebugEcho message # # Output message if we are debugging # DebugEcho() { $DEBUG_DO echo "$@" } ## # Debugging # # return 0 if we are debugging. # Debugging() { test "$DEBUG_SKIP" } ## # DebugLog message # # Outout message with timestamp if we are debugging # DebugLog() { $DEBUG_SKIP return 0 echo `date '+@ %s [%Y-%m-%d %H:%M:%S %Z]'` "$@" } ## # DebugTrace message # # Something hard to miss when wading through huge -x output # DebugTrace() { $DEBUG_SKIP return 0 set +x echo "@ ==================== [ $DEBUG_ON ] ====================" DebugLog "$@" echo "@ ==================== [ $DEBUG_ON ] ====================" set -x } ## # DebugOn [-e] [-o] match ... # # Turn on debugging if any $match is found in $DEBUG_SH. # DebugOn() { eval ${local:-:} _e _match _off _rc _rc=0 # avoid problems with set -e _off=: while : do case "$1" in -e) _rc=1; shift;; # caller ok with return 1 -o) _off=; shift;; # off unless we have a match *) break;; esac done case ",${DEBUG_SH:-$DEBUG}," in ,,) return $_rc;; *,[Dd]ebug,*) ;; *) $DEBUG_DO set +x;; # reduce the noise esac _match= # if debugging is off because of a !e # don't add 'all' to the On list. case "$_off$DEBUG_OFF" in :) _e=all;; *) _e=;; esac for _e in ${*:-$Myname} $_e do : $_e in ,${DEBUG_SH:-$DEBUG}, case ",${DEBUG_SH:-$DEBUG}," in *,!$_e,*|*,!$Myname:$_e,*) # only turn it off if it was on _rc=0 $DEBUG_DO _debugOff $_e $DEBUG_ON $1 break ;; *,$_e,*|*,$Myname:$_e,*) # only turn it on if it was off _rc=0 _match=$_e $DEBUG_SKIP _debugOn $_e $1 break ;; esac done if test -z "$_off$_match"; then # off unless explicit match, but # only turn it off if it was on $DEBUG_DO _debugOff $_e $DEBUG_ON $1 fi DEBUGGING=$DEBUG_SKIP # backwards compatability $DEBUG_DO set -x # back on if needed $DEBUG_DO set -x # make sure we see it in trace return $_rc } ## # DebugOff [-e] [-o] [rc=$?] match ... # # Only turn debugging off if one of our args was the reason it # was turned on. # # We normally return 0, but caller can pass rc=$? as first arg # so that we preserve the status of last statement. # # The options '-e' and '-o' are ignored, they just make it easier to # keep DebugOn and DebugOff lines in sync. # DebugOff() { eval ${local:-:} _e _rc case ",${DEBUG_SH:-$DEBUG}," in *,[Dd]ebug,*) ;; *) $DEBUG_DO set +x;; # reduce the noise esac _rc=0 # always happy while : do case "$1" in -[eo]) shift;; # ignore it rc=*) eval "_$1"; shift;; *) break;; esac done for _e in $* do : $_e==$DEBUG_OFF DEBUG_OFF case "$DEBUG_OFF" in "") break;; $_e) _debugOn $DEBUG_ON $1; return $_rc;; esac done for _e in $* do : $_e==$DEBUG_ON DEBUG_ON case "$DEBUG_ON" in "") break;; $_e) _debugOff "" "" $1; return $_rc;; esac done DEBUGGING=$DEBUG_SKIP # backwards compatability $DEBUG_DO set -x # back on if needed $DEBUG_DO set -x # make sure we see it in trace return $_rc } _TTY=${_TTY:-`test -t 0 && tty`}; export _TTY # override this if you like _debugShell() { test "x$_TTY" != x || return 0 { echo DebugShell "$@" echo "Type 'exit' to continue..." } > $_TTY ${DEBUG_SHELL:-${SHELL:-/bin/sh}} < $_TTY > $_TTY 2>&1 } # Run an interactive shell if appropriate # Note: you can use $DEBUG_SKIP DebugShell ... to skip unless debugOn DebugShell() { eval ${local:-:} _e case "$_TTY%${DEBUG_INTERACTIVE}" in *%|%*) return 0;; # no tty or no spec esac for _e in ${*:-$Myname} all do case ",${DEBUG_INTERACTIVE}," in *,!$_e,*|*,!$Myname:$_e,*) return 0 ;; *,$_e,*|*,$Myname:$_e,*) # Provide clues as to why/where _debugShell "$_e: $@" return $? ;; esac done return 0 } # For backwards compatability Debug() { case "${DEBUG_SH:-$DEBUG}" in "") ;; *) DEBUG_ON=${DEBUG_ON:-_Debug} DebugOn -e $* || DebugOff $DEBUG_LAST DEBUGGING=$DEBUG_SKIP ;; esac } diff --git a/libexec/rc/hooks.sh b/libexec/rc/hooks.sh index 3b0c50f10191..7c478fbeda15 100755 --- a/libexec/rc/hooks.sh +++ b/libexec/rc/hooks.sh @@ -1,276 +1,277 @@ : # SPDX-License-Identifier: BSD-2-Clause # NAME: # hooks.sh - provide hooks for customization # # SYNOPSIS: # hooks_add_all HOOKS [--first] func [...] # hooks_add_once HOOKS [--first] func [...] # hooks_add_default_set {all,once} # hooks_add HOOKS func [...] # hooks_get [--lifo] HOOKS # hooks_run [--lifo] HOOKS ["args"] # hooks_run_all [--lifo] HOOKS ["args"] # hooks_has HOOKS func # # add_hooks HOOKS [--first] func [...] # run_hooks HOOKS [LIFO] ["args"] # run_hooks_all HOOKS [LIFO] ["args"] # # DESCRIPTION: # The functions add_hooks and run_hooks are retained for # backwards compatability. They are aliases for hooks_add and # hooks_run. # # hooks_add_all simply adds the "func"s to the list "HOOKS". # # If the first arg is '--first' "func"s are added to the start # of the list. # # hooks_add_once does the same but only if "func" is not in "HOOKS". # hooks_add uses one of the above based on "option", '--all' (default) # or '--once'. # # hooks_add_default_set sets the default behavior of hooks_add # # hooks_get simply returns the named list of functions. # # hooks_has indicates whether "func" in in "HOOKS". # # hooks_run runs each "func" in $HOOKS and stops if any of them # return a bad status. # # hooks_run_all does the same but does not stop on error. # # If run_hooks or run_hooks_all is given a flag of '--lifo' or # 2nd argument of LIFO the hooks are run in the reverse order of # calls to hooks_add. # Any "args" specified are passed to each hook function. # # RCSid: -# $Id: hooks.sh,v 1.21 2024/09/06 16:53:45 sjg Exp $ +# $Id: hooks.sh,v 1.24 2024/12/13 03:55:52 sjg Exp $ # # @(#)Copyright (c) 2000-2024 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redistribute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # avoid multiple inclusion _HOOKS_SH=: -# We want to use local if we can -# if isposix-shell.sh has been sourced isPOSIX_SHELL will be set -# as will local -case "$local" in -local|:) ;; -*) if (echo ${PATH%:*}) > /dev/null 2>&1; then - local=local - else - local=: - fi - ;; -esac +# does local *actually* work? +local_works() { + local _fu +} + +if local_works > /dev/null 2>&1; then + _local=local +else + _local=: +fi +# for backwards compatability +local=$_local + ## # hooks_add_all list func ... # # add "func"s to "list" regardless # hooks_add_all() { - eval $local __h + eval $_local __h __h=$1; shift case "$1" in --first) shift eval "$__h=\"$* \$$__h\"" ;; *) eval "$__h=\"\$$__h $*\"";; esac } ## # hooks_add_once list func ... # # add "func"s to "list" if not already there # hooks_add_once() { - eval $local __h __hh __first + eval $_local __h __hh __first __h=$1; shift case "$1" in --first) shift; __first=:;; *) __first=;; esac eval "__hh=\$$__h" while [ $# -gt 0 ] do : __hh="$__hh" 1="$1" case "$__first $__hh " in *" $1 "*) ;; # dupe :*) __hh="$1 $__hh";; *) __hh="$__hh $1";; esac shift done eval "$__h=\"$__hh\"" } ## # hooks_add_default_set [--]{all,once} # # change the default method of hooks_add # hooks_add_default_set() { case "$1" in once|--once) HOOKS_ADD_DEFAULT=once;; *) HOOKS_ADD_DEFAULT=all;; esac } ## # hooks_add [--{all,once}] list func ... # # add "func"s to "list" # # If '--once' use hooks_add_once, # default is hooks_add_all. # hooks_add() { case "$1" in --all) shift; hooks_add_all "$@";; --once) shift; hooks_add_once "$@";; *) hooks_add_${HOOKS_ADD_DEFAULT:-all} "$@";; esac } ## # hooks_get [--lifo] list [LIFO] # # return $list # hooks_get() { - eval $local __h __h2 e __l + eval $_local __h __h2 e __l case "$1" in --lifo) __l=LIFO; shift;; esac eval "__h=\$$1" case "$__l$2" in LIFO*) __h2="$__h" __h= for e in $__h2 do __h="$e $__h" done ;; esac echo "$__h" } ## # hooks_has list func # # is func in $list ? # hooks_has() { - eval $local __h + eval $_local __h eval "__h=\$$1" case " $__h " in *" $1 "*) return 0;; esac return 1 } ## # hooks_run [--all] [--lifo] list [LIFO] [args] # # pass "args" to each function in "list" # Without '--all'; if any return non-zero return that immediately # hooks_run() { - eval $local __a e __h __hl __h2 __l + eval $_local __a e __h __hl __h2 __l __a=return __l= while : do case "$1" in --all) __a=:; shift;; --lifo) __l=$1; shift;; *) break;; esac done __hl=$1; shift case "$1" in LIFO) __l=--lifo; shift;; esac __h=`hooks_get $__l $__hl` for e in $__h do $e "$@" || $__a $? done } ## # hooks_run_all [--lifo] list [LIFO] [args] # # pass "args" to each function in "list" # hooks_run_all() { hooks_run --all "$@" } ## # add_hooks,run_hooks[_all] aliases # add_hooks() { hooks_add "$@" } run_hooks() { hooks_run "$@" } run_hooks_all() { hooks_run --all "$@" } case /$0 in */hooks.sh) # simple unit-test list=HOOKS flags= while : do : 1=$1 case "$1" in HOOKS|*hooks) list=$1; shift;; --*) flags="$flags $1"; shift;; *) break;; esac done for f in "$@" do : f=$f case "$f" in LIFO) ;; false|true) ;; *) eval "$f() { echo This is $f; }";; esac done echo hooks_add $flags $list "$@" hooks_add $flags $list "$@" echo hooks_run $list hooks_run $list echo hooks_run --all --lifo $list hooks_run --all --lifo $list echo hooks_run $list LIFO hooks_run $list LIFO ;; esac