From nobody Tue Sep 10 19:05:04 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4X3CnY13jtz5WSpv; Tue, 10 Sep 2024 19:05:05 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4X3CnY0Vwfz4Sbt; Tue, 10 Sep 2024 19:05:05 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1725995105; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=D0oRfP9qgtSJclXiZ/XKhuqA4et/WywdKEZJ9uEONRg=; b=MwZgbKfknoLbKR2FmUT1+SqsUTxUpfQLOlz80Ck5Kc04mTgqEsLSX4sLjz80OBMuKkNg5W Tzg+QRNh44Mg2h2MB6EBmmvES8OXN8tJkHwxsSy4tILkEz98X5kJ3RmuZ/RiwpAOce9NwM SEcMpHyjshqYFpmubtRnoRupAwzTM5ZmY3cmL3kI5YOVmyvAHuR5GLCtpL2giN40RtqWa2 +9oaSWspmaMuTe4ATbV+dWTSSxIa+syNbY/UaNFuEErAYoxeZe0KzYaa2OViLpbHx8jHD+ NwfSPT7yYtwGv0hDp2iDJaWxGcj3ydNsulReT3DIxOi7A7YNObBb63hf2a1Nzg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1725995105; a=rsa-sha256; cv=none; b=Z+1caLx4dTJx5VXLk1Yo71z+Br+vKYAwdhcxNTD9dCLdzxyuoY6eqib22wZnGGLRpd7Te+ BhDx55K6EQ3pFuhgnpOqRC95VphckdoK/BAP7/r95QqIawbq0sZ3FqnzM4LnCgF1QbdT7n jwYI45eWGKPaXWFiYS1X2QgqX1ixbQcIcQnHwpe1uyrnx59aXfnFxvZFN+fi+i9ulQI2Uu EsPFqHIH68ehFIUNzmGyvsiOJolXnr8uqcrPep+f8P9AJeEuHNAHsVYYyqAL4fSX54p3Zv QkhDGj7d92cW549QtDQqTp5MtE8vr6wPVUMPojh8FjDaJDLiI0fLlEa0A/qIbw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1725995105; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=D0oRfP9qgtSJclXiZ/XKhuqA4et/WywdKEZJ9uEONRg=; b=YL2O2gaTHr3IJThc9/fNoE9Fasiy1KnN95tv5BgBaMizPqvd3Aa1X8cJXFomd0WrSN6naA n8xkMt1JRNP+Z6AyUvK7vWZdVoEtlqDSNsvPIVqBkI/RryGYDO0oKEstt96G0MjSXRQAnh iSx3NqoE1m3dbmY6JRFgN4rVMKm3FeNfndMSGGM3p1Wn2ER2ZSxH6KNPOWvBfIkifOZbk5 vOhmVLc/l2ZB5pFXxLbCg4S3QC95n+JGr4/0LGMhRYSvTptD2RlQTz7/yzA5uPYxjktBnK bUSx3U1Ic1MMufoOThpz4UlC8ELY52MId946pznxeGUKIIS3eM1+jJd/5Lqffg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4X3CnX6s4tzyfy; Tue, 10 Sep 2024 19:05:04 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 48AJ54Gc008328; Tue, 10 Sep 2024 19:05:04 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 48AJ54vI008325; Tue, 10 Sep 2024 19:05:04 GMT (envelope-from git) Date: Tue, 10 Sep 2024 19:05:04 GMT Message-Id: <202409101905.48AJ54vI008325@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Simon J. Gerraty" Subject: git: 7e1c014a9e3a - main - debug.sh take advantage of hooks.sh List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: sjg X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 7e1c014a9e3a632099efd1fa34a583b627b71bb3 Auto-Submitted: auto-generated The branch main has been updated by sjg: URL: https://cgit.FreeBSD.org/src/commit/?id=7e1c014a9e3a632099efd1fa34a583b627b71bb3 commit 7e1c014a9e3a632099efd1fa34a583b627b71bb3 Author: Simon J. Gerraty AuthorDate: 2024-09-10 19:04:15 +0000 Commit: Simon J. Gerraty CommitDate: 2024-09-10 19:04:15 +0000 debug.sh take advantage of hooks.sh Allow Debug{On,Off} to run associated hooks. This makes it feasible to collect extra debug info at runtime without needing to modify any potentially verified and hence immutable scripts. Like debug.sh, hooks.sh is extremely handy and used extensively in many parts of Junos and its build environment. It is provided here in the hope that others may benefit. We do not dot hooks.sh by default to reduce overhead, but it can but done from rc.conf et al using $_HOOKS_SH . /libexec/hooks.sh to avoid including more than once. Reviewed by: stevek Sponsored by: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D46552 --- libexec/rc/Makefile | 2 +- libexec/rc/debug.sh | 97 ++++++++++++++++-- libexec/rc/hooks.sh | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+), 9 deletions(-) diff --git a/libexec/rc/Makefile b/libexec/rc/Makefile index 9a5aa11424ae..e82b582462d0 100644 --- a/libexec/rc/Makefile +++ b/libexec/rc/Makefile @@ -18,7 +18,7 @@ CONFETCDEFAULTS= rc.conf CONFETCDEFAULTSPACKAGE= rc FILESGROUPS= LIBEXEC_SCRIPTS -LIBEXEC_SCRIPTS= debug.sh safe_eval.sh +LIBEXEC_SCRIPTS= debug.sh hooks.sh safe_eval.sh LIBEXEC_SCRIPTSDIR= /libexec LIBEXEC_SCRIPTSMODE= 755 LIBEXEC_SCRIPTSPACKAGE= rc diff --git a/libexec/rc/debug.sh b/libexec/rc/debug.sh index 7bbb500e2d22..eea8a011bc09 100755 --- a/libexec/rc/debug.sh +++ b/libexec/rc/debug.sh @@ -74,7 +74,7 @@ # Simon J. Gerraty # RCSid: -# $Id: debug.sh,v 1.35 2024/02/03 19:04:47 sjg Exp $ +# $Id: debug.sh,v 1.40 2024/09/09 20:06:00 sjg Exp $ # # @(#) Copyright (c) 1994-2024 Simon J. Gerraty # @@ -93,11 +93,37 @@ _DEBUG_SH=: Myname=${Myname:-`basename $0 .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 + DEBUGGING= DEBUG_DO=: DEBUG_SKIP= export DEBUGGING DEBUG_DO DEBUG_SKIP +## +# _debugOn match first +# +# Actually turn on tracing, set $DEBUG_ON=$match +# +# 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= @@ -105,11 +131,36 @@ _debugOn() { DEBUG_X=-x 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= @@ -120,16 +171,30 @@ 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]'` "$@" } -# something hard to miss when wading through huge -x output +## +# DebugTrace message +# +# Something hard to miss when wading through huge -x output +# DebugTrace() { $DEBUG_SKIP return 0 set +x @@ -139,8 +204,13 @@ DebugTrace() { set -x } -# Turn on debugging if appropriate +## +# 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 : @@ -170,14 +240,14 @@ DebugOn() { *,!$_e,*|*,!$Myname:$_e,*) # only turn it off if it was on _rc=0 - $DEBUG_DO _debugOff $_e $DEBUG_ON + $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 + $DEBUG_SKIP _debugOn $_e $1 break ;; esac @@ -185,7 +255,7 @@ DebugOn() { 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 + $DEBUG_DO _debugOff $_e $DEBUG_ON $1 fi DEBUGGING=$DEBUG_SKIP # backwards compatability $DEBUG_DO set -x # back on if needed @@ -193,11 +263,20 @@ DebugOn() { 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 @@ -216,7 +295,7 @@ DebugOff() { : $_e==$DEBUG_OFF DEBUG_OFF case "$DEBUG_OFF" in "") break;; - $_e) _debugOn $DEBUG_ON; return $_rc;; + $_e) _debugOn $DEBUG_ON $1; return $_rc;; esac done for _e in $* @@ -224,7 +303,7 @@ DebugOff() { : $_e==$DEBUG_ON DEBUG_ON case "$DEBUG_ON" in "") break;; - $_e) _debugOff; return $_rc;; + $_e) _debugOff "" "" $1; return $_rc;; esac done DEBUGGING=$DEBUG_SKIP # backwards compatability @@ -237,6 +316,7 @@ _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..." @@ -247,6 +327,7 @@ _debugShell() { # 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 diff --git a/libexec/rc/hooks.sh b/libexec/rc/hooks.sh new file mode 100755 index 000000000000..3b0c50f10191 --- /dev/null +++ b/libexec/rc/hooks.sh @@ -0,0 +1,276 @@ +: +# 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 $ +# +# @(#)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 + +## +# hooks_add_all list func ... +# +# add "func"s to "list" regardless +# +hooks_add_all() { + 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 + __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 + 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 "__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 + __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