1233541Sjchandra: 2233541Sjchandra# SPDX-License-Identifier: BSD-2-Clause 3233541Sjchandra 4233541Sjchandra# NAME: 5233541Sjchandra# debug.sh - selectively debug scripts 6233541Sjchandra# 7233541Sjchandra# SYNOPSIS: 8233541Sjchandra# $_DEBUG_SH . debug.sh 9233541Sjchandra# DebugOn [-eo] "tag" ... 10233541Sjchandra# DebugOff [-eo] [rc="rc"] "tag" ... 11233541Sjchandra# Debugging 12233541Sjchandra# DebugEcho ... 13233541Sjchandra# DebugLog ... 14233541Sjchandra# DebugShell "tag" ... 15233541Sjchandra# DebugTrace ... 16233541Sjchandra# Debug "tag" ... 17233541Sjchandra# 18233541Sjchandra# $DEBUG_SKIP echo skipped when Debug "tag" is true. 19233541Sjchandra# $DEBUG_DO echo only done when Debug "tag" is true. 20233541Sjchandra# 21233541Sjchandra# DESCRIPTION: 22233541Sjchandra# debug.sh provides the following functions to facilitate 23233541Sjchandra# flexible run-time tracing of complicated shell scripts. 24233541Sjchandra# 25233541Sjchandra# DebugOn turns tracing on if any "tag" is found in "DEBUG_SH". 26233541Sjchandra# It turns tracing off if "!tag" is found in "DEBUG_SH". 27233541Sjchandra# It also sets "DEBUG_ON" to the "tag" that caused tracing to be 28233541Sjchandra# enabled, or "DEBUG_OFF" if we matched "!tag". 29233541Sjchandra# If '-e' option given returns 1 if no "tag" matched. 30233541Sjchandra# If the '-o' flag is given, tracing is turned off unless there 31233541Sjchandra# was a matched "tag", useful for functions too noisy to tace. 32233541Sjchandra# 33233541Sjchandra# DebugOff turns tracing on if any "tag" matches "DEBUG_OFF" or 34233541Sjchandra# off if any "tag" matches "DEBUG_ON". This allows nested 35233541Sjchandra# functions to not interfere with each other. 36233541Sjchandra# 37233541Sjchandra# DebugOff accepts but ignores the '-e' and '-o' options. 38233541Sjchandra# The optional "rc" value will be returned rather than the 39233541Sjchandra# default of 0. Thus if DebugOff is the last operation in a 40233541Sjchandra# function, "rc" will be the return code of that function. 41233541Sjchandra# 42233541Sjchandra# DebugEcho is just shorthand for: 43233541Sjchandra#.nf 44233541Sjchandra# $DEBUG_DO echo "$@" 45233541Sjchandra#.fi 46233541Sjchandra# 47233541Sjchandra# Debugging returns true if tracing is enabled. 48233541Sjchandra# It is useful for bounding complex debug actions, rather than 49233541Sjchandra# using lots of "DEBUG_DO" lines. 50233541Sjchandra# 51233541Sjchandra# DebugShell runs an interactive shell if any "tag" is found in 52233541Sjchandra# "DEBUG_INTERACTIVE", and there is a tty available. 53233541Sjchandra# The shell used is defined by "DEBUG_SHELL" or "SHELL" and 54233541Sjchandra# defaults to '/bin/sh'. 55233541Sjchandra# 56233541Sjchandra# Debug calls DebugOn and if that does not turn tracing on, it 57233541Sjchandra# calls DebugOff to turn it off. 58233541Sjchandra# 59233541Sjchandra# The variables "DEBUG_SKIP" and "DEBUG_DO" are set so as to 60233541Sjchandra# enable/disable code that should be skipped/run when debugging 61233541Sjchandra# is turned on. "DEBUGGING" is the same as "DEBUG_SKIP" for 62233541Sjchandra# backwards compatability. 63233541Sjchandra# 64233541Sjchandra# The use of $_DEBUG_SH is to prevent multiple inclusion, though 65233541Sjchandra# it does no harm in this case. 66233541Sjchandra# 67233541Sjchandra# BUGS: 68233541Sjchandra# Does not work with some versions of ksh. 69233541Sjchandra# If a function turns tracing on, ksh turns it off when the 70233541Sjchandra# function returns - useless. 71233541Sjchandra# PD ksh works ok ;-) 72233541Sjchandra# 73233541Sjchandra# AUTHOR: 74233541Sjchandra# Simon J. Gerraty <sjg@crufty.net> 75233541Sjchandra 76233541Sjchandra# RCSid: 77233541Sjchandra# $Id: debug.sh,v 1.35 2024/02/03 19:04:47 sjg Exp $ 78233541Sjchandra# 79233541Sjchandra# @(#) Copyright (c) 1994-2024 Simon J. Gerraty 80233541Sjchandra# 81233541Sjchandra# This file is provided in the hope that it will 82233541Sjchandra# be of use. There is absolutely NO WARRANTY. 83233541Sjchandra# Permission to copy, redistribute or otherwise 84233541Sjchandra# use this file is hereby granted provided that 85233541Sjchandra# the above copyright notice and this notice are 86233541Sjchandra# left intact. 87233541Sjchandra# 88233541Sjchandra# Please send copies of changes and bug-fixes to: 89233541Sjchandra# sjg@crufty.net 90233541Sjchandra# 91233541Sjchandra 92233541Sjchandra_DEBUG_SH=: 93233541Sjchandra 94233541SjchandraMyname=${Myname:-`basename $0 .sh`} 95233541Sjchandra 96233541SjchandraDEBUGGING= 97233541SjchandraDEBUG_DO=: 98233541SjchandraDEBUG_SKIP= 99233541Sjchandraexport DEBUGGING DEBUG_DO DEBUG_SKIP 100233541Sjchandra 101233541Sjchandra_debugOn() { 102233541Sjchandra DEBUG_OFF= 103233541Sjchandra DEBUG_DO= 104233541Sjchandra DEBUG_SKIP=: 105233541Sjchandra DEBUG_X=-x 106233541Sjchandra set -x 107233541Sjchandra DEBUG_ON=$1 108233541Sjchandra} 109233541Sjchandra 110233541Sjchandra_debugOff() { 111233541Sjchandra DEBUG_OFF=$1 112233541Sjchandra set +x 113233541Sjchandra DEBUG_ON=$2 114233541Sjchandra DEBUG_DO=: 115233541Sjchandra DEBUG_SKIP= 116233541Sjchandra DEBUG_X= 117233541Sjchandra} 118233541Sjchandra 119233541SjchandraDebugEcho() { 120233541Sjchandra $DEBUG_DO echo "$@" 121233541Sjchandra} 122233541Sjchandra 123233541SjchandraDebugging() { 124233541Sjchandra test "$DEBUG_SKIP" 125233541Sjchandra} 126233541Sjchandra 127233541SjchandraDebugLog() { 128233541Sjchandra $DEBUG_SKIP return 0 129233541Sjchandra echo `date '+@ %s [%Y-%m-%d %H:%M:%S %Z]'` "$@" 130233541Sjchandra} 131233541Sjchandra 132233541Sjchandra# something hard to miss when wading through huge -x output 133233541SjchandraDebugTrace() { 134233541Sjchandra $DEBUG_SKIP return 0 135233541Sjchandra set +x 136233541Sjchandra echo "@ ==================== [ $DEBUG_ON ] ====================" 137233541Sjchandra DebugLog "$@" 138233541Sjchandra echo "@ ==================== [ $DEBUG_ON ] ====================" 139233541Sjchandra set -x 140233541Sjchandra} 141233541Sjchandra 142233541Sjchandra# Turn on debugging if appropriate 143233541SjchandraDebugOn() { 144233541Sjchandra _rc=0 # avoid problems with set -e 145233541Sjchandra _off=: 146233541Sjchandra while : 147233541Sjchandra do 148233541Sjchandra case "$1" in 149233541Sjchandra -e) _rc=1; shift;; # caller ok with return 1 150233541Sjchandra -o) _off=; shift;; # off unless we have a match 151233541Sjchandra *) break;; 152233541Sjchandra esac 153233541Sjchandra done 154233541Sjchandra case ",${DEBUG_SH:-$DEBUG}," in 155233541Sjchandra ,,) return $_rc;; 156233541Sjchandra *,[Dd]ebug,*) ;; 157233541Sjchandra *) $DEBUG_DO set +x;; # reduce the noise 158 esac 159 _match= 160 # if debugging is off because of a !e 161 # don't add 'all' to the On list. 162 case "$_off$DEBUG_OFF" in 163 :) _e=all;; 164 *) _e=;; 165 esac 166 for _e in ${*:-$Myname} $_e 167 do 168 : $_e in ,${DEBUG_SH:-$DEBUG}, 169 case ",${DEBUG_SH:-$DEBUG}," in 170 *,!$_e,*|*,!$Myname:$_e,*) 171 # only turn it off if it was on 172 _rc=0 173 $DEBUG_DO _debugOff $_e $DEBUG_ON 174 break 175 ;; 176 *,$_e,*|*,$Myname:$_e,*) 177 # only turn it on if it was off 178 _rc=0 179 _match=$_e 180 $DEBUG_SKIP _debugOn $_e 181 break 182 ;; 183 esac 184 done 185 if test -z "$_off$_match"; then 186 # off unless explicit match, but 187 # only turn it off if it was on 188 $DEBUG_DO _debugOff $_e $DEBUG_ON 189 fi 190 DEBUGGING=$DEBUG_SKIP # backwards compatability 191 $DEBUG_DO set -x # back on if needed 192 $DEBUG_DO set -x # make sure we see it in trace 193 return $_rc 194} 195 196# Only turn debugging off if one of our args was the reason it 197# was turned on. 198# We normally return 0, but caller can pass rc=$? as first arg 199# so that we preserve the status of last statement. 200DebugOff() { 201 case ",${DEBUG_SH:-$DEBUG}," in 202 *,[Dd]ebug,*) ;; 203 *) $DEBUG_DO set +x;; # reduce the noise 204 esac 205 _rc=0 # always happy 206 while : 207 do 208 case "$1" in 209 -[eo]) shift;; # ignore it 210 rc=*) eval "_$1"; shift;; 211 *) break;; 212 esac 213 done 214 for _e in $* 215 do 216 : $_e==$DEBUG_OFF DEBUG_OFF 217 case "$DEBUG_OFF" in 218 "") break;; 219 $_e) _debugOn $DEBUG_ON; return $_rc;; 220 esac 221 done 222 for _e in $* 223 do 224 : $_e==$DEBUG_ON DEBUG_ON 225 case "$DEBUG_ON" in 226 "") break;; 227 $_e) _debugOff; return $_rc;; 228 esac 229 done 230 DEBUGGING=$DEBUG_SKIP # backwards compatability 231 $DEBUG_DO set -x # back on if needed 232 $DEBUG_DO set -x # make sure we see it in trace 233 return $_rc 234} 235 236_TTY=${_TTY:-`test -t 0 && tty`}; export _TTY 237 238# override this if you like 239_debugShell() { 240 { 241 echo DebugShell "$@" 242 echo "Type 'exit' to continue..." 243 } > $_TTY 244 ${DEBUG_SHELL:-${SHELL:-/bin/sh}} < $_TTY > $_TTY 2>&1 245} 246 247# Run an interactive shell if appropriate 248# Note: you can use $DEBUG_SKIP DebugShell ... to skip unless debugOn 249DebugShell() { 250 case "$_TTY%${DEBUG_INTERACTIVE}" in 251 *%|%*) return 0;; # no tty or no spec 252 esac 253 for _e in ${*:-$Myname} all 254 do 255 case ",${DEBUG_INTERACTIVE}," in 256 *,!$_e,*|*,!$Myname:$_e,*) 257 return 0 258 ;; 259 *,$_e,*|*,$Myname:$_e,*) 260 # Provide clues as to why/where 261 _debugShell "$_e: $@" 262 return $? 263 ;; 264 esac 265 done 266 return 0 267} 268 269# For backwards compatability 270Debug() { 271 case "${DEBUG_SH:-$DEBUG}" in 272 "") ;; 273 *) DEBUG_ON=${DEBUG_ON:-_Debug} 274 DebugOn -e $* || DebugOff $DEBUG_LAST 275 DEBUGGING=$DEBUG_SKIP 276 ;; 277 esac 278} 279