xref: /freebsd/cddl/usr.sbin/dwatch/dwatch (revision f5335513)
15bf5ca77SDevin Teske#!/bin/sh
25bf5ca77SDevin Teske#-
35bf5ca77SDevin Teske# Copyright (c) 2014-2018 Devin Teske
45bf5ca77SDevin Teske# All rights reserved.
55bf5ca77SDevin Teske#
65bf5ca77SDevin Teske# Redistribution and use in source and binary forms, with or without
75bf5ca77SDevin Teske# modification, are permitted provided that the following conditions
85bf5ca77SDevin Teske# are met:
95bf5ca77SDevin Teske# 1. Redistributions of source code must retain the above copyright
105bf5ca77SDevin Teske#    notice, this list of conditions and the following disclaimer.
115bf5ca77SDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
125bf5ca77SDevin Teske#    notice, this list of conditions and the following disclaimer in the
135bf5ca77SDevin Teske#    documentation and/or other materials provided with the distribution.
145bf5ca77SDevin Teske#
155bf5ca77SDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165bf5ca77SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175bf5ca77SDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185bf5ca77SDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195bf5ca77SDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205bf5ca77SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215bf5ca77SDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225bf5ca77SDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235bf5ca77SDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245bf5ca77SDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255bf5ca77SDevin Teske# SUCH DAMAGE.
265bf5ca77SDevin Teske#
275bf5ca77SDevin Teske############################################################ IDENT(1)
285bf5ca77SDevin Teske#
295bf5ca77SDevin Teske# $Title: Watch processes as they trigger a particular DTrace probe $
305bf5ca77SDevin Teske#
315bf5ca77SDevin Teske############################################################ CONFIGURATION
325bf5ca77SDevin Teske
335bf5ca77SDevin Teske#
345bf5ca77SDevin Teske# DTrace pragma settings
355bf5ca77SDevin Teske#
365bf5ca77SDevin TeskeDTRACE_PRAGMA="
375bf5ca77SDevin Teske	option quiet
385bf5ca77SDevin Teske	option dynvarsize=16m
395bf5ca77SDevin Teske	option switchrate=10hz
405bf5ca77SDevin Teske" # END-QUOTE
415bf5ca77SDevin Teske
425bf5ca77SDevin Teske#
435bf5ca77SDevin Teske# Profiles
445bf5ca77SDevin Teske#
455bf5ca77SDevin Teske: ${DWATCH_PROFILES_PATH="/usr/libexec/dwatch:/usr/local/libexec/dwatch"}
465bf5ca77SDevin Teske
475bf5ca77SDevin Teske############################################################ GLOBALS
485bf5ca77SDevin Teske
497d958cc9SDevin TeskeVERSION='$Version: 1.4 $' # -V
505bf5ca77SDevin Teske
515bf5ca77SDevin Teskepgm="${0##*/}" # Program basename
525bf5ca77SDevin Teske
535bf5ca77SDevin Teske#
545bf5ca77SDevin Teske# Command-line arguments
555bf5ca77SDevin Teske#
565bf5ca77SDevin TeskePROBE_ARG=
575bf5ca77SDevin Teske
585bf5ca77SDevin Teske#
595f2202d1SDevin Teske# Command-line defaults
605f2202d1SDevin Teske#
615f2202d1SDevin Teske_MAX_ARGS=64		# -B num
625f2202d1SDevin Teske_MAX_DEPTH=64		# -K num
635f2202d1SDevin Teske
645f2202d1SDevin Teske#
655bf5ca77SDevin Teske# Command-line options
665bf5ca77SDevin Teske#
675bf5ca77SDevin TeskeCONSOLE=		# -y
685bf5ca77SDevin TeskeCONSOLE_FORCE=		# -y
695bf5ca77SDevin Teske[ -t 1 ] && CONSOLE=1	# -y
705bf5ca77SDevin TeskeCOUNT=0			# -N count
715bf5ca77SDevin TeskeCUSTOM_DETAILS=		# -E code
725bf5ca77SDevin TeskeCUSTOM_TEST=		# -t test
735bf5ca77SDevin TeskeDEBUG=			# -d
745bf5ca77SDevin TeskeDESTRUCTIVE_ACTIONS=	# -w
75bcce9a2bSDevin TeskeDEVELOPER=		# -dev
765bf5ca77SDevin TeskeEXECNAME=		# -k name
775bf5ca77SDevin TeskeEXECREGEX=		# -z regex
785bf5ca77SDevin TeskeEXIT_AFTER_COMPILE=	# -e
795bf5ca77SDevin TeskeFILTER=			# -r regex
805bf5ca77SDevin TeskePROBE_COALESCE=		# -F
815bf5ca77SDevin TeskeGROUP=			# -g group
825bf5ca77SDevin TeskeJID=			# -j jail
835bf5ca77SDevin TeskeLIST=			# -l
845bf5ca77SDevin TeskeLIST_PROFILES=		# -Q
855f2202d1SDevin TeskeMAX_ARGS=$_MAX_ARGS	# -B num
865f2202d1SDevin TeskeMAX_DEPTH=$_MAX_DEPTH	# -K num
875bf5ca77SDevin TeskeONELINE=		# -1
885bf5ca77SDevin TeskeOUTPUT=			# -o file
895bf5ca77SDevin TeskeOUTPUT_CMD=		# -O cmd
905bf5ca77SDevin TeskePID=			# -p pid
915bf5ca77SDevin TeskePROBE_TYPE=		# -f -m -n -P
925bf5ca77SDevin TeskePROFILE=		# -X profile
935bf5ca77SDevin TeskePSTREE=			# -R
945bf5ca77SDevin TeskeQUIET=			# -q
955bf5ca77SDevin TeskeTIMEOUT=		# -T time
965bf5ca77SDevin TeskeTRACE=			# -x
975bf5ca77SDevin TeskeUSER=			# -u user
985bf5ca77SDevin TeskeUSE_PROFILE=		# -X profile
995bf5ca77SDevin TeskeVERBOSE=		# -v
1005bf5ca77SDevin Teske
1015bf5ca77SDevin Teske#
1025bf5ca77SDevin Teske# Global exit status
1035bf5ca77SDevin Teske#
1045bf5ca77SDevin TeskeSUCCESS=0
1055bf5ca77SDevin TeskeFAILURE=1
1065bf5ca77SDevin Teske
1075bf5ca77SDevin Teske#
1085bf5ca77SDevin Teske# Miscellaneous
1095bf5ca77SDevin Teske#
1105bf5ca77SDevin TeskeACTIONS=
1115bf5ca77SDevin TeskeEVENT_DETAILS=
1125bf5ca77SDevin TeskeEVENT_TAG='printf("%d.%d %s[%d]: ",
1135bf5ca77SDevin Teske		this->uid0, this->gid0, execname, this->pid0);'
1145bf5ca77SDevin TeskeEVENT_TEST=
1155bf5ca77SDevin TeskeFILE=
1165bf5ca77SDevin TeskeID=3
1175bf5ca77SDevin TeskeMODULE_CHECKED=
1185bf5ca77SDevin TeskePROBE=
1195bf5ca77SDevin TeskePSARGS=1
1205bf5ca77SDevin TeskeRGID=
1215bf5ca77SDevin TeskeRUID=
1225bf5ca77SDevin TeskeSUDO=
1235bf5ca77SDevin Teskeexport SUDO_PROMPT="[sudo] Password:"
1245bf5ca77SDevin TeskeTITLE=\$Title:
1255bf5ca77SDevin Teske
1265bf5ca77SDevin Teske############################################################ FUNCTIONS
1275bf5ca77SDevin Teske
1285bf5ca77SDevin Teskeansi() { local fmt="$2 $4"; [ "$CONSOLE" ] && fmt="\\033[$1m$2\\033[$3m $4";
1295bf5ca77SDevin Teske	shift 4; printf "$fmt\n" "$@"; }
1305bf5ca77SDevin Teskedie() { exec >&2; [ "$*" ] && echo "$pgm:" "$@"; exit $FAILURE; }
1315bf5ca77SDevin Teskeinfo() { [ "$QUIET" ] || ansi 35 "INFO" 39 "$@" >&2; }
1325bf5ca77SDevin Teske
1335bf5ca77SDevin Teskeusage()
1345bf5ca77SDevin Teske{
1355bf5ca77SDevin Teske	local optfmt="\t%-10s %s\n"
1365bf5ca77SDevin Teske	exec >&2
1375bf5ca77SDevin Teske	[ "$*" ] && printf "%s: %s\n" "$pgm" "$*"
1385bf5ca77SDevin Teske	printf "Usage: %s [-1defFmnPqRvVwxy] [%s] [%s] [%s] [%s]\n" "$pgm" \
1395bf5ca77SDevin Teske		"-B num" "-E code" "-g group" "-j jail"
1405bf5ca77SDevin Teske	printf "\t      [%s] [%s] [%s] [%s] [%s] [%s]\n" \
1415bf5ca77SDevin Teske		"-k name" "-K num" "-N count" "-o file" "-O cmd" "-p pid"
1425bf5ca77SDevin Teske	printf "\t      [%s] [%s] [%s] [%s] [%s] [%s]\n" \
1435bf5ca77SDevin Teske		"-r regex" "-t test" "-T time" "-u user" "-X profile" \
1445bf5ca77SDevin Teske		"-z regex"
1455bf5ca77SDevin Teske	printf "\t      probe[,...] [args ...]\n"
1465bf5ca77SDevin Teske	printf "       %s -l [-fmnPqy] [-r regex] [probe ...]\n" "$pgm"
1475bf5ca77SDevin Teske	printf "       %s -Q [-1qy] [-r regex]\n" "$pgm"
1485bf5ca77SDevin Teske	printf "\n"
1495bf5ca77SDevin Teske	printf "$optfmt" "-1" \
1505bf5ca77SDevin Teske		"Print one line per process/profile (Default; disables \`-R')."
1515bf5ca77SDevin Teske	printf "$optfmt" "-B num" \
1525f2202d1SDevin Teske		"Maximum process arguments to display (Default $_MAX_ARGS)."
1535bf5ca77SDevin Teske	printf "$optfmt" "-d" \
1545bf5ca77SDevin Teske		"Debug. Send dtrace(1) script to stdout instead of executing."
1555bf5ca77SDevin Teske	printf "$optfmt" "-e" \
1565bf5ca77SDevin Teske		"Exit after compiling request but prior to enabling probes."
1575bf5ca77SDevin Teske	printf "$optfmt" "-E code" \
1585bf5ca77SDevin Teske		"DTrace code for event details. If \`-', read from stdin."
1595bf5ca77SDevin Teske	printf "$optfmt" "-f" \
1605bf5ca77SDevin Teske		"Enable probe matching the specified function name."
1615bf5ca77SDevin Teske	printf "$optfmt" "-F" \
1625bf5ca77SDevin Teske		"Coalesce trace output by function."
1635bf5ca77SDevin Teske	printf "$optfmt" "-g group" \
1645bf5ca77SDevin Teske		"Group filter. Only show processes matching group name/gid."
1655bf5ca77SDevin Teske	printf "$optfmt" "-j jail" \
1665bf5ca77SDevin Teske		"Jail filter. Only show processes matching jail name/jid."
1675bf5ca77SDevin Teske	printf "$optfmt" "-k name" \
1685bf5ca77SDevin Teske		"Only show processes matching name."
1695bf5ca77SDevin Teske	printf "$optfmt" "-K num" \
1705f2202d1SDevin Teske		"Maximum directory depth to display (Default $_MAX_DEPTH)."
1715bf5ca77SDevin Teske	printf "$optfmt" "-l" \
1725bf5ca77SDevin Teske		"List available probes on standard output and exit."
1735bf5ca77SDevin Teske	printf "$optfmt" "-m" \
1745bf5ca77SDevin Teske		"Enable probe matching the specified module name."
1755bf5ca77SDevin Teske	printf "$optfmt" "-n" \
1765bf5ca77SDevin Teske		"Enable probe matching the specified probe name."
1775bf5ca77SDevin Teske	printf "$optfmt" "-N count" \
1785bf5ca77SDevin Teske		"Exit after count matching entries (Default 0 for disabled)."
1795bf5ca77SDevin Teske	printf "$optfmt" "-o file" \
1805bf5ca77SDevin Teske		"Set output file. If \`-', the path \`/dev/stdout' is used."
1815bf5ca77SDevin Teske	printf "$optfmt" "-O cmd" \
1825bf5ca77SDevin Teske		"Execute cmd for each event."
1835bf5ca77SDevin Teske	printf "$optfmt" "-p pid" \
1845bf5ca77SDevin Teske		"Process id filter. Only show processes with matching pid."
1855bf5ca77SDevin Teske	printf "$optfmt" "-P" \
1865bf5ca77SDevin Teske		"Enable probe matching the specified provider name."
1875bf5ca77SDevin Teske	printf "$optfmt" "-q" \
1885bf5ca77SDevin Teske		"Quiet. Hide informational messages and all dtrace(1) errors."
1895bf5ca77SDevin Teske	printf "$optfmt" "-Q" \
1905bf5ca77SDevin Teske		"List available profiles in DWATCH_PROFILES_PATH and exit."
1915bf5ca77SDevin Teske	printf "$optfmt" "-r regex" \
1925bf5ca77SDevin Teske		"Filter. Only show blocks matching awk(1) regular expression."
1935bf5ca77SDevin Teske	printf "$optfmt" "-R" \
1945bf5ca77SDevin Teske		"Show parent, grandparent, and ancestor of process."
1955bf5ca77SDevin Teske	printf "$optfmt" "-t test" \
1965bf5ca77SDevin Teske		"Test clause (predicate) to limit events (Default none)."
1975bf5ca77SDevin Teske	printf "$optfmt" "-T time" \
1985bf5ca77SDevin Teske		"Timeout. Format is \`\#[smhd]' or simply \`\#' for seconds."
1995bf5ca77SDevin Teske	printf "$optfmt" "-u user" \
2005bf5ca77SDevin Teske		"User filter. Only show processes matching user name/uid."
2015bf5ca77SDevin Teske	printf "$optfmt" "-v" \
2025bf5ca77SDevin Teske		"Verbose. Show all errors from dtrace(1)."
2035bf5ca77SDevin Teske	printf "$optfmt" "-V" \
2045bf5ca77SDevin Teske		"Report dwatch version on standard output and exit."
2055bf5ca77SDevin Teske	printf "$optfmt" "-w" \
2065bf5ca77SDevin Teske		"Permit destructive actions (copyout*, stop, panic, etc.)."
2075bf5ca77SDevin Teske	printf "$optfmt" "-x" \
2085bf5ca77SDevin Teske		"Trace. Print \`<probe-id>' when a probe is triggered."
2095bf5ca77SDevin Teske	printf "$optfmt" "-X profile" \
2105bf5ca77SDevin Teske		"Load profile name from DWATCH_PROFILES_PATH."
2115bf5ca77SDevin Teske	printf "$optfmt" "-y" \
2125bf5ca77SDevin Teske		"Always treat stdout as console (enable colors/columns/etc.)."
2135bf5ca77SDevin Teske	printf "$optfmt" "-z regex" \
2145bf5ca77SDevin Teske		"Only show processes matching awk(1) regular expression."
2155bf5ca77SDevin Teske	die
2165bf5ca77SDevin Teske}
2175bf5ca77SDevin Teske
2185bf5ca77SDevin Teskedtrace_cmd()
2195bf5ca77SDevin Teske{
2205bf5ca77SDevin Teske	local status stdout
2215bf5ca77SDevin Teske	local timeout=
2225bf5ca77SDevin Teske
2235bf5ca77SDevin Teske	if [ "$1" = "-t" ]; then
2245bf5ca77SDevin Teske		shift
2255bf5ca77SDevin Teske		[ "$TIMEOUT" ] && timeout=1
2265bf5ca77SDevin Teske	fi
2275bf5ca77SDevin Teske
2285bf5ca77SDevin Teske	exec 3>&1
2295bf5ca77SDevin Teske	stdout=3
2305bf5ca77SDevin Teske
2315bf5ca77SDevin Teske	#
2325bf5ca77SDevin Teske	# Filter dtrace(1) stderr while preserving exit status
2335bf5ca77SDevin Teske	#
2345bf5ca77SDevin Teske	status=$(
2355bf5ca77SDevin Teske		exec 4>&1
2365bf5ca77SDevin Teske		to_status=4
2375bf5ca77SDevin Teske		( trap 'echo $? >&$to_status' EXIT
2385bf5ca77SDevin Teske			eval $SUDO ${timeout:+timeout \"\$TIMEOUT\"} dtrace \
2395bf5ca77SDevin Teske				\"\$@\" 2>&1 ${QUIET:+2> /dev/null} >&$stdout
2405bf5ca77SDevin Teske		) | dtrace_stderr_filter >&2
2415bf5ca77SDevin Teske	)
2425bf5ca77SDevin Teske
2435bf5ca77SDevin Teske	return $status
2445bf5ca77SDevin Teske}
2455bf5ca77SDevin Teske
2465bf5ca77SDevin Teskedtrace_stderr_filter()
2475bf5ca77SDevin Teske{
2485bf5ca77SDevin Teske	if [ "$VERBOSE" ]; then
2495bf5ca77SDevin Teske		cat
2505bf5ca77SDevin Teske		return
2515bf5ca77SDevin Teske		# NOTREACHED
2525bf5ca77SDevin Teske	fi
2535bf5ca77SDevin Teske
2545bf5ca77SDevin Teske	awk ' # Start awk(1) stderr-filter
2555bf5ca77SDevin Teske	/[[:digit:]]+ drops? on CPU [[:digit:]]+/ { next }
2565bf5ca77SDevin Teske	/failed to write to <stdout>: No such file or directory/ { next }
2575bf5ca77SDevin Teske	/failed to write to <stdout>: Broken pipe/ { next }
2585bf5ca77SDevin Teske	/processing aborted: Broken pipe/ { next }
2595bf5ca77SDevin Teske	/invalid address \(0x[[:xdigit:]]+\) in action #[[:digit:]]+/ { next }
2605bf5ca77SDevin Teske	/out of scratch space in action #[[:digit:]]+/ { next }
2615bf5ca77SDevin Teske	/^Bus error$/ { next }
2625bf5ca77SDevin Teske	{ print; fflush() }
2635bf5ca77SDevin Teske	' # END-QUOTE
2645bf5ca77SDevin Teske}
2655bf5ca77SDevin Teske
2665bf5ca77SDevin Teskeexpand_probe()
2675bf5ca77SDevin Teske{
2685bf5ca77SDevin Teske	local OPTIND=1 OPTARG flag
2695bf5ca77SDevin Teske	local type=
2705bf5ca77SDevin Teske
2715bf5ca77SDevin Teske	while getopts t: flag; do
2725bf5ca77SDevin Teske		case "$flag" in
2735bf5ca77SDevin Teske		t) type="$OPTARG" ;;
2745bf5ca77SDevin Teske		esac
2755bf5ca77SDevin Teske	done
2765bf5ca77SDevin Teske	shift $(( $OPTIND - 1 ))
2775bf5ca77SDevin Teske
2785bf5ca77SDevin Teske	local probe="$1"
2795bf5ca77SDevin Teske	case "$probe" in
2805bf5ca77SDevin Teske	*:*)
2815bf5ca77SDevin Teske		echo "$probe"
2825bf5ca77SDevin Teske		return $SUCCESS
2835bf5ca77SDevin Teske		;;
2845bf5ca77SDevin Teske	esac
2855bf5ca77SDevin Teske
2865bf5ca77SDevin Teske	dtrace_cmd -l | awk -v probe="$probe" -v type="$type" '
2875bf5ca77SDevin Teske	# Start awk(1) processor
2885bf5ca77SDevin Teske	#################################################### BEGIN
2895bf5ca77SDevin Teske	BEGIN { getline dtrace_header }
2905bf5ca77SDevin Teske	#################################################### FUNCTIONS
2915bf5ca77SDevin Teske	function dump(unused1,unused2) {
2925bf5ca77SDevin Teske		if (n) {
2935bf5ca77SDevin Teske			if (NcF[n] == 1) f = N2F[n]
2945bf5ca77SDevin Teske			if (NcM[n] == 1) m = N2M[n]
2955bf5ca77SDevin Teske			if (NcP[n] == 1) p = N2P[n]
2965bf5ca77SDevin Teske		} else if (f) {
2975bf5ca77SDevin Teske			if (FcM[f] == 1) m = F2M[f]
2985bf5ca77SDevin Teske			if (FcP[f] == 1) p = F2P[f]
2995bf5ca77SDevin Teske			if (FcN[f] == 0 && found) n = "entry"
3005bf5ca77SDevin Teske		} else if (m) {
3015bf5ca77SDevin Teske			if (McP[m] == 1) p = M2P[m]
3025bf5ca77SDevin Teske		}
3035bf5ca77SDevin Teske		printf "%s:%s:%s:%s\n", p, m, f, n
3045bf5ca77SDevin Teske		exit !found
3055bf5ca77SDevin Teske	}
3065bf5ca77SDevin Teske	function inFMP() { return probe in F || probe in M || probe in P }
3075bf5ca77SDevin Teske	function inNMP() { return probe in N || probe in M || probe in P }
3085bf5ca77SDevin Teske	function inNFP() { return probe in N || probe in F || probe in P }
3095bf5ca77SDevin Teske	function inNFM() { return probe in N || probe in F || probe in M }
3105bf5ca77SDevin Teske	function diva(value, peerA, peerB, peerC) {
3115bf5ca77SDevin Teske		return value >= peerA && value >= peerB && value >= peerC
3125bf5ca77SDevin Teske	}
3135bf5ca77SDevin Teske	#################################################### MAIN
3145bf5ca77SDevin Teske	type == "name" && $NF != probe { next }
3155bf5ca77SDevin Teske	type == "function" && NF >=4 && $(NF-1) != probe { next }
3165bf5ca77SDevin Teske	type == "module" && NF == 5 && $(NF-2) != probe { next }
3175bf5ca77SDevin Teske	type == "provider" && $2 != probe { next }
3185bf5ca77SDevin Teske	type || $2 == probe || $3 == probe || $4 == probe || $5 == probe {
3195bf5ca77SDevin Teske		P[_p = $2]++
3205bf5ca77SDevin Teske		M[_m = (NF >= 5 ? $(NF-2) : "")]++
3215bf5ca77SDevin Teske		F[_f = (NF >= 4 ? $(NF-1) : "")]++
3225bf5ca77SDevin Teske		N[_n = $NF]++
3235bf5ca77SDevin Teske		if (N2F[_n] != _f) NcF[_n]++; N2F[_n] = _f
3245bf5ca77SDevin Teske		if (N2M[_n] != _m) NcM[_n]++; N2M[_n] = _m
3255bf5ca77SDevin Teske		if (N2P[_n] != _p) NcP[_n]++; N2P[_n] = _p
3265bf5ca77SDevin Teske		if (_n !~ /entry|return/) {
3275bf5ca77SDevin Teske			if (F2N[_f] != _n) FcN[_f]++
3285bf5ca77SDevin Teske			F2N[_f] = _n
3295bf5ca77SDevin Teske		}
3305bf5ca77SDevin Teske		if (F2M[_f] != _m) FcM[_f]++; F2M[_f] = _m
3315bf5ca77SDevin Teske		if (F2P[_f] != _p) FcP[_f]++; F2P[_f] = _p
3325bf5ca77SDevin Teske		if (M2P[_m] != _p) McP[_m]++; M2P[_m] = _p
3335bf5ca77SDevin Teske	}
3345bf5ca77SDevin Teske	#################################################### END
3355bf5ca77SDevin Teske	END {
3365bf5ca77SDevin Teske		if (type == "name")     dump(n = probe, found = probe in N)
3375bf5ca77SDevin Teske		if (type == "function") dump(f = probe, found = probe in F)
3385bf5ca77SDevin Teske		if (type == "module")   dump(m = probe, found = probe in M)
3395bf5ca77SDevin Teske		if (type == "provider") dump(p = probe, found = probe in P)
3405bf5ca77SDevin Teske		if (probe in N) {
3415bf5ca77SDevin Teske			found = 1
3425bf5ca77SDevin Teske			if (!inFMP()) dump(n = probe)
3435bf5ca77SDevin Teske			if (diva(F[probe], N[probe], M[probe], P[probe]))
3445bf5ca77SDevin Teske				dump(f = probe)
3455bf5ca77SDevin Teske			if (diva(M[probe], N[probe], F[probe], P[probe]))
3465bf5ca77SDevin Teske				dump(m = probe)
3475bf5ca77SDevin Teske			if (diva(P[probe], N[probe], F[probe], M[probe]))
3485bf5ca77SDevin Teske				dump(p = probe)
3495bf5ca77SDevin Teske			dump(n = probe) # N is the diva
3505bf5ca77SDevin Teske		} else if (probe in F) {
3515bf5ca77SDevin Teske			found = 1
3525bf5ca77SDevin Teske			if (!inNMP()) dump(f = probe)
3535bf5ca77SDevin Teske			if (diva(N[probe], F[probe], M[probe], P[probe]))
3545bf5ca77SDevin Teske				dump(n = probe)
3555bf5ca77SDevin Teske			if (diva(M[probe], F[probe], N[probe], P[probe]))
3565bf5ca77SDevin Teske				dump(m = probe)
3575bf5ca77SDevin Teske			if (diva(P[probe], F[probe], N[probe], M[probe]))
3585bf5ca77SDevin Teske				dump(p = probe)
3595bf5ca77SDevin Teske			dump(f = probe) # F is the diva
3605bf5ca77SDevin Teske		} else if (probe in M) {
3615bf5ca77SDevin Teske			found = 1
3625bf5ca77SDevin Teske			if (!inNFP()) dump(m = probe)
3635bf5ca77SDevin Teske			if (diva(N[probe], M[probe], F[probe], P[probe]))
3645bf5ca77SDevin Teske				dump(n = probe)
3655bf5ca77SDevin Teske			if (diva(F[probe], M[probe], N[probe], P[probe]))
3665bf5ca77SDevin Teske				dump(f = probe)
3675bf5ca77SDevin Teske			if (diva(P[probe], M[probe], N[probe], F[probe]))
3685bf5ca77SDevin Teske				dump(p = probe)
3695bf5ca77SDevin Teske			dump(m = probe) # M is the diva
3705bf5ca77SDevin Teske		} else if (probe in P) {
3715bf5ca77SDevin Teske			found = 1
3725bf5ca77SDevin Teske			if (!inNFM()) dump(p = probe)
3735bf5ca77SDevin Teske			if (diva(N[probe], P[probe], F[probe], M[probe]))
3745bf5ca77SDevin Teske				dump(n = probe)
3755bf5ca77SDevin Teske			if (diva(F[probe], P[probe], N[probe], M[probe]))
3765bf5ca77SDevin Teske				dump(f = probe)
3775bf5ca77SDevin Teske			if (diva(M[probe], P[probe], N[probe], F[probe]))
3785bf5ca77SDevin Teske				dump(m = probe)
3795bf5ca77SDevin Teske			dump(p = probe) # P is the diva
3805bf5ca77SDevin Teske		}
3815bf5ca77SDevin Teske		if (!found) print probe
3825bf5ca77SDevin Teske		exit !found
3835bf5ca77SDevin Teske	}
3845bf5ca77SDevin Teske	' # END-QUOTE
3855bf5ca77SDevin Teske}
3865bf5ca77SDevin Teske
3875bf5ca77SDevin Teskelist_probes()
3885bf5ca77SDevin Teske{
3895bf5ca77SDevin Teske	local OPTIND=1 OPTARG flag
3905bf5ca77SDevin Teske	local column=0 header="PROVIDER:MODULE:FUNCTION:NAME"
3915bf5ca77SDevin Teske	local filter= quiet= type=
3925bf5ca77SDevin Teske
3935bf5ca77SDevin Teske	while getopts f:qt: flag; do
3945bf5ca77SDevin Teske		case "$flag" in
3955bf5ca77SDevin Teske		f) filter="$OPTARG" ;;
3965bf5ca77SDevin Teske		q) quiet=1 ;;
3975bf5ca77SDevin Teske		t) type="$OPTARG" ;;
3985bf5ca77SDevin Teske		esac
3995bf5ca77SDevin Teske	done
4005bf5ca77SDevin Teske	shift $(( $OPTIND - 1 ))
4015bf5ca77SDevin Teske
4025bf5ca77SDevin Teske	if [ $# -eq 0 ]; then
4035bf5ca77SDevin Teske		case "$type" in
4045bf5ca77SDevin Teske		provider) column=1 header="PROVIDER" ;;
4055bf5ca77SDevin Teske		module)   column=2 header="MODULE" ;;
4065bf5ca77SDevin Teske		function) column=3 header="FUNCTION" ;;
4075bf5ca77SDevin Teske		name)     column=4 header="NAME" ;;
4085bf5ca77SDevin Teske		esac
4095bf5ca77SDevin Teske	fi
4105bf5ca77SDevin Teske
4115bf5ca77SDevin Teske	[ "$quiet" ] || echo "$header"
4125bf5ca77SDevin Teske
4135bf5ca77SDevin Teske	local arg probe=
4145bf5ca77SDevin Teske	for arg in "$@"; do
4155bf5ca77SDevin Teske		arg=$( expand_probe -t "$type" -- "$arg" )
4165bf5ca77SDevin Teske		probe="$probe${probe:+, }$arg"
4175bf5ca77SDevin Teske	done
4185bf5ca77SDevin Teske
4195bf5ca77SDevin Teske	dtrace_cmd -l${probe:+n "$probe"} | awk -v pattern="$(
4205bf5ca77SDevin Teske		# Prevent backslashes from being lost
4215bf5ca77SDevin Teske		echo "$filter" | awk 'gsub(/\\/,"&&")||1'
4225bf5ca77SDevin Teske	)" -v want="$column" -v console="$CONSOLE" '
4235bf5ca77SDevin Teske		BEGIN { getline dtrace_header }
4245bf5ca77SDevin Teske		function ans(seq) { return console ? "\033[" seq "m" : "" }
4255bf5ca77SDevin Teske		NF > 3 && $(NF-1) ~ /^#/ { next }
4265bf5ca77SDevin Teske		!_[$0 = column[0] = sprintf("%s:%s:%s:%s",
4275bf5ca77SDevin Teske			column[1] = $2,
4285bf5ca77SDevin Teske			column[2] = (NF >= 5 ? $(NF-2) : ""),
4295bf5ca77SDevin Teske			column[3] = (NF >= 4 ? $(NF-1) : ""),
4305bf5ca77SDevin Teske			column[4] = $NF)]++ &&
4315bf5ca77SDevin Teske			!__[$0 = column[want]]++ &&
4325bf5ca77SDevin Teske			gsub(pattern, ans("31;1") "&" ans("39;22")) {
4335bf5ca77SDevin Teske				print | "sort"
4345bf5ca77SDevin Teske			}
4355bf5ca77SDevin Teske		END { close("sort") }
4365bf5ca77SDevin Teske	' # END-QUOTE
4375bf5ca77SDevin Teske
4385bf5ca77SDevin Teske	exit $SUCCESS
4395bf5ca77SDevin Teske}
4405bf5ca77SDevin Teske
4415bf5ca77SDevin Teskelist_profiles()
4425bf5ca77SDevin Teske{
4435bf5ca77SDevin Teske	local OPTIND=1 OPTARG flag
4445bf5ca77SDevin Teske	local filter= oneline= quiet=
4455bf5ca77SDevin Teske
4465bf5ca77SDevin Teske	while getopts 1f:q flag; do
4475bf5ca77SDevin Teske		case "$flag" in
4485bf5ca77SDevin Teske		1) oneline=1 ;;
4495bf5ca77SDevin Teske		f) filter="$OPTARG" ;;
4505bf5ca77SDevin Teske		q) quiet=1 ;;
4515bf5ca77SDevin Teske		esac
4525bf5ca77SDevin Teske	done
4535bf5ca77SDevin Teske	shift $(( $OPTIND - 1 ))
4545bf5ca77SDevin Teske
4555bf5ca77SDevin Teske	# Prevent backslashes from being lost
4565bf5ca77SDevin Teske	filter=$( echo "$filter" | awk 'gsub(/\\/,"&&")||1' )
4575bf5ca77SDevin Teske
4585bf5ca77SDevin Teske	# Build a list of profiles available
4595bf5ca77SDevin Teske	local profiles
4605bf5ca77SDevin Teske	profiles=$( { IFS=:
4615bf5ca77SDevin Teske		for dir in $DWATCH_PROFILES_PATH; do
4625bf5ca77SDevin Teske			[ -d "$dir" ] || continue
4635bf5ca77SDevin Teske			for path in $dir/*; do
4645bf5ca77SDevin Teske				[ -f "$path" ] || continue
4655bf5ca77SDevin Teske				name="${path##*/}"
4665bf5ca77SDevin Teske				[ "$name" = "${name%%[!0-9A-Za-z_-]*}" ] ||
4675bf5ca77SDevin Teske					continue
4685bf5ca77SDevin Teske				echo $name
4695bf5ca77SDevin Teske			done
4705bf5ca77SDevin Teske		done
4715bf5ca77SDevin Teske	} | sort -u )
4725bf5ca77SDevin Teske
4735bf5ca77SDevin Teske	# Get the longest profile name
4745bf5ca77SDevin Teske	local longest_profile_name
4755bf5ca77SDevin Teske	longest_profile_name=$( echo "$profiles" |
4765bf5ca77SDevin Teske		awk -v N=0 '(L = length($0)) > N { N = L } END { print N }' )
4775bf5ca77SDevin Teske
4785bf5ca77SDevin Teske	# Get the width of the terminal
4795bf5ca77SDevin Teske	local max_size="$( stty size 2> /dev/null )"
4805bf5ca77SDevin Teske	: ${max_size:=24 80}
4815bf5ca77SDevin Teske	local max_width="${max_size#*[$IFS]}"
4825bf5ca77SDevin Teske
4835bf5ca77SDevin Teske	# Determine how many columns we can display
4845bf5ca77SDevin Teske	local x=$longest_profile_name ncols=1
4855bf5ca77SDevin Teske	[ "$QUIET" ] || x=$(( $x + 8 )) # Accommodate leading tab character
4865bf5ca77SDevin Teske	x=$(( $x + 3 + $longest_profile_name )) # Preload end of next column
4875bf5ca77SDevin Teske	while [ $x -lt $max_width ]; do
4885bf5ca77SDevin Teske		ncols=$(( $ncols + 1 ))
4895bf5ca77SDevin Teske		x=$(( $x + 3 + $longest_profile_name ))
4905bf5ca77SDevin Teske	done
4915bf5ca77SDevin Teske
4925bf5ca77SDevin Teske	# Output single lines if sent to a pipe
4935bf5ca77SDevin Teske	if [ "$oneline" ]; then
4945bf5ca77SDevin Teske		echo "$profiles" | awk -v filter="$filter" -v cons="$CONSOLE" '
4955bf5ca77SDevin Teske			function ans(s) { return cons ? "\033[" s "m" : "" }
4965bf5ca77SDevin Teske			gsub(filter, ans("31;1") "&" ans("39;22"))
4975bf5ca77SDevin Teske		' # END-QUOTE
4984a84c26cSDevin Teske		exit $SUCCESS
4995bf5ca77SDevin Teske	fi
5005bf5ca77SDevin Teske
5015bf5ca77SDevin Teske	[ "$quiet" ] || echo PROFILES:
5025bf5ca77SDevin Teske	echo "$profiles" | awk \
5035bf5ca77SDevin Teske		-v colsize=$longest_profile_name \
5045bf5ca77SDevin Teske		-v console="$CONSOLE" \
5055bf5ca77SDevin Teske		-v ncols=$ncols \
5065bf5ca77SDevin Teske		-v quiet="$quiet" \
5075bf5ca77SDevin Teske		-v filter="$filter" \
5085bf5ca77SDevin Teske	' # Begin awk(1) processor
5095bf5ca77SDevin Teske		function ans(seq) { return console ? "\033[" seq "m" : "" }
5105bf5ca77SDevin Teske		BEGIN {
5115bf5ca77SDevin Teske			row_item[1] = ""
5125bf5ca77SDevin Teske			replace = ans("31;1") "&" ans("39;22")
5135bf5ca77SDevin Teske			ansi_offset = length(replace) - 1
5145bf5ca77SDevin Teske		}
5155bf5ca77SDevin Teske		function print_row()
5165bf5ca77SDevin Teske		{
5175bf5ca77SDevin Teske			cs = colsize + ansi_offset * \
5185bf5ca77SDevin Teske				gsub(filter, replace, row_item[1])
5195bf5ca77SDevin Teske			printf "%s%-*s", quiet ? "" : "\t", cs, row_item[1]
5205bf5ca77SDevin Teske			for (i = 2; i <= cur_col; i++) {
5215bf5ca77SDevin Teske				cs = colsize + ansi_offset * \
5225bf5ca77SDevin Teske					gsub(filter, replace, row_item[i])
5235bf5ca77SDevin Teske				printf "   %-*s", cs, row_item[i]
5245bf5ca77SDevin Teske			}
5255bf5ca77SDevin Teske			printf "\n"
5265bf5ca77SDevin Teske		}
5275bf5ca77SDevin Teske		$0 ~ filter {
5285bf5ca77SDevin Teske			n++
5295bf5ca77SDevin Teske			cur_col = ((n - 1) % ncols) + 1
5305bf5ca77SDevin Teske			row_item[cur_col] = $0
5315bf5ca77SDevin Teske			if (cur_col == ncols) print_row()
5325bf5ca77SDevin Teske		}
5335bf5ca77SDevin Teske		END { if (cur_col < ncols) print_row() }
5345bf5ca77SDevin Teske	' # END-QUOTE
5355bf5ca77SDevin Teske
5365bf5ca77SDevin Teske	exit $SUCCESS
5375bf5ca77SDevin Teske}
5385bf5ca77SDevin Teske
5396a21b3cdSDevin Teskeshell_escape()
5406a21b3cdSDevin Teske{
5416a21b3cdSDevin Teske	echo "$*" | awk 'gsub(/'\''/, "&\\\\&&")||1'
5426a21b3cdSDevin Teske}
5436a21b3cdSDevin Teske
5445bf5ca77SDevin Teskeload_profile()
5455bf5ca77SDevin Teske{
5465bf5ca77SDevin Teske	local profile="$1"
5475bf5ca77SDevin Teske
5485bf5ca77SDevin Teske	[ "$profile" ] ||
5495bf5ca77SDevin Teske		die "missing profile argument (\`$pgm -Q' to list profiles)"
5505bf5ca77SDevin Teske
5515bf5ca77SDevin Teske	local oldIFS="$IFS"
5525bf5ca77SDevin Teske	local dir found=
5536a21b3cdSDevin Teske	local ARGV=
5546a21b3cdSDevin Teske
5556a21b3cdSDevin Teske	[ $COUNT -gt 0 ] &&			ARGV="$ARGV -N $COUNT"
5566a21b3cdSDevin Teske	[ "$DEBUG" ] &&				ARGV="$ARGV -d"
5576a21b3cdSDevin Teske	[ "$DESTRUCTIVE_ACTIONS" ] &&		ARGV="$ARGV -w"
5586a21b3cdSDevin Teske	[ "$EXIT_AFTER_COMPILE" ] &&		ARGV="$ARGV -e"
5596a21b3cdSDevin Teske	[ "$GROUP" ] &&				ARGV="$ARGV -g $GROUP"
5606a21b3cdSDevin Teske	[ "$JID" ] &&				ARGV="$ARGV -j $JID"
5616a21b3cdSDevin Teske	[ $MAX_ARGS -ne $_MAX_ARGS ] &&		ARGV="$ARGV -B $MAX_ARGS"
5626a21b3cdSDevin Teske	[ $MAX_DEPTH -ne $_MAX_DEPTH ] &&	ARGV="$ARGV -K $MAX_DEPTH"
5636a21b3cdSDevin Teske	[ "$ONELINE" ] &&			ARGV="$ARGV -1"
5646a21b3cdSDevin Teske	[ "$PID" ] &&				ARGV="$ARGV -p $PID"
5656a21b3cdSDevin Teske	[ "$PSTREE" ] &&			ARGV="$ARGV -R"
5666a21b3cdSDevin Teske	[ "$QUIET" ] &&				ARGV="$ARGV -q"
5676a21b3cdSDevin Teske	[ "$TIMEOUT" ] &&			ARGV="$ARGV -T $TIMEOUT"
5686a21b3cdSDevin Teske	[ "$TRACE" ] &&				ARGV="$ARGV -x"
5696a21b3cdSDevin Teske	[ "$USER" ] &&				ARGV="$ARGV -u $USER"
5706a21b3cdSDevin Teske	[ "$VERBOSE" ] &&			ARGV="$ARGV -v"
5716a21b3cdSDevin Teske
5726a21b3cdSDevin Teske	[ "$FILTER" ] &&
5736a21b3cdSDevin Teske		ARGV="$ARGV -r '$( shell_escape "$FILTER" )'"
5746a21b3cdSDevin Teske	[ "$EXECREGEX" ] &&
5756a21b3cdSDevin Teske		ARGV="$ARGV -z '$( shell_escape "$EXECREGEX" )'"
5766a21b3cdSDevin Teske	[ "$CUSTOM_DETAILS" ] &&
5776a21b3cdSDevin Teske		ARGV="$ARGV -E '$( shell_escape "$EVENT_DETAILS" )'"
5787d958cc9SDevin Teske	[ "$CUSTOM_TEST" ] &&
5797d958cc9SDevin Teske		ARGV="$ARGV -t '$( shell_escape "$CUSTOM_TEST" )'"
5806a21b3cdSDevin Teske	[ "$OUTPUT" ] &&
5816a21b3cdSDevin Teske		ARGV="$ARGV -o '$( shell_escape "$OUTPUT" )'"
5826a21b3cdSDevin Teske	[ "$OUTPUT_CMD" ] &&
5836a21b3cdSDevin Teske		ARGV="$ARGV -O '$( shell_escape "$OUTPUT_CMD" )'"
5846a21b3cdSDevin Teske
5856a21b3cdSDevin Teske	case "$PROBE_TYPE" in
5866a21b3cdSDevin Teske	provider) ARGV="$ARGV -P" ;;
5876a21b3cdSDevin Teske	  module) ARGV="$ARGV -m" ;;
5886a21b3cdSDevin Teske	function) ARGV="$ARGV -f" ;;
5896a21b3cdSDevin Teske	    name) ARGV="$ARGV -n" ;;
5906a21b3cdSDevin Teske	esac
5915bf5ca77SDevin Teske
5925bf5ca77SDevin Teske	IFS=:
5935bf5ca77SDevin Teske	for dir in $DWATCH_PROFILES_PATH; do
5945bf5ca77SDevin Teske		[ -d "$dir" ] || continue
5955bf5ca77SDevin Teske		[ -f "$dir/$profile" ] || continue
5965bf5ca77SDevin Teske		PROFILE="$profile" found=1
5975bf5ca77SDevin Teske		info "Sourcing $profile profile [found in %s]" "$dir"
5985bf5ca77SDevin Teske		. "$dir/$profile"
5995bf5ca77SDevin Teske		break
6005bf5ca77SDevin Teske	done
6015bf5ca77SDevin Teske	IFS="$oldIFS"
6025bf5ca77SDevin Teske
6035bf5ca77SDevin Teske	[ "$found" ] ||
6045bf5ca77SDevin Teske		die "no module named \`$profile' (\`$pgm -Q' to list profiles)"
6055bf5ca77SDevin Teske}
6065bf5ca77SDevin Teske
6075bf5ca77SDevin Teskepproc()
6085bf5ca77SDevin Teske{
6095bf5ca77SDevin Teske	local OPTIND=1 OPTARG flag
6105bf5ca77SDevin Teske	local P= N=0
6115bf5ca77SDevin Teske
6125bf5ca77SDevin Teske	while getopts P: flag; do
6135bf5ca77SDevin Teske		case "$flag" in
6145bf5ca77SDevin Teske		P) P="$OPTARG" ;;
6155bf5ca77SDevin Teske		esac
6165bf5ca77SDevin Teske	done
6175bf5ca77SDevin Teske	shift $(( OPTIND - 1 ))
6185bf5ca77SDevin Teske
6195bf5ca77SDevin Teske	local proc=$1
6205bf5ca77SDevin Teske	if [ ! "$proc" ]; then
6215bf5ca77SDevin Teske		if [ "$P" = "0" ]; then
6225bf5ca77SDevin Teske			proc="curthread->td_proc"
6235bf5ca77SDevin Teske		else
6245bf5ca77SDevin Teske			proc="this->proc ? this->proc->p_pptr : NULL"
6255bf5ca77SDevin Teske		fi
6265bf5ca77SDevin Teske	fi
6275bf5ca77SDevin Teske
6285bf5ca77SDevin Teske	awk 'NR > 1 && $0 { $0 = "\t" $0 }
6295bf5ca77SDevin Teske		gsub(/\\\t/, "\t") || 1
6305bf5ca77SDevin Teske	' <<-EOFPREAMBLE
6315bf5ca77SDevin Teske	this->proc = $proc;
6325bf5ca77SDevin Teske	this->uid$P = this->proc ? this->proc->p_ucred->cr_uid : -1;
6335bf5ca77SDevin Teske	this->gid$P = this->proc ? this->proc->p_ucred->cr_rgid : -1;
6345bf5ca77SDevin Teske	this->pid$P = this->proc ? this->proc->p_pid : -1;
6355bf5ca77SDevin Teske	this->jid$P = this->proc ? this->proc->p_ucred->cr_prison->pr_id : -1;
6365bf5ca77SDevin Teske
6375bf5ca77SDevin Teske	this->p_args = this->proc ? this->proc->p_args : 0;
6385bf5ca77SDevin Teske	this->ar_length = this->p_args ? this->p_args->ar_length : 0;
6395bf5ca77SDevin Teske	this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
6405bf5ca77SDevin Teske
6415bf5ca77SDevin Teske	this->args$P = this->arg${P}_$N = this->ar_length > 0 ?
6425bf5ca77SDevin Teske	\	this->ar_args : stringof(this->proc->p_comm);
6435bf5ca77SDevin Teske	this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
6445bf5ca77SDevin Teske	this->ar_args += this->len;
6455bf5ca77SDevin Teske	this->ar_length -= this->len;
6465bf5ca77SDevin Teske
6475bf5ca77SDevin Teske	EOFPREAMBLE
6485bf5ca77SDevin Teske
6495bf5ca77SDevin Teske	awk -v P=$P -v MAX_ARGS=$MAX_ARGS '
6505bf5ca77SDevin Teske		$0 { $0 = "\t" $0 }
6515bf5ca77SDevin Teske		buf = buf $0 "\n" { }
6525bf5ca77SDevin Teske		END {
6535bf5ca77SDevin Teske			while (++N <= MAX_ARGS) {
6545bf5ca77SDevin Teske				$0 = buf
6555bf5ca77SDevin Teske				gsub(/P/, P)
6565bf5ca77SDevin Teske				gsub(/N/, N)
6575bf5ca77SDevin Teske				gsub(/\\\t/, "\t")
6585bf5ca77SDevin Teske				sub(/\n$/, "")
6595bf5ca77SDevin Teske				print
6605bf5ca77SDevin Teske			}
6615bf5ca77SDevin Teske		}
6625bf5ca77SDevin Teske	' <<-EOFARGS
6635bf5ca77SDevin Teske	this->argP_N = this->ar_length > 0 ? this->ar_args : "";
6645bf5ca77SDevin Teske	this->argsP = strjoin(this->argsP,
6655bf5ca77SDevin Teske	\	strjoin(this->argP_N != "" ? " " : "", this->argP_N));
6665bf5ca77SDevin Teske	this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
6675bf5ca77SDevin Teske	this->ar_args += this->len;
6685bf5ca77SDevin Teske	this->ar_length -= this->len;
6695bf5ca77SDevin Teske
6705bf5ca77SDevin Teske	EOFARGS
6715bf5ca77SDevin Teske
6725bf5ca77SDevin Teske	N=$(( $MAX_ARGS + 1 ))
6735bf5ca77SDevin Teske	awk 'sub(/^\\\t/, "\t") || 1, $0 = "\t" $0' <<-EOFPROC
6745bf5ca77SDevin Teske	this->arg${P}_$N = this->ar_length > 0 ? "..." : "";
6755bf5ca77SDevin Teske	this->args$P = strjoin(this->args$P,
6765bf5ca77SDevin Teske	\	strjoin(this->arg${P}_$N != "" ? " " : "", this->arg${P}_$N));
6775bf5ca77SDevin Teske	EOFPROC
6785bf5ca77SDevin Teske}
6795bf5ca77SDevin Teske
6805bf5ca77SDevin Teskepproc_dump()
6815bf5ca77SDevin Teske{
6825bf5ca77SDevin Teske	local OPTIND=1 OPTARG flag
6835bf5ca77SDevin Teske	local verbose=
6845bf5ca77SDevin Teske
6855bf5ca77SDevin Teske	while getopts v flag; do
6865bf5ca77SDevin Teske		case "$flag" in
6875bf5ca77SDevin Teske		v) verbose=1 ;;
6885bf5ca77SDevin Teske		esac
6895bf5ca77SDevin Teske	done
6905bf5ca77SDevin Teske	shift $(( $OPTIND - 1 ))
6915bf5ca77SDevin Teske
6925bf5ca77SDevin Teske	local P=$1
6935bf5ca77SDevin Teske	if [ "$verbose" ]; then
6945bf5ca77SDevin Teske		awk -v P=$P '
6955bf5ca77SDevin Teske			BEGIN { printf "\t" }
6965bf5ca77SDevin Teske			NR > 1 && $0 { $0 = "\t" $0 }
6975bf5ca77SDevin Teske			buf = buf $0 "\n" { }
6985bf5ca77SDevin Teske			END {
6995bf5ca77SDevin Teske				$0 = buf
7005bf5ca77SDevin Teske				if (P < 3) S = sprintf("%" 7-2*(P+1) "s", "")
7015bf5ca77SDevin Teske				gsub(/S/, S)
7025bf5ca77SDevin Teske				gsub(/B/, P < 3 ? "\\" : "")
7035bf5ca77SDevin Teske				gsub(/\\\t/, "\t")
7045bf5ca77SDevin Teske				sub(/\n$/, "")
7055bf5ca77SDevin Teske				print
7065bf5ca77SDevin Teske			}
7075bf5ca77SDevin Teske		' <<-EOFPREAMBLE
7085bf5ca77SDevin Teske		printf(" SB-+= %05d %d.%d %s\n",
7095bf5ca77SDevin Teske		\	this->pid$P, this->uid$P, this->gid$P, this->args$P);
7105bf5ca77SDevin Teske		EOFPREAMBLE
7115bf5ca77SDevin Teske	else
7125bf5ca77SDevin Teske		cat <<-EOFPREAMBLE
7135bf5ca77SDevin Teske		printf("%s", this->args$P);
7145bf5ca77SDevin Teske		EOFPREAMBLE
7155bf5ca77SDevin Teske	fi
7165bf5ca77SDevin Teske}
7175bf5ca77SDevin Teske
7185bf5ca77SDevin Teske############################################################ MAIN
7195bf5ca77SDevin Teske
7205bf5ca77SDevin Teske# If we're running as root, no need for sudo(8)
7215bf5ca77SDevin Teske[ "$( id -u )" != 0 ] && type sudo > /dev/null 2>&1 && SUDO=sudo
7225bf5ca77SDevin Teske
7235bf5ca77SDevin Teske#
7245bf5ca77SDevin Teske# Process command-line options
7255bf5ca77SDevin Teske#
7265bf5ca77SDevin Teskewhile getopts 1B:deE:fFg:j:k:K:lmnN:o:O:p:PqQr:Rt:T:u:vVwxX:yz: flag; do
7275bf5ca77SDevin Teske	case "$flag" in
7285bf5ca77SDevin Teske	1) ONELINE=1 PSTREE= ;;
7295bf5ca77SDevin Teske	B) MAX_ARGS="$OPTARG" ;;
7305bf5ca77SDevin Teske	d) DEBUG=1 ;;
7315bf5ca77SDevin Teske	e) EXIT_AFTER_COMPILE=1 ;;
7325bf5ca77SDevin Teske	E) CUSTOM_DETAILS=1
7335bf5ca77SDevin Teske	   EVENT_DETAILS="${EVENT_DETAILS%;}"
7345bf5ca77SDevin Teske	   [ "$EVENT_DETAILS" ] && EVENT_DETAILS="$EVENT_DETAILS;
7355bf5ca77SDevin Teske		printf(\" \");
7365bf5ca77SDevin Teske		" # END-QUOTE
7375bf5ca77SDevin Teske	   # Read event code from stdin if `-' is argument
7385bf5ca77SDevin Teske	   [ "$OPTARG" = "-" ] && OPTARG=$( cat )
7395bf5ca77SDevin Teske	   EVENT_DETAILS="$EVENT_DETAILS$OPTARG" ;;
7405bf5ca77SDevin Teske	f) PROBE_TYPE=function ;;
7415bf5ca77SDevin Teske	F) PROBE_COALESCE=1 ;;
7425bf5ca77SDevin Teske	g) GROUP="$OPTARG" ;;
7435bf5ca77SDevin Teske	j) JID="$OPTARG" ;;
7445bf5ca77SDevin Teske	k) EXECNAME="$EXECNAME${EXECNAME:+ }$OPTARG"
7455bf5ca77SDevin Teske	   case "$OPTARG" in
7465bf5ca77SDevin Teske	   \**\*) name="${OPTARG%\*}"
7475bf5ca77SDevin Teske		predicate="strstr(execname, \"${name#\*}\") != NULL" ;;
7485bf5ca77SDevin Teske	   \**) name="${OPTARG#\*}"
7495bf5ca77SDevin Teske		predicate="strstr(execname, \"$name\") == (execname +"
7505bf5ca77SDevin Teske		predicate="$predicate strlen(execname) - ${#name})" ;;
7515bf5ca77SDevin Teske	   *\*) predicate="strstr(execname, \"${OPTARG%\*}\") == execname" ;;
7525bf5ca77SDevin Teske	   *) predicate="execname == \"$OPTARG\""
7535bf5ca77SDevin Teske	   esac
7545bf5ca77SDevin Teske	   EVENT_TEST="$predicate${EVENT_TEST:+ ||
7555bf5ca77SDevin Teske		($EVENT_TEST)}" ;;
7565bf5ca77SDevin Teske	K) MAX_DEPTH="$OPTARG" ;;
7575bf5ca77SDevin Teske	l) LIST=1 ;;
7585bf5ca77SDevin Teske	m) PROBE_TYPE=module ;;
7595bf5ca77SDevin Teske	n) PROBE_TYPE=name ;;
7605bf5ca77SDevin Teske	N) COUNT="$OPTARG" ;;
7615bf5ca77SDevin Teske	o) OUTPUT="$OPTARG" ;;
7625bf5ca77SDevin Teske	O) OUTPUT_CMD="$OPTARG" ;;
7635bf5ca77SDevin Teske	p) PID="$OPTARG" ;;
7645bf5ca77SDevin Teske	P) PROBE_TYPE=provider ;;
7655bf5ca77SDevin Teske	q) QUIET=1 ;;
7665bf5ca77SDevin Teske	Q) LIST_PROFILES=1 ;;
7675bf5ca77SDevin Teske	r) FILTER="$OPTARG" ;;
7685bf5ca77SDevin Teske	R) PSTREE=1 ;;
7695bf5ca77SDevin Teske	t) CUSTOM_TEST="${CUSTOM_TEST:+($CUSTOM_TEST) && }$OPTARG" ;;
7705bf5ca77SDevin Teske	T) TIMEOUT="$OPTARG" ;;
7715bf5ca77SDevin Teske	u) USER="$OPTARG" ;;
7725bf5ca77SDevin Teske	v) VERBOSE=1 ;;
7735bf5ca77SDevin Teske	V) vers="${VERSION#\$*[:\$]}"
7745bf5ca77SDevin Teske	   vers="${vers% \$}"
7755bf5ca77SDevin Teske	   printf "%s: %s\n" "$pgm" "${vers# }"
7765bf5ca77SDevin Teske	   exit ;;
7775bf5ca77SDevin Teske	w) DESTRUCTIVE_ACTIONS=1 ;;
7785bf5ca77SDevin Teske	x) TRACE=1 ;;
7795bf5ca77SDevin Teske	X) USE_PROFILE=1 PROFILE="$OPTARG" ;;
7805bf5ca77SDevin Teske	y) CONSOLE=1 CONSOLE_FORCE=1 ;;
7815bf5ca77SDevin Teske	z) EXECREGEX="$OPTARG" ;;
7825bf5ca77SDevin Teske	*) usage
7835bf5ca77SDevin Teske	   # NOTREACHED
7845bf5ca77SDevin Teske	esac
7855bf5ca77SDevin Teskedone
7865bf5ca77SDevin Teskeshift $(( $OPTIND - 1 ))
7875bf5ca77SDevin Teske
7885bf5ca77SDevin Teske#
7895bf5ca77SDevin Teske# List probes if `-l' was given
7905bf5ca77SDevin Teske#
7915bf5ca77SDevin Teske[ "$LIST" ] &&
7925bf5ca77SDevin Teske	list_probes -f "$FILTER" ${QUIET:+-q} -t "$PROBE_TYPE" -- "$@"
7935bf5ca77SDevin Teske	# NOTREACHED
7945bf5ca77SDevin Teske
7955bf5ca77SDevin Teske#
7965bf5ca77SDevin Teske# List profiles if `-Q' was given
7975bf5ca77SDevin Teske#
7985bf5ca77SDevin Teske[ "$LIST_PROFILES" ] &&
7995bf5ca77SDevin Teske	list_profiles ${ONELINE:+-1} -f "$FILTER" ${QUIET:+-q}
8005bf5ca77SDevin Teske	# NOTREACHED
8015bf5ca77SDevin Teske
8025bf5ca77SDevin Teske#
8035bf5ca77SDevin Teske# Validate number of arguments
8045bf5ca77SDevin Teske#
8055bf5ca77SDevin Teskeif [ ! "$PROFILE" ]; then
8065bf5ca77SDevin Teske	# If not given `-X profile' then a probe argument is required
8075bf5ca77SDevin Teske	[ $# -gt 0 ] || usage # NOTREACHED
8085bf5ca77SDevin Teskefi
8095bf5ca77SDevin Teske
8105bf5ca77SDevin Teske#
8115bf5ca77SDevin Teske# Validate `-N count' option argument
8125bf5ca77SDevin Teske#
8135bf5ca77SDevin Teskecase "$COUNT" in
8145bf5ca77SDevin Teske"") usage "-N option requires a number argument" ;; # NOTREACHED
8155bf5ca77SDevin Teske*[!0-9]*) usage "-N argument must be a number" ;; # NOTREACHED
8165bf5ca77SDevin Teskeesac
8175bf5ca77SDevin Teske
8185bf5ca77SDevin Teske#
8195bf5ca77SDevin Teske# Validate `-B num' option argument
8205bf5ca77SDevin Teske#
8215bf5ca77SDevin Teskecase "$MAX_ARGS" in
8225bf5ca77SDevin Teske"") usage "-B option requires a number argument" ;; # NOTREACHED
8235bf5ca77SDevin Teske*[!0-9]*) usage "-B argument must be a number" ;; # NOTREACHED
8245bf5ca77SDevin Teskeesac
8255bf5ca77SDevin Teske
8265bf5ca77SDevin Teske#
8275bf5ca77SDevin Teske# Validate `-K num' option argument
8285bf5ca77SDevin Teske#
8295bf5ca77SDevin Teskecase "$MAX_DEPTH" in
8305bf5ca77SDevin Teske"") usage "-K option requires a number argument" ;; # NOTREACHED
8315bf5ca77SDevin Teske*[!0-9]*) usage "-K argument must be a number" ;; # NOTREACHED
8325bf5ca77SDevin Teskeesac
8335bf5ca77SDevin Teske
8345bf5ca77SDevin Teske#
8355bf5ca77SDevin Teske# Validate `-j jail' option argument
8365bf5ca77SDevin Teske#
8375bf5ca77SDevin Teskecase "$JID" in
8385bf5ca77SDevin Teske"") : fall through ;;
8395bf5ca77SDevin Teske*[!0-9]*) JID=$( jls -j "$JID" jid ) || exit ;;
8405bf5ca77SDevin Teskeesac
8415bf5ca77SDevin Teske
8425bf5ca77SDevin Teske#
8435bf5ca77SDevin Teske# Validate `-u user' option argument
8445bf5ca77SDevin Teske#
8455bf5ca77SDevin Teskecase "$USER" in
8465bf5ca77SDevin Teske"") : fall through ;;
8475bf5ca77SDevin Teske*[![:alnum:]_-]*) RUID="$USER" ;;
8485bf5ca77SDevin Teske*[!0-9]*) RUID=$( id -u "$USER" 2> /dev/null ) || die "No such user: $USER" ;;
8495bf5ca77SDevin Teske*) RUID=$USER
8505bf5ca77SDevin Teskeesac
8515bf5ca77SDevin Teske
8525bf5ca77SDevin Teske#
8535bf5ca77SDevin Teske# Validate `-g group' option argument
8545bf5ca77SDevin Teske#
8555bf5ca77SDevin Teskecase "$GROUP" in
8565bf5ca77SDevin Teske"") : fall-through ;;
8575bf5ca77SDevin Teske*[![:alnum:]_-]*) RGID="$GROUP" ;;
8585bf5ca77SDevin Teske*[!0-9]*)
8595bf5ca77SDevin Teske	RGID=$( getent group | awk -F: -v group="$GROUP" '
8605bf5ca77SDevin Teske		$1 == group { print $3; exit found=1 }
8615bf5ca77SDevin Teske		END { exit !found }
8625bf5ca77SDevin Teske	' ) || die "No such group: $GROUP" ;;
8635bf5ca77SDevin Teske*) RGID=$GROUP
8645bf5ca77SDevin Teskeesac
8655bf5ca77SDevin Teske
8665bf5ca77SDevin Teske#
8675bf5ca77SDevin Teske# Expand probe argument into probe(s)
8685bf5ca77SDevin Teske#
8695bf5ca77SDevin Teskecase "$1" in
8705bf5ca77SDevin Teske-*) : Assume dtrace options such as "-c cmd" or "-p pid" ;; # No probe(s) given
8715bf5ca77SDevin Teske*)
8725bf5ca77SDevin Teske	PROBE_ARG="$1"
8735bf5ca77SDevin Teske	shift
8745bf5ca77SDevin Teskeesac
8755bf5ca77SDevin Teskeif [ "$PROBE_ARG" ]; then
8765bf5ca77SDevin Teske	oldIFS="$IFS"
8775bf5ca77SDevin Teske	IFS="$IFS,"
8785bf5ca77SDevin Teske	for arg in $PROBE_ARG; do
8795bf5ca77SDevin Teske		arg=$( expand_probe -t "$PROBE_TYPE" -- "$arg" )
8805bf5ca77SDevin Teske		PROBE="$PROBE${PROBE:+, }$arg"
8815bf5ca77SDevin Teske	done
8825bf5ca77SDevin Teske	IFS="$oldIFS"
8835bf5ca77SDevin Teskefi
8845bf5ca77SDevin Teske
8855bf5ca77SDevin Teske#
886bcce9a2bSDevin Teske# Developer switch
887bcce9a2bSDevin Teske#
888bcce9a2bSDevin Teske[ "$DEBUG" -a "$EXIT_AFTER_COMPILE" -a "$VERBOSE" ] && DEVELOPER=1 DEBUG=
889bcce9a2bSDevin Teske
890bcce9a2bSDevin Teske#
8915bf5ca77SDevin Teske# Set default event details if `-E code' was not given
8925bf5ca77SDevin Teske#
8935bf5ca77SDevin Teske[ "$CUSTOM_DETAILS" ] || EVENT_DETAILS=$( pproc_dump 0 )
8945bf5ca77SDevin Teske
8955bf5ca77SDevin Teske#
8965bf5ca77SDevin Teske# Load profile if given `-X profile'
8975bf5ca77SDevin Teske#
8985bf5ca77SDevin Teske[ "$USE_PROFILE" ] && load_profile "$PROFILE"
8995bf5ca77SDevin Teske[ "$PROBE" ] || die "PROBE not defined by profile and none given as argument"
9005bf5ca77SDevin Teske
9015bf5ca77SDevin Teske#
9025bf5ca77SDevin Teske# Show the user what's being watched
9035bf5ca77SDevin Teske#
9044a73674eSDevin Teske[ "$DEBUG$EXIT_AFTER_COMPILE" ] || info "Watching '$PROBE' ..."
9055bf5ca77SDevin Teske
9065bf5ca77SDevin Teske#
9075bf5ca77SDevin Teske# Header for watched probe entry
9085bf5ca77SDevin Teske#
9095bf5ca77SDevin Teskecase "$PROBE" in
9105bf5ca77SDevin Teske*,*) : fall-through ;;
9115bf5ca77SDevin Teske*:execve:entry|execve:entry)
9125bf5ca77SDevin Teske	ACTIONS=$( awk 'gsub(/\\\t/, "\t") || 1' <<-EOF
9135bf5ca77SDevin Teske		$PROBE /* probe ID $ID */
9145bf5ca77SDevin Teske		{${TRACE:+
9155bf5ca77SDevin Teske		\	printf("<$ID>");}
9165bf5ca77SDevin Teske		\	this->caller_execname = execname;
9175bf5ca77SDevin Teske		}
9185bf5ca77SDevin Teske		EOF
9195bf5ca77SDevin Teske	)
9205bf5ca77SDevin Teske	PROBE="${PROBE%entry}return"
9215bf5ca77SDevin Teske	ID=$(( $ID + 1 ))
9225bf5ca77SDevin Teske	EVENT_TEST="execname != this->caller_execname${EVENT_TEST:+ &&
9235bf5ca77SDevin Teske		($EVENT_TEST)}"
9245bf5ca77SDevin Teske	EVENT_TAG='printf("%d.%d %s[%d]: ",
9255bf5ca77SDevin Teske		this->uid1, this->gid1, this->caller_execname, this->pid1);'
9265bf5ca77SDevin Teske	;;
9275bf5ca77SDevin Teskeesac
9285bf5ca77SDevin Teske
9295bf5ca77SDevin Teske#
9305bf5ca77SDevin Teske# Jail clause/predicate
9315bf5ca77SDevin Teske#
9325bf5ca77SDevin Teskeif [ "$JID" ]; then
9335bf5ca77SDevin Teske	prison_id="curthread->td_proc->p_ucred->cr_prison->pr_id"
9345bf5ca77SDevin Teske	EVENT_TEST="$prison_id == $JID${EVENT_TEST:+ &&
9355bf5ca77SDevin Teske		($EVENT_TEST)}"
9365bf5ca77SDevin Teskefi
9375bf5ca77SDevin Teske
9385bf5ca77SDevin Teske#
9395bf5ca77SDevin Teske# Custom test clause/predicate
9405bf5ca77SDevin Teske#
9415bf5ca77SDevin Teskeif [ "$CUSTOM_TEST" ]; then
9425bf5ca77SDevin Teske	case "$EVENT_TEST" in
9435bf5ca77SDevin Teske	"") EVENT_TEST="$CUSTOM_TEST" ;;
9445bf5ca77SDevin Teske	 *) EVENT_TEST="$EVENT_TEST &&
9455bf5ca77SDevin Teske		($CUSTOM_TEST)"
9465bf5ca77SDevin Teske	esac
9475bf5ca77SDevin Teskefi
9485bf5ca77SDevin Teske
9495bf5ca77SDevin Teske#
9505bf5ca77SDevin Teske# Make sure dynamic code has trailing semi-colons if non-NULL
9515bf5ca77SDevin Teske#
9525bf5ca77SDevin TeskeEVENT_TAG="${EVENT_TAG%;}${EVENT_TAG:+;}"
9535bf5ca77SDevin TeskeEVENT_DETAILS="${EVENT_DETAILS%;}${EVENT_DETAILS:+;}"
9545bf5ca77SDevin Teske
9555bf5ca77SDevin Teske#
9565bf5ca77SDevin Teske# DTrace script
9575bf5ca77SDevin Teske#
9585bf5ca77SDevin Teske# If `-d' is given, script is sent to stdout for debugging
9595bf5ca77SDevin Teske# If `-c count", `-g group', `-r regex', or `-u user' is given, run script with
9605bf5ca77SDevin Teske# dtrace and send output to awk(1) post-processor (making sure to preserve the
9615bf5ca77SDevin Teske# exit code returned by dtrace invocation). Otherwise, simply run script with
9625bf5ca77SDevin Teske# dtrace and then exit.
9635bf5ca77SDevin Teske#
9645bf5ca77SDevin Teskeexec 9<<EOF
9655bf5ca77SDevin Teske$PROBE /* probe ID 2 */
9665bf5ca77SDevin Teske{${TRACE:+
9675bf5ca77SDevin Teske	printf("<2>");
9685bf5ca77SDevin Teske}
9695bf5ca77SDevin Teske	/*
9705bf5ca77SDevin Teske	 * Examine process, parent process, and grandparent process details
9715bf5ca77SDevin Teske	 */
9725bf5ca77SDevin Teske
9735bf5ca77SDevin Teske	/******************* CURPROC *******************/
9745bf5ca77SDevin Teske
9755bf5ca77SDevin Teske	$( pproc -P0 )
9765bf5ca77SDevin Teske
9775bf5ca77SDevin Teske	/******************* PPARENT *******************/
9785bf5ca77SDevin Teske
9795bf5ca77SDevin Teske	$( if [ "$PSTREE" ]; then pproc -P1; else echo -n \
9805bf5ca77SDevin Teske	"this->proc = this->proc ? this->proc->p_pptr : NULL;
9815bf5ca77SDevin Teske	this->pid1 = this->proc ? this->proc->p_pid : -1;
9825bf5ca77SDevin Teske	this->uid1 = this->proc ? this->proc->p_ucred->cr_uid : -1;
9835bf5ca77SDevin Teske	this->gid1 = this->proc ? this->proc->p_ucred->cr_rgid : -1;
9845bf5ca77SDevin Teske	this->jid1 = this->proc ? this->proc->p_ucred->cr_prison->pr_id : -1;"
9855bf5ca77SDevin Teske	fi )
9865bf5ca77SDevin Teske
9875bf5ca77SDevin Teske	/******************* GPARENT *******************/
9885bf5ca77SDevin Teske
9895bf5ca77SDevin Teske	$( [ "$PSTREE" ] && pproc -P2 )
9905bf5ca77SDevin Teske
9915bf5ca77SDevin Teske	/******************* APARENT *******************/
9925bf5ca77SDevin Teske
9935bf5ca77SDevin Teske	$( [ "$PSTREE" ] && pproc -P3 )
9945bf5ca77SDevin Teske}
9955bf5ca77SDevin TeskeEOF
9965bf5ca77SDevin TeskePSARGS_ACTION=$( cat <&9 )
9975bf5ca77SDevin Teske[ "$OUTPUT" -a ! "$CONSOLE_FORCE" ] && CONSOLE=
9985bf5ca77SDevin Teske{
9995bf5ca77SDevin Teske	if [ "$DEBUG" ]; then
10005bf5ca77SDevin Teske		# Send script to stdout
10015bf5ca77SDevin Teske		cat
10025bf5ca77SDevin Teske		exit
10035bf5ca77SDevin Teske	fi
10045bf5ca77SDevin Teske
10055bf5ca77SDevin Teske	if [ "$CUSTOM_TEST$EXECNAME$JID$OUTPUT$TIMEOUT$TRACE$VERBOSE" -a \
10065bf5ca77SDevin Teske	    ! "$QUIET" ]
10075bf5ca77SDevin Teske	then
10085bf5ca77SDevin Teske		msg=Setting
10095bf5ca77SDevin Teske		[ "$CUSTOM_TEST" ] && msg="$msg test: $CUSTOM_TEST"
10105bf5ca77SDevin Teske		[ "$EXECNAME" ] && msg="$msg execname: $EXECNAME"
10115bf5ca77SDevin Teske		[ "$JID" ] && msg="$msg jid: $JID"
10125bf5ca77SDevin Teske		[ "$OUTPUT" ] && msg="$msg output: $OUTPUT"
10135bf5ca77SDevin Teske		[ "$TIMEOUT" ] && msg="$msg timeout: $TIMEOUT"
10145bf5ca77SDevin Teske		[ "$TRACE" ] && msg="$msg trace: $TRACE"
10155bf5ca77SDevin Teske		[ "$VERBOSE" ] && msg="$msg verbose: $VERBOSE"
10165bf5ca77SDevin Teske		info "$msg"
10175bf5ca77SDevin Teske	fi
10185bf5ca77SDevin Teske
10195bf5ca77SDevin Teske	exec 3>&1
10205bf5ca77SDevin Teske	console_stdout=3
10215bf5ca77SDevin Teske
1022bcce9a2bSDevin Teske	#
1023bcce9a2bSDevin Teske	# Developer debugging aide
1024bcce9a2bSDevin Teske	#
1025bcce9a2bSDevin Teske	if [ "$DEVELOPER" ]; then
1026bcce9a2bSDevin Teske		#
1027bcce9a2bSDevin Teske		# Run, capture the error line, and focus it
1028bcce9a2bSDevin Teske		#
1029bcce9a2bSDevin Teske		# Example error text to capture line number from:
1030bcce9a2bSDevin Teske		# 	dtrace: failed to compile script /dev/stdin: line 669: ...
1031bcce9a2bSDevin Teske		#
1032bcce9a2bSDevin Teske		errline=
1033bcce9a2bSDevin Teske		stdin_buf=$( cat )
1034bcce9a2bSDevin Teske		stderr_buf=$( echo "$stdin_buf" |
1035bcce9a2bSDevin Teske			dtrace_cmd -t -es /dev/stdin "$@" 2>&1 > /dev/null )
1036bcce9a2bSDevin Teske		status=$?
1037bcce9a2bSDevin Teske		if [ "$stderr_buf" ]; then
1038bcce9a2bSDevin Teske			errline=$( echo "$stderr_buf" | awk '
1039bcce9a2bSDevin Teske				BEGIN {
1040bcce9a2bSDevin Teske					ti = "\033[31m"
1041bcce9a2bSDevin Teske					te = "\033[39m"
1042bcce9a2bSDevin Teske				}
1043bcce9a2bSDevin Teske				{ line = $0 }
1044bcce9a2bSDevin Teske				sub(/.*: line /, "") && sub(/:.*/, "") {
1045bcce9a2bSDevin Teske					print # to errline
1046bcce9a2bSDevin Teske					sub("line " $0, ti "&" te, line)
1047bcce9a2bSDevin Teske				}
1048bcce9a2bSDevin Teske				{ print line > "/dev/stderr" }
1049bcce9a2bSDevin Teske			' 2>&3 )
1050bcce9a2bSDevin Teske		fi
1051bcce9a2bSDevin Teske		if  [ "$errline" ]; then
1052bcce9a2bSDevin Teske			echo "$stdin_buf" | awk -v line="${errline%%[^0-9]*}" '
1053bcce9a2bSDevin Teske				BEGIN {
1054bcce9a2bSDevin Teske					start = line < 10 ? 1 : line - 10
1055bcce9a2bSDevin Teske					end = line + 10
1056bcce9a2bSDevin Teske					slen = length(sprintf("%u", start))
1057bcce9a2bSDevin Teske					elen = length(sprintf("%u", end))
1058bcce9a2bSDevin Teske					N = elen > slen ? elen : slen
1059bcce9a2bSDevin Teske					ti[line] = "\033[31m"
1060bcce9a2bSDevin Teske					te[line] = "\033[39m"
1061bcce9a2bSDevin Teske					fmt = "%s%*u %s%s\n"
1062bcce9a2bSDevin Teske				}
1063bcce9a2bSDevin Teske				NR < start { next }
1064bcce9a2bSDevin Teske				NR == start, NR == end {
1065bcce9a2bSDevin Teske					printf(fmt, ti[NR], N, NR, $0, te[NR])
1066bcce9a2bSDevin Teske				}
1067bcce9a2bSDevin Teske				NR > end { exit }
1068bcce9a2bSDevin Teske			' # END-QUOTE
1069bcce9a2bSDevin Teske		fi
1070bcce9a2bSDevin Teske		exit $status
1071bcce9a2bSDevin Teske	fi
1072bcce9a2bSDevin Teske
10735bf5ca77SDevin Teske	if [ $COUNT -eq 0 -a ! "$EXECREGEX$FILTER$GROUP$OUTPUT_CMD$PID$USER" ]
10745bf5ca77SDevin Teske	then
10755bf5ca77SDevin Teske		case "$OUTPUT" in
10765bf5ca77SDevin Teske		-) output_path=/dev/stdout ;;
10775bf5ca77SDevin Teske		*) output_path="$OUTPUT"
10785bf5ca77SDevin Teske		esac
10795bf5ca77SDevin Teske
10805bf5ca77SDevin Teske		# Run script without pipe to awk post-processor
10815bf5ca77SDevin Teske		dtrace_cmd -t \
10825bf5ca77SDevin Teske			${DESTRUCTIVE_ACTIONS:+-w} \
10835bf5ca77SDevin Teske			${EXIT_AFTER_COMPILE:+-e} \
10845bf5ca77SDevin Teske			${OUTPUT:+-o "$output_path"} \
10855bf5ca77SDevin Teske			-s /dev/stdin \
10865bf5ca77SDevin Teske			"$@"
10875bf5ca77SDevin Teske		exit
10885bf5ca77SDevin Teske	fi
10895bf5ca77SDevin Teske
10905bf5ca77SDevin Teske	# Prevent backslashes from being lost
10915bf5ca77SDevin Teske	FILTER=$( echo "$FILTER" | awk 'gsub(/\\/,"&&")||1' )
10925bf5ca77SDevin Teske	EXECREGEX=$( echo "$EXECREGEX" | awk 'gsub(/\\/,"&&")||1' )
10935bf5ca77SDevin Teske
10945bf5ca77SDevin Teske	if [ ! "$QUIET" ]; then
10955bf5ca77SDevin Teske		msg=Filtering
10965bf5ca77SDevin Teske		[ "$EXECREGEX" ] && msg="$msg execregex: $EXECREGEX"
10975bf5ca77SDevin Teske		[ "$FILTER" ] && msg="$msg filter: $FILTER"
10985bf5ca77SDevin Teske		[ "$GROUP" ] && msg="$msg group: $GROUP"
10995bf5ca77SDevin Teske		[ "$OUTPUT_CMD" ] && msg="$msg cmd: $OUTPUT_CMD"
11005bf5ca77SDevin Teske		[ "$PID" ] && msg="$msg pid: $PID"
11015bf5ca77SDevin Teske		[ "$USER" ] && msg="$msg user: $USER"
11025bf5ca77SDevin Teske		[ $COUNT -gt 0 ] && msg="$msg count: $COUNT"
11035bf5ca77SDevin Teske		info "$msg"
11045bf5ca77SDevin Teske	fi
11055bf5ca77SDevin Teske
11065bf5ca77SDevin Teske	#
11075bf5ca77SDevin Teske	# Send script output to post-processor for filtering
11085bf5ca77SDevin Teske	#
11095bf5ca77SDevin Teske	status=$(
11105bf5ca77SDevin Teske		exec 4>&1
11115bf5ca77SDevin Teske		to_status=4
11125bf5ca77SDevin Teske		( exec 5>&1; to_dtrace_stderr_filter=5; (
11135bf5ca77SDevin Teske			trap 'echo $? >&$to_status' EXIT
11145bf5ca77SDevin Teske			eval $SUDO ${TIMEOUT:+timeout \"\$TIMEOUT\"} dtrace \
11155bf5ca77SDevin Teske				${EXIT_AFTER_COMPILE:+-e} \
11165bf5ca77SDevin Teske				${DESTRUCTIVE_ACTIONS:+-w} \
11175bf5ca77SDevin Teske				-s /dev/stdin \
11185bf5ca77SDevin Teske				\"\$@\" \
11195bf5ca77SDevin Teske				2>&$to_dtrace_stderr_filter \
11205bf5ca77SDevin Teske				${QUIET:+2> /dev/null}
11215bf5ca77SDevin Teske		) | $SUDO awk \
11225bf5ca77SDevin Teske			-v cmd="$OUTPUT_CMD" \
11235bf5ca77SDevin Teske			-v console="$CONSOLE" \
11245bf5ca77SDevin Teske			-v count=$COUNT \
11255bf5ca77SDevin Teske			-v execregex="$EXECREGEX" \
11265bf5ca77SDevin Teske			-v filter="$FILTER" \
11275bf5ca77SDevin Teske			-v gid="$RGID" \
11285bf5ca77SDevin Teske			-v output="$OUTPUT" \
11295bf5ca77SDevin Teske			-v pid="$PID" \
11305bf5ca77SDevin Teske			-v pstree=$PSTREE \
11315bf5ca77SDevin Teske			-v quiet=$QUIET \
11325bf5ca77SDevin Teske			-v tty=$( ps -o tty= -p $$ ) \
11335bf5ca77SDevin Teske			-v uid="$RUID" \
11345bf5ca77SDevin Teske		' # Start awk(1) post-processor
11355bf5ca77SDevin Teske		############################################ BEGIN
11365bf5ca77SDevin Teske		BEGIN {
11375bf5ca77SDevin Teske			true = 1
11385bf5ca77SDevin Teske			ansi = "(\\033\\[[[:digit:];]+m)?"
11395bf5ca77SDevin Teske			num = year = day = "[[:digit:]]+"
11405bf5ca77SDevin Teske			month = "[[:alpha:]]+"
11415bf5ca77SDevin Teske			date = year " " month " +" day
11425bf5ca77SDevin Teske			time = "[012][0-9]:[0-5][0-9]:[0-5][0-9]"
11435bf5ca77SDevin Teske			date_time = ansi date " +" time ansi
11445bf5ca77SDevin Teske			name1 = "[^\\[]*"
11455bf5ca77SDevin Teske			name2 = "[^\\n]*"
11465bf5ca77SDevin Teske			if (output == "-")
11475bf5ca77SDevin Teske				output = "/dev/stdout"
11485bf5ca77SDevin Teske
11495bf5ca77SDevin Teske			#
11505bf5ca77SDevin Teske			# Field definitions
11515bf5ca77SDevin Teske			#
11525bf5ca77SDevin Teske			nexecmatches = 2
11535bf5ca77SDevin Teske			execstart[1] = sprintf( \
11545bf5ca77SDevin Teske				"^(%s) (%s)\\.(%s) (%s)\\[(%s)\\]: ",
11555bf5ca77SDevin Teske				date_time, num, num, name1, num)
11565bf5ca77SDevin Teske			execstart[2] = sprintf( \
11575bf5ca77SDevin Teske				"\\n +\\\\?-\\+= (%s) (%s)\\.(%s) ",
11585bf5ca77SDevin Teske				num, num, num)
11595bf5ca77SDevin Teske			npidmatches = 2
11605bf5ca77SDevin Teske			pidstart[1] = sprintf("^(%s) (%s)\\.(%s) (%s)\\[",
11615bf5ca77SDevin Teske				date_time, num, num, name1)
11625bf5ca77SDevin Teske			pidstart[2] = "\\n +\\\\?-\\+= "
11635bf5ca77SDevin Teske			pidpreen[2] = "^0*"
11645bf5ca77SDevin Teske			piddeflt[2] = "0"
11655bf5ca77SDevin Teske			ngidmatches = 2
11665bf5ca77SDevin Teske			gidstart[1] = sprintf("^(%s) (%s)\\.", date_time, num)
11675bf5ca77SDevin Teske			gidstart[2] = sprintf("\\n +\\\\?-\\+= (%s) (%s)\\.",
11685bf5ca77SDevin Teske				ansi num ansi, num)
11695bf5ca77SDevin Teske			nuidmatches = 2
11705bf5ca77SDevin Teske			uidstart[1] = sprintf("^(%s) ", date_time)
11715bf5ca77SDevin Teske			uidstart[2] = sprintf("\\n +\\\\?-\\+= (%s) ",
11725bf5ca77SDevin Teske				ansi num ansi)
11735bf5ca77SDevin Teske		}
11745bf5ca77SDevin Teske		############################################ FUNCTIONS
11755bf5ca77SDevin Teske		function strip(s) { gsub(/\033\[[0-9;]*m/, "", s); return s }
11765bf5ca77SDevin Teske		function esc(str) { gsub(/'\''/, "&\\\\&&", str); return str }
11775bf5ca77SDevin Teske		function arg(str) { return "'\''" esc(str) "'\''" }
11785bf5ca77SDevin Teske		function env(var, str) { return var "=" arg(str) " " }
11795bf5ca77SDevin Teske		function ans(seq) { return console ? "\033[" seq "m" : "" }
11805bf5ca77SDevin Teske		function runcmd() {
11815bf5ca77SDevin Teske			return system(sprintf("%s/bin/sh -c %s",
11825bf5ca77SDevin Teske				env("TAG", strip(tag)) \
11835bf5ca77SDevin Teske					env("DETAILS", strip(details)),
11845bf5ca77SDevin Teske				arg(cmd)))
11855bf5ca77SDevin Teske		}
11865bf5ca77SDevin Teske		function filter_block() {
11875bf5ca77SDevin Teske			if (length(lines) < 1) return 0
11885bf5ca77SDevin Teske			block_match = 0
11895bf5ca77SDevin Teske			newstr = ""
11905bf5ca77SDevin Teske			start = 1
11915bf5ca77SDevin Teske			if (match(lines, "^(" date_time ") ")) {
11925bf5ca77SDevin Teske				newstr = newstr substr(lines, 1,
11935bf5ca77SDevin Teske					RSTART + RLENGTH - 1)
11945bf5ca77SDevin Teske				start = RSTART + RLENGTH
11955bf5ca77SDevin Teske			}
11965bf5ca77SDevin Teske			replace = ans("31;1") "&" ans("39;22")
11975bf5ca77SDevin Teske			workstr = substr(lines, start)
11985bf5ca77SDevin Teske			if (gsub(filter, replace, workstr)) block_match = 1
11995bf5ca77SDevin Teske			lines = newstr workstr
12005bf5ca77SDevin Teske			return block_match
12015bf5ca77SDevin Teske		}
12025bf5ca77SDevin Teske		function filter_field(startre, fieldre, matchre, isword,
12035bf5ca77SDevin Teske			preenre, defaultstr)
12045bf5ca77SDevin Teske		{
12055bf5ca77SDevin Teske			if (length(lines) < 1) return 0
12065bf5ca77SDevin Teske			field_match = 0
12075bf5ca77SDevin Teske			newstr = ""
12085bf5ca77SDevin Teske			start = 1
12095bf5ca77SDevin Teske			while ((workstr = substr(lines, start)) &&
12105bf5ca77SDevin Teske				(workstr ~ (startre fieldre)))
12115bf5ca77SDevin Teske			{
12125bf5ca77SDevin Teske				match(workstr, startre)
12135bf5ca77SDevin Teske				start += end = RSTART + RLENGTH - 1
12145bf5ca77SDevin Teske				newstr = newstr substr(workstr, 1, end)
12155bf5ca77SDevin Teske				workstr = substr(workstr, end + 1)
12165bf5ca77SDevin Teske				match(workstr, fieldre)
12175bf5ca77SDevin Teske				start += end = RSTART + RLENGTH - 1
12185bf5ca77SDevin Teske				field = matchstr = substr(workstr, 1, end)
12195bf5ca77SDevin Teske				sub(preenre, "", matchstr)
12205bf5ca77SDevin Teske				if (!matchstr) matchstr = defaultstr
12215bf5ca77SDevin Teske				if (isword) {
12225bf5ca77SDevin Teske					if (match(matchstr, matchre) &&
12235bf5ca77SDevin Teske						RSTART == 1 &&
12245bf5ca77SDevin Teske						RLENGTH == length(matchstr)) {
12255bf5ca77SDevin Teske						field_match = 1
12265bf5ca77SDevin Teske						field = ans(7) field ans(27)
12275bf5ca77SDevin Teske					}
12285bf5ca77SDevin Teske				} else {
12295bf5ca77SDevin Teske					replace = ans(7) "&" ans(27)
12305bf5ca77SDevin Teske					if (gsub(matchre, replace, matchstr)) {
12315bf5ca77SDevin Teske						field_match = 1
12325bf5ca77SDevin Teske						field = matchstr
12335bf5ca77SDevin Teske					}
12345bf5ca77SDevin Teske				}
12355bf5ca77SDevin Teske				newstr = newstr field
12365bf5ca77SDevin Teske			}
12375bf5ca77SDevin Teske			lines = newstr workstr
12385bf5ca77SDevin Teske			return field_match
12395bf5ca77SDevin Teske		}
12405bf5ca77SDevin Teske		function dump() {
12415bf5ca77SDevin Teske			lines = block
12425bf5ca77SDevin Teske			block = ""
12435bf5ca77SDevin Teske			found = 0
12445bf5ca77SDevin Teske			if (execregex != "") {
12455bf5ca77SDevin Teske				for (n = 1; n <= nexecmatches; n++)
12465bf5ca77SDevin Teske					if (filter_field(execstart[n], name2,
12475bf5ca77SDevin Teske						execregex)) found = 1
12485bf5ca77SDevin Teske				if (!found) return
12495bf5ca77SDevin Teske			}
12505bf5ca77SDevin Teske			if (pid != "") {
12515bf5ca77SDevin Teske				for (n = 1; n <= npidmatches; n++)
12525bf5ca77SDevin Teske					if (filter_field(pidstart[n], num, pid,
12535bf5ca77SDevin Teske						true, pidpreen[n],
12545bf5ca77SDevin Teske						piddeflt[n])) found = 1
12555bf5ca77SDevin Teske				if (!found) return
12565bf5ca77SDevin Teske			}
12575bf5ca77SDevin Teske			if (gid != "") {
12585bf5ca77SDevin Teske				for (n = 1; n <= ngidmatches; n++)
12595bf5ca77SDevin Teske					if (filter_field(gidstart[n], num,
12605bf5ca77SDevin Teske						gid, true)) found = 1
12615bf5ca77SDevin Teske				if (!found) return
12625bf5ca77SDevin Teske			}
12635bf5ca77SDevin Teske			if (uid != "") {
12645bf5ca77SDevin Teske				for (n = 1; n <= nuidmatches; n++)
12655bf5ca77SDevin Teske					if (filter_field(uidstart[n], num,
12665bf5ca77SDevin Teske						uid, true)) found = 1
12675bf5ca77SDevin Teske				if (!found) return
12685bf5ca77SDevin Teske			}
12695bf5ca77SDevin Teske			if (filter != "" && !filter_block()) return
12705bf5ca77SDevin Teske			if (lines) {
12715bf5ca77SDevin Teske				stdout = 1
12725bf5ca77SDevin Teske				if (output) {
12735bf5ca77SDevin Teske					stdout = 0
12745bf5ca77SDevin Teske					if (!console) lines = strip(lines)
12755bf5ca77SDevin Teske					print lines > output
12765bf5ca77SDevin Teske				} else if (cmd) {
12775bf5ca77SDevin Teske					if (!quiet) print lines
12785bf5ca77SDevin Teske					tag = details = lines
12795bf5ca77SDevin Teske					sub(/: .*/, "", tag)
12805bf5ca77SDevin Teske					sub(/.*: /, "", details)
12815bf5ca77SDevin Teske					if (!console) tag = strip(tag)
12825bf5ca77SDevin Teske					runcmd()
12835bf5ca77SDevin Teske				} else print lines
12845bf5ca77SDevin Teske			}
12855bf5ca77SDevin Teske			fflush()
12865bf5ca77SDevin Teske			++matches
12875bf5ca77SDevin Teske		}
12885bf5ca77SDevin Teske		############################################ MAIN
12895bf5ca77SDevin Teske		{ block = (block ? block "\n" : block) $0 }
12905bf5ca77SDevin Teske		!pstree { dump() }
12915bf5ca77SDevin Teske		$0 ~ sprintf("^%6s\\\\-\\+= %s ", "", num) { dump() }
12925bf5ca77SDevin Teske		count && matches >= count { exit }
12935bf5ca77SDevin Teske		############################################ END
12945bf5ca77SDevin Teske		END {
12955bf5ca77SDevin Teske			dump()
12965bf5ca77SDevin Teske			system(sprintf("pkill -t %s dtrace %s", tty,
12975bf5ca77SDevin Teske				quiet ? "2> /dev/null" : ""))
12985bf5ca77SDevin Teske		}
12995bf5ca77SDevin Teske		' >&$console_stdout ) | dtrace_stderr_filter >&2
13005bf5ca77SDevin Teske	) # status
13015bf5ca77SDevin Teske	exit $status
13025bf5ca77SDevin Teske
13035bf5ca77SDevin Teske} <<EOF
13045bf5ca77SDevin Teske#!/usr/sbin/dtrace -s
13055bf5ca77SDevin Teske/* -
13065bf5ca77SDevin Teske * Copyright (c) 2014-2018 Devin Teske <dteske@FreeBSD.org>
13075bf5ca77SDevin Teske * All rights reserved.
13085bf5ca77SDevin Teske * Redistribution and use in source and binary forms, with or without
13095bf5ca77SDevin Teske * modification, are permitted provided that the following conditions
13105bf5ca77SDevin Teske * are met:
13115bf5ca77SDevin Teske * 1. Redistributions of source code must retain the above copyright
13125bf5ca77SDevin Teske *    notice, this list of conditions and the following disclaimer.
13135bf5ca77SDevin Teske * 2. Redistributions in binary form must reproduce the above copyright
13145bf5ca77SDevin Teske *    notice, this list of conditions and the following disclaimer in the
13155bf5ca77SDevin Teske *    documentation and/or other materials provided with the distribution.
13165bf5ca77SDevin Teske *
13175bf5ca77SDevin Teske * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS \`\`AS IS'' AND
13185bf5ca77SDevin Teske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13195bf5ca77SDevin Teske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13205bf5ca77SDevin Teske * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
13215bf5ca77SDevin Teske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13225bf5ca77SDevin Teske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13235bf5ca77SDevin Teske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13245bf5ca77SDevin Teske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13255bf5ca77SDevin Teske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13265bf5ca77SDevin Teske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13275bf5ca77SDevin Teske * SUCH DAMAGE.
13285bf5ca77SDevin Teske *
13295bf5ca77SDevin Teske * $TITLE dtrace(1) script to log process(es) triggering $PROBE $
13305bf5ca77SDevin Teske */
13315bf5ca77SDevin Teske
13325bf5ca77SDevin Teske$( echo "$DTRACE_PRAGMA" | awk '
13335bf5ca77SDevin Teske	!/^[[:space:]]*(#|$)/, sub(/^[[:space:]]*/, "#pragma D ")||1
13345bf5ca77SDevin Teske' )
13355bf5ca77SDevin Teske
13365bf5ca77SDevin Teskeint console;
13375bf5ca77SDevin Teske
13385bf5ca77SDevin Teskedtrace:::BEGIN { console = ${CONSOLE:-0} } /* probe ID 1 */
13395bf5ca77SDevin Teske
13405bf5ca77SDevin Teske/*********************************************************/
13415bf5ca77SDevin Teske
13425bf5ca77SDevin Teske${PSARGS:+$PSARGS_ACTION}
13435bf5ca77SDevin Teske${ACTIONS:+
13445bf5ca77SDevin Teske/*********************************************************/
13455bf5ca77SDevin Teske
13465bf5ca77SDevin Teske$ACTIONS
13475bf5ca77SDevin Teske}
13485bf5ca77SDevin Teske/*********************************************************/
13495bf5ca77SDevin Teske
13505bf5ca77SDevin Teske$PROBE${EVENT_TEST:+ / $EVENT_TEST /} /* probe ID $ID */
13515bf5ca77SDevin Teske{${TRACE:+
13525bf5ca77SDevin Teske	printf("<$ID>");
13535bf5ca77SDevin Teske}
13545bf5ca77SDevin Teske	/***********************************************/
13555bf5ca77SDevin Teske
13565bf5ca77SDevin Teske	printf("%s%Y%s ",
13575bf5ca77SDevin Teske		console ? "\033[32m" : "",
13585bf5ca77SDevin Teske		walltimestamp,
13595bf5ca77SDevin Teske		console ? "\033[39m" : "");
13605bf5ca77SDevin Teske
13615bf5ca77SDevin Teske	/****************** EVENT_TAG ******************/
13625bf5ca77SDevin Teske
13635bf5ca77SDevin Teske	${EVENT_TAG#[[:space:]]}
13645bf5ca77SDevin Teske${PROBE_COALESCE:+
13655bf5ca77SDevin Teske	/**************** PROBE_COALESCE ***************/
13665bf5ca77SDevin Teske
13675bf5ca77SDevin Teske	printf("%s%s:%s:%s:%s ", probename == "entry" ? "-> " :
13685bf5ca77SDevin Teske			probename == "return" ? "<- " :
13695bf5ca77SDevin Teske			probename == "start" ? "-> " :
13705bf5ca77SDevin Teske			probename == "done" ? "<- " : " | ",
13715bf5ca77SDevin Teske		probeprov, probemod, probefunc, probename);
13725bf5ca77SDevin Teske}
13735bf5ca77SDevin Teske	/**************** EVENT_DETAILS ****************/
13745bf5ca77SDevin Teske
13755bf5ca77SDevin Teske	${EVENT_DETAILS#[[:space:]]}
13765bf5ca77SDevin Teske
13775bf5ca77SDevin Teske	/***********************************************/
13785bf5ca77SDevin Teske
13795bf5ca77SDevin Teske	printf("\\n");
13805bf5ca77SDevin Teske${PSTREE:+
13815bf5ca77SDevin Teske	/*
13825bf5ca77SDevin Teske	 * Print process, parent, grandparent, and ancestor details
13835bf5ca77SDevin Teske	 */
13845bf5ca77SDevin Teske$(	pproc_dump -v 3
13855bf5ca77SDevin Teske	pproc_dump -v 2
13865bf5ca77SDevin Teske	pproc_dump -v 1
13875bf5ca77SDevin Teske	pproc_dump -v 0
13885bf5ca77SDevin Teske)}
13895bf5ca77SDevin Teske}
13905bf5ca77SDevin TeskeEOF
1391bcce9a2bSDevin Teske# NOTREACHED
13925bf5ca77SDevin Teske
13935bf5ca77SDevin Teske################################################################################
13945bf5ca77SDevin Teske# END
13955bf5ca77SDevin Teske################################################################################
1396