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