Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144544527
D10006.id29314.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
110 KB
Referenced Files
None
Subscribers
None
D10006.id29314.diff
View Options
Index: ObsoleteFiles.inc
===================================================================
--- ObsoleteFiles.inc
+++ ObsoleteFiles.inc
@@ -38,6 +38,10 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20170418: remove DTrace scripts made obsolete by dwatch(8)
+OLD_FILES+=usr/share/dtrace/watch_execve
+OLD_FILES+=usr/share/dtrace/watch_kill
+OLD_FILES+=usr/share/dtrace/watch_vop_remove
# 20170531: removal of groff
OLD_FILES+=usr/bin/addftinfo
OLD_FILES+=usr/bin/afmtodit
Index: cddl/usr.sbin/dwatch/Makefile
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+SUBDIR= libexec
+
+.if ${MK_EXAMPLES} != "no"
+SUBDIR+= examples
+.endif
+
+SCRIPTS= dwatch
+
+MAN= dwatch.1
+
+.include <bsd.prog.mk>
Index: cddl/usr.sbin/dwatch/dwatch
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/dwatch
@@ -0,0 +1,1100 @@
+#!/bin/sh
+#-
+# Copyright (c) 2014-2017 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+############################################################ IDENT(1)
+#
+# $Title: Watch processes as they trigger a particular DTrace probe $
+# $FreeBSD$
+#
+############################################################ CONFIGURATION
+
+#
+# DTrace pragma settings
+#
+DTRACE_PRAGMA="
+ option quiet
+ option dynvarsize=16m
+ option switchrate=10hz
+" # END-QUOTE
+
+#
+# Profiles
+#
+: ${DWATCH_PROFILES_PATH="/usr/libexec/dwatch:/usr/local/libexec/dwatch"}
+
+############################################################ GLOBALS
+
+VERSION='$Version: 1.0-beta-1 $' # -V
+
+pgm="${0##*/}" # Program basename
+
+#
+# Command-line arguments
+#
+PROBE_ARG=
+
+#
+# Command-line options
+#
+CONSOLE= # -y
+[ -t 1 ] && CONSOLE=1 # -y
+COUNT=0 # -N count
+CUSTOM_DETAILS= # -E code
+CUSTOM_TEST= # -t test
+DEBUG= # -d
+DESTRUCTIVE_ACTIONS= # -w
+EXECNAME= # -k name
+EXECREGEX= # -z regex
+EXIT_AFTER_COMPILE= # -e
+FILTER= # -r regex
+GROUP= # -g group
+JID= # -j jail
+LIST= # -l
+LIST_PROFILES= # -Q
+MAX_ARGS=64 # -B num
+MAX_DEPTH=64 # -K num
+ONELINE= # -1
+PID= # -p pid
+PROBE_TYPE= # -f -m -n -P
+PROFILE= # -M name
+PSTREE= # -R
+QUIET= # -q
+TIMEOUT= # -T time
+TRACE= # -x
+USER= # -u user
+USE_PROFILE= # -M name
+VERBOSE= # -v
+
+#
+# Global exit status
+#
+SUCCESS=0
+FAILURE=1
+
+#
+# Miscellaneous
+#
+ACTIONS=
+E=$( :|awk 'BEGIN{printf "\033"}' )
+EVENT_DETAILS=
+EVENT_TAG='printf("%d.%d %s[%d]: ",
+ this->uid0, this->gid0, execname, this->pid0);'
+EVENT_TEST=
+FILE=
+FUNC_COALESCE_DETAILS='
+ /**************** FUNC_COALESCE ****************/
+
+ printf("%s%s:%s:%s:%s ", probename == "entry" ? "=> " :
+ probename == "return" ? "<= " :
+ probename == "start" ? "=> " :
+ probename == "done" ? "<= " : "",
+ probeprov, probemod, probefunc, probename);'
+ID=1
+MODULE_CHECKED=
+PROBE=
+RGID=
+RUID=
+SUDO=
+export SUDO_PROMPT="[sudo] Password:"
+
+############################################################ FUNCTIONS
+
+ansi() { local fmt="$2 $4"; [ "$CONSOLE" ] && fmt="$E[$1m$2$E[$3m $4";
+ shift 4; printf "$fmt\n" "$@"; }
+die() { exec >&2; [ "$*" ] && echo "$pgm:" "$@"; exit $FAILURE; }
+info() { [ "$QUIET" ] || ansi 35 "INFO" 39 "$@" >&2; }
+
+usage()
+{
+ local usagefmt="%6s %s"
+ local optfmt="\t%-9s %s\n"
+ exec >&2
+ [ "$*" ] && printf "%s: %s\n" "$pgm" "$*"
+ printf "Usage: %s [-1defFmnPqRvVwxy] [%s] [%s] [%s] [%s]\n" "$pgm" \
+ "-B num" "-E code" "-g group" "-j jail"
+ printf "\t [%s] [%s] [%s] [%s] [%s] [%s]\n" \
+ "-k name" "-K num" "-M name" "-N count" "-p pid" "-r regex"
+ printf "\t [%s] [%s] [%s] [%s] probe ...\n" \
+ "-t test" "-T time" "-u user" "-z regex"
+ printf " %s -l [-fmnPqy] [-r regex] [probe ...]\n" "$pgm"
+ printf " %s -Q [-1qy] [-r regex]\n" "$pgm"
+ printf "\n"
+ printf "$optfmt" "-1" \
+ "Print one line per process/profile (Default; disables \`-R')."
+ printf "$optfmt" "-B num" \
+ "Maximum number of arguments to display (Default $MAX_ARGS)."
+ printf "$optfmt" "-d" \
+ "Debug. Send dtrace(1) script to stdout instead of executing."
+ printf "$optfmt" "-e" \
+ "Exit after compiling request but prior to enabling probes."
+ printf "$optfmt" "-E code" \
+ "DTrace code for event details. If \`-', read from stdin."
+ printf "$optfmt" "-f" \
+ "Enable probe matching the specified function name."
+ printf "$optfmt" "-F" \
+ "Coalesce trace output by function."
+ printf "$optfmt" "-g group" \
+ "Group filter. Only show processes matching group name/gid."
+ printf "$optfmt" "-j jail" \
+ "Jail filter. Only show processes matching jail name/jid."
+ printf "$optfmt" "-k name" \
+ "Only show processes matching name."
+ printf "$optfmt" "-K num" \
+ "Maximum directory depth to display (Default $MAX_DEPTH)."
+ printf "$optfmt" "-l" \
+ "List available probes on standard output and exit."
+ printf "$optfmt" "-m" \
+ "Enable probe matching the specified module name."
+ printf "$optfmt" "-M name" \
+ "Load profile name from DWATCH_PROFILES_PATH."
+ printf "$optfmt" "-n" \
+ "Enable probe matching the specified probe name."
+ printf "$optfmt" "-N count" \
+ "Exit after count matching entries (Default 0 for disabled)."
+ printf "$optfmt" "-p pid" \
+ "Process id filter. Only show processes with matching pid."
+ printf "$optfmt" "-P" \
+ "Enable probe matching the specified provider name."
+ printf "$optfmt" "-q" \
+ "Quiet. Hide informational messages and all dtrace(1) errors."
+ printf "$optfmt" "-Q" \
+ "List available profiles in DWATCH_PROFILES_PATH and exit."
+ printf "$optfmt" "-r regex" \
+ "Filter. Only show blocks matching awk(1) regular expression."
+ printf "$optfmt" "-R" \
+ "Show parent, grandparent, and ancestor of process."
+ printf "$optfmt" "-t test" \
+ "Test clause (predicate) to limit events (Default none)."
+ printf "$optfmt" "-T time" \
+ "Timeout. Format is \`#[smhd]' or simply \`#' for seconds."
+ printf "$optfmt" "-u user" \
+ "User filter. Only show processes matching user name/uid."
+ printf "$optfmt" "-v" \
+ "Verbose. Show all errors from dtrace(1)."
+ printf "$optfmt" "-V" \
+ "Report dwatch version on standard output and exit."
+ printf "$optfmt" "-w" \
+ "Permit destructive actions (copyout*, stop, panic, etc.)."
+ printf "$optfmt" "-x" \
+ "Trace. Print \`<probe-id>' when a probe is triggered."
+ printf "$optfmt" "-y" \
+ "Always treat stdout as console (enable colors/columns/etc.)."
+ printf "$optfmt" "-z regex" \
+ "Only show processes matching awk(1) regular expression."
+ die
+}
+
+process_flag()
+{
+ local flag="$1"
+ local name predicate vers
+
+ case "$flag" in
+ 1) ONELINE=1 PSTREE= ;;
+ B) MAX_ARGS="$OPTARG" ;;
+ d) DEBUG=1 ;;
+ e) EXIT_AFTER_COMPILE=1 ;;
+ E) CUSTOM_DETAILS=1 EVENT_DETAILS="$OPTARG" ;;
+ f) PROBE_TYPE=function ;;
+ F) CUSTOM_DETAILS=1 EVENT_DETAILS="$FUNC_COALESCE_DETAILS" ;;
+ g) GROUP="$OPTARG" ;;
+ j) JID="$OPTARG" ;;
+ k) EXECNAME="$EXECNAME${EXECNAME:+ }$OPTARG"
+ case "$OPTARG" in
+ \**\*) name="${OPTARG%\*}"
+ predicate="strstr(execname, \"${name#\*}\") != NULL" ;;
+ \**) name="${OPTARG#\*}"
+ predicate="strstr(execname, \"$name\") == (execname +"
+ predicate="$predicate strlen(execname) - ${#name})" ;;
+ *\*) predicate="strstr(execname, \"${OPTARG%\*}\") == execname" ;;
+ *) predicate="execname == \"$OPTARG\""
+ esac
+ EVENT_TEST="$predicate${EVENT_TEST:+ ||
+ ($EVENT_TEST)}" ;;
+ K) MAX_DEPTH="$OPTARG" ;;
+ l) LIST=1 ;;
+ m) PROBE_TYPE=module ;;
+ M) USE_PROFILE=1 PROFILE="$OPTARG" ;;
+ n) PROBE_TYPE=name ;;
+ N) COUNT="$OPTARG" ;;
+ p) PID="$OPTARG" ;;
+ P) PROBE_TYPE=provider ;;
+ q) QUIET=1 ;;
+ Q) LIST_PROFILES=1 ;;
+ r) FILTER="$OPTARG" ;;
+ R) PSTREE=1 ;;
+ t) CUSTOM_TEST="$OPTARG" ;;
+ T) TIMEOUT="$OPTARG" ;;
+ u) USER="$OPTARG" ;;
+ v) VERBOSE=1 ;;
+ V) vers="${VERSION#\$*[:\$]}"
+ vers="${vers% \$}"
+ printf "%s: %s\n" "$pgm" "${vers# }"
+ exit ;;
+ w) DESTRUCTIVE_ACTIONS=1 ;;
+ x) TRACE=1 ;;
+ y) CONSOLE=1 ;;
+ z) EXECREGEX="$OPTARG" ;;
+ *) usage
+ # NOTREACHED
+ esac
+}
+
+dtrace_load()
+{
+ [ "$MODULE_CHECKED" ] && return
+ MODULE_CHECKED=1
+
+ #
+ # Load kernel module(s) if necessary
+ #
+ if type kldstat > /dev/null 2>&1; then
+ eval kldstat -qm dtrace ${QUIET:+2> /dev/null} ||
+ $SUDO kldload dtraceall ||
+ exit
+ fi
+}
+
+dtrace_cmd()
+{
+ local status stdout
+ local timeout=
+
+ if [ "$1" = "-t" ]; then
+ shift
+ [ "$TIMEOUT" ] && timeout=1
+ fi
+
+ dtrace_load
+
+ exec 3>&1
+ stdout=3
+
+ #
+ # Filter dtrace(1) stderr while preserving exit status
+ #
+ status=$(
+ exec 4>&1
+ to_status=4
+ ( trap 'echo $? >&$to_status' EXIT
+ eval $SUDO ${timeout:+timeout \"\$TIMEOUT\"} dtrace \
+ \"\$@\" 2>&1 ${QUIET:+2> /dev/null} >&$stdout
+ ) | dtrace_stderr_filter >&2
+ )
+
+ return $status
+}
+
+dtrace_stderr_filter()
+{
+ if [ "$VERBOSE" ]; then
+ cat
+ return
+ # NOTREACHED
+ fi
+
+ awk ' # Start awk(1) stderr-filter
+ /[[:digit:]]+ drops? on CPU [[:digit:]]+/ { next }
+ /failed to write to <stdout>: No such file or directory/ { next }
+ /failed to write to <stdout>: Broken pipe/ { next }
+ /processing aborted: Broken pipe/ { next }
+ { print; fflush() }
+ ' # END-QUOTE
+}
+
+expand_probe()
+{
+ local OPTIND=1 OPTARG flag
+ local type=
+
+ while getopts t: flag; do
+ case "$flag" in
+ t) type="$OPTARG" ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ local probe="$1"
+ case "$probe" in
+ *:*)
+ echo "$probe"
+ return $SUCCESS
+ ;;
+ esac
+
+ dtrace_cmd -l | awk -v probe="$1" -v type="$type" '
+ # Start awk(1) processor
+ #################################################### BEGIN
+ BEGIN { getline dtrace_header }
+ #################################################### FUNCTIONS
+ function dump(unused1,unused2) {
+ if (n) {
+ if (NcF[n] == 1) f = N2F[n]
+ if (NcM[n] == 1) m = N2M[n]
+ if (NcP[n] == 1) p = N2P[n]
+ } else if (f) {
+ if (FcM[f] == 1) m = F2M[f]
+ if (FcP[f] == 1) p = F2P[f]
+ if (FcN[f] == 0 && found) n = "entry"
+ } else if (m) {
+ if (McP[m] == 1) p = M2P[m]
+ }
+ printf "%s:%s:%s:%s\n", p, m, f, n
+ exit !found
+ }
+ function inFMP() { return probe in F || probe in M || probe in P }
+ function inNMP() { return probe in N || probe in M || probe in P }
+ function inNFP() { return probe in N || probe in F || probe in P }
+ function inNFM() { return probe in N || probe in F || probe in M }
+ function diva(value, peerA, peerB, peerC) {
+ return value >= peerA && value >= peerB && value >= peerC
+ }
+ #################################################### MAIN
+ type == "name" && $NF != probe { next }
+ type == "function" && NF >=4 && $(NF-1) != probe { next }
+ type == "module" && NF == 5 && $(NF-2) != probe { next }
+ type == "provider" && $2 != probe { next }
+ type || $2 == probe || $3 == probe || $4 == probe || $5 == probe {
+ P[_p = $2]++
+ M[_m = (NF >= 5 ? $(NF-2) : "")]++
+ F[_f = (NF >= 4 ? $(NF-1) : "")]++
+ N[_n = $NF]++
+ if (N2F[_n] != _f) NcF[_n]++; N2F[_n] = _f
+ if (N2M[_n] != _m) NcM[_n]++; N2M[_n] = _m
+ if (N2P[_n] != _p) NcP[_n]++; N2P[_n] = _p
+ if (_n !~ /entry|return/) {
+ if (F2N[_f] != _n) FcN[_f]++
+ F2N[_f] = _n
+ }
+ if (F2M[_f] != _m) FcM[_f]++; F2M[_f] = _m
+ if (F2P[_f] != _p) FcP[_f]++; F2P[_f] = _p
+ if (M2P[_m] != _p) McP[_m]++; M2P[_m] = _p
+ }
+ #################################################### END
+ END {
+ if (type == "name") dump(n = probe, found = probe in N)
+ if (type == "function") dump(f = probe, found = probe in F)
+ if (type == "module") dump(m = probe, found = probe in M)
+ if (type == "provider") dump(p = probe, found = probe in P)
+ if (probe in N) {
+ found = 1
+ if (!inFMP()) dump(n = probe)
+ if (diva(F[probe], N[probe], M[probe], P[probe]))
+ dump(f = probe)
+ if (diva(M[probe], N[probe], F[probe], P[probe]))
+ dump(m = probe)
+ if (diva(P[probe], N[probe], F[probe], M[probe]))
+ dump(p = probe)
+ dump(n = probe) # N is the diva
+ } else if (probe in F) {
+ found = 1
+ if (!inNMP()) dump(f = probe)
+ if (diva(N[probe], F[probe], M[probe], P[probe]))
+ dump(n = probe)
+ if (diva(M[probe], F[probe], N[probe], P[probe]))
+ dump(m = probe)
+ if (diva(P[probe], F[probe], N[probe], M[probe]))
+ dump(p = probe)
+ dump(f = probe) # F is the diva
+ } else if (probe in M) {
+ found = 1
+ if (!inNFP()) dump(m = probe)
+ if (diva(N[probe], M[probe], F[probe], P[probe]))
+ dump(n = probe)
+ if (diva(F[probe], M[probe], N[probe], P[probe]))
+ dump(f = probe)
+ if (diva(P[probe], M[probe], N[probe], F[probe]))
+ dump(p = probe)
+ dump(m = probe) # M is the diva
+ } else if (probe in P) {
+ found = 1
+ if (!inNFM()) dump(p = probe)
+ if (diva(N[probe], P[probe], F[probe], M[probe]))
+ dump(n = probe)
+ if (diva(F[probe], P[probe], N[probe], M[probe]))
+ dump(f = probe)
+ if (diva(M[probe], P[probe], N[probe], F[probe]))
+ dump(m = probe)
+ dump(p = probe) # P is the diva
+ }
+ if (!found) print probe
+ exit !found
+ }
+ ' # END-QUOTE
+}
+
+list_probes()
+{
+ local column=0 header="PROVIDER:MODULE:FUNCTION:NAME"
+
+ if [ ! "$PROBE" ]; then
+ case "$PROBE_TYPE" in
+ provider) column=1 header="PROVIDER" ;;
+ module) column=2 header="MODULE" ;;
+ function) column=3 header="FUNCTION" ;;
+ name) column=4 header="NAME" ;;
+ esac
+ fi
+
+ [ "$QUIET" ] || echo "$header"
+
+ dtrace_cmd -l${PROBE:+n "$PROBE"} | awk -v pattern="$(
+ # Prevent backslashes from being lost
+ echo "$FILTER" | awk 'gsub(/\\/,"&&")||1'
+ )" -v want="$column" -v sort="sort" '
+ BEGIN { getline dtrace_header }
+ NF > 3 && $(NF-1) ~ /^#/ { next }
+ !_[$0 = column[0] = sprintf("%s:%s:%s:%s",
+ column[1] = $2,
+ column[2] = (NF >= 5 ? $(NF-2) : ""),
+ column[3] = (NF >= 4 ? $(NF-1) : ""),
+ column[4] = $NF)]++ &&
+ !__[$0 = column[want]]++ &&
+ $0 ~ pattern { print | sort }
+ END { close(sort) }
+ ' # END-QUOTE
+}
+
+list_profiles()
+{
+ local regex
+
+ # Prevent backslashes from being lost
+ regex=$( echo "$FILTER" | awk 'gsub(/\\/,"&&")||1' )
+
+ # Build a list of profiles available
+ local profiles
+ profiles=$( { IFS=:
+ for dir in $DWATCH_PROFILES_PATH; do
+ [ -d "$dir" ] || continue
+ for path in $dir/*; do
+ [ -f "$path" ] || continue
+ name="${path##*/}"
+ [ "$name" = "${name%%[!0-9A-Za-z_-]*}" ] ||
+ continue
+ echo $name
+ done
+ done
+ } | sort -u )
+
+ # Get the longest profile name
+ local longest_profile_name
+ longest_profile_name=$( echo "$profiles" |
+ awk -v N=0 '(L = length($0)) > N { N = L } END { print N }' )
+
+ # Get the width of the terminal
+ local max_size="$( stty size 2> /dev/null )"
+ : ${max_size:=24 80}
+ local max_width="${max_size#*[$IFS]}"
+
+ # Determine how many columns we can display
+ local x=$longest_profile_name ncols=1
+ [ "$QUIET" ] || x=$(( $x + 8 )) # Accommodate leading tab character
+ x=$(( $x + 3 + $longest_profile_name )) # Preload end of next column
+ while [ $x -lt $max_width ]; do
+ ncols=$(( $ncols + 1 ))
+ x=$(( $x + 3 + $longest_profile_name ))
+ done
+
+ # Output single lines if sent to a pipe
+ if [ "$ONELINE" ]; then
+ echo "$profiles" | awk -v regex="$regex" '$0 ~ regex'
+ return $SUCCESS
+ # NOTREACHED
+ fi
+
+ [ "$QUIET" ] || printf "PROFILES:\n"
+ echo "$profiles" | awk \
+ -v ncols=$ncols \
+ -v colsize=$longest_profile_name \
+ -v quiet="$QUIET" \
+ -v regex="$regex" \
+ ' # Begin awk(1) processor
+ BEGIN { row_item[1] = "" }
+ function print_row()
+ {
+ printf "%s%-*s", quiet ? "" : "\t",
+ colsize, row_item[1]
+ for (i = 2; i <= cur_col; i++)
+ printf " %-*s", colsize, row_item[i]
+ printf "\n"
+ }
+ $0 ~ regex {
+ n++
+ cur_col = (( n - 1 ) % ncols ) + 1
+ row_item[cur_col] = $0
+ if ( cur_col == ncols ) print_row()
+ }
+ END { if (cur_col < ncols) print_row() }
+ ' # END-QUOTE
+ return $SUCCESS
+}
+
+load_profile()
+{
+ local profile="$1"
+
+ [ "$profile" ] ||
+ die "missing profile argument (\`$pgm -Q' to list profiles)"
+
+ local oldIFS="$IFS"
+ local dir found=
+
+ IFS=:
+ for dir in $DWATCH_PROFILES_PATH; do
+ [ -d "$dir" ] || continue
+ [ -f "$dir/$profile" ] || continue
+ PROFILE="$profile" found=1
+ info "Sourcing $profile profile [found in %s]" "$dir"
+ . "$dir/$profile"
+ break
+ done
+ IFS="$oldIFS"
+
+ [ "$found" ] ||
+ die "no module named \`$profile' (\`$pgm -Q' to list profiles)"
+}
+
+pproc()
+{
+ local proc="curthread->td_proc"
+ [ $1 -gt 0 ] && proc="this->proc->p_pptr"
+
+ awk 'NR > 1 && $0 { $0 = "\t" $0 }
+ gsub(/\\\t/, "\t") || 1' <<-EOFPREAMBLE
+ this->proc = $proc;
+ this->pid$1 = this->proc->p_pid;
+ this->uid$1 = this->proc->p_ucred->cr_uid;
+ this->gid$1 = this->proc->p_ucred->cr_rgid;
+ this->jid$1 = this->proc->p_ucred->cr_prison->pr_id;
+ this->p_args = this->proc ? this->proc->p_args : 0;
+ this->ar_length = this->p_args ? this->p_args->ar_length : 0;
+ this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
+
+ this->arg${1}_0 = this->ar_length > 0 ?
+ \ this->ar_args : stringof(this->proc->p_comm);
+ this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
+ this->ar_args += this->len;
+ this->ar_length -= this->len;
+
+ EOFPREAMBLE
+
+ awk -v P=$1 -v MAX_ARGS=$MAX_ARGS '
+ $0 { $0 = "\t" $0 }
+ buf = buf $0 "\n" { }
+ END {
+ while (++N <= MAX_ARGS) {
+ $0 = buf
+ gsub(/P/, P)
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFARGS
+ this->argP_N = this->ar_length > 0 ? this->ar_args : "";
+ this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
+ this->ar_args += this->len;
+ this->ar_length -= this->len;
+
+ EOFARGS
+
+ awk '$0 = "\t" $0' <<-EOFPROC
+ this->arg${1}_$(( $MAX_ARGS + 1 )) = this->ar_length > 0 ? "..." : "";
+ EOFPROC
+}
+
+pproc_dump()
+{
+ local OPTIND=1 OPTARG flag
+ local indent= nl=1 verbose=
+
+ while getopts inv flag; do
+ case "$flag" in
+ i) indent=1 ;;
+ n) nl= ;;
+ v) verbose=1 ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ echo
+
+ [ "$verbose" ] && awk -v indent=$indent -v P=$1 '
+ BEGIN { if (indent) printf "\t" }
+ NR > 1 && $0 { $0 = "\t" $0 }
+ buf = buf $0 "\n" { }
+ END {
+ $0 = buf
+ gsub(/S/, P < 3 ? sprintf("%" 7-2*(P+1) "s", "") : "")
+ gsub(/B/, P < 3 ? "\\" : "")
+ gsub(/\\\t/, "\t")
+ sub(/\n$/, "")
+ print
+ }
+ ' <<-EOFPREAMBLE
+ printf(" SB-+= %05d %d.%d %s",
+ \ this->pid$1, this->uid$1, this->gid$1, this->arg${1}_0);
+ EOFPREAMBLE
+
+ awk -v indent=$indent -v P=$1 -v MAX_ARGS=$MAX_ARGS '
+ BEGIN { if (indent) printf "\t" }
+ $0 { $0 = "\t" $0 }
+ buf = buf $0 "\n" { }
+ END {
+ while (++N <= MAX_ARGS + 1) {
+ $0 = buf
+ if (N == 1) sub(/^\t/, "")
+ gsub(/P/, P)
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFARGS
+ printf("%s%s", this->argP_N != "" ? " " : "", this->argP_N);
+ EOFARGS
+
+ if [ "$nl" ]; then
+ awk '$0 = "\t" $0' <<-EOFTAIL
+ printf("%s", this->arg${1}_0 != "" ? "\\n" : "");
+ EOFTAIL
+ fi
+}
+
+############################################################ MAIN
+
+# If we're running as root, no need for sudo(8)
+[ "$( id -u )" != 0 ] && type sudo > /dev/null 2>&1 && SUDO=sudo
+
+#
+# Process command-line options and arguments
+#
+while :; do
+ OPTIND=1
+ while getopts 1B:deE:fFg:j:k:K:lmM:nN:p:PqQr:Rt:T:u:vVwxyz: flag; do
+ process_flag "$flag"
+ done
+ shift $(( $OPTIND - 1 ))
+
+ # Validate number of arguments
+ [ "$PROBE$PROFILE$LIST$LIST_PROFILES" -o $# -gt 0 ] ||
+ usage # NOTREACHED
+
+ PROBE_ARG="$1"
+ shift
+
+ #
+ # Expand probe
+ #
+ # NB: No need to do this if `-Q' was given (this prevents $SUDO access
+ # when listing profiles since probe names are unused by `-Q').
+ #
+ if [ "$PROBE_ARG" -a ! "$LIST_PROFILES" ]; then
+ PROBE_ARG=$( expand_probe -t "$PROBE_TYPE" -- "$PROBE_ARG" )
+ PROBE="$PROBE${PROBE:+, }$PROBE_ARG"
+ fi
+
+ [ $# -eq 0 ] && break
+done
+
+#
+# List probes if `-l' was given
+#
+if [ "$LIST" ]; then
+ list_probes
+ exit $SUCCESS
+fi
+
+#
+# List profiles if `-Q' was given
+#
+if [ "$LIST_PROFILES" ]; then
+ list_profiles
+ exit $SUCCESS
+fi
+
+#
+# Validate `-N count' option argument
+#
+case "$COUNT" in
+"") usage "-N option requires a number argument" ;; # NOTREACHED
+*[!0-9]*) usage "-N argument must be a number" ;; # NOTREACHED
+esac
+
+#
+# Validate `-B num' option argument
+#
+case "$MAX_ARGS" in
+"") usage "-B option requires a number argument" ;; # NOTREACHED
+*[!0-9]*) usage "-B argument must be a number" ;; # NOTREACHED
+esac
+
+#
+# Validate `-K num' option argument
+#
+case "$MAX_DEPTH" in
+"") usage "-K option requires a number argument" ;; # NOTREACHED
+*[!0-9]*) usage "-K argument must be a number" ;; # NOTREACHED
+esac
+
+#
+# Validate `-j jail' option argument
+#
+case "$JID" in
+"") : fall through ;;
+*[!0-9]*) JID=$( jls -j "$JID" jid ) || exit ;;
+esac
+
+#
+# Validate `-u user' option argument
+#
+case "$USER" in
+"") : fall through ;;
+*[![:alnum:]_-]*) RUID="$USER" ;;
+*[!0-9]*) RUID=$( id -u "$USER" 2> /dev/null ) || die "No such user: $USER" ;;
+*) RUID=$USER
+esac
+
+#
+# Validate `-g group' option argument
+#
+case "$GROUP" in
+"") : fall-through ;;
+*[![:alnum:]_-]*) RGID="$GROUP" ;;
+*[!0-9]*)
+ RGID=$( getent group | awk -F: -v group="$GROUP" '
+ $1 == group { print $3; exit found=1 }
+ END { exit !found }
+ ' ) || die "No such group: $GROUP" ;;
+*) RGID=$GROUP
+esac
+
+#
+# Read event code from stdin if `-' is the argument to `-E code' option
+#
+[ "$CUSTOM_DETAILS" -a "$EVENT_DETAILS" = "-" ] && EVENT_DETAILS=$( cat )
+
+#
+# Default event details
+#
+[ "$CUSTOM_DETAILS" ] || EVENT_DETAILS="printf(\"%s\", this->arg0_0);$(
+ pproc_dump -in 0
+)"
+
+#
+# Load profile if given with `-M name'
+#
+[ "$USE_PROFILE" ] && load_profile "$PROFILE"
+[ "$PROBE" ] || die "PROBE not defined by profile and none given as argument"
+
+#
+# Show the user what's being watched
+#
+[ "$DEBUG$QUIET$EXIT_AFTER_COMPILE" ] || info "Watching '$PROBE' ..."
+
+#
+# Header for watched probe entry
+#
+case "$PROBE" in
+*,*) : fall-through ;;
+*:execve:entry|execve:entry)
+ ACTIONS=$( awk 'gsub(/\\\t/, "\t") || 1' <<-EOF
+ $PROBE /* probe ID 1 */
+ {${TRACE:+
+ \ printf("<1>");}
+ \ this->caller_execname = execname;
+ }
+ EOF
+ )
+ PROBE="${PROBE%entry}return"
+ ID=2
+ EVENT_TEST="execname != this->caller_execname${EVENT_TEST:+ &&
+ ($EVENT_TEST)}"
+ EVENT_TAG='printf("%d.%d %s[%d]: ",
+ this->uid1, this->gid1, this->caller_execname, this->pid1);'
+ ;;
+esac
+
+#
+# Jail clause/predicate
+#
+if [ "$JID" ]; then
+ prison_id="curthread->td_proc->p_ucred->cr_prison->pr_id"
+ EVENT_TEST="$prison_id == $JID${EVENT_TEST:+ &&
+ ($EVENT_TEST)}"
+fi
+
+#
+# Custom test clause/predicate
+#
+if [ "$CUSTOM_TEST" ]; then
+ case "$EVENT_TEST" in
+ "") EVENT_TEST="$CUSTOM_TEST" ;;
+ *) EVENT_TEST="$EVENT_TEST &&
+ ($CUSTOM_TEST)"
+ esac
+fi
+
+#
+# Make sure dynamic code has trailing semi-colons if non-NULL
+#
+EVENT_TAG="${EVENT_TAG%;}${EVENT_TAG:+;}"
+EVENT_DETAILS="${EVENT_DETAILS%;}${EVENT_DETAILS:+;}"
+
+#
+# DTrace script
+#
+# If `-d' is given, script is sent to stdout for debugging
+# If `-c count", `-g group', `-r regex', or `-u user' is given, run script with
+# dtrace and send output to awk(1) post-processor (making sure to preserve the
+# exit code returned by dtrace invocation). Otherwise, simply run script with
+# dtrace and then exit.
+#
+{
+ if [ "$DEBUG" ]; then
+ # Send script to stdout
+ cat
+ exit
+ fi
+
+ if [ "$VERBOSE$JID$EXECNAME$CUSTOM_TEST$TRACE$TIMEOUT" -a ! "$QUIET" ]
+ then
+ msg=Settings
+ [ "$TIMEOUT" ] && msg="$msg timeout: $TIMEOUT"
+ [ "$TRACE" ] && msg="$msg trace: $TRACE"
+ [ "$VERBOSE" ] && msg="$msg verbose: $VERBOSE"
+ [ "$JID" ] && msg="$msg jid: $JID"
+ [ "$EXECNAME" ] && msg="$msg execname: $EXECNAME"
+ [ "$CUSTOM_TEST" ] && msg="$msg test: $CUSTOM_TEST"
+ info "$msg"
+ fi
+
+ exec 3>&1
+ console_stdout=3
+
+ if [ $COUNT -eq 0 -a ! "$EXECREGEX$FILTER$PID$USER$GROUP" ]; then
+ # Run script without pipe to awk post-processor
+ dtrace_cmd -t ${EXIT_AFTER_COMPILE:+-e} \
+ ${DESTRUCTIVE_ACTIONS:+-w} -s /dev/stdin
+ exit
+ fi
+
+ if [ ! "$QUIET" ]; then
+ msg=Filtering
+ [ $COUNT -gt 0 ] && msg="$msg count: $COUNT"
+ [ "$EXECREGEX" ] && msg="$msg execregex: $EXECREGEX"
+ [ "$FILTER" ] && msg="$msg filter: $FILTER"
+ [ "$PID" ] && msg="$msg pid: $PID"
+ [ "$USER" ] && msg="$msg user: $USER"
+ [ "$GROUP" ] && msg="$msg group: $GROUP"
+ info "$msg"
+ fi
+
+ #
+ # Send script output to post-processor for filtering
+ #
+ dtrace_load
+ status=$(
+ exec 4>&1
+ to_status=4
+ ( exec 5>&1; to_dtrace_stderr_filter=5; (
+ trap 'echo $? >&$to_status' EXIT
+ eval $SUDO ${TIMEOUT:+timeout \"\$TIMEOUT\"} dtrace \
+ ${EXIT_AFTER_COMPILE:+-e} \
+ ${DESTRUCTIVE_ACTIONS:+-w} \
+ -s /dev/stdin \
+ 2>&$to_dtrace_stderr_filter \
+ ${QUIET:+2> /dev/null}
+ ) | $SUDO awk \
+ -v count=$COUNT \
+ -v execregex="$EXECREGEX" \
+ -v filter="$FILTER" \
+ -v pid="$PID" \
+ -v uid="$RUID" \
+ -v gid="$RGID" \
+ -v quiet=$QUIET \
+ -v pstree=$PSTREE \
+ -v tty=$( ps -o tty= -p $$ ) \
+ ' # Start awk(1) post-processor
+ ############################################ BEGIN
+ BEGIN {
+ num = "[[:digit:]]+"
+ name1 = "[^\\[]*"
+ name2 = "[^[:space:]]+"
+ gsub(/\\/,"&&", execregex)
+ fmt = sprintf("(%s|%s)",
+ "^[^\\n]* (%s)\\.(%s) (%s)\\[(%s)\\]: ",
+ "\\n +\\\\?-\\+= (%s) (%s)\\.(%s) (%s)")
+ pidfilter = sprintf(fmt,
+ num, num, name1, pid,
+ pid, num, num, name2)
+ uidfilter = sprintf(fmt,
+ uid, num, name1, num,
+ num, uid, num, name2)
+ gidfilter = sprintf(fmt,
+ num, gid, name1, num,
+ num, num, gid, name2)
+ execfilter = sprintf(fmt,
+ num, num, execregex, num,
+ num, num, num, execregex)
+ }
+ ############################################ FUNCTIONS
+ function dump() {
+ lines = block
+ block = ""
+ if (execregex != "" && lines !~ execfilter) return
+ if (pid != "" && lines !~ pidfilter) return
+ if (uid != "" && lines !~ uidfilter) return
+ if (gid != "" && lines !~ gidfilter) return
+ if (filter != "" && lines !~ filter) return
+ if (lines) print lines
+ fflush()
+ ++matches
+ }
+ ############################################ MAIN
+ { block = (block ? block "\n" : block) $0 }
+ !pstree { dump() }
+ $0 ~ sprintf("^%6s\\\\-\\+= %s ", "", num) { dump() }
+ count && matches >= count { exit }
+ ############################################ END
+ END {
+ dump()
+ system(sprintf("pkill -t %s dtrace %s", tty,
+ quiet ? "2> /dev/null" : ""))
+ }
+ ' >&$console_stdout ) | dtrace_stderr_filter >&2
+ ) # status
+ exit $status
+
+} <<EOF
+#!/usr/sbin/dtrace -s
+/* -
+ * Copyright (c) 2014-2017 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS \`\`AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * \$Title: dtrace(1) script to log process(es) triggering $PROBE $
+ * \$FreeBSD$
+ */
+
+$( echo "$DTRACE_PRAGMA" | awk '
+ !/^[[:space:]]*(#|$)/, sub(/^[[:space:]]*/, "#pragma D ")||1
+' )
+
+int console;
+
+dtrace:::BEGIN { console = ${CONSOLE:-0} }
+${ACTIONS:+
+/*********************************************************/
+
+$ACTIONS
+}
+/*********************************************************/
+
+$PROBE${EVENT_TEST:+ /$EVENT_TEST/} /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * Examine process, parent process, and grandparent process details
+ */
+
+ /******************* CURPROC *******************/
+
+ $( pproc 0 )
+
+ /******************* PPARENT *******************/
+
+ $( if [ "$PSTREE" ]; then pproc 1; else echo -n \
+ "this->proc = this->proc->p_pptr;
+ this->pid1 = this->proc->p_pid;
+ this->uid1 = this->proc->p_ucred->cr_uid;
+ this->gid1 = this->proc->p_ucred->cr_rgid;
+ this->jid1 = this->proc->p_ucred->cr_prison->pr_id;"
+ fi )
+
+ /******************* GPARENT *******************/
+
+ $( [ "$PSTREE" ] && pproc 2 )
+
+ /******************* APARENT *******************/
+
+ $( [ "$PSTREE" ] && pproc 3 )
+
+ /***********************************************/
+
+ /*
+ * Print process, parent, grandparent, and ancestor details
+ */
+
+ printf("%s%Y%s ",
+ console ? "\033[32m" : "",
+ walltimestamp,
+ console ? "\033[39m" : "");
+
+ /****************** EVENT_TAG ******************/
+
+ ${EVENT_TAG#[[:space:]]}
+
+ /**************** EVENT_DETAILS ****************/
+
+ ${EVENT_DETAILS#[[:space:]]}
+
+ /***********************************************/
+
+ printf("\\n");
+$( if [ "$PSTREE" ]; then
+ pproc_dump -iv 3
+ pproc_dump -iv 2
+ pproc_dump -iv 1
+ pproc_dump -iv 0
+fi )
+}
+EOF
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/dwatch.1
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/dwatch.1
@@ -0,0 +1,613 @@
+.\" Copyright (c) 2014-2017 Devin Teske
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 2, 2017
+.Dt DWATCH 1
+.Os
+.Sh NAME
+.Nm dwatch
+.Nd watch processes as they trigger a particular DTrace probe
+.Sh SYNOPSIS
+.Nm
+.Op Fl 1defFmnPqRvVwxy
+.Op Fl B Ar num
+.Op Fl E Ar code
+.Op Fl g Ar group
+.Op Fl j Ar jail
+.Op Fl k Ar name
+.Op Fl K Ar num
+.Op Fl M Ar name
+.Op Fl N Ar count
+.Op Fl p Ar pid
+.Op Fl r Ar regex
+.Op Fl t Ar test
+.Op Fl T Ar time
+.Op Fl u Ar user
+.Op Fl z Ar regex
+probe ...
+.Nm
+.Fl l
+.Op Fl fmnPqy
+.Op Fl r Ar regex
+.Op probe ...
+.Nm
+.Fl Q
+.Op Fl 1qy
+.Op Fl r Ar regex
+.Sh DESCRIPTION
+The
+.Nm
+utility uses
+.Xr dtrace 1
+to display process info when DTrace hits a given probe proint.
+.Pp
+.Nm
+automates the process of generating DTrace scripts to coalesce trace output by
+date/time,
+process info,
+and
+.Op optionally
+probe-specific data.
+.Pp
+Output format without options is:
+.Pp
+.Dl date/time uid.gid execname[pid]: psargs
+.Pp
+For example,
+the command
+.Ql dwatch BEGIN
+produces the output:
+.Pp
+.Dl INFO Watching 'dtrace:::BEGIN' ...
+.Dl 2017 May 29 08:23:20 0.0 dtrace[60671]: dtrace -s /dev/stdin
+.Pp
+The
+.Fl F
+option causes
+.Nm
+to instead coalesce trace output by date/time,
+process info,
+and function traversal.
+.Pp
+Output format with
+.Ql Fl F
+option is:
+.Pp
+.Dl date/time uid.gid execname[pid]: [=> |<= ]prov:mod:func:name
+.Pp
+For example,
+the command
+.Ql dwatch -F BEGIN
+produces the output:
+.Pp
+.Dl INFO Watching 'dtrace:::BEGIN' ...
+.Dl 2017 May 29 21:34:41 0.0 dtrace[86593]: dtrace:::BEGIN
+.Pp
+The
+.Fl R
+option causes
+.Nm
+to display a process tree containing the parent,
+grandparent,
+and ancestor process info.
+.Pp
+Output format with
+.Ql Fl R
+option is:
+.Pp
+.Dl date/time uid0.gid0 execname[pid0]: psargs0
+.Dl " -+= pid3 uid3.gid3 psargs3"
+.Dl " \\\-+= pid2 uid2.gid2 psargs2"
+.Dl " \\\-+= pid1 uid1.gid1 psargs1"
+.Dl " \\\-+= pid0 uid0.guid0 psargs0"
+.Pp
+For example,
+the command
+.Ql dwatch -R BEGIN
+produces the output:
+.Pp
+.Dl INFO Watching 'dtrace:::BEGIN' ...
+.Dl 2017 May 29 21:38:54 0.0 dtrace[86899]: dtrace -s /dev/stdin
+.Dl " -+= 86855 604.604 -bash"
+.Dl " \-+= 86857 604.604 /bin/sh /usr/sbin/dwatch -R BEGIN"
+.Dl " \-+= 86897 0.0 sudo dtrace -s /dev/stdin"
+.Dl " \-+= 86899 0.0 dtrace -s /dev/stdin"
+.Pp
+Of particular interest is the ability to filter using regular expressions.
+The
+.Ql Fl g Ar group ,
+.Ql Fl p Ar pid ,
+.Ql Fl r Ar regex ,
+.Ql Fl u Ar user ,
+and
+.Ql Fl z Ar regex
+options can be combined with
+.Ql Fl R
+to match on parent process criteria as well as current process info.
+.Pp
+In contrast,
+the
+.Ql Fl j Ar jail ,
+and
+.Ql Fl k Ar name
+options apply only to the current process even if
+.Ql Fl R
+is given.
+.Pp
+The
+.Ql Fl E Ar code
+option gives the ability to customize probe-specific data.
+For example,
+the command:
+.Pp
+.Dl dwatch -E 'printf("%s", copyinstr(arg0))' chdir
+.Pp
+displays the path argument sent to
+.Xr chdir 2
+calls.
+.Pp
+Profiles can be written for more complex routines or convenience.
+To list available profiles use the
+.Ql Fl Q
+option.
+Use the
+.Ql Fl M Ar name
+option to use a particular profile.
+.Pp
+For example,
+the command
+.Ql dwatch -M kill
+displays arguments sent to
+.Xr kill 2 .
+.Pp
+Since this uses DTrace, only the root user or users with
+.Xr sudo 8
+access can run this command.
+.Sh OPTIONS
+If a
+.Ar probe
+argument does not contain colon
+.Pq Ql Li ":"
+and none of
+.Ql Fl P ,
+.Ql Fl m ,
+.Ql Fl f ,
+or
+.Ql Fl n
+are given,
+the probe argument is intelligently mapped to its most-likely value.
+Use
+.Ql Nm Fl l Ar name
+to see what probes will match a given name.
+.Bl -tag -width "-c count"
+.It Fl 1
+Print one line per process/profile
+.Pq Default; disables Ql Fl R .
+.It Fl B Ar num
+Maximum number of arguments to display
+.Pq Default 64 .
+.It Fl d
+Debug.
+Send
+.Xr dtrace 1
+script to stdout instead of executing.
+.It Fl e
+Exit after compiling request but prior to enabling probes.
+.It Fl E Ar code
+DTrace
+.Ar code
+for event details.
+If `-',
+read from stdin.
+This allows the customization of what is printed after the date/time
+and process info.
+By default,
+the name and arguments of the program triggering the probe are shown.
+.It Fl f
+Enable probe matching the specified function name.
+.It Fl F
+Coalesce trace output by function.
+.It Fl g Ar group
+Group filter.
+Only show processes matching
+.Ar group
+name/gid.
+This can be an
+.Xr awk 1
+regular expression to match a numerical gid.
+.It Fl j Ar jail
+Jail filter.
+Only show processes matching
+.Ar jail
+name/jid.
+.It Fl k Ar name
+Only show processes matching
+.Ar name .
+Can also be of the format
+.Ql Li name*
+to indicate
+.Dq Li begins with ,
+.Ql Li *name
+to indicate
+.Dq Li ends with ,
+or
+.Ql Li *name*
+to indicate
+.Dq Li contains .
+.It Fl K Ar num
+Maximum directory depth to display
+.Pq Default 64 .
+.It Fl l
+List available probes on standard output and exit.
+.It Fl m
+Enable probe matching the specified module name.
+.It Fl M Ar name
+Load profile name from DWATCH_PROFILES_PATH.
+.It Fl n
+Enable probe matching the specified probe name.
+.It Fl N Ar count
+Exit after
+.Ar count
+matching entries
+.Pq Default 0 for disabled .
+.It Fl p Ar pid
+Process id filter.
+Only show processes with matching
+.Ar pid .
+This can be an
+.Xr awk 1
+regular expression.
+.It Fl P
+Enable probe matching the specified provider name.
+.It Fl q
+Quiet.
+Hide informational messages and all dtrace(1) errors.
+.It Fl Q
+List available profiles in DWATCH_PROFILES_PATH and exit.
+.It Fl r Ar regex
+Filter.
+Only show blocks matching
+.Xr awk 1
+regular expression.
+.It Fl R
+Show parent,
+grandparent,
+and ancestor of process.
+.It Fl t Ar test
+Test clause
+.Pq predicate
+to limit events
+.Pq Default none .
+.It Fl T Ar time
+Timeout.
+Format is
+.Ql Li #[smhd]
+or just
+.Ql Li #
+for seconds.
+.It Fl u Ar user
+User filter.
+Only show processes matching
+.Ar user
+name/uid.
+This can be an
+.Xr awk 1
+regular expression to match a numerical uid.
+.It Fl v
+Verbose.
+Show all errors from
+.Xr dtrace 1 .
+.It Fl V
+Report dwatch version on standard output and exit.
+.It Fl w
+Permit destructive actions
+.Pq copyout*, stop, panic, etc. .
+.It Fl x
+Trace.
+Print
+.Ql Li <probe-id>
+when a probe is triggered.
+.It Fl y
+Always treat stdout as console
+.Pq enable colors/columns/etc. .
+.It Fl z Ar regex
+Only show processes matching
+.Xr awk 1
+regular expression.
+.El
+.Sh PROFILES
+Profiles customize the data printed during events.
+Profiles are loaded from a colon-separated list of directories in
+.Ev DWATCH_PROFILES_PATH .
+Below is an incomplete list of profiles with basic descriptions:
+.Bl -tag -width "vop_readdir"
+.It chmod
+Print arguments being passed to chmod(2)
+.It fchmod
+Print arguments being passed to fchmod(2)
+.It fchmodat
+Print arguments being passed to fchmodat(2)
+.It kill
+Print arguments being passed to kill(2)
+.It lchmod
+Print arguments being passed to lchmod(2)
+.It nanosleep
+Print arguments being passed to nanosleep(2)
+.It vop_create
+Print filesystem paths being created by VOP_CREATE(9)
+.It vop_lookup
+Print filesystem paths being looked-up by VOP_LOOKUP(9)
+.It vop_mkdir
+Print directory paths being created by VOP_MKDIR(9)
+.It vop_mknod
+Print device node paths being created by VOP_MKNOD(9)
+.It vop_readdir
+Print directory paths being read by VOP_READDIR(9)
+.It vop_remove
+Print filesystem paths being removed by VOP_REMOVE(9)
+.It vop_rename
+Print filesystem paths being renamed by VOP_RENAME(9)
+.It vop_rmdir
+Print directory paths being removed by VOP_RMDIR(9)
+.It vop_symlink
+Print symlink paths being created by VOP_SYMLINK(9)
+.El
+.Sh ENVIRONMENT
+These environment variables affect the execution of
+.Nm :
+.Bl -tag -width "DWATCH_PROFILES_PATH"
+.It Ev DWATCH_PROFILES_PATH
+If DWATCH_PROFILES_PATH is set,
+.Nm
+will search for profiles in the colon-separated list of directories
+instead of the default
+.Ql Li /usr/libexec/dwatch:/usr/local/libexec/dwatch .
+If set to NULL,
+no profiles will be loaded.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Below are some examples of how to use
+.Nm
+to watch system activity:
+.Pp
+.Nm
+.Ar on-cpu
+.Dl Watch processes entering system CPU scheduler.
+.Pp
+.Nm
+.Fl 1
+.Fl Q
+.Dl List available profiles, one line per profile.
+.Pp
+.Nm
+.Fl d
+fsync
+.Dl "Do not" execute Xr dtrace 1 but display script on stdout and exit.
+.Pp
+.Nm
+.Fl e
+.Ar test_probe
+.Dl Compile and test but do not execute code generatd with given probe.
+.Pp
+.Nm
+.Fl E Ar 'printf("%i", arg1)'
+zfs_sync
+.Dl Print argument one being passed to each call of zfs_sync().
+.Pp
+.Nm
+.Fl f
+.Ar read
+.Dl Watch all functions named Ql Li read .
+.Pp
+.Nm
+.Fl F
+.Ar ":"
+.Dl Watch all function traversal.
+.Pp
+.Nm
+.Fl F
+.Ar syscall
+.Dl Watch syscall function traversal.
+.Pp
+.Nm
+.Fl g Ar wheel
+execve
+.Dl Display only processes belonging to wheel super-group.
+.Pp
+.Nm
+.Fl g Ar '1|65534'
+.Ar execve
+.Dl Display only processes belonging to groups \
+So Li daemon Sc \
+or \
+So Li nobody Sc .
+.Pp
+.Nm
+.Fl j Ar 0
+execve
+.Dl Ignore jails, displaying only base system processes.
+.Pp
+.Nm
+.Fl j Ar myjail
+execve
+.Dl Display only processes running inside the jail named Ql Li myjail .
+.Pp
+.Nm
+.Fl k Ar 'ruby*'
+.Fl F
+.Ar syscall
+.Dl Watch syscall function traversal by ruby processes.
+.Pp
+.Nm
+.Fl k Ar '*daemon*'
+.Fl F
+.Ar syscall
+.Dl Watch syscall function traversal by processes containing Ql Li daemon
+.Dl in their name.
+.Pp
+.Nm
+.Fl l
+.Fl f
+.Dl Display a list of unique functions available.
+.Pp
+.Nm
+.Fl l
+.Fl f Ar '*read'
+.Dl List available probes for functions ending in Ql Li read .
+.Pp
+.Nm
+.Fl l
+.Fl r Ar 'read$'
+.Dl List available probes ending in Dq Li read .
+.Pp
+.Nm
+.Fl l
+.Fl P
+.Dl Display a list of unique providers.
+.Pp
+.Nm
+.Fl M Ar vop_remove
+.Dl Watch paths being removed by Xr VOP_REMOVE 9 .
+.Pp
+.Nm
+.Fl M Ar kill
+.Dl Watch signals being passed to Xr kill 2 .
+.Pp
+.Nm
+.Fl n Ar read
+.Dl Watch the name \
+So Li read Sc \
+instead of the function \
+So Li read Sc . \
+The dwatch selection algorithm will commonly favor the function named \
+So Li read Sc \
+when not given a type \
+Po using So Fl P Sc , So Fl m Sc , So Fl f Sc , or So Fl n Sc Pc \
+because there are more probes matching the function named \
+So Li read Sc \
+than probes matching \
+So Li read Sc \
+for any other type.
+.Pp
+.Nm
+.Fl N Ar 1
+kill
+.Dl Display the first process to call Xr kill 2 and then exit.
+.Pp
+.Nm
+.Fl p Ar 1234
+execve
+.Dl Watch processes forked by pid 1234.
+.Pp
+.Nm
+.Fl p Ar '1234|5678' execve
+.Dl Watch processes forked by either pid 1234 or pid 5678.
+.Pp
+.Nm
+.Fl P
+.Ar random
+.Dl Watch the provider \
+So Li random Sc \
+instead of the function \
+So Li random Sc . \
+The dwatch selection algorithm will commonly favor the function named \
+So Li random Sc \
+when not given a type \
+Po using So Fl P Sc , So Fl m Sc , So Fl f Sc , or So Fl n Sc Pc \
+because there are more probes matching the function named \
+So Li random Sc \
+than probes matching the provider named \
+So Li random Sc .
+.Pp
+.Nm
+.Fl Q
+.Fl r Ar vop
+.Dl Display available profiles matching Ql Li vop .
+.Pp
+.Nm
+.Fl r Ar /lib/
+.Fl M Ar vop_lookup
+.Dl Watch Xr VOP_LOOKUP 9 paths containing So Li /lib/ Sc .
+.Pp
+.Nm
+.Fl R
+execve
+.Dl Show process tree for each command as it is executed.
+.Pp
+.Nm
+.Fl R Fl p Ar 1234
+execve
+.Dl Watch processes forked by pid 1234 or children thereof .
+.Pp
+.Nm
+.Fl t Ar 'arg2<10'
+.Fl E Ar 'printf("%d",arg2)'
+write
+.Dl Display processes calling Xr write 2 with Do nbytes Dc less than 10 .
+.Pp
+.Nm
+.Fl T Ar 5m
+.Ar statfs
+.Dl Watch So Li statfs Sc for 5 minutes and exit.
+.Pp
+.Nm
+.Fl u Ar root
+execve
+.Dl Display only processes belonging to the root super-user.
+.Pp
+.Nm
+.Fl u Ar '1|65534'
+.Ar execve
+.Dl Display only processes belonging to users \
+So Li daemon Sc \
+or \
+So Li nobody Sc .
+.Pp
+.Nm
+.Fl V
+.Dl Print version and exit.
+.Pp
+.Nm
+.Fl y
+.Fl N Ar 100
+preempt | less
+.Fl R
+.Dl View the first 100 scheduler preemptions.
+.Pp
+.Nm
+.Fl z Ar '(mk|rm)dir'
+execve
+.Dl Display processes matching either Do Li mkdir Dc or Do Li rmdir Dc .
+.Sh SEE ALSO
+.Xr dtrace 1
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 12.0-CURRENT .
+.Sh AUTHORS
+.An Devin Teske Aq Mt dteske@FreeBSD.org
Index: cddl/usr.sbin/dwatch/examples/Makefile
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/examples/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+FILESDIR= ${SHAREDIR}/examples/dwatch
+FILES= profile_template
+
+.include <bsd.prog.mk>
Index: cddl/usr.sbin/dwatch/examples/profile_template
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/examples/profile_template
@@ -0,0 +1,74 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) profile for XXX entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# XXX
+#
+############################################################ PRAGMAS
+
+# Optional: You can override the default pragmas (shown below)
+
+#DTRACE_PRAGMA="
+# option quiet
+# option dynvarsize=16m
+# switchrate=10hz
+#" # END-QUOTE
+
+############################################################ PROBE
+
+# Optional: dwatch(8) initializes this to the expanded probe arguments
+
+#: ${PROBE:="XXX"}
+
+############################################################ ACTIONS
+
+# Optional actions to be performed before hitting the final print action
+
+#exec 9<<EOF
+#EOF
+#ACTIONS=$( cat <&9 )
+#ID=
+
+############################################################ EVENT ACTION
+
+# The default EVENT value is simply `entry'. This is paired with $PROBE.
+
+#EVENT=
+
+# Optional predicate which must be true before the event action will run
+
+#EVENT_TEST=
+
+############################################################ EVENT TAG
+
+# The EVENT_TAG is run inside the print action after the timestamp has been
+# printed. By default, `UID.GID CMD[PID]: ' of the process is printed.
+
+#exec 9<<EOF
+#EOF
+#EVENT_TAG=$( cat <&9 )
+
+############################################################ EVENT DETAILS
+
+# The DETAILS are run after the EVENT_TAG and by default, the program name and
+# arguments of the process hitting the EVENT action are shown. This can be
+# customized to call-specific information because the `-v' flag of dwatch(8)
+# can provide detailed process information for the EVENT action on lines below
+# the DETAILS.
+#
+# NB: Should produce a single-line and not print a trailing newline.
+
+#exec 9<<EOF
+# printf("XXX");
+#EOF
+#DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/Makefile
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+FILESDIR= ${LIBEXECDIR}/dwatch
+FILES= chmod \
+ fchmod \
+ fchmodat \
+ kill \
+ nanosleep \
+ vop_create \
+ vop_readdir \
+ vop_rename \
+ vop_symlink
+
+LINKS= ${LIBEXECDIR}/dwatch/chmod ${LIBEXECDIR}/dwatch/lchmod
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_mkdir
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_mknod
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_remove
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_rmdir
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_lookup
+
+.include <bsd.prog.mk>
Index: cddl/usr.sbin/dwatch/libexec/chmod
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/chmod
@@ -0,0 +1,27 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for [l]chmod(2) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to chmod(2), lchmod(2), and/or similar
+#
+############################################################ PROBE
+
+: ${PROBE:="syscall::$PROFILE:entry"}
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ printf("%s(path \"%s\", mode %04o)",
+ probefunc, (string)copyinstr(arg0), (mode_t)arg1);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/fchmod
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/fchmod
@@ -0,0 +1,26 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for fchmod(2) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to fchmod(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:="syscall::$PROFILE:entry"}
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ printf("%s(fd %i, mode %04o)", probefunc, (int)arg0, (mode_t)arg1);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/fchmodat
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/fchmodat
@@ -0,0 +1,30 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for fchmodat(2) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to fchmodat(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:="syscall::$PROFILE:entry"}
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ printf("%s(fd %i, path \"%s\", mode %04o, flag %i)",
+ probefunc,
+ (int)arg0,
+ (string)copyinstr(arg1),
+ (mode_t)arg2, (int)arg3);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/kill
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/kill
@@ -0,0 +1,26 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for kill(2) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to kill(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:="syscall::$PROFILE:entry"}
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ printf("%s(pid %d, sig %i)", probefunc, (pid_t)arg0, (int)arg1);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/nanosleep
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/nanosleep
@@ -0,0 +1,31 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for nanosleep(2) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to nanosleep(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:="syscall::$PROFILE:entry"}
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ this->rqtp = (struct timespec *)copyin(arg0, sizeof(struct timespec));
+ this->rmtp = (struct timespec *)copyin(arg1, sizeof(struct timespec));
+ printf("%s(rqtp {%ds, %dns}, rmtp {%ds, %dns})",
+ probefunc,
+ this->rqtp->tv_sec, this->rqtp->tv_nsec,
+ this->rmtp->tv_sec, this->rmtp->tv_nsec);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/vop_create
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/vop_create
@@ -0,0 +1,173 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for VOP_CREATE(9) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print filesystem paths being operated-on by VOP_CREATE(9) [or similar]
+# NB: All paths are shown even if error prevents operation.
+#
+############################################################ PROBE
+
+: ${PROBE:="vfs:vop:$PROFILE:entry"}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+$PROBE /* probe ID 1 */
+{${TRACE:+
+ printf("<1>");}
+ this->vp = (struct vnode *)arg0;
+ this->ncp = this->vp != NULL ?
+ this->vp->v_cache_dst.tqh_first : 0;
+ this->fi_name = args[1] ? (
+ args[1]->a_cnp != NULL ?
+ stringof(args[1]->a_cnp->cn_nameptr) : ""
+ ) : "";
+ this->mount = this->vp != NULL ?
+ this->vp->v_mount : NULL; /* ptr to vfs we are in */
+ this->fi_fs = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_fstypename) : "";
+ this->fi_mount = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_mntonname) : "";
+ this->d_name = args[0]->v_cache_dd != NULL ?
+ stringof(args[0]->v_cache_dd->nc_name) : "";
+
+$( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+ this->nameDEPTH = "";
+EOFDEPTH
+)
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->fi_name == ""/ /* probe ID 2 */
+{${TRACE:+
+ printf("<2>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID 3 (depth 1) */
+{${TRACE:+
+ printf("<3>");}
+ this->dvp = this->ncp->nc_dvp != NULL ?
+ this->ncp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name1 = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+$PROBE /this->name1 == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->name1 == "/" || this->name1 == ""/ /* probe ID 4 */
+{${TRACE:+
+ printf("<4>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=5 -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+$PROBE /this->dvp/ /* probe ID IDNUM (depth DEPTH) */
+{${TRACE:+
+ printf("<IDNUM>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->nameDEPTH = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+EOFDEPTH
+)
+
+$PROBE /this->dvp/ /* probe ID $(( $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $MAX_DEPTH + 4 ))>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name$(( $MAX_DEPTH + 1 )) = this->dvp != 0 ? (
+ this->dvp->nc_dvp != NULL ? "..." : ""
+ ) : "";
+}
+
+/*
+ * END Pathname-depth iterators
+ */
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ /*
+ * Print full path
+ * NB: Up-to but not including the parent directory (printed below)
+ */
+ printf("%s%s", this->fi_mount, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ $0 = (N <= MAX_DEPTH ? "\t" : "") buf
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFDEPTH
+ printf("%s%s", this->name = this->nameN, this->name != "" ? "/" : "");
+ EOFDEPTH
+ )
+
+ /* Print the parent directory name */
+ this->name = this->d_name != 0 ? this->d_name : "";
+ printf("%s%s", this->name, this->name != "" ? "/" : "");
+
+ /* Print the entry name */
+ this->name = this->fi_name != 0 ? this->fi_name : "";
+ printf("%s", this->name);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/vop_readdir
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/vop_readdir
@@ -0,0 +1,164 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for VOP_READDIR(9) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print directory paths being read by VOP_READDIR(9) [or similar]
+# NB: All paths are shown even if error prevents their reading.
+#
+############################################################ PROBE
+
+: ${PROBE:="vfs:vop:$PROFILE:entry"}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+$PROBE /* probe ID 1 */
+{${TRACE:+
+ printf("<1>");}
+ this->vp = (struct vnode *)arg0;
+ this->ncp = this->vp != NULL ?
+ this->vp->v_cache_dst.tqh_first : 0;
+ this->mount = this->vp != NULL ?
+ this->vp->v_mount : NULL; /* ptr to vfs we are in */
+ this->fi_fs = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_fstypename) : "";
+ this->fi_mount = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_mntonname) : "";
+ this->d_name = args[0]->v_cache_dd != NULL ?
+ stringof(args[0]->v_cache_dd->nc_name) : "";
+
+$( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+ this->nameDEPTH = "";
+EOFDEPTH
+)
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == ""/ /* probe ID 2 */
+{${TRACE:+
+ printf("<2>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID 3 (depth 1) */
+{${TRACE:+
+ printf("<3>");}
+ this->dvp = this->ncp->nc_dvp != NULL ?
+ this->ncp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name1 = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+$PROBE /this->name1 == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->name1 == "/" || this->name1 == ""/ /* probe ID 4 */
+{${TRACE:+
+ printf("<4>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=5 -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+$PROBE /this->dvp/ /* probe ID IDNUM (depth DEPTH) */
+{${TRACE:+
+ printf("<IDNUM>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->nameDEPTH = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+EOFDEPTH
+)
+
+$PROBE /this->dvp/ /* probe ID $(( $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $MAX_DEPTH + 4 ))>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name$(( $MAX_DEPTH + 1 )) = this->dvp != 0 ? (
+ this->dvp->nc_dvp != NULL ? "..." : ""
+ ) : "";
+}
+
+/*
+ * END Pathname-depth iterators
+ */
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ /*
+ * Print full path
+ * NB: Up-to but not including the parent directory (printed below)
+ */
+ printf("%s%s", this->fi_mount, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ $0 = (N <= MAX_DEPTH ? "\t" : "") buf
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFDEPTH
+ printf("%s%s", this->name = this->nameN, this->name != "" ? "/" : "");
+ EOFDEPTH
+ )
+
+ /* Print the parent directory name */
+ this->name = this->d_name != 0 ? this->d_name : "";
+ printf("%s%s", this->name, this->name != "" ? "/" : "");
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/vop_rename
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/vop_rename
@@ -0,0 +1,269 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for VOP_RENAME(9) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print filesystem paths being renamed by VOP_RENAME(9) [or similar]
+# NB: All paths are shown even if error prevents their rename.
+#
+############################################################ PROBE
+
+: ${PROBE:="vfs:vop:$PROFILE:entry"}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+$PROBE /* probe ID 1 */
+{${TRACE:+
+ printf("<1>");}
+ this->fvp = args[1] ? args[1]->a_fdvp : NULL;
+ this->fncp = this->fvp != NULL ?
+ this->fvp->v_cache_dst.tqh_first : 0;
+ this->ffi_name = args[1] ? (
+ args[1]->a_fcnp != NULL ?
+ stringof(args[1]->a_fcnp->cn_nameptr) : ""
+ ) : "";
+ this->fmount = this->fvp != NULL ?
+ this->fvp->v_mount : NULL; /* ptr to vfs we are in */
+ this->ffi_fs = this->fmount != NULL ?
+ stringof(this->fmount->mnt_stat.f_fstypename) : "";
+ this->ffi_mount = this->fmount != NULL ?
+ stringof(this->fmount->mnt_stat.f_mntonname) : "";
+ this->fd_name = args[0]->v_cache_dd != NULL ?
+ stringof(args[0]->v_cache_dd->nc_name) : "";
+
+ this->tvp = args[1] ? args[1]->a_tdvp : NULL;
+ this->tncp = this->tvp != NULL ?
+ this->tvp->v_cache_dst.tqh_first : 0;
+ this->tfi_name = args[1] ? (
+ args[1]->a_tcnp != NULL ?
+ stringof(args[1]->a_tcnp->cn_nameptr) : ""
+ ) : "";
+ this->tmount = this->tvp != NULL ?
+ this->tvp->v_mount : NULL; /* ptr to vfs we are in */
+ this->tfi_fs = this->tmount != NULL ?
+ stringof(this->tmount->mnt_stat.f_fstypename) : "";
+ this->tfi_mount = this->tmount != NULL ?
+ stringof(this->tmount->mnt_stat.f_mntonname) : "";
+ this->td_name = this->tvp != NULL ? (
+ this->tvp->v_cache_dd != NULL ?
+ stringof(this->tvp->v_cache_dd->nc_name) : ""
+ ) : "";
+
+$( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+ this->fnameDEPTH = this->tnameDEPTH = "";
+EOFDEPTH
+)
+}
+
+$PROBE /this->fvp == 0 || this->ffi_fs == 0 ||
+ this->ffi_fs == "devfs" || this->ffi_fs == "" ||
+ this->ffi_name == ""/ /* probe ID 2 */
+{${TRACE:+
+ printf("<2>");}
+ this->fncp = 0;
+}
+
+$PROBE /this->tvp == 0 || this->tfi_fs == 0 ||
+ this->tfi_fs == "devfs" || this->tfi_fs == "" ||
+ this->tfi_name == ""/ /* probe ID 3 */
+{${TRACE:+
+ printf("<3>");}
+ this->tncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->fncp/ /* probe ID 4 (depth 1) */
+{${TRACE:+
+ printf("<4>");}
+ this->fdvp = this->fncp->nc_dvp != NULL ?
+ this->fncp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->fname1 = this->fdvp != 0 ? (
+ this->fdvp->nc_name != 0 ? stringof(this->fdvp->nc_name) : ""
+ ) : "";
+}
+
+$PROBE /this->tncp/ /* probe ID 5 (depth 1) */
+{${TRACE:+
+ printf("<5>");}
+ this->tdvp = this->tncp->nc_dvp != NULL ?
+ this->tncp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->tname1 = this->tdvp != 0 ? (
+ this->tdvp->nc_name != 0 ? stringof(this->tdvp->nc_name) : ""
+ ) : "";
+}
+
+$PROBE /this->fname1 == 0 || this->ffi_fs == 0 ||
+ this->ffi_fs == "devfs" || this->ffi_fs == "" ||
+ this->fname1 == "/" || this->fname1 == ""/ /* probe ID 6 */
+{${TRACE:+
+ printf("<6>");}
+ this->fdvp = 0;
+}
+
+$PROBE /this->tname1 == 0 || this->tfi_fs == 0 ||
+ this->tfi_fs == "devfs" || this->tfi_fs == "" ||
+ this->tname1 == "/" || this->tname1 == ""/ /* probe ID 7 */
+{${TRACE:+
+ printf("<7>");}
+ this->tdvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=8 -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM1/, ID)
+ gsub(/IDNUM2/, ID + 1)
+ sub(/\n$/, "")
+ print
+ ID = ID + 2
+ }
+ }
+' <<EOFDEPTH
+$PROBE /this->fdvp/ /* probe ID IDNUM1 (depth DEPTH) */
+{${TRACE:+
+ printf("<IDNUM1>");}
+ this->fdvp = this->fdvp->nc_dvp != NULL ?
+ this->fdvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->fnameDEPTH = this->fdvp != 0 ? (
+ this->fdvp->nc_name != 0 ? stringof(this->fdvp->nc_name) : ""
+ ) : "";
+}
+$PROBE /this->tdvp/ /* probe ID IDNUM2 (depth DEPTH) */
+{${TRACE:+
+ printf("<IDNUM2>");}
+ this->tdvp = this->tdvp->nc_dvp != NULL ?
+ this->tdvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->tnameDEPTH = this->tdvp != 0 ? (
+ this->tdvp->nc_name != 0 ? stringof(this->tdvp->nc_name) : ""
+ ) : "";
+}
+
+EOFDEPTH
+)
+
+$PROBE /this->fdvp/ /* probe ID $(( $MAX_DEPTH * 2 + 6 )) */
+{${TRACE:+
+ printf("<$(( $MAX_DEPTH * 2 + 6 ))>");}
+ this->fdvp = this->fdvp->nc_dvp != NULL ?
+ this->fdvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->fname$(( $MAX_DEPTH + 1 )) = this->fdvp != 0 ? (
+ this->fdvp->nc_dvp != NULL ? "..." : ""
+ ) : "";
+}
+$PROBE /this->tdvp/ /* probe ID $(( $MAX_DEPTH * 2 + 7 )) */
+{${TRACE:+
+ printf("<$(( $MAX_DEPTH * 2 + 7 ))>");}
+ this->tdvp = this->tdvp->nc_dvp != NULL ?
+ this->tdvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->tname$(( $MAX_DEPTH + 1 )) = this->tdvp != 0 ? (
+ this->tdvp->nc_dvp != NULL ? "..." : ""
+ ) : "";
+}
+
+/*
+ * END Pathname-depth iterators
+ */
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $MAX_DEPTH * 2 + 8 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->ffi_mount != 0 && this->tfi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ /*
+ * Print 'from' full path
+ * NB: Up-to but not including the parent directory (printed below)
+ */
+ printf("%s%s", this->ffi_mount, this->ffi_mount != 0 ? (
+ this->ffi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ $0 = (N <= MAX_DEPTH ? "\t" : "") buf
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFDEPTH
+ printf("%s%s", this->fname = this->fnameN, this->fname != "" ? "/" : "");
+ EOFDEPTH
+ )
+
+ /* Print the 'from' parent directory name */
+ this->fname = this->fd_name != 0 ? this->fd_name : "";
+ printf("%s%s", this->fname, this->fname != "" ? "/" : "");
+
+ /* Print the 'from' entry name */
+ this->fname = this->ffi_name != 0 ? this->ffi_name : "";
+ printf("%s", this->fname);
+
+ printf(" -> ");
+
+ /*
+ * Print 'to' full path
+ * NB: Up-to but not including the parent directory (printed below)
+ */
+ printf("%s%s", this->tfi_mount, this->tfi_mount != 0 ? (
+ this->tfi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ $0 = (N <= MAX_DEPTH ? "\t" : "") buf
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFDEPTH
+ printf("%s%s", this->tname = this->tnameN, this->tname != "" ? "/" : "");
+ EOFDEPTH
+ )
+
+ /* Print the 'to' parent directory name */
+ this->tname = this->td_name != 0 ? this->td_name : "";
+ printf("%s%s", this->tname, this->tname != "" ? "/" : "");
+
+ /* Print the 'to' entry name */
+ this->tname = this->tfi_name != 0 ? this->tfi_name : "";
+ printf("%s", this->tname);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: cddl/usr.sbin/dwatch/libexec/vop_symlink
===================================================================
--- /dev/null
+++ cddl/usr.sbin/dwatch/libexec/vop_symlink
@@ -0,0 +1,177 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for VOP_SYMLINK(9) [or similar] entry $
+# $Copyright: 2014-2017 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print symlink paths being created by VOP_SYMLINK(9) [or similar]
+# NB: All paths are shown even if error prevents their creation.
+#
+############################################################ PROBE
+
+: ${PROBE:="vfs:vop:$PROFILE:entry"}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+$PROBE /* probe ID 1 */
+{${TRACE:+
+ printf("<1>");}
+ this->vp = (struct vnode *)arg0;
+ this->ncp = this->vp != NULL ?
+ this->vp->v_cache_dst.tqh_first : 0;
+ this->target = args[1] ? args[1]->a_target : "";
+ this->fi_name = args[1] ? (
+ args[1]->a_cnp != NULL ?
+ stringof(args[1]->a_cnp->cn_nameptr) : ""
+ ) : "";
+ this->mount = this->vp != NULL ?
+ this->vp->v_mount : NULL; /* ptr to vfs we are in */
+ this->fi_fs = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_fstypename) : "";
+ this->fi_mount = this->mount != NULL ?
+ stringof(this->mount->mnt_stat.f_mntonname) : "";
+ this->d_name = args[0]->v_cache_dd != NULL ?
+ stringof(args[0]->v_cache_dd->nc_name) : "";
+
+$( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+ this->nameDEPTH = "";
+EOFDEPTH
+)
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->fi_name == ""/ /* probe ID 2 */
+{${TRACE:+
+ printf("<2>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID 3 (depth 1) */
+{${TRACE:+
+ printf("<3>");}
+ this->dvp = this->ncp->nc_dvp != NULL ?
+ this->ncp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name1 = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+$PROBE /this->name1 == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->name1 == "/" || this->name1 == ""/ /* probe ID 4 */
+{${TRACE:+
+ printf("<4>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=5 -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ sub(/\n$/, "")
+ print
+ }
+ }
+' <<EOFDEPTH
+$PROBE /this->dvp/ /* probe ID IDNUM (depth DEPTH) */
+{${TRACE:+
+ printf("<IDNUM>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->nameDEPTH = this->dvp != 0 ? (
+ this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
+ ) : "";
+}
+
+EOFDEPTH
+)
+
+$PROBE /this->dvp/ /* probe ID $(( $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $MAX_DEPTH + 4 ))>");}
+ this->dvp = this->dvp->nc_dvp != NULL ?
+ this->dvp->nc_dvp->v_cache_dst.tqh_first : 0;
+ this->name$(( $MAX_DEPTH + 1 )) = this->dvp != 0 ? (
+ this->dvp->nc_dvp != NULL ? "..." : ""
+ ) : "";
+}
+
+/*
+ * END Pathname-depth iterators
+ */
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+exec 9<<EOF
+ /*
+ * Print full path
+ * NB: Up-to but not including the parent directory (printed below)
+ */
+ printf("%s%s", this->fi_mount, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ buf = buf $0 "\n" { }
+ END {
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ $0 = (N <= MAX_DEPTH ? "\t" : "") buf
+ gsub(/N/, N)
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFDEPTH
+ printf("%s%s", this->name = this->nameN, this->name != "" ? "/" : "");
+ EOFDEPTH
+ )
+
+ /* Print the parent directory name */
+ this->name = this->d_name != 0 ? this->d_name : "";
+ printf("%s%s", this->name, this->name != "" ? "/" : "");
+
+ /* Print the entry name */
+ this->name = this->fi_name != 0 ? this->fi_name : "";
+ printf("%s", this->name);
+
+ /* Print the target */
+ printf(" -> %s", this->target);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+
+################################################################################
+# END
+################################################################################
Index: etc/mtree/BSD.usr.dist
===================================================================
--- etc/mtree/BSD.usr.dist
+++ etc/mtree/BSD.usr.dist
@@ -124,6 +124,8 @@
..
bsdinstall
..
+ dwatch
+ ..
hyperv
..
lpr
@@ -333,6 +335,8 @@
..
drivers
..
+ dwatch
+ ..
etc
defaults
..
Index: share/dtrace/Makefile
===================================================================
--- share/dtrace/Makefile
+++ share/dtrace/Makefile
@@ -17,10 +17,7 @@
tcpdebug \
tcpstate \
tcptrack \
- udptrack \
- watch_execve \
- watch_kill \
- watch_vop_remove
+ udptrack
SCRIPTSDIR= ${SHAREDIR}/dtrace
Index: share/dtrace/watch_execve
===================================================================
--- share/dtrace/watch_execve
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/sbin/dtrace -s
-/* -
- * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Title: dtrace(1) script to log process(es) entering syscall::execve $
- * $FreeBSD$
- */
-
-#pragma D option quiet
-#pragma D option dynvarsize=16m
-#pragma D option switchrate=10hz
-
-/*********************************************************/
-
-syscall::execve:entry /* probe ID 1 */
-{
- this->caller_execname = execname;
-}
-
-/*********************************************************/
-
-syscall::execve:return /execname != this->caller_execname/ /* probe ID 2 */
-{
- /*
- * Examine process, parent process, and grandparent process details
- */
-
- /******************* CURPROC *******************/
-
- this->proc = curthread->td_proc;
- this->pid0 = this->proc->p_pid;
- this->uid0 = this->proc->p_ucred->cr_uid;
- this->gid0 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc->p_args;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg0_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* PPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid1 = this->proc->p_pid;
- this->uid1 = this->proc->p_ucred->cr_uid;
- this->gid1 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg1_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* GPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid2 = this->proc->p_pid;
- this->uid2 = this->proc->p_ucred->cr_uid;
- this->gid2 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg2_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* APARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid3 = this->proc->p_pid;
- this->uid3 = this->proc->p_ucred->cr_uid;
- this->gid3 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg3_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_4 = this->ar_length > 0 ? "..." : "";
-
- /***********************************************/
-
- /*
- * Print process, parent, and grandparent details
- */
-
- printf("%Y %s[%d]: ", timestamp + 1406598400000000000,
- this->caller_execname, this->pid1);
- printf("%s", this->arg0_0);
- printf("%s%s", this->arg0_1 != "" ? " " : "", this->arg0_1);
- printf("%s%s", this->arg0_2 != "" ? " " : "", this->arg0_2);
- printf("%s%s", this->arg0_3 != "" ? " " : "", this->arg0_3);
- printf("%s%s", this->arg0_4 != "" ? " " : "", this->arg0_4);
- printf("\n");
-
- printf(" -+= %05d %d.%d %s",
- this->pid3, this->uid3, this->gid3, this->arg3_0);
- printf("%s%s", this->arg3_1 != "" ? " " : "", this->arg3_1);
- printf("%s%s", this->arg3_2 != "" ? " " : "", this->arg3_2);
- printf("%s%s", this->arg3_3 != "" ? " " : "", this->arg3_3);
- printf("%s%s", this->arg3_4 != "" ? " " : "", this->arg3_4);
- printf("%s", this->arg3_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid2, this->uid2, this->gid2, this->arg2_0);
- printf("%s%s", this->arg2_1 != "" ? " " : "", this->arg2_1);
- printf("%s%s", this->arg2_2 != "" ? " " : "", this->arg2_2);
- printf("%s%s", this->arg2_3 != "" ? " " : "", this->arg2_3);
- printf("%s%s", this->arg2_4 != "" ? " " : "", this->arg2_4);
- printf("%s", this->arg2_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid1, this->uid1, this->gid1, this->arg1_0);
- printf("%s%s", this->arg1_1 != "" ? " " : "", this->arg1_1);
- printf("%s%s", this->arg1_2 != "" ? " " : "", this->arg1_2);
- printf("%s%s", this->arg1_3 != "" ? " " : "", this->arg1_3);
- printf("%s%s", this->arg1_4 != "" ? " " : "", this->arg1_4);
- printf("%s", this->arg1_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid0, this->uid0, this->gid0, this->arg0_0);
- printf("%s%s", this->arg0_1 != "" ? " " : "", this->arg0_1);
- printf("%s%s", this->arg0_2 != "" ? " " : "", this->arg0_2);
- printf("%s%s", this->arg0_3 != "" ? " " : "", this->arg0_3);
- printf("%s%s", this->arg0_4 != "" ? " " : "", this->arg0_4);
- printf("%s", this->arg0_0 != "" ? "\n" : "");
-}
Index: share/dtrace/watch_kill
===================================================================
--- share/dtrace/watch_kill
+++ /dev/null
@@ -1,232 +0,0 @@
-#!/usr/sbin/dtrace -s
-/* -
- * Copyright (c) 2014-2016 Devin Teske <dteske@FreeBSD.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Title: dtrace(1) script to log process(es) entering syscall::kill $
- * $FreeBSD$
- */
-
-#pragma D option quiet
-#pragma D option dynvarsize=16m
-#pragma D option switchrate=10hz
-
-/*********************************************************/
-
-syscall::execve:entry /* probe ID 1 */
-{
- this->caller_execname = execname;
-}
-
-/*********************************************************/
-
-syscall::kill:entry /* probe ID 2 */
-{
- this->pid_to_kill = (pid_t)arg0;
- this->kill_signal = (int)arg1;
-
- /*
- * Examine process, parent process, and grandparent process details
- */
-
- /******************* CURPROC *******************/
-
- this->proc = curthread->td_proc;
- this->pid0 = this->proc->p_pid;
- this->uid0 = this->proc->p_ucred->cr_uid;
- this->gid0 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc->p_args;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg0_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* PPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid1 = this->proc->p_pid;
- this->uid1 = this->proc->p_ucred->cr_uid;
- this->gid1 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg1_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* GPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid2 = this->proc->p_pid;
- this->uid2 = this->proc->p_ucred->cr_uid;
- this->gid2 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg2_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* APARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid3 = this->proc->p_pid;
- this->uid3 = this->proc->p_ucred->cr_uid;
- this->gid3 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg3_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg3_4 = this->ar_length > 0 ? "..." : "";
-
- /***********************************************/
-
- /*
- * Print process, parent, and grandparent details
- */
-
- printf("%Y %s[%d]: ", timestamp + 1406598400000000000,
- this->caller_execname, this->pid1);
- printf("%s", this->arg0_0);
- printf("%s%s", this->arg0_1 != "" ? " " : "", this->arg0_1);
- printf("%s%s", this->arg0_2 != "" ? " " : "", this->arg0_2);
- printf("%s%s", this->arg0_3 != "" ? " " : "", this->arg0_3);
- printf("%s%s", this->arg0_4 != "" ? " " : "", this->arg0_4);
- printf(" (sending signal %u to pid %u)",
- this->kill_signal, this->pid_to_kill);
- printf("\n");
-
- printf(" -+= %05d %d.%d %s",
- this->pid3, this->uid3, this->gid3, this->arg3_0);
- printf("%s%s", this->arg3_1 != "" ? " " : "", this->arg3_1);
- printf("%s%s", this->arg3_2 != "" ? " " : "", this->arg3_2);
- printf("%s%s", this->arg3_3 != "" ? " " : "", this->arg3_3);
- printf("%s%s", this->arg3_4 != "" ? " " : "", this->arg3_4);
- printf("%s", this->arg3_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid2, this->uid2, this->gid2, this->arg2_0);
- printf("%s%s", this->arg2_1 != "" ? " " : "", this->arg2_1);
- printf("%s%s", this->arg2_2 != "" ? " " : "", this->arg2_2);
- printf("%s%s", this->arg2_3 != "" ? " " : "", this->arg2_3);
- printf("%s%s", this->arg2_4 != "" ? " " : "", this->arg2_4);
- printf("%s", this->arg2_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid1, this->uid1, this->gid1, this->arg1_0);
- printf("%s%s", this->arg1_1 != "" ? " " : "", this->arg1_1);
- printf("%s%s", this->arg1_2 != "" ? " " : "", this->arg1_2);
- printf("%s%s", this->arg1_3 != "" ? " " : "", this->arg1_3);
- printf("%s%s", this->arg1_4 != "" ? " " : "", this->arg1_4);
- printf("%s", this->arg1_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid0, this->uid0, this->gid0, this->arg0_0);
- printf("%s%s", this->arg0_1 != "" ? " " : "", this->arg0_1);
- printf("%s%s", this->arg0_2 != "" ? " " : "", this->arg0_2);
- printf("%s%s", this->arg0_3 != "" ? " " : "", this->arg0_3);
- printf("%s%s", this->arg0_4 != "" ? " " : "", this->arg0_4);
- printf("%s", this->arg0_0 != "" ? "\n" : "");
-}
Index: share/dtrace/watch_vop_remove
===================================================================
--- share/dtrace/watch_vop_remove
+++ /dev/null
@@ -1,476 +0,0 @@
-#!/usr/sbin/dtrace -s
-/* -
- * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Title: dtrace(1) script to log process(es) entering vfs::vop_remove $
- * $FreeBSD$
- */
-
-#pragma D option quiet
-#pragma D option dynvarsize=16m
-#pragma D option switchrate=10hz
-
-/*********************************************************/
-
-vfs::vop_remove:entry /* probe ID 1 */
-{
- this->vp = (struct vnode *)arg0;
- this->ncp = &(this->vp->v_cache_dst) != NULL ?
- this->vp->v_cache_dst.tqh_first : 0;
- this->fi_name = args[1] ? (
- args[1]->a_cnp != NULL ?
- stringof(args[1]->a_cnp->cn_nameptr) : ""
- ) : "";
- this->mount = this->vp->v_mount; /* ptr to vfs we are in */
- this->fi_fs = this->mount != 0 ?
- stringof(this->mount->mnt_stat.f_fstypename) : "";
- this->fi_mount = this->mount != 0 ?
- stringof(this->mount->mnt_stat.f_mntonname) : "";
- this->d_name = args[0]->v_cache_dd != NULL ?
- stringof(args[0]->v_cache_dd->nc_name) : "";
-}
-
-vfs::vop_remove:entry /this->vp == 0 || this->fi_fs == 0 ||
- this->fi_fs == "devfs" || this->fi_fs == "" ||
- this->fi_name == ""/ /* probe ID 2 */
-{
- this->ncp = 0;
-}
-
-/*********************************************************/
-
-vfs::vop_remove:entry /this->ncp/ /* probe ID 3 (depth 1) */
-{
- this->dvp = this->ncp->nc_dvp != NULL ? (
- &(this->ncp->nc_dvp->v_cache_dst) != NULL ?
- this->ncp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name1 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->name1 == 0 || this->fi_fs == 0 ||
- this->fi_fs == "devfs" || this->fi_fs == "" ||
- this->name1 == "/" || this->name1 == ""/ /* probe ID 4 */
-{
- this->dvp = 0;
-}
-
-/*********************************************************/
-
-/*
- * BEGIN Pathname-depth iterators (copy/paste as many times as-desired)
- */
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 5 (depth 2) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name2 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 6 (depth 3) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name3 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 7 (depth 4) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name4 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 8 (depth 5) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name5 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 9 (depth 6) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name6 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 10 (depth 7) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name7 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 11 (depth 8) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name8 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 12 (depth 9) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name9 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 13 (depth 10) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name10 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 14 (depth 11) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name11 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 15 (depth 12) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name12 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 16 (depth 13) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name13 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 17 (depth 14) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name14 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 18 (depth 15) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name15 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 19 (depth 16) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name16 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 20 (depth 17) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name17 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 21 (depth 18) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name18 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 22 (depth 19) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name19 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-vfs::vop_remove:entry /this->dvp/ /* probe ID 23 (depth 20) */
-{
- this->dvp = this->dvp->nc_dvp != NULL ? (
- &(this->dvp->nc_dvp->v_cache_dst) != NULL ?
- this->dvp->nc_dvp->v_cache_dst.tqh_first : 0
- ) : 0;
- this->name20 = this->dvp != 0 ? (
- this->dvp->nc_name != 0 ? stringof(this->dvp->nc_name) : ""
- ) : "";
-}
-
-/*
- * END Pathname-depth iterators
- */
-
-/*********************************************************/
-
-vfs::vop_remove:entry /this->fi_mount != 0/ /* probe ID 24 */
-{
- printf("%Y %s[%d]: ", timestamp + 1406598400000000000, execname, pid);
-
- /*
- * Print full path of file to delete
- * NB: Up-to but not including the parent directory (printed below)
- */
- printf("%s%s", this->fi_mount, this->fi_mount != 0 ? (
- this->fi_mount == "/" ? "" : "/"
- ) : "/");
- printf("%s%s", this->name = this->name20, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name19, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name18, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name17, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name16, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name15, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name14, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name13, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name12, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name11, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name10, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name9, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name8, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name7, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name6, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name5, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name4, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name3, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name2, this->name != "" ? "/" : "");
- printf("%s%s", this->name = this->name1, this->name != "" ? "/" : "");
-
- /* Print the parent directory name */
- this->name = this->d_name != 0 ? this->d_name : "";
- printf("%s%s", this->name, this->name != "" ? "/" : "");
-
- /* Print the entry name */
- this->name = this->fi_name != 0 ? this->fi_name : "";
- printf("%s", this->name);
-
- printf("\n");
-
- /*
- * Examine process, parent process, and grandparent process details
- */
-
- /******************* CURPROC *******************/
-
- this->proc = curthread->td_proc;
- this->pid0 = this->proc->p_pid;
- this->uid0 = this->proc->p_ucred->cr_uid;
- this->gid0 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc->p_args;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg0_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg0_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* PPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid1 = this->proc->p_pid;
- this->uid1 = this->proc->p_ucred->cr_uid;
- this->gid1 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg1_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg1_4 = this->ar_length > 0 ? "..." : "";
-
- /******************* GPARENT *******************/
-
- this->proc = this->proc->p_pptr;
- this->pid2 = this->proc->p_pid;
- this->uid2 = this->proc->p_ucred->cr_uid;
- this->gid2 = this->proc->p_ucred->cr_rgid;
- this->p_args = this->proc ? this->proc->p_args : 0;
- this->ar_length = this->p_args ? this->p_args->ar_length : 0;
- this->ar_args = (char *)(this->p_args ? this->p_args->ar_args : 0);
-
- this->arg2_0 = this->ar_length > 0 ?
- this->ar_args : stringof(this->proc->p_comm);
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_1 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_2 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_3 = this->ar_length > 0 ? this->ar_args : "";
- this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
- this->ar_args += this->len;
- this->ar_length -= this->len;
-
- this->arg2_4 = this->ar_length > 0 ? "..." : "";
-
- /***********************************************/
-
- /*
- * Print process, parent, and grandparent details
- */
-
- printf(" -+= %05d %d.%d %s",
- this->pid2, this->uid2, this->gid2, this->arg2_0);
- printf("%s%s", this->arg2_1 != "" ? " " : "", this->arg2_1);
- printf("%s%s", this->arg2_2 != "" ? " " : "", this->arg2_2);
- printf("%s%s", this->arg2_3 != "" ? " " : "", this->arg2_3);
- printf("%s%s", this->arg2_4 != "" ? " " : "", this->arg2_4);
- printf("%s", this->arg2_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid1, this->uid1, this->gid1, this->arg1_0);
- printf("%s%s", this->arg1_1 != "" ? " " : "", this->arg1_1);
- printf("%s%s", this->arg1_2 != "" ? " " : "", this->arg1_2);
- printf("%s%s", this->arg1_3 != "" ? " " : "", this->arg1_3);
- printf("%s%s", this->arg1_4 != "" ? " " : "", this->arg1_4);
- printf("%s", this->arg1_0 != "" ? "\n" : "");
-
- printf(" \-+= %05d %d.%d %s",
- this->pid0, this->uid0, this->gid0, this->arg0_0);
- printf("%s%s", this->arg0_1 != "" ? " " : "", this->arg0_1);
- printf("%s%s", this->arg0_2 != "" ? " " : "", this->arg0_2);
- printf("%s%s", this->arg0_3 != "" ? " " : "", this->arg0_3);
- printf("%s%s", this->arg0_4 != "" ? " " : "", this->arg0_4);
- printf("%s", this->arg0_0 != "" ? "\n" : "");
-}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Feb 10, 10:03 AM (9 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28620416
Default Alt Text
D10006.id29314.diff (110 KB)
Attached To
Mode
D10006: Add dwatch(8) for watching processes as they trigger dtrace probe
Attached
Detach File
Event Timeline
Log In to Comment