aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevin Teske <dteske@FreeBSD.org>2018-05-15 00:00:44 +0000
committerDevin Teske <dteske@FreeBSD.org>2018-05-15 00:00:44 +0000
commit16cdefa52d001a5c36b1500ef7de709d082a558e (patch)
treeb9aec09d785257e5ea37aaa6291e72aaba5cd548
parent94de7f96ec37e1922d7b20f020d4e5b86408503c (diff)
downloadsrc-16cdefa52d001a5c36b1500ef7de709d082a558e.tar.gz
src-16cdefa52d001a5c36b1500ef7de709d082a558e.zip
MFC SVN r329188,329334,329353,329914,329995-329996: DTrace Enhancements
r329188: Use tabs in io.d, fix alignment issues, remove extra newlines r329334: Add errno definitions to /usr/lib/dtrace/errno.d r329353: Add inline to errno.d for translating int to string r329914: Updates and enhancements to io.d to aid DTrace scripting r329995: Updates and enhancements to signal.d to aid DTrace scripting r329996: Consistent casing for fallback SIGCHLD (s/Unknown/unknown/) MFC SVN r330559-330560,330672,332865-332867,333513-333519: dwatch(1) r330559: Introduce dwatch(1) as a tool for making DTrace more useful r330560: Bump dwatch(1) internal version from 1.0-beta-91 to 1.0 r330672: Fix display of wrong pid from dtrace_sched(4) r332865: Add `-dev' option to aid debugging of profiles r332866: Add profile for send(2)/recv(2) syscalls r332867: Remove the line used to demonstrate `-dev' option r333513: Bugfix, usage displayed with `-1Q' r333514: Separate default values so `-[BK] num' don't affect usage r333515: Simplify info message test r333516: Export ARGV to profiles loaded via load_profile() r333517: Allow `-E code' to override profile EVENT_DETAILS r333518: Expose process for ip/tcp/udp r333519: Refactor sendrecv profile Reviewed by: markj, gnn, bdrewery (head; earlier version) Approved by: re (gjb) Relnotes: yes Sponsored by: Smule, Inc. Differential Revision: https://reviews.freebsd.org/D15418
Notes
Notes: svn path=/stable/11/; revision=333617
-rw-r--r--ObsoleteFiles.inc4
-rw-r--r--cddl/lib/libdtrace/errno.d122
-rw-r--r--cddl/lib/libdtrace/io.d212
-rw-r--r--cddl/lib/libdtrace/ip.d8
-rw-r--r--cddl/lib/libdtrace/libproc_compat.h2
-rw-r--r--cddl/lib/libdtrace/psinfo.d1
-rw-r--r--cddl/lib/libdtrace/regs_x86.d3
-rw-r--r--cddl/lib/libdtrace/sched.d1
-rw-r--r--cddl/lib/libdtrace/signal.d52
-rw-r--r--cddl/lib/libdtrace/tcp.d140
-rw-r--r--cddl/lib/libdtrace/udp.d2
-rw-r--r--cddl/usr.sbin/Makefile5
-rw-r--r--cddl/usr.sbin/dwatch/Makefile15
-rwxr-xr-xcddl/usr.sbin/dwatch/dwatch1401
-rw-r--r--cddl/usr.sbin/dwatch/dwatch.1766
-rw-r--r--cddl/usr.sbin/dwatch/examples/Makefile6
-rw-r--r--cddl/usr.sbin/dwatch/examples/profile_template74
-rw-r--r--cddl/usr.sbin/dwatch/libexec/Makefile87
-rw-r--r--cddl/usr.sbin/dwatch/libexec/chmod65
-rw-r--r--cddl/usr.sbin/dwatch/libexec/errno37
-rw-r--r--cddl/usr.sbin/dwatch/libexec/io108
-rw-r--r--cddl/usr.sbin/dwatch/libexec/ip76
-rw-r--r--cddl/usr.sbin/dwatch/libexec/kill47
-rw-r--r--cddl/usr.sbin/dwatch/libexec/nanosleep54
-rw-r--r--cddl/usr.sbin/dwatch/libexec/open57
-rw-r--r--cddl/usr.sbin/dwatch/libexec/proc164
-rw-r--r--cddl/usr.sbin/dwatch/libexec/rw74
-rw-r--r--cddl/usr.sbin/dwatch/libexec/sched109
-rw-r--r--cddl/usr.sbin/dwatch/libexec/sendrecv229
-rw-r--r--cddl/usr.sbin/dwatch/libexec/tcp210
-rw-r--r--cddl/usr.sbin/dwatch/libexec/udp89
-rw-r--r--cddl/usr.sbin/dwatch/libexec/vop_create196
-rw-r--r--cddl/usr.sbin/dwatch/libexec/vop_readdir188
-rw-r--r--cddl/usr.sbin/dwatch/libexec/vop_rename302
-rw-r--r--cddl/usr.sbin/dwatch/libexec/vop_symlink197
-rw-r--r--etc/mtree/BSD.usr.dist4
-rw-r--r--share/dtrace/Makefile5
-rwxr-xr-xshare/dtrace/watch_execve227
-rwxr-xr-xshare/dtrace/watch_kill232
-rwxr-xr-xshare/dtrace/watch_vop_remove476
40 files changed, 4997 insertions, 1050 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 0f374c9a7604..89051510b2a6 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -38,6 +38,10 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20180513: remove DTrace scripts made obsolete by dwatch(1)
+OLD_FILES+=usr/share/dtrace/watch_execve
+OLD_FILES+=usr/share/dtrace/watch_kill
+OLD_FILES+=usr/share/dtrace/watch_vop_remove
# 20180331: new clang import which bumps version from 5.0.1 to 6.0.0.
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/5.0.1/include/sanitizer/asan_interface.h
diff --git a/cddl/lib/libdtrace/errno.d b/cddl/lib/libdtrace/errno.d
index b9a25e029f10..373657b5beb4 100644
--- a/cddl/lib/libdtrace/errno.d
+++ b/cddl/lib/libdtrace/errno.d
@@ -20,6 +20,7 @@
* CDDL HEADER END
*
* Portions Copyright 2006-2008 John Birrell jb@freebsd.org
+ * Portions Copyright 2018 Devin Teske dteske@freebsd.org
*
* $FreeBSD$
*/
@@ -216,7 +217,15 @@ inline int ENOLINK = 91;
#pragma D binding "1.0" ENOLINK
inline int EPROTO = 92;
#pragma D binding "1.0" EPROTO
-inline int ELAST = 92;
+inline int ENOTCAPABLE = 93;
+#pragma D binding "1.13" ENOTCAPABLE
+inline int ECAPMODE = 94;
+#pragma D binding "1.13" ECAPMODE
+inline int ENOTRECOVERABLE = 95;
+#pragma D binding "1.13" ENOTRECOVERABLE
+inline int EOWNERDEAD = 96;
+#pragma D binding "1.13" EOWNERDEAD
+inline int ELAST = 96;
#pragma D binding "1.0" ELAST
inline int ERESTART = -1;
#pragma D binding "1.0" ERESTART
@@ -226,3 +235,114 @@ inline int ENOIOCTL = -3;
#pragma D binding "1.0" ENOIOCTL
inline int EDIRIOCTL = -4;
#pragma D binding "1.0" EDIRIOCTL
+inline int ERELOOKUP = -5;
+#pragma D binding "1.13" ERELOOKUP
+
+/*
+ * Error strings from <sys/errno.h>
+ */
+#pragma D binding "1.13" strerror
+inline string strerror[int errno] =
+ errno == 0 ? "Success" :
+ errno == EPERM ? "Operation not permitted" :
+ errno == ENOENT ? "No such file or directory" :
+ errno == ESRCH ? "No such process" :
+ errno == EINTR ? "Interrupted system call" :
+ errno == EIO ? "Input/output error" :
+ errno == ENXIO ? "Device not configured" :
+ errno == E2BIG ? "Argument list too long" :
+ errno == ENOEXEC ? "Exec format error" :
+ errno == EBADF ? "Bad file descriptor" :
+ errno == ECHILD ? "No child processes" :
+ errno == EDEADLK ? "Resource deadlock avoided" :
+ errno == ENOMEM ? "Cannot allocate memory" :
+ errno == EACCES ? "Permission denied" :
+ errno == EFAULT ? "Bad address" :
+ errno == ENOTBLK ? "Block device required" :
+ errno == EBUSY ? "Device busy" :
+ errno == EEXIST ? "File exists" :
+ errno == EXDEV ? "Cross-device link" :
+ errno == ENODEV ? "Operation not supported by device" :
+ errno == ENOTDIR ? "Not a directory" :
+ errno == EISDIR ? "Is a directory" :
+ errno == EINVAL ? "Invalid argument" :
+ errno == ENFILE ? "Too many open files in system" :
+ errno == EMFILE ? "Too many open files" :
+ errno == ENOTTY ? "Inappropriate ioctl for device" :
+ errno == ETXTBSY ? "Text file busy" :
+ errno == EFBIG ? "File too large" :
+ errno == ENOSPC ? "No space left on device" :
+ errno == ESPIPE ? "Illegal seek" :
+ errno == EROFS ? "Read-only filesystem" :
+ errno == EMLINK ? "Too many links" :
+ errno == EPIPE ? "Broken pipe" :
+ errno == EDOM ? "Numerical argument out of domain" :
+ errno == ERANGE ? "Result too large" :
+ errno == EAGAIN ? "Resource temporarily unavailable" :
+ errno == EINPROGRESS ? "Operation now in progress" :
+ errno == EALREADY ? "Operation already in progress" :
+ errno == ENOTSOCK ? "Socket operation on non-socket" :
+ errno == EDESTADDRREQ ? "Destination address required" :
+ errno == EMSGSIZE ? "Message too long" :
+ errno == EPROTOTYPE ? "Protocol wrong type for socket" :
+ errno == ENOPROTOOPT ? "Protocol not available" :
+ errno == EPROTONOSUPPORT ? "Protocol not supported" :
+ errno == ESOCKTNOSUPPORT ? "Socket type not supported" :
+ errno == EOPNOTSUPP ? "Operation not supported" :
+ errno == EPFNOSUPPORT ? "Protocol family not supported" :
+ errno == EAFNOSUPPORT ? "Address family not supported by protocol family" :
+ errno == EADDRINUSE ? "Address already in use" :
+ errno == EADDRNOTAVAIL ? "Can't assign requested address" :
+ errno == ENETDOWN ? "Network is down" :
+ errno == ENETUNREACH ? "Network is unreachable" :
+ errno == ENETRESET ? "Network dropped connection on reset" :
+ errno == ECONNABORTED ? "Software caused connection abort" :
+ errno == ECONNRESET ? "Connection reset by peer" :
+ errno == ENOBUFS ? "No buffer space available" :
+ errno == EISCONN ? "Socket is already connected" :
+ errno == ENOTCONN ? "Socket is not connected" :
+ errno == ESHUTDOWN ? "Can't send after socket shutdown" :
+ errno == ETOOMANYREFS ? "Too many references: can't splice" :
+ errno == ETIMEDOUT ? "Operation timed out" :
+ errno == ECONNREFUSED ? "Connection refused" :
+ errno == ELOOP ? "Too many levels of symbolic links" :
+ errno == ENAMETOOLONG ? "File name too long" :
+ errno == EHOSTDOWN ? "Host is down" :
+ errno == EHOSTUNREACH ? "No route to host" :
+ errno == ENOTEMPTY ? "Directory not empty" :
+ errno == EPROCLIM ? "Too many processes" :
+ errno == EUSERS ? "Too many users" :
+ errno == EDQUOT ? "Disc quota exceeded" :
+ errno == ESTALE ? "Stale NFS file handle" :
+ errno == EREMOTE ? "Too many levels of remote in path" :
+ errno == EBADRPC ? "RPC struct is bad" :
+ errno == ERPCMISMATCH ? "RPC version wrong" :
+ errno == EPROGUNAVAIL ? "RPC prog. not avail" :
+ errno == EPROGMISMATCH ? "Program version wrong" :
+ errno == EPROCUNAVAIL ? "Bad procedure for program" :
+ errno == ENOLCK ? "No locks available" :
+ errno == ENOSYS ? "Function not implemented" :
+ errno == EFTYPE ? "Inappropriate file type or format" :
+ errno == EAUTH ? "Authentication error" :
+ errno == ENEEDAUTH ? "Need authenticator" :
+ errno == EIDRM ? "Identifier removed" :
+ errno == ENOMSG ? "No message of desired type" :
+ errno == EOVERFLOW ? "Value too large to be stored in data type" :
+ errno == ECANCELED ? "Operation canceled" :
+ errno == EILSEQ ? "Illegal byte sequence" :
+ errno == ENOATTR ? "Attribute not found" :
+ errno == EDOOFUS ? "Programming error" :
+ errno == EBADMSG ? "Bad message" :
+ errno == EMULTIHOP ? "Multihop attempted" :
+ errno == ENOLINK ? "Link has been severed" :
+ errno == EPROTO ? "Protocol error" :
+ errno == ENOTCAPABLE ? "Capabilities insufficient" :
+ errno == ECAPMODE ? "Not permitted in capability mode" :
+ errno == ENOTRECOVERABLE ? "State not recoverable" :
+ errno == EOWNERDEAD ? "Previous owner died" :
+ errno == ERESTART ? "restart syscall" :
+ errno == EJUSTRETURN ? "don't modify regs, just return" :
+ errno == ENOIOCTL ? "ioctl not handled by this layer" :
+ errno == EDIRIOCTL ? "do direct ioctl in GEOM" :
+ errno == ERELOOKUP ? "retry the directory lookup" :
+ "Unknown error";
diff --git a/cddl/lib/libdtrace/io.d b/cddl/lib/libdtrace/io.d
index 41f7aa1533b8..d643ad732a94 100644
--- a/cddl/lib/libdtrace/io.d
+++ b/cddl/lib/libdtrace/io.d
@@ -18,6 +18,8 @@
*
* CDDL HEADER END
*
+ * Portions Copyright 2018 Devin Teske dteske@freebsd.org
+ *
* $FreeBSD$
*/
/*
@@ -29,47 +31,51 @@
#pragma D depends_on provider io
typedef struct devinfo {
- int dev_major; /* major number */
- int dev_minor; /* minor number */
- int dev_instance; /* instance number */
- string dev_name; /* name of device */
- string dev_statname; /* name of device + instance/minor */
- string dev_pathname; /* pathname of device */
+ int dev_major; /* major number */
+ int dev_minor; /* minor number */
+ int dev_instance; /* instance number */
+ int dev_type; /* type of device */
+ string dev_name; /* name of device */
+ string dev_statname; /* name of device + instance/minor */
+ string dev_pathname; /* pathname of device */
} devinfo_t;
#pragma D binding "1.0" translator
translator devinfo_t < struct devstat *D > {
- dev_major = D->device_number;
- dev_minor = D->unit_number;
- dev_instance = 0;
- dev_name = stringof(D->device_name);
- dev_statname = stringof(D->device_name);
- dev_pathname = stringof(D->device_name);
+ dev_major = D->device_number;
+ dev_minor = D->unit_number;
+ dev_instance = 0;
+ dev_type = D->device_type;
+ dev_name = stringof(D->device_name);
+ dev_statname = stringof(D->device_name);
+ dev_pathname = stringof(D->device_name);
};
typedef struct bufinfo {
- int b_flags; /* flags */
- long b_bcount; /* number of bytes */
- caddr_t b_addr; /* buffer address */
- uint64_t b_blkno; /* expanded block # on device */
- uint64_t b_lblkno; /* block # on device */
- size_t b_resid; /* # of bytes not transferred */
- size_t b_bufsize; /* size of allocated buffer */
-/* caddr_t b_iodone; I/O completion routine */
- int b_error; /* expanded error field */
-/* dev_t b_edev; extended device */
+ int b_cmd; /* I/O operation */
+ int b_flags; /* flags */
+ long b_bcount; /* number of bytes */
+ caddr_t b_addr; /* buffer address */
+ uint64_t b_blkno; /* expanded block # on device */
+ uint64_t b_lblkno; /* block # on device */
+ size_t b_resid; /* # of bytes not transferred */
+ size_t b_bufsize; /* size of allocated buffer */
+/* caddr_t b_iodone; I/O completion routine */
+ int b_error; /* expanded error field */
+/* dev_t b_edev; extended device */
} bufinfo_t;
#pragma D binding "1.0" translator
translator bufinfo_t < struct bio *B > {
- b_flags = B->bio_flags;
- b_bcount = B->bio_bcount;
- b_addr = B->bio_data;
- b_blkno = 0;
- b_lblkno = 0;
- b_resid = B->bio_resid;
- b_bufsize = 0; /* XXX gnn */
- b_error = B->bio_error;
+ b_cmd = B->bio_cmd;
+ b_flags = B->bio_flags;
+ b_bcount = B->bio_bcount;
+ b_addr = B->bio_data;
+ b_blkno = 0;
+ b_lblkno = 0;
+ b_resid = B->bio_resid;
+ b_bufsize = 0; /* XXX gnn */
+ b_error = B->bio_error;
};
/*
@@ -106,4 +112,150 @@ inline int O_SYNC = 0x0080;
inline int O_TRUNC = 0x0400;
#pragma D binding "1.1" O_TRUNC
+/*
+ * The following inline constants can be used to examine bio_cmd of struct bio
+ * or a translated bufinfo_t.
+ */
+inline int BIO_READ = 0x01;
+#pragma D binding "1.13" BIO_READ
+inline int BIO_WRITE = 0x02;
+#pragma D binding "1.13" BIO_WRITE
+inline int BIO_DELETE = 0x03;
+#pragma D binding "1.13" BIO_DELETE
+inline int BIO_GETATTR = 0x04;
+#pragma D binding "1.13" BIO_GETATTR
+inline int BIO_FLUSH = 0x05;
+#pragma D binding "1.13" BIO_FLUSH
+inline int BIO_CMD0 = 0x06;
+#pragma D binding "1.13" BIO_CMD0
+inline int BIO_CMD1 = 0x07;
+#pragma D binding "1.13" BIO_CMD1
+inline int BIO_CMD2 = 0x08;
+#pragma D binding "1.13" BIO_CMD2
+inline int BIO_ZONE = 0x09;
+#pragma D binding "1.13" BIO_ZONE
+
+/*
+ * The following inline constants can be used to examine bio_flags of struct
+ * bio or a translated bufinfo_t.
+ */
+inline int BIO_ERROR = 0x01;
+#pragma D binding "1.13" BIO_ERROR
+inline int BIO_DONE = 0x02;
+#pragma D binding "1.13" BIO_DONE
+inline int BIO_ONQUEUE = 0x04;
+#pragma D binding "1.13" BIO_ONQUEUE
+inline int BIO_ORDERED = 0x08;
+#pragma D binding "1.13" BIO_ORDERED
+inline int BIO_UNMAPPED = 0x10;
+#pragma D binding "1.13" BIO_UNMAPPED
+inline int BIO_TRANSIENT_MAPPING = 0x20;
+#pragma D binding "1.13" BIO_TRANSIENT_MAPPING
+inline int BIO_VLIST = 0x40;
+#pragma D binding "1.13" BIO_VLIST
+
+/*
+ * The following inline constants can be used to examine device_type of struct
+ * devstat or a translated devinfo_t.
+ */
+inline int DEVSTAT_TYPE_DIRECT = 0x000;
+#pragma D binding "1.13" DEVSTAT_TYPE_DIRECT
+inline int DEVSTAT_TYPE_SEQUENTIAL = 0x001;
+#pragma D binding "1.13" DEVSTAT_TYPE_SEQUENTIAL
+inline int DEVSTAT_TYPE_PRINTER = 0x002;
+#pragma D binding "1.13" DEVSTAT_TYPE_PRINTER
+inline int DEVSTAT_TYPE_PROCESSOR = 0x003;
+#pragma D binding "1.13" DEVSTAT_TYPE_PROCESSOR
+inline int DEVSTAT_TYPE_WORM = 0x004;
+#pragma D binding "1.13" DEVSTAT_TYPE_WORM
+inline int DEVSTAT_TYPE_CDROM = 0x005;
+#pragma D binding "1.13" DEVSTAT_TYPE_CDROM
+inline int DEVSTAT_TYPE_SCANNER = 0x006;
+#pragma D binding "1.13" DEVSTAT_TYPE_SCANNER
+inline int DEVSTAT_TYPE_OPTICAL = 0x007;
+#pragma D binding "1.13" DEVSTAT_TYPE_OPTICAL
+inline int DEVSTAT_TYPE_CHANGER = 0x008;
+#pragma D binding "1.13" DEVSTAT_TYPE_CHANGER
+inline int DEVSTAT_TYPE_COMM = 0x009;
+#pragma D binding "1.13" DEVSTAT_TYPE_COMM
+inline int DEVSTAT_TYPE_ASC0 = 0x00a;
+#pragma D binding "1.13" DEVSTAT_TYPE_ASC0
+inline int DEVSTAT_TYPE_ASC1 = 0x00b;
+#pragma D binding "1.13" DEVSTAT_TYPE_ASC1
+inline int DEVSTAT_TYPE_STORARRAY = 0x00c;
+#pragma D binding "1.13" DEVSTAT_TYPE_STORARRAY
+inline int DEVSTAT_TYPE_ENCLOSURE = 0x00d;
+#pragma D binding "1.13" DEVSTAT_TYPE_ENCLOSURE
+inline int DEVSTAT_TYPE_FLOPPY = 0x00e;
+#pragma D binding "1.13" DEVSTAT_TYPE_FLOPPY
+inline int DEVSTAT_TYPE_MASK = 0x00f;
+#pragma D binding "1.13" DEVSTAT_TYPE_MASK
+inline int DEVSTAT_TYPE_IF_SCSI = 0x010;
+#pragma D binding "1.13" DEVSTAT_TYPE_IF_SCSI
+inline int DEVSTAT_TYPE_IF_IDE = 0x020;
+#pragma D binding "1.13" DEVSTAT_TYPE_IF_IDE
+inline int DEVSTAT_TYPE_IF_OTHER = 0x030;
+#pragma D binding "1.13" DEVSTAT_TYPE_IF_OTHER
+inline int DEVSTAT_TYPE_IF_MASK = 0x0f0;
+#pragma D binding "1.13" DEVSTAT_TYPE_IF_MASK
+inline int DEVSTAT_TYPE_PASS = 0x100;
+#pragma D binding "1.13" DEVSTAT_TYPE_PASS
+
+#pragma D binding "1.13" device_type_string
+inline string device_type_string[int type] =
+ type == DEVSTAT_TYPE_DIRECT ? "DIRECT" :
+ type == DEVSTAT_TYPE_SEQUENTIAL ? "SEQUENTIAL" :
+ type == DEVSTAT_TYPE_PRINTER ? "PRINTER" :
+ type == DEVSTAT_TYPE_PROCESSOR ? "PROCESSOR" :
+ type == DEVSTAT_TYPE_WORM ? "WORM" :
+ type == DEVSTAT_TYPE_CDROM ? "CDROM" :
+ type == DEVSTAT_TYPE_SCANNER ? "SCANNER" :
+ type == DEVSTAT_TYPE_OPTICAL ? "OPTICAL" :
+ type == DEVSTAT_TYPE_CHANGER ? "CHANGER" :
+ type == DEVSTAT_TYPE_COMM ? "COMM" :
+ type == DEVSTAT_TYPE_ASC0 ? "ASC0" :
+ type == DEVSTAT_TYPE_ASC1 ? "ASC1" :
+ type == DEVSTAT_TYPE_STORARRAY ? "STORARRAY" :
+ type == DEVSTAT_TYPE_ENCLOSURE ? "ENCLOSURE" :
+ type == DEVSTAT_TYPE_FLOPPY ? "FLOPPY" :
+ strjoin("UNKNOWN(", strjoin(lltostr(type), ")"));
+
+#pragma D binding "1.13" device_type
+inline string device_type[int type] =
+ device_type_string[type & DEVSTAT_TYPE_MASK];
+
+#pragma D binding "1.13" device_if_string
+inline string device_if_string[int type] =
+ type == 0 ? "ACCESS" :
+ type == DEVSTAT_TYPE_IF_SCSI ? "SCSI" :
+ type == DEVSTAT_TYPE_IF_IDE ? "IDE" :
+ type == DEVSTAT_TYPE_IF_OTHER ? "OTHER" :
+ strjoin("UNKNOWN(", strjoin(lltostr(type), ")"));
+
+#pragma D binding "1.13" device_if
+inline string device_if[int type] =
+ device_if_string[type & DEVSTAT_TYPE_IF_MASK];
+
+#pragma D binding "1.13" bio_cmd_string
+inline string bio_cmd_string[int cmd] =
+ cmd == BIO_READ ? "READ" :
+ cmd == BIO_WRITE ? "WRITE" :
+ cmd == BIO_DELETE ? "DELETE" :
+ cmd == BIO_GETATTR ? "GETATTR" :
+ cmd == BIO_FLUSH ? "FLUSH" :
+ cmd == BIO_CMD0 ? "CMD0" :
+ cmd == BIO_CMD1 ? "CMD1" :
+ cmd == BIO_CMD2 ? "CMD2" :
+ cmd == BIO_ZONE ? "ZONE" :
+ strjoin("UNKNOWN(", strjoin(lltostr(cmd), ")"));
+#pragma D binding "1.13" bio_flag_string
+inline string bio_flag_string[int flag] =
+ flag == BIO_ERROR ? "ERROR" :
+ flag == BIO_DONE ? "DONE" :
+ flag == BIO_ONQUEUE ? "ONQUEUE" :
+ flag == BIO_ORDERED ? "ORDERED" :
+ flag == BIO_UNMAPPED ? "UNMAPPED" :
+ flag == BIO_TRANSIENT_MAPPING ? "TRANSIENT_MAPPING" :
+ flag == BIO_VLIST ? "VLIST" :
+ "";
diff --git a/cddl/lib/libdtrace/ip.d b/cddl/lib/libdtrace/ip.d
index bf487e62f938..2c7bde161aa8 100644
--- a/cddl/lib/libdtrace/ip.d
+++ b/cddl/lib/libdtrace/ip.d
@@ -215,10 +215,10 @@ translator csinfo_t < void *p > {
#pragma D binding "1.6.3" translator
translator csinfo_t < struct inpcb *p > {
- cs_addr = NULL;
- cs_cid = (uint64_t)p;
- cs_pid = 0; /* XXX */
- cs_zoneid = 0;
+ cs_addr = NULL;
+ cs_cid = (uint64_t)p;
+ cs_pid = 0; /* XXX */
+ cs_zoneid = 0;
};
#pragma D binding "1.5" translator
diff --git a/cddl/lib/libdtrace/libproc_compat.h b/cddl/lib/libdtrace/libproc_compat.h
index 8704b820df58..b097897dad7f 100644
--- a/cddl/lib/libdtrace/libproc_compat.h
+++ b/cddl/lib/libdtrace/libproc_compat.h
@@ -4,7 +4,7 @@
*
* This software was developed by Rui Paulo under sponsorship from the
* FreeBSD Foundation.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
diff --git a/cddl/lib/libdtrace/psinfo.d b/cddl/lib/libdtrace/psinfo.d
index c391804e101d..0f5ca63c39a4 100644
--- a/cddl/lib/libdtrace/psinfo.d
+++ b/cddl/lib/libdtrace/psinfo.d
@@ -97,4 +97,3 @@ inline psinfo_t *curpsinfo = xlate <psinfo_t *> (curthread->td_proc);
inline lwpsinfo_t *curlwpsinfo = xlate <lwpsinfo_t *> (curthread);
#pragma D attributes Stable/Stable/Common curlwpsinfo
#pragma D binding "1.0" curlwpsinfo
-
diff --git a/cddl/lib/libdtrace/regs_x86.d b/cddl/lib/libdtrace/regs_x86.d
index 03528a6423d3..3f625f9f4445 100644
--- a/cddl/lib/libdtrace/regs_x86.d
+++ b/cddl/lib/libdtrace/regs_x86.d
@@ -1,4 +1,4 @@
-/*
+/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
@@ -116,4 +116,3 @@ inline int R_R14 = 18 + 1 + 1;
#pragma D binding "1.0" R_R14
inline int R_R15 = 18 + 1 + 0;
#pragma D binding "1.0" R_R15
-
diff --git a/cddl/lib/libdtrace/sched.d b/cddl/lib/libdtrace/sched.d
index 104fd571e4c0..82fdf3ab0c05 100644
--- a/cddl/lib/libdtrace/sched.d
+++ b/cddl/lib/libdtrace/sched.d
@@ -81,4 +81,3 @@ inline chipid_t chip = curcpu->cpu_chip;
inline lgrp_id_t lgrp = curcpu->cpu_lgrp;
#pragma D attributes Stable/Stable/Common lgrp
#pragma D binding "1.0" lgrp
-
diff --git a/cddl/lib/libdtrace/signal.d b/cddl/lib/libdtrace/signal.d
index 5a4c2f6b5dc5..cdd433883397 100644
--- a/cddl/lib/libdtrace/signal.d
+++ b/cddl/lib/libdtrace/signal.d
@@ -20,6 +20,7 @@
* CDDL HEADER END
*
* Portions Copyright 2008 John Birrell jb@freebsd.org
+ * Portions Copyright 2018 Devin Teske dteske@freebsd.org
*
* $FreeBSD$
*/
@@ -86,6 +87,47 @@ inline int SIGUSR1 = 30;
#pragma D binding "1.0" SIGUSR1
inline int SIGUSR2 = 31;
#pragma D binding "1.0" SIGUSR2
+inline int SIGTHR = 32;
+#pragma D binding "1.13" SIGTHR
+inline int SIGLIBRT = 33;
+#pragma D binding "1.13" SIGLIBRT
+
+#pragma D binding "1.13" signal_string
+inline string signal_string[int signal] =
+ signal == SIGHUP ? "SIGHUP" :
+ signal == SIGINT ? "SIGINT" :
+ signal == SIGQUIT ? "SIGQUIT" :
+ signal == SIGILL ? "SIGILL":
+ signal == SIGTRAP ? "SIGTRAP" :
+ signal == SIGABRT ? "SIGABRT" :
+ signal == SIGEMT ? "SIGEMT" :
+ signal == SIGFPE ? "SIGFPE" :
+ signal == SIGKILL ? "SIGKILL" :
+ signal == SIGBUS ? "SIGBUS" :
+ signal == SIGSEGV ? "SIGSEGV" :
+ signal == SIGSYS ? "SIGSYS" :
+ signal == SIGPIPE ? "SIGPIPE" :
+ signal == SIGALRM ? "SIGALRM" :
+ signal == SIGTERM ? "SIGTERM" :
+ signal == SIGURG ? "SIGURG" :
+ signal == SIGSTOP ? "SIGSTOP" :
+ signal == SIGTSTP ? "SIGTSTP" :
+ signal == SIGCONT ? "SIGCONT" :
+ signal == SIGCHLD ? "SIGCHLD" :
+ signal == SIGTTIN ? "SIGTTIN" :
+ signal == SIGTTOU ? "SIGTTOU" :
+ signal == SIGIO ? "SIGIO" :
+ signal == SIGXCPU ? "SIGXCPU" :
+ signal == SIGXFSZ ? "SIGXFSZ" :
+ signal == SIGVTALRM ? "SIGVTALRM" :
+ signal == SIGPROF ? "SIGPROF" :
+ signal == SIGWINCH ? "SIGWINCH" :
+ signal == SIGINFO ? "SIGINFO" :
+ signal == SIGUSR1 ? "SIGUSR1" :
+ signal == SIGUSR2 ? "SIGUSR2" :
+ signal == SIGTHR ? "SIGTHR" :
+ signal == SIGLIBRT ? "SIGLIBRT" :
+ "UNKNOWN";
inline int CLD_EXITED = 1;
#pragma D binding "1.0" CLD_EXITED
@@ -99,3 +141,13 @@ inline int CLD_STOPPED = 5;
#pragma D binding "1.0" CLD_STOPPED
inline int CLD_CONTINUED = 6;
#pragma D binding "1.0" CLD_CONTINUED
+
+#pragma D binding "1.13" child_signal_string
+inline string child_signal_string[int child_signal] =
+ child_signal == CLD_EXITED ? "child exited" :
+ child_signal == CLD_KILLED ? "child terminated abnormally" :
+ child_signal == CLD_DUMPED ? "child core dumped" :
+ child_signal == CLD_TRAPPED ? "traced child trapped" :
+ child_signal == CLD_STOPPED ? "child stopped" :
+ child_signal == CLD_CONTINUED ? "stopped child continued" :
+ strjoin("unknown SIGCHLD code (", strjoin(lltostr(child_signal), ")"));
diff --git a/cddl/lib/libdtrace/tcp.d b/cddl/lib/libdtrace/tcp.d
index 3dbc17298346..b3e1764ff1a5 100644
--- a/cddl/lib/libdtrace/tcp.d
+++ b/cddl/lib/libdtrace/tcp.d
@@ -118,18 +118,18 @@ typedef struct tcpsinfo {
int32_t tcps_rcv_ws; /* receive window scaling */
u_long tcps_cwnd; /* congestion window */
u_long tcps_cwnd_ssthresh; /* threshold for congestion avoidance */
- uint32_t tcps_srecover; /* for use in NewReno Fast Recovery */
+ uint32_t tcps_srecover; /* for use in NewReno Fast Recovery */
uint32_t tcps_sack_fack; /* SACK sequence # we have acked */
uint32_t tcps_sack_snxt; /* next SACK seq # for retransmission */
uint32_t tcps_rto; /* round-trip timeout, msec */
uint32_t tcps_mss; /* max segment size */
int tcps_retransmit; /* retransmit send event, boolean */
int tcps_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
- int tcps_debug; /* socket has SO_DEBUG set */
- int tcps_cookie; /* expose the socket's SO_USER_COOKIE */
- int32_t tcps_dupacks; /* consecutive dup acks received */
- uint32_t tcps_rtttime; /* RTT measurement start time */
- uint32_t tcps_rtseq; /* sequence # being timed */
+ int tcps_debug; /* socket has SO_DEBUG set */
+ int tcps_cookie; /* expose the socket's SO_USER_COOKIE */
+ int32_t tcps_dupacks; /* consecutive dup acks received */
+ uint32_t tcps_rtttime; /* RTT measurement start time */
+ uint32_t tcps_rtseq; /* sequence # being timed */
uint32_t tcps_ts_recent; /* timestamp echo data */
} tcpsinfo_t;
@@ -206,31 +206,31 @@ translator tcpsinfo_t < struct tcpcb *p > {
tcps_snxt = p == NULL ? 0 : p->snd_nxt;
tcps_rack = p == NULL ? 0 : p->last_ack_sent;
tcps_rnxt = p == NULL ? 0 : p->rcv_nxt;
- tcps_swnd = p == NULL ? -1 : p->snd_wnd;
- tcps_snd_ws = p == NULL ? -1 : p->snd_scale;
- tcps_swl1 = p == NULL ? -1 : p->snd_wl1;
- tcps_swl2 = p == NULL ? -1 : p->snd_wl2;
- tcps_radv = p == NULL ? -1 : p->rcv_adv;
- tcps_rwnd = p == NULL ? -1 : p->rcv_wnd;
- tcps_rup = p == NULL ? -1 : p->rcv_up;
- tcps_rcv_ws = p == NULL ? -1 : p->rcv_scale;
- tcps_cwnd = p == NULL ? -1 : p->snd_cwnd;
- tcps_cwnd_ssthresh = p == NULL ? -1 : p->snd_ssthresh;
- tcps_srecover = p == NULL ? -1 : p->snd_recover;
+ tcps_swnd = p == NULL ? -1 : p->snd_wnd;
+ tcps_snd_ws = p == NULL ? -1 : p->snd_scale;
+ tcps_swl1 = p == NULL ? -1 : p->snd_wl1;
+ tcps_swl2 = p == NULL ? -1 : p->snd_wl2;
+ tcps_radv = p == NULL ? -1 : p->rcv_adv;
+ tcps_rwnd = p == NULL ? -1 : p->rcv_wnd;
+ tcps_rup = p == NULL ? -1 : p->rcv_up;
+ tcps_rcv_ws = p == NULL ? -1 : p->rcv_scale;
+ tcps_cwnd = p == NULL ? -1 : p->snd_cwnd;
+ tcps_cwnd_ssthresh = p == NULL ? -1 : p->snd_ssthresh;
+ tcps_srecover = p == NULL ? -1 : p->snd_recover;
tcps_sack_fack = p == NULL ? 0 : p->snd_fack;
tcps_sack_snxt = p == NULL ? 0 : p->sack_newdata;
tcps_rto = p == NULL ? -1 : (p->t_rxtcur * 1000) / `hz;
- tcps_mss = p == NULL ? -1 : p->t_maxseg;
+ tcps_mss = p == NULL ? -1 : p->t_maxseg;
tcps_retransmit = p == NULL ? -1 : p->t_rxtshift > 0 ? 1 : 0;
- tcps_srtt = p == NULL ? -1 : p->t_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
+ tcps_srtt = p == NULL ? -1 : p->t_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */
tcps_debug = p == NULL ? 0 :
p->t_inpcb->inp_socket->so_options & 1;
tcps_cookie = p == NULL ? -1 :
p->t_inpcb->inp_socket->so_user_cookie;
- tcps_dupacks = p == NULL ? -1 : p->t_dupacks;
- tcps_rtttime = p == NULL ? -1 : p->t_rtttime;
- tcps_rtseq = p == NULL ? -1 : p->t_rtseq;
- tcps_ts_recent = p == NULL ? -1 : p->ts_recent;
+ tcps_dupacks = p == NULL ? -1 : p->t_dupacks;
+ tcps_rtttime = p == NULL ? -1 : p->t_rtttime;
+ tcps_rtseq = p == NULL ? -1 : p->t_rtseq;
+ tcps_ts_recent = p == NULL ? -1 : p->ts_recent;
};
#pragma D binding "1.6.3" translator
@@ -319,74 +319,74 @@ inline int PRU_LISTEN = 3;
#pragma D binding "1.12.1" PRU_CONNECT
inline int PRU_CONNECT = 4;
#pragma D binding "1.12.1" PRU_ACCEPT
-inline int PRU_ACCEPT = 5 ;
+inline int PRU_ACCEPT = 5 ;
#pragma D binding "1.12.1" PRU_DISCONNECT
-inline int PRU_DISCONNECT= 6;
+inline int PRU_DISCONNECT = 6;
#pragma D binding "1.12.1" PRU_SHUTDOWN
-inline int PRU_SHUTDOWN = 7;
+inline int PRU_SHUTDOWN = 7;
#pragma D binding "1.12.1" PRU_RCVD
-inline int PRU_RCVD = 8;
+inline int PRU_RCVD = 8;
#pragma D binding "1.12.1" PRU_SEND
-inline int PRU_SEND = 9;
+inline int PRU_SEND = 9;
#pragma D binding "1.12.1" PRU_ABORT
-inline int PRU_ABORT = 10;
+inline int PRU_ABORT = 10;
#pragma D binding "1.12.1" PRU_CONTROL
-inline int PRU_CONTROL = 11;
+inline int PRU_CONTROL = 11;
#pragma D binding "1.12.1" PRU_SENSE
-inline int PRU_SENSE = 12;
+inline int PRU_SENSE = 12;
#pragma D binding "1.12.1" PRU_RCVOOB
-inline int PRU_RCVOOB = 13;
+inline int PRU_RCVOOB = 13;
#pragma D binding "1.12.1" PRU_SENDOOB
-inline int PRU_SENDOOB = 14;
+inline int PRU_SENDOOB = 14;
#pragma D binding "1.12.1" PRU_SOCKADDR
-inline int PRU_SOCKADDR = 15;
+inline int PRU_SOCKADDR = 15;
#pragma D binding "1.12.1" PRU_PEERADDR
-inline int PRU_PEERADDR = 16;
+inline int PRU_PEERADDR = 16;
#pragma D binding "1.12.1" PRU_CONNECT2
-inline int PRU_CONNECT2 = 17;
+inline int PRU_CONNECT2 = 17;
#pragma D binding "1.12.1" PRU_FASTTIMO
-inline int PRU_FASTTIMO = 18;
+inline int PRU_FASTTIMO = 18;
#pragma D binding "1.12.1" PRU_SLOWTIMO
-inline int PRU_SLOWTIMO = 19;
+inline int PRU_SLOWTIMO = 19;
#pragma D binding "1.12.1" PRU_PROTORCV
-inline int PRU_PROTORCV = 20;
+inline int PRU_PROTORCV = 20;
#pragma D binding "1.12.1" PRU_PROTOSEND
-inline int PRU_PROTOSEND = 21;
+inline int PRU_PROTOSEND = 21;
#pragma D binding "1.12.1" PRU_SEND_EOF
-inline int PRU_SEND_EOF = 22;
+inline int PRU_SEND_EOF = 22;
#pragma D binding "1.12.1" PRU_SOSETLABEL
-inline int PRU_SOSETLABEL = 23;
+inline int PRU_SOSETLABEL = 23;
#pragma D binding "1.12.1" PRU_CLOSE
-inline int PRU_CLOSE = 24;
+inline int PRU_CLOSE = 24;
#pragma D binding "1.12.1" PRU_FLUSH
-inline int PRU_FLUSH = 25;
+inline int PRU_FLUSH = 25;
#pragma D binding "1.12.1" prureq_string
inline string prureq_string[uint8_t req] =
- req == PRU_ATTACH ? "ATTACH" :
- req == PRU_DETACH ? "DETACH" :
- req == PRU_BIND ? "BIND" :
- req == PRU_LISTEN ? "LISTEN" :
- req == PRU_CONNECT ? "CONNECT" :
- req == PRU_ACCEPT ? "ACCEPT" :
- req == PRU_DISCONNECT ? "DISCONNECT" :
- req == PRU_SHUTDOWN ? "SHUTDOWN" :
- req == PRU_RCVD ? "RCVD" :
- req == PRU_SEND ? "SEND" :
- req == PRU_ABORT ? "ABORT" :
- req == PRU_CONTROL ? "CONTROL" :
- req == PRU_SENSE ? "SENSE" :
- req == PRU_RCVOOB ? "RCVOOB" :
- req == PRU_SENDOOB ? "SENDOOB" :
- req == PRU_SOCKADDR ? "SOCKADDR" :
- req == PRU_PEERADDR ? "PEERADDR" :
- req == PRU_CONNECT2 ? "CONNECT2" :
- req == PRU_FASTTIMO ? "FASTTIMO" :
- req == PRU_SLOWTIMO ? "SLOWTIMO" :
- req == PRU_PROTORCV ? "PROTORCV" :
- req == PRU_PROTOSEND ? "PROTOSEND" :
- req == PRU_SEND ? "SEND_EOF" :
- req == PRU_SOSETLABEL ? "SOSETLABEL" :
- req == PRU_CLOSE ? "CLOSE" :
- req == PRU_FLUSH ? "FLUSE" :
+ req == PRU_ATTACH ? "ATTACH" :
+ req == PRU_DETACH ? "DETACH" :
+ req == PRU_BIND ? "BIND" :
+ req == PRU_LISTEN ? "LISTEN" :
+ req == PRU_CONNECT ? "CONNECT" :
+ req == PRU_ACCEPT ? "ACCEPT" :
+ req == PRU_DISCONNECT ? "DISCONNECT" :
+ req == PRU_SHUTDOWN ? "SHUTDOWN" :
+ req == PRU_RCVD ? "RCVD" :
+ req == PRU_SEND ? "SEND" :
+ req == PRU_ABORT ? "ABORT" :
+ req == PRU_CONTROL ? "CONTROL" :
+ req == PRU_SENSE ? "SENSE" :
+ req == PRU_RCVOOB ? "RCVOOB" :
+ req == PRU_SENDOOB ? "SENDOOB" :
+ req == PRU_SOCKADDR ? "SOCKADDR" :
+ req == PRU_PEERADDR ? "PEERADDR" :
+ req == PRU_CONNECT2 ? "CONNECT2" :
+ req == PRU_FASTTIMO ? "FASTTIMO" :
+ req == PRU_SLOWTIMO ? "SLOWTIMO" :
+ req == PRU_PROTORCV ? "PROTORCV" :
+ req == PRU_PROTOSEND ? "PROTOSEND" :
+ req == PRU_SEND ? "SEND_EOF" :
+ req == PRU_SOSETLABEL ? "SOSETLABEL" :
+ req == PRU_CLOSE ? "CLOSE" :
+ req == PRU_FLUSH ? "FLUSE" :
"unknown" ;
diff --git a/cddl/lib/libdtrace/udp.d b/cddl/lib/libdtrace/udp.d
index eeba58c8752f..70652cbfce48 100644
--- a/cddl/lib/libdtrace/udp.d
+++ b/cddl/lib/libdtrace/udp.d
@@ -47,7 +47,7 @@ typedef struct udpinfo {
uint16_t udp_sport; /* source port */
uint16_t udp_dport; /* destination port */
uint16_t udp_length; /* total length */
- uint16_t udp_checksum; /* headers + data checksum */
+ uint16_t udp_checksum; /* headers + data checksum */
struct udphdr *udp_hdr; /* raw UDP header */
} udpinfo_t;
diff --git a/cddl/usr.sbin/Makefile b/cddl/usr.sbin/Makefile
index 8fb489ad3259..fed0bb8269f1 100644
--- a/cddl/usr.sbin/Makefile
+++ b/cddl/usr.sbin/Makefile
@@ -3,6 +3,7 @@
.include <src.opts.mk>
SUBDIR= ${_dtrace} \
+ ${_dwatch} \
${_lockstat} \
${_plockstat} \
${_tests} \
@@ -26,6 +27,7 @@ _zfsd= zfsd
.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386"
_dtrace= dtrace
+_dwatch= dwatch
_lockstat= lockstat
_plockstat= plockstat
.endif
@@ -33,15 +35,18 @@ _plockstat= plockstat
.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \
${MACHINE_CPUARCH} == "riscv"
_dtrace= dtrace
+_dwatch= dwatch
_lockstat= lockstat
.endif
.if ${MACHINE_CPUARCH} == "mips"
_dtrace= dtrace
+_dwatch= dwatch
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
_dtrace= dtrace
+_dwatch= dwatch
_lockstat= lockstat
.endif
diff --git a/cddl/usr.sbin/dwatch/Makefile b/cddl/usr.sbin/dwatch/Makefile
new file mode 100644
index 000000000000..647f07388890
--- /dev/null
+++ b/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>
diff --git a/cddl/usr.sbin/dwatch/dwatch b/cddl/usr.sbin/dwatch/dwatch
new file mode 100755
index 000000000000..05fe5921993f
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/dwatch
@@ -0,0 +1,1401 @@
+#!/bin/sh
+#-
+# Copyright (c) 2014-2018 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.2 $' # -V
+
+pgm="${0##*/}" # Program basename
+
+#
+# Command-line arguments
+#
+PROBE_ARG=
+
+#
+# Command-line defaults
+#
+_MAX_ARGS=64 # -B num
+_MAX_DEPTH=64 # -K num
+
+#
+# Command-line options
+#
+CONSOLE= # -y
+CONSOLE_FORCE= # -y
+[ -t 1 ] && CONSOLE=1 # -y
+COUNT=0 # -N count
+CUSTOM_DETAILS= # -E code
+CUSTOM_TEST= # -t test
+DEBUG= # -d
+DESTRUCTIVE_ACTIONS= # -w
+DEVELOPER= # -dev
+EXECNAME= # -k name
+EXECREGEX= # -z regex
+EXIT_AFTER_COMPILE= # -e
+FILTER= # -r regex
+PROBE_COALESCE= # -F
+GROUP= # -g group
+JID= # -j jail
+LIST= # -l
+LIST_PROFILES= # -Q
+MAX_ARGS=$_MAX_ARGS # -B num
+MAX_DEPTH=$_MAX_DEPTH # -K num
+ONELINE= # -1
+OUTPUT= # -o file
+OUTPUT_CMD= # -O cmd
+PID= # -p pid
+PROBE_TYPE= # -f -m -n -P
+PROFILE= # -X profile
+PSTREE= # -R
+QUIET= # -q
+TIMEOUT= # -T time
+TRACE= # -x
+USER= # -u user
+USE_PROFILE= # -X profile
+VERBOSE= # -v
+
+#
+# Global exit status
+#
+SUCCESS=0
+FAILURE=1
+
+#
+# Miscellaneous
+#
+ACTIONS=
+EVENT_DETAILS=
+EVENT_TAG='printf("%d.%d %s[%d]: ",
+ this->uid0, this->gid0, execname, this->pid0);'
+EVENT_TEST=
+FILE=
+ID=3
+MODULE_CHECKED=
+PROBE=
+PSARGS=1
+RGID=
+RUID=
+SUDO=
+export SUDO_PROMPT="[sudo] Password:"
+TITLE=\$Title:
+
+############################################################ FUNCTIONS
+
+ansi() { local fmt="$2 $4"; [ "$CONSOLE" ] && fmt="\\033[$1m$2\\033[$3m $4";
+ shift 4; printf "$fmt\n" "$@"; }
+die() { exec >&2; [ "$*" ] && echo "$pgm:" "$@"; exit $FAILURE; }
+info() { [ "$QUIET" ] || ansi 35 "INFO" 39 "$@" >&2; }
+
+usage()
+{
+ local optfmt="\t%-10s %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" "-N count" "-o file" "-O cmd" "-p pid"
+ printf "\t [%s] [%s] [%s] [%s] [%s] [%s]\n" \
+ "-r regex" "-t test" "-T time" "-u user" "-X profile" \
+ "-z regex"
+ printf "\t probe[,...] [args ...]\n"
+ 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 process 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" "-n" \
+ "Enable probe matching the specified probe name."
+ printf "$optfmt" "-N count" \
+ "Exit after count matching entries (Default 0 for disabled)."
+ printf "$optfmt" "-o file" \
+ "Set output file. If \`-', the path \`/dev/stdout' is used."
+ printf "$optfmt" "-O cmd" \
+ "Execute cmd for each event."
+ 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" "-X profile" \
+ "Load profile name from DWATCH_PROFILES_PATH."
+ 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
+}
+
+dtrace_cmd()
+{
+ local status stdout
+ local timeout=
+
+ if [ "$1" = "-t" ]; then
+ shift
+ [ "$TIMEOUT" ] && timeout=1
+ fi
+
+ 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 }
+ /invalid address \(0x[[:xdigit:]]+\) in action #[[:digit:]]+/ { next }
+ /out of scratch space in action #[[:digit:]]+/ { next }
+ /^Bus error$/ { 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="$probe" -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 OPTIND=1 OPTARG flag
+ local column=0 header="PROVIDER:MODULE:FUNCTION:NAME"
+ local filter= quiet= type=
+
+ while getopts f:qt: flag; do
+ case "$flag" in
+ f) filter="$OPTARG" ;;
+ q) quiet=1 ;;
+ t) type="$OPTARG" ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ if [ $# -eq 0 ]; then
+ case "$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"
+
+ local arg probe=
+ for arg in "$@"; do
+ arg=$( expand_probe -t "$type" -- "$arg" )
+ probe="$probe${probe:+, }$arg"
+ done
+
+ dtrace_cmd -l${probe:+n "$probe"} | awk -v pattern="$(
+ # Prevent backslashes from being lost
+ echo "$filter" | awk 'gsub(/\\/,"&&")||1'
+ )" -v want="$column" -v console="$CONSOLE" '
+ BEGIN { getline dtrace_header }
+ function ans(seq) { return console ? "\033[" seq "m" : "" }
+ 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]]++ &&
+ gsub(pattern, ans("31;1") "&" ans("39;22")) {
+ print | "sort"
+ }
+ END { close("sort") }
+ ' # END-QUOTE
+
+ exit $SUCCESS
+}
+
+list_profiles()
+{
+ local OPTIND=1 OPTARG flag
+ local filter= oneline= quiet=
+
+ while getopts 1f:q flag; do
+ case "$flag" in
+ 1) oneline=1 ;;
+ f) filter="$OPTARG" ;;
+ q) quiet=1 ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ # Prevent backslashes from being lost
+ filter=$( 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 filter="$filter" -v cons="$CONSOLE" '
+ function ans(s) { return cons ? "\033[" s "m" : "" }
+ gsub(filter, ans("31;1") "&" ans("39;22"))
+ ' # END-QUOTE
+ exit $SUCCESS
+ fi
+
+ [ "$quiet" ] || echo PROFILES:
+ echo "$profiles" | awk \
+ -v colsize=$longest_profile_name \
+ -v console="$CONSOLE" \
+ -v ncols=$ncols \
+ -v quiet="$quiet" \
+ -v filter="$filter" \
+ ' # Begin awk(1) processor
+ function ans(seq) { return console ? "\033[" seq "m" : "" }
+ BEGIN {
+ row_item[1] = ""
+ replace = ans("31;1") "&" ans("39;22")
+ ansi_offset = length(replace) - 1
+ }
+ function print_row()
+ {
+ cs = colsize + ansi_offset * \
+ gsub(filter, replace, row_item[1])
+ printf "%s%-*s", quiet ? "" : "\t", cs, row_item[1]
+ for (i = 2; i <= cur_col; i++) {
+ cs = colsize + ansi_offset * \
+ gsub(filter, replace, row_item[i])
+ printf " %-*s", cs, row_item[i]
+ }
+ printf "\n"
+ }
+ $0 ~ filter {
+ 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
+
+ exit $SUCCESS
+}
+
+shell_escape()
+{
+ echo "$*" | awk 'gsub(/'\''/, "&\\\\&&")||1'
+}
+
+load_profile()
+{
+ local profile="$1"
+
+ [ "$profile" ] ||
+ die "missing profile argument (\`$pgm -Q' to list profiles)"
+
+ local oldIFS="$IFS"
+ local dir found=
+ local ARGV=
+
+ [ $COUNT -gt 0 ] && ARGV="$ARGV -N $COUNT"
+ [ "$DEBUG" ] && ARGV="$ARGV -d"
+ [ "$DESTRUCTIVE_ACTIONS" ] && ARGV="$ARGV -w"
+ [ "$EXIT_AFTER_COMPILE" ] && ARGV="$ARGV -e"
+ [ "$GROUP" ] && ARGV="$ARGV -g $GROUP"
+ [ "$JID" ] && ARGV="$ARGV -j $JID"
+ [ $MAX_ARGS -ne $_MAX_ARGS ] && ARGV="$ARGV -B $MAX_ARGS"
+ [ $MAX_DEPTH -ne $_MAX_DEPTH ] && ARGV="$ARGV -K $MAX_DEPTH"
+ [ "$ONELINE" ] && ARGV="$ARGV -1"
+ [ "$PID" ] && ARGV="$ARGV -p $PID"
+ [ "$PSTREE" ] && ARGV="$ARGV -R"
+ [ "$QUIET" ] && ARGV="$ARGV -q"
+ [ "$TIMEOUT" ] && ARGV="$ARGV -T $TIMEOUT"
+ [ "$TRACE" ] && ARGV="$ARGV -x"
+ [ "$USER" ] && ARGV="$ARGV -u $USER"
+ [ "$VERBOSE" ] && ARGV="$ARGV -v"
+
+ [ "$FILTER" ] &&
+ ARGV="$ARGV -r '$( shell_escape "$FILTER" )'"
+ [ "$EXECREGEX" ] &&
+ ARGV="$ARGV -z '$( shell_escape "$EXECREGEX" )'"
+ [ "$CUSTOM_DETAILS" ] &&
+ ARGV="$ARGV -E '$( shell_escape "$EVENT_DETAILS" )'"
+ [ "$EVENT_TEST" ] &&
+ ARGV="$ARGV -t '$( shell_escape "$EVENT_TEST" )'"
+ [ "$OUTPUT" ] &&
+ ARGV="$ARGV -o '$( shell_escape "$OUTPUT" )'"
+ [ "$OUTPUT_CMD" ] &&
+ ARGV="$ARGV -O '$( shell_escape "$OUTPUT_CMD" )'"
+
+ case "$PROBE_TYPE" in
+ provider) ARGV="$ARGV -P" ;;
+ module) ARGV="$ARGV -m" ;;
+ function) ARGV="$ARGV -f" ;;
+ name) ARGV="$ARGV -n" ;;
+ esac
+
+ 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 OPTIND=1 OPTARG flag
+ local P= N=0
+
+ while getopts P: flag; do
+ case "$flag" in
+ P) P="$OPTARG" ;;
+ esac
+ done
+ shift $(( OPTIND - 1 ))
+
+ local proc=$1
+ if [ ! "$proc" ]; then
+ if [ "$P" = "0" ]; then
+ proc="curthread->td_proc"
+ else
+ proc="this->proc ? this->proc->p_pptr : NULL"
+ fi
+ fi
+
+ awk 'NR > 1 && $0 { $0 = "\t" $0 }
+ gsub(/\\\t/, "\t") || 1
+ ' <<-EOFPREAMBLE
+ this->proc = $proc;
+ this->uid$P = this->proc ? this->proc->p_ucred->cr_uid : -1;
+ this->gid$P = this->proc ? this->proc->p_ucred->cr_rgid : -1;
+ this->pid$P = this->proc ? this->proc->p_pid : -1;
+ this->jid$P = this->proc ? this->proc->p_ucred->cr_prison->pr_id : -1;
+
+ 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->args$P = this->arg${P}_$N = 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=$P -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)
+ gsub(/\\\t/, "\t")
+ sub(/\n$/, "")
+ print
+ }
+ }
+ ' <<-EOFARGS
+ this->argP_N = this->ar_length > 0 ? this->ar_args : "";
+ this->argsP = strjoin(this->argsP,
+ \ strjoin(this->argP_N != "" ? " " : "", this->argP_N));
+ this->len = this->ar_length > 0 ? strlen(this->ar_args) + 1 : 0;
+ this->ar_args += this->len;
+ this->ar_length -= this->len;
+
+ EOFARGS
+
+ N=$(( $MAX_ARGS + 1 ))
+ awk 'sub(/^\\\t/, "\t") || 1, $0 = "\t" $0' <<-EOFPROC
+ this->arg${P}_$N = this->ar_length > 0 ? "..." : "";
+ this->args$P = strjoin(this->args$P,
+ \ strjoin(this->arg${P}_$N != "" ? " " : "", this->arg${P}_$N));
+ EOFPROC
+}
+
+pproc_dump()
+{
+ local OPTIND=1 OPTARG flag
+ local verbose=
+
+ while getopts v flag; do
+ case "$flag" in
+ v) verbose=1 ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ local P=$1
+ if [ "$verbose" ]; then
+ awk -v P=$P '
+ BEGIN { printf "\t" }
+ NR > 1 && $0 { $0 = "\t" $0 }
+ buf = buf $0 "\n" { }
+ END {
+ $0 = buf
+ if (P < 3) S = sprintf("%" 7-2*(P+1) "s", "")
+ gsub(/S/, S)
+ gsub(/B/, P < 3 ? "\\" : "")
+ gsub(/\\\t/, "\t")
+ sub(/\n$/, "")
+ print
+ }
+ ' <<-EOFPREAMBLE
+ printf(" SB-+= %05d %d.%d %s\n",
+ \ this->pid$P, this->uid$P, this->gid$P, this->args$P);
+ EOFPREAMBLE
+ else
+ cat <<-EOFPREAMBLE
+ printf("%s", this->args$P);
+ EOFPREAMBLE
+ 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
+#
+while getopts 1B:deE:fFg:j:k:K:lmnN:o:O:p:PqQr:Rt:T:u:vVwxX:yz: flag; do
+ 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="${EVENT_DETAILS%;}"
+ [ "$EVENT_DETAILS" ] && EVENT_DETAILS="$EVENT_DETAILS;
+ printf(\" \");
+ " # END-QUOTE
+ # Read event code from stdin if `-' is argument
+ [ "$OPTARG" = "-" ] && OPTARG=$( cat )
+ EVENT_DETAILS="$EVENT_DETAILS$OPTARG" ;;
+ f) PROBE_TYPE=function ;;
+ F) PROBE_COALESCE=1 ;;
+ 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 ;;
+ n) PROBE_TYPE=name ;;
+ N) COUNT="$OPTARG" ;;
+ o) OUTPUT="$OPTARG" ;;
+ O) OUTPUT_CMD="$OPTARG" ;;
+ p) PID="$OPTARG" ;;
+ P) PROBE_TYPE=provider ;;
+ q) QUIET=1 ;;
+ Q) LIST_PROFILES=1 ;;
+ r) FILTER="$OPTARG" ;;
+ R) PSTREE=1 ;;
+ t) CUSTOM_TEST="${CUSTOM_TEST:+($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 ;;
+ X) USE_PROFILE=1 PROFILE="$OPTARG" ;;
+ y) CONSOLE=1 CONSOLE_FORCE=1 ;;
+ z) EXECREGEX="$OPTARG" ;;
+ *) usage
+ # NOTREACHED
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+#
+# List probes if `-l' was given
+#
+[ "$LIST" ] &&
+ list_probes -f "$FILTER" ${QUIET:+-q} -t "$PROBE_TYPE" -- "$@"
+ # NOTREACHED
+
+#
+# List profiles if `-Q' was given
+#
+[ "$LIST_PROFILES" ] &&
+ list_profiles ${ONELINE:+-1} -f "$FILTER" ${QUIET:+-q}
+ # NOTREACHED
+
+#
+# Validate number of arguments
+#
+if [ ! "$PROFILE" ]; then
+ # If not given `-X profile' then a probe argument is required
+ [ $# -gt 0 ] || usage # NOTREACHED
+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
+
+#
+# Expand probe argument into probe(s)
+#
+case "$1" in
+-*) : Assume dtrace options such as "-c cmd" or "-p pid" ;; # No probe(s) given
+*)
+ PROBE_ARG="$1"
+ shift
+esac
+if [ "$PROBE_ARG" ]; then
+ oldIFS="$IFS"
+ IFS="$IFS,"
+ for arg in $PROBE_ARG; do
+ arg=$( expand_probe -t "$PROBE_TYPE" -- "$arg" )
+ PROBE="$PROBE${PROBE:+, }$arg"
+ done
+ IFS="$oldIFS"
+fi
+
+#
+# Developer switch
+#
+[ "$DEBUG" -a "$EXIT_AFTER_COMPILE" -a "$VERBOSE" ] && DEVELOPER=1 DEBUG=
+
+#
+# Set default event details if `-E code' was not given
+#
+[ "$CUSTOM_DETAILS" ] || EVENT_DETAILS=$( pproc_dump 0 )
+
+#
+# Load profile if given `-X profile'
+#
+[ "$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$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 $ID */
+ {${TRACE:+
+ \ printf("<$ID>");}
+ \ this->caller_execname = execname;
+ }
+ EOF
+ )
+ PROBE="${PROBE%entry}return"
+ ID=$(( $ID + 1 ))
+ 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.
+#
+exec 9<<EOF
+$PROBE /* probe ID 2 */
+{${TRACE:+
+ printf("<2>");
+}
+ /*
+ * Examine process, parent process, and grandparent process details
+ */
+
+ /******************* CURPROC *******************/
+
+ $( pproc -P0 )
+
+ /******************* PPARENT *******************/
+
+ $( if [ "$PSTREE" ]; then pproc -P1; else echo -n \
+ "this->proc = this->proc ? this->proc->p_pptr : NULL;
+ this->pid1 = this->proc ? this->proc->p_pid : -1;
+ this->uid1 = this->proc ? this->proc->p_ucred->cr_uid : -1;
+ this->gid1 = this->proc ? this->proc->p_ucred->cr_rgid : -1;
+ this->jid1 = this->proc ? this->proc->p_ucred->cr_prison->pr_id : -1;"
+ fi )
+
+ /******************* GPARENT *******************/
+
+ $( [ "$PSTREE" ] && pproc -P2 )
+
+ /******************* APARENT *******************/
+
+ $( [ "$PSTREE" ] && pproc -P3 )
+}
+EOF
+PSARGS_ACTION=$( cat <&9 )
+[ "$OUTPUT" -a ! "$CONSOLE_FORCE" ] && CONSOLE=
+{
+ if [ "$DEBUG" ]; then
+ # Send script to stdout
+ cat
+ exit
+ fi
+
+ if [ "$CUSTOM_TEST$EXECNAME$JID$OUTPUT$TIMEOUT$TRACE$VERBOSE" -a \
+ ! "$QUIET" ]
+ then
+ msg=Setting
+ [ "$CUSTOM_TEST" ] && msg="$msg test: $CUSTOM_TEST"
+ [ "$EXECNAME" ] && msg="$msg execname: $EXECNAME"
+ [ "$JID" ] && msg="$msg jid: $JID"
+ [ "$OUTPUT" ] && msg="$msg output: $OUTPUT"
+ [ "$TIMEOUT" ] && msg="$msg timeout: $TIMEOUT"
+ [ "$TRACE" ] && msg="$msg trace: $TRACE"
+ [ "$VERBOSE" ] && msg="$msg verbose: $VERBOSE"
+ info "$msg"
+ fi
+
+ exec 3>&1
+ console_stdout=3
+
+ #
+ # Developer debugging aide
+ #
+ if [ "$DEVELOPER" ]; then
+ #
+ # Run, capture the error line, and focus it
+ #
+ # Example error text to capture line number from:
+ # dtrace: failed to compile script /dev/stdin: line 669: ...
+ #
+ errline=
+ stdin_buf=$( cat )
+ stderr_buf=$( echo "$stdin_buf" |
+ dtrace_cmd -t -es /dev/stdin "$@" 2>&1 > /dev/null )
+ status=$?
+ if [ "$stderr_buf" ]; then
+ errline=$( echo "$stderr_buf" | awk '
+ BEGIN {
+ ti = "\033[31m"
+ te = "\033[39m"
+ }
+ { line = $0 }
+ sub(/.*: line /, "") && sub(/:.*/, "") {
+ print # to errline
+ sub("line " $0, ti "&" te, line)
+ }
+ { print line > "/dev/stderr" }
+ ' 2>&3 )
+ fi
+ if [ "$errline" ]; then
+ echo "$stdin_buf" | awk -v line="${errline%%[^0-9]*}" '
+ BEGIN {
+ start = line < 10 ? 1 : line - 10
+ end = line + 10
+ slen = length(sprintf("%u", start))
+ elen = length(sprintf("%u", end))
+ N = elen > slen ? elen : slen
+ for (i = start; i <= end; i++) {
+ ti[i] = "\033[2m"
+ te[i] = "\033[22m"
+ }
+ ti[line] = "\033[31m"
+ te[line] = "\033[39m"
+ fmt = "%s%*u %s%s\n"
+ }
+ NR < start { next }
+ NR == start, NR == end {
+ printf(fmt, ti[NR], N, NR, $0, te[NR])
+ }
+ NR > end { exit }
+ ' # END-QUOTE
+ fi
+ exit $status
+ fi
+
+ if [ $COUNT -eq 0 -a ! "$EXECREGEX$FILTER$GROUP$OUTPUT_CMD$PID$USER" ]
+ then
+ case "$OUTPUT" in
+ -) output_path=/dev/stdout ;;
+ *) output_path="$OUTPUT"
+ esac
+
+ # Run script without pipe to awk post-processor
+ dtrace_cmd -t \
+ ${DESTRUCTIVE_ACTIONS:+-w} \
+ ${EXIT_AFTER_COMPILE:+-e} \
+ ${OUTPUT:+-o "$output_path"} \
+ -s /dev/stdin \
+ "$@"
+ exit
+ fi
+
+ # Prevent backslashes from being lost
+ FILTER=$( echo "$FILTER" | awk 'gsub(/\\/,"&&")||1' )
+ EXECREGEX=$( echo "$EXECREGEX" | awk 'gsub(/\\/,"&&")||1' )
+
+ if [ ! "$QUIET" ]; then
+ msg=Filtering
+ [ "$EXECREGEX" ] && msg="$msg execregex: $EXECREGEX"
+ [ "$FILTER" ] && msg="$msg filter: $FILTER"
+ [ "$GROUP" ] && msg="$msg group: $GROUP"
+ [ "$OUTPUT_CMD" ] && msg="$msg cmd: $OUTPUT_CMD"
+ [ "$PID" ] && msg="$msg pid: $PID"
+ [ "$USER" ] && msg="$msg user: $USER"
+ [ $COUNT -gt 0 ] && msg="$msg count: $COUNT"
+ info "$msg"
+ fi
+
+ #
+ # Send script output to post-processor for filtering
+ #
+ 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 cmd="$OUTPUT_CMD" \
+ -v console="$CONSOLE" \
+ -v count=$COUNT \
+ -v execregex="$EXECREGEX" \
+ -v filter="$FILTER" \
+ -v gid="$RGID" \
+ -v output="$OUTPUT" \
+ -v pid="$PID" \
+ -v pstree=$PSTREE \
+ -v quiet=$QUIET \
+ -v tty=$( ps -o tty= -p $$ ) \
+ -v uid="$RUID" \
+ ' # Start awk(1) post-processor
+ ############################################ BEGIN
+ BEGIN {
+ true = 1
+ ansi = "(\\033\\[[[:digit:];]+m)?"
+ num = year = day = "[[:digit:]]+"
+ month = "[[:alpha:]]+"
+ date = year " " month " +" day
+ time = "[012][0-9]:[0-5][0-9]:[0-5][0-9]"
+ date_time = ansi date " +" time ansi
+ name1 = "[^\\[]*"
+ name2 = "[^\\n]*"
+ if (output == "-")
+ output = "/dev/stdout"
+
+ #
+ # Field definitions
+ #
+ nexecmatches = 2
+ execstart[1] = sprintf( \
+ "^(%s) (%s)\\.(%s) (%s)\\[(%s)\\]: ",
+ date_time, num, num, name1, num)
+ execstart[2] = sprintf( \
+ "\\n +\\\\?-\\+= (%s) (%s)\\.(%s) ",
+ num, num, num)
+ npidmatches = 2
+ pidstart[1] = sprintf("^(%s) (%s)\\.(%s) (%s)\\[",
+ date_time, num, num, name1)
+ pidstart[2] = "\\n +\\\\?-\\+= "
+ pidpreen[2] = "^0*"
+ piddeflt[2] = "0"
+ ngidmatches = 2
+ gidstart[1] = sprintf("^(%s) (%s)\\.", date_time, num)
+ gidstart[2] = sprintf("\\n +\\\\?-\\+= (%s) (%s)\\.",
+ ansi num ansi, num)
+ nuidmatches = 2
+ uidstart[1] = sprintf("^(%s) ", date_time)
+ uidstart[2] = sprintf("\\n +\\\\?-\\+= (%s) ",
+ ansi num ansi)
+ }
+ ############################################ FUNCTIONS
+ function strip(s) { gsub(/\033\[[0-9;]*m/, "", s); return s }
+ function esc(str) { gsub(/'\''/, "&\\\\&&", str); return str }
+ function arg(str) { return "'\''" esc(str) "'\''" }
+ function env(var, str) { return var "=" arg(str) " " }
+ function ans(seq) { return console ? "\033[" seq "m" : "" }
+ function runcmd() {
+ return system(sprintf("%s/bin/sh -c %s",
+ env("TAG", strip(tag)) \
+ env("DETAILS", strip(details)),
+ arg(cmd)))
+ }
+ function filter_block() {
+ if (length(lines) < 1) return 0
+ block_match = 0
+ newstr = ""
+ start = 1
+ if (match(lines, "^(" date_time ") ")) {
+ newstr = newstr substr(lines, 1,
+ RSTART + RLENGTH - 1)
+ start = RSTART + RLENGTH
+ }
+ replace = ans("31;1") "&" ans("39;22")
+ workstr = substr(lines, start)
+ if (gsub(filter, replace, workstr)) block_match = 1
+ lines = newstr workstr
+ return block_match
+ }
+ function filter_field(startre, fieldre, matchre, isword,
+ preenre, defaultstr)
+ {
+ if (length(lines) < 1) return 0
+ field_match = 0
+ newstr = ""
+ start = 1
+ while ((workstr = substr(lines, start)) &&
+ (workstr ~ (startre fieldre)))
+ {
+ match(workstr, startre)
+ start += end = RSTART + RLENGTH - 1
+ newstr = newstr substr(workstr, 1, end)
+ workstr = substr(workstr, end + 1)
+ match(workstr, fieldre)
+ start += end = RSTART + RLENGTH - 1
+ field = matchstr = substr(workstr, 1, end)
+ sub(preenre, "", matchstr)
+ if (!matchstr) matchstr = defaultstr
+ if (isword) {
+ if (match(matchstr, matchre) &&
+ RSTART == 1 &&
+ RLENGTH == length(matchstr)) {
+ field_match = 1
+ field = ans(7) field ans(27)
+ }
+ } else {
+ replace = ans(7) "&" ans(27)
+ if (gsub(matchre, replace, matchstr)) {
+ field_match = 1
+ field = matchstr
+ }
+ }
+ newstr = newstr field
+ }
+ lines = newstr workstr
+ return field_match
+ }
+ function dump() {
+ lines = block
+ block = ""
+ found = 0
+ if (execregex != "") {
+ for (n = 1; n <= nexecmatches; n++)
+ if (filter_field(execstart[n], name2,
+ execregex)) found = 1
+ if (!found) return
+ }
+ if (pid != "") {
+ for (n = 1; n <= npidmatches; n++)
+ if (filter_field(pidstart[n], num, pid,
+ true, pidpreen[n],
+ piddeflt[n])) found = 1
+ if (!found) return
+ }
+ if (gid != "") {
+ for (n = 1; n <= ngidmatches; n++)
+ if (filter_field(gidstart[n], num,
+ gid, true)) found = 1
+ if (!found) return
+ }
+ if (uid != "") {
+ for (n = 1; n <= nuidmatches; n++)
+ if (filter_field(uidstart[n], num,
+ uid, true)) found = 1
+ if (!found) return
+ }
+ if (filter != "" && !filter_block()) return
+ if (lines) {
+ stdout = 1
+ if (output) {
+ stdout = 0
+ if (!console) lines = strip(lines)
+ print lines > output
+ } else if (cmd) {
+ if (!quiet) print lines
+ tag = details = lines
+ sub(/: .*/, "", tag)
+ sub(/.*: /, "", details)
+ if (!console) tag = strip(tag)
+ runcmd()
+ } else 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-2018 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} } /* probe ID 1 */
+
+/*********************************************************/
+
+${PSARGS:+$PSARGS_ACTION}
+${ACTIONS:+
+/*********************************************************/
+
+$ACTIONS
+}
+/*********************************************************/
+
+$PROBE${EVENT_TEST:+ /$EVENT_TEST/} /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /***********************************************/
+
+ printf("%s%Y%s ",
+ console ? "\033[32m" : "",
+ walltimestamp,
+ console ? "\033[39m" : "");
+
+ /****************** EVENT_TAG ******************/
+
+ ${EVENT_TAG#[[:space:]]}
+${PROBE_COALESCE:+
+ /**************** PROBE_COALESCE ***************/
+
+ printf("%s%s:%s:%s:%s ", probename == "entry" ? "-> " :
+ probename == "return" ? "<- " :
+ probename == "start" ? "-> " :
+ probename == "done" ? "<- " : " | ",
+ probeprov, probemod, probefunc, probename);
+}
+ /**************** EVENT_DETAILS ****************/
+
+ ${EVENT_DETAILS#[[:space:]]}
+
+ /***********************************************/
+
+ printf("\\n");
+${PSTREE:+
+ /*
+ * Print process, parent, grandparent, and ancestor details
+ */
+$( pproc_dump -v 3
+ pproc_dump -v 2
+ pproc_dump -v 1
+ pproc_dump -v 0
+)}
+}
+EOF
+# NOTREACHED
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/dwatch.1 b/cddl/usr.sbin/dwatch/dwatch.1
new file mode 100644
index 000000000000..f70e4fcb43ac
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/dwatch.1
@@ -0,0 +1,766 @@
+.\" Copyright (c) 2014-2018 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 February 9, 2018
+.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 N Ar count
+.Op Fl o Ar file
+.Op Fl O Ar cmd
+.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 X Ar profile
+.Op Fl z Ar regex
+.Op Fl -
+.Op probe[,...]
+.Op args ...
+.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 a given DTrace probe point is triggered.
+Only the root user or users with
+.Xr sudo 8
+access can run this command.
+.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:
+.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 probe traversal.
+.Pp
+Output format with the
+.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:
+.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 the
+.Ql Fl R
+option is:
+.Pp
+.Dl date/time uid0.gid0 execname[pid0]: psargs0
+.Dl " -+= pid3 uid3.gid3 psargs3"
+.Dl " \e\\-+= pid2 uid2.gid2 psargs2"
+.Dl " \e\\-+= pid1 uid1.gid1 psargs1"
+.Dl " \e\\-+= pid0 uid0.guid0 psargs0"
+.Pp
+For example,
+the command
+.Ql dwatch -R BEGIN
+produces:
+.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 " \e\\-+= 86857 604.604 /bin/sh /usr/sbin/dwatch -R BEGIN"
+.Dl " \e\\-+= 86897 0.0 sudo dtrace -s /dev/stdin"
+.Dl " \e\\-+= 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 and/or convenience.
+To list available profiles use the
+.Ql Fl Q
+option.
+Use the
+.Ql Fl X Ar profile
+option to use a particular profile.
+.Pp
+For example,
+the command
+.Ql dwatch -X kill
+displays arguments sent to
+.Xr kill 2 .
+.Sh OPTIONS
+If a
+.Ar probe
+argument does not contain colon
+.Pq Qo Li ":" Qc
+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.
+.Pp
+Multiple probes must be given as a single
+.Pq quoted
+argument,
+separated by comma and/or whitespace.
+Any/all arguments following said probes will be passed to
+.Xr dtrace 1
+unmodified.
+.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 customization of what is printed after date/time and process info.
+By default,
+the name and arguments of the program triggering the probe are shown.
+Can be specified multiple times.
+.It Fl f
+Enable probes matching the specified function names.
+.It Fl F
+Coalesce trace output by probe.
+.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 .
+Can be specified multiple times.
+.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 probes matching the specified module names.
+.It Fl X Ar profile
+Load profile from DWATCH_PROFILES_PATH.
+.It Fl n
+Enable probes matching the specified probe names.
+.It Fl N Ar count
+Exit after
+.Ar count
+matching entries
+.Pq Default 0 for disabled .
+.It Fl o Ar file
+Set output file.
+If
+.Ql Li - ,
+the path
+.Ql Li /dev/stdout
+is used.
+.It Fl O Ar cmd
+Execute
+.Ar cmd
+for each event.
+This can be any valid
+.Xr sh 1
+command.
+The environment variables
+.Ql Li $TAG
+and
+.Ql Li $DETAILS
+are set for the given
+.Ar cmd .
+.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 .
+Can be specified multiple times.
+.It Fl T Ar time
+Timeout.
+The 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
+.Nm
+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 .
+This is an incomplete list of profiles with basic descriptions:
+.Bl -tag -width "vop_readdir"
+.It chmod
+Print mode and path from
+.Xr chmod 2 ,
+.Xr lchmod 2 ,
+.Xr fchmodat 2
+.It errno
+Print non-zero errno results from system calls
+.It io
+Print disk I/O details provided by
+.Xr dtrace_io 4
+.It ip
+Print IPv4 and IPv6 details provided by
+.Xr dtrace_ip 4
+.It kill
+Print signal and pid from
+.Xr kill 2
+.It nanosleep
+Print requested time from
+.Xr nanosleep 2
+.It open
+Print path from
+.Xr open 2 ,
+.Xr openat 2
+.It proc
+Print process execution details provided by
+.Xr dtrace_proc 4
+.It proc-signal
+Print process signal details provided by
+.Xr dtrace_proc 4
+.It rw
+Print buffer contents from
+.Xr read 2 ,
+.Xr write 2
+.It sched
+Print CPU scheduling details provided by
+.Xr dtrace_sched 4
+.It tcp
+Print TCP address/port details provided by
+.Xr dtrace_tcp 4
+.It tcp-io
+Print TCP I/O details provided by
+.Xr dtrace_tcp 4
+.It udp
+Print UDP I/O details provided by
+.Xr dtrace_udp 4
+.It vop_create
+Print filesystem paths being created by
+.Xr VOP_CREATE 9
+.It vop_lookup
+Print filesystem paths being looked-up by
+.Xr VOP_LOOKUP 9
+.It vop_mkdir
+Print directory paths being created by
+.Xr VOP_MKDIR 9
+.It vop_mknod
+Print device node paths being created by
+.Xr VOP_MKNOD 9
+.It vop_readdir
+Print directory paths being read by
+.Xr VOP_READDIR 9
+.It vop_remove
+Print filesystem paths being removed by
+.Xr VOP_REMOVE 9
+.It vop_rename
+Print filesystem paths being renamed by
+.Xr VOP_RENAME 9
+.It vop_rmdir
+Print directory paths being removed by
+.Xr VOP_RMDIR 9
+.It vop_symlink
+Print symlink paths being created by
+.Xr 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
+.Ev DWATCH_PROFILES_PATH
+is set,
+.Nm
+searches for profiles in the colon-separated list of directories in that
+variable instead of the default
+.Ql Li /usr/libexec/dwatch:/usr/local/libexec/dwatch .
+If set to NULL,
+profiles are not loaded.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Watch processes entering system CPU scheduler.
+.Bd -literal -offset indent
+dwatch on-cpu
+.Ed
+.Pp
+List available profiles,
+one line per profile.
+.Bd -literal -offset indent
+dwatch -1 -Q
+.Ed
+.Pp
+Do not execute
+.Xr dtrace 1
+but display script on stdout and exit.
+.Bd -literal -offset indent
+dwatch -d fsync
+.Ed
+.Pp
+Compile and test but do not execute code generated with given probe.
+.Bd -literal -offset indent
+dwatch -e test_probe
+.Ed
+.Pp
+Print argument one being passed to each call of zfs_sync().
+.Bd -literal -offset indent
+dwatch -E 'printf("%i", arg1)' zfs_sync
+.Ed
+.Pp
+Watch all functions named
+.Ql Li read .
+.Bd -literal -offset indent
+dwatch -f read
+.Ed
+.Pp
+Watch all probe traversal.
+.Bd -literal -offset indent
+dwatch -F :
+.Ed
+.Pp
+Watch syscall probe traversal.
+.Bd -literal -offset indent
+dwatch -F syscall
+.Ed
+.Pp
+Display only processes belonging to wheel super-group.
+.Bd -literal -offset indent
+dwatch -g wheel execve
+.Ed
+.Pp
+Display only processes belonging to groups
+.Ql Li daemon
+or
+.Ql Li nobody .
+.Bd -literal -offset indent
+dwatch -g '1|65534' execve
+.Ed
+.Pp
+Ignore jails,
+displaying only base system processes.
+.Bd -literal -offset indent
+dwatch -j 0 execve
+.Ed
+.Pp
+Display only processes running inside the jail named
+.Ql Li myjail .
+.Bd -literal -offset indent
+dwatch -j myjail execve
+.Ed
+.Pp
+Watch syscall traversal by ruby processes.
+.Bd -literal -offset indent
+dwatch -k 'ruby*' -F syscall
+.Ed
+.Pp
+Watch syscall traversal by processes containing
+.Ql Li daemon
+in their name.
+.Bd -literal -offset indent
+dwatch -k '*daemon*' -F syscall
+.Ed
+.Pp
+Watch signals being passed to
+.Xr kill 2 .
+.Bd -literal -offset indent
+dwatch -X kill
+.Ed
+.Pp
+Watch signals being passed between
+.Xr bash 1
+and
+.Xr vi 1 .
+.Bd -literal -offset indent
+dwatch -k bash -k vi -X kill
+.Ed
+.Pp
+Display a list of unique functions available.
+.Bd -literal -offset indent
+dwatch -l -f
+.Ed
+.Pp
+List available probes for functions ending in
+.Ql Li read .
+.Bd -literal -offset indent
+dwatch -l -f '*read'
+.Ed
+.Pp
+List available probes ending in
+.Dq Li read .
+.Bd -literal -offset indent
+dwatch -l -r 'read$'
+.Ed
+.Pp
+Display a list of unique providers.
+.Bd -literal -offset indent
+dwatch -l -P
+.Ed
+.Pp
+Watch paths being removed by
+.Xr VOP_REMOVE 9 .
+.Bd -literal -offset indent
+dwatch -X vop_remove
+.Ed
+.Pp
+Watch the name
+.Ql Li read
+instead of the function
+.Ql Li read .
+The
+.Nm
+selection algorithm will commonly favor the function named
+.Ql Li read
+when not given a type
+.Pq using So Fl P Sc , So Fl m Sc , So Fl f Sc , or So Fl n Sc
+because there are more probes matching the function named
+.Ql Li read
+than probes matching
+.Ql Li read
+for any other type.
+.Bd -literal -offset indent
+dwatch -n read
+.Ed
+.Pp
+Display the first process to call
+.Xr kill 2
+and then exit.
+.Bd -literal -offset indent
+dwatch -N 1 kill
+.Ed
+.Pp
+Watch processes forked by pid 1234.
+.Bd -literal -offset indent
+dwatch -p 1234 execve
+.Ed
+.Pp
+Watch processes forked by either pid 1234 or pid 5678.
+.Bd -literal -offset indent
+dwatch -p '1234|5678' execve
+.Ed
+.Pp
+Watch the provider
+.Ql Li random
+instead of the function
+.Ql Li random .
+The
+.Nm
+selection algorithm will commonly favor the function named
+.Ql Li random
+when not given a type
+.Pq using So Fl P Sc , So Fl m Sc , So Fl f Sc , or So Fl n Sc
+because there are more probes matching the function named
+.Ql Li random
+than probes matching the provider named
+.Ql Li random .
+.Bd -literal -offset indent
+dwatch -P random
+.Ed
+.Pp
+Display available profiles matching
+.Ql Li vop .
+.Bd -literal -offset indent
+dwatch -Q -r vop
+.Ed
+.Pp
+Watch
+.Xr VOP_LOOKUP 9
+paths containing
+.Ql Li /lib/ .
+.Bd -literal -offset indent
+dwatch -r /lib/ -X vop_lookup
+.Ed
+.Pp
+Show process tree for each command as it is executed.
+.Bd -literal -offset indent
+dwatch -R execve
+.Ed
+.Pp
+Watch processes forked by pid 1234 or children thereof.
+.Bd -literal -offset indent
+dwatch -R -p 1234 execve
+.Ed
+.Pp
+Display processes calling
+.Xr write 2
+with
+.Dq nbytes
+less than 10.
+.Bd -literal -offset indent
+dwatch -t 'arg2<10' -E 'printf("%d",arg2)' write
+.Ed
+.Pp
+Display
+.Xr write 2
+buffer when
+.Dq execname
+is not
+.Ql Li dtrace
+and
+.Dq nbytes
+is less than 10.
+.Bd -literal -offset indent
+dwatch -X write -t 'execname != "dtrace" && this->nbytes < 10'
+.Ed
+.Pp
+Watch
+.Ql Li statfs
+for 5 minutes and exit.
+.Bd -literal -offset indent
+dwatch -T 5m statfs
+.Ed
+.Pp
+Display only processes belonging to the root super-user.
+.Bd -literal -offset indent
+dwatch -u root execve
+.Ed
+.Pp
+Display only processes belonging to users
+.Ql Li daemon
+or
+.Ql Li nobody .
+.Bd -literal -offset indent
+dwatch -u '1|65534' execve
+.Ed
+.Pp
+Print version and exit.
+.Bd -literal -offset indent
+dwatch -V
+.Ed
+.Pp
+View the first 100 scheduler preemptions.
+.Bd -literal -offset indent
+dwatch -y -N 100 preempt | less -R
+.Ed
+.Pp
+Display processes matching either
+.Dq Li mkdir
+or
+.Dq Li rmdir .
+.Bd -literal -offset indent
+dwatch -z '(mk|rm)dir' execve
+.Ed
+.Pp
+Run a command and watch network activity only while that command runs.
+.Bd -literal -offset indent
+dwatch -X tcp -- -c "nc -zvw10 google.com 22"
+.Ed
+.Pp
+Watch
+.Xr open 2
+and
+.Xr openat 2
+calls only while pid 1234 is active.
+.Bd -literal -offset indent
+dwatch -X open -- -p 1234
+.Ed
+.Pp
+Watch probe traversal for a given command.
+Note that
+.Dq Li -c true
+is passed to
+.Xr dtrace 1
+since it appears after the
+.Nm
+probe argument.
+.Bd -literal -offset indent
+dwatch -F 'pid$target:::entry' -c true
+.Ed
+.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
diff --git a/cddl/usr.sbin/dwatch/examples/Makefile b/cddl/usr.sbin/dwatch/examples/Makefile
new file mode 100644
index 000000000000..33364044942f
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/examples/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+FILESDIR= ${SHAREDIR}/examples/dwatch
+FILES= profile_template
+
+.include <bsd.prog.mk>
diff --git a/cddl/usr.sbin/dwatch/examples/profile_template b/cddl/usr.sbin/dwatch/examples/profile_template
new file mode 100644
index 000000000000..8bb3acfed2fb
--- /dev/null
+++ b/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-2018 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
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/Makefile b/cddl/usr.sbin/dwatch/libexec/Makefile
new file mode 100644
index 000000000000..b0d3940914e0
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/Makefile
@@ -0,0 +1,87 @@
+# $FreeBSD$
+
+FILESDIR= ${LIBEXECDIR}/dwatch
+FILES= chmod \
+ errno \
+ io \
+ ip \
+ kill \
+ nanosleep \
+ open \
+ proc \
+ rw \
+ sched \
+ sendrecv \
+ tcp \
+ udp \
+ vop_create \
+ vop_readdir \
+ vop_rename \
+ vop_symlink
+
+LINKS= ${LIBEXECDIR}/dwatch/chmod ${LIBEXECDIR}/dwatch/fchmodat
+LINKS+= ${LIBEXECDIR}/dwatch/chmod ${LIBEXECDIR}/dwatch/lchmod
+LINKS+= ${LIBEXECDIR}/dwatch/io ${LIBEXECDIR}/dwatch/io-done
+LINKS+= ${LIBEXECDIR}/dwatch/io ${LIBEXECDIR}/dwatch/io-start
+LINKS+= ${LIBEXECDIR}/dwatch/ip ${LIBEXECDIR}/dwatch/ip-receive
+LINKS+= ${LIBEXECDIR}/dwatch/ip ${LIBEXECDIR}/dwatch/ip-send
+LINKS+= ${LIBEXECDIR}/dwatch/open ${LIBEXECDIR}/dwatch/openat
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-create
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-exec
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-exec-failure
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-exec-success
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-exit
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-signal
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-signal-clear
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-signal-discard
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-signal-send
+LINKS+= ${LIBEXECDIR}/dwatch/proc ${LIBEXECDIR}/dwatch/proc-status
+LINKS+= ${LIBEXECDIR}/dwatch/rw ${LIBEXECDIR}/dwatch/read
+LINKS+= ${LIBEXECDIR}/dwatch/rw ${LIBEXECDIR}/dwatch/write
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-change-pri
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-cpu
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-dequeue
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-enqueue
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-exec
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-lend-pri
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-load-change
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-off-cpu
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-on-cpu
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-preempt
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-pri
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-queue
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-remain-cpu
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-sleep
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-surrender
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-tick
+LINKS+= ${LIBEXECDIR}/dwatch/sched ${LIBEXECDIR}/dwatch/sched-wakeup
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/recv
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/recvfrom
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/recvmsg
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/send
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/sendmsg
+LINKS+= ${LIBEXECDIR}/dwatch/sendrecv ${LIBEXECDIR}/dwatch/sendto
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-accept
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-accept-established
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-accept-refused
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-connect
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-connect-established
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-connect-refused
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-connect-request
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-established
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-init
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-io
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-receive
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-refused
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-send
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-state-change
+LINKS+= ${LIBEXECDIR}/dwatch/tcp ${LIBEXECDIR}/dwatch/tcp-status
+LINKS+= ${LIBEXECDIR}/dwatch/udp ${LIBEXECDIR}/dwatch/udp-receive
+LINKS+= ${LIBEXECDIR}/dwatch/udp ${LIBEXECDIR}/dwatch/udp-send
+LINKS+= ${LIBEXECDIR}/dwatch/vop_create ${LIBEXECDIR}/dwatch/vop_lookup
+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
+
+.include <bsd.prog.mk>
diff --git a/cddl/usr.sbin/dwatch/libexec/chmod b/cddl/usr.sbin/dwatch/libexec/chmod
new file mode 100644
index 000000000000..d131109a0d66
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/chmod
@@ -0,0 +1,65 @@
+# -*- 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), fchmodat(2), or similar entry $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print mode/path being passed to chmod(2), lchmod(2), fchmodat(2), or similar
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+chmod)
+ : ${PROBE:=$( echo \
+ syscall::chmod:entry, \
+ syscall::lchmod:entry, \
+ syscall::fchmodat:entry )}
+ ;;
+*)
+ : ${PROBE:=syscall::$PROFILE:entry}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this mode_t mode;
+this string path;
+this u_char at;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * Should we expect the first argument to be a file descriptor?
+ * NB: Based on probefunc ending in "at" (e.g., fchmodat(2))
+ */
+ this->at = strstr(probefunc, "at") ==
+ (probefunc + strlen(probefunc) - 2) ? 1 : 0;
+
+ this->mode = (mode_t)(this->at ? arg2 : arg1);
+ this->path = copyinstr(this->at ? arg1 : arg0);
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print mode/path details
+ */
+ printf("%04o %s", this->mode, this->path);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/errno b/cddl/usr.sbin/dwatch/libexec/errno
new file mode 100644
index 000000000000..42fce4ab8faa
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/errno
@@ -0,0 +1,37 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for syscall errno logging $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print when syscall returns with non-zero errno (default) or other condition.
+# To override the default test condition, use (for example) `-t errno==2' to
+# test for specific value or simply `-t 1' to unconditionally show all values.
+#
+############################################################ PROBE
+
+: ${PROBE:=syscall:::return}
+
+############################################################ EVENT ACTION
+
+[ "$CUSTOM_TEST" ] || EVENT_TEST="errno > 0"
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print errno details
+ */
+ printf("%s: %s (%i)", probefunc, strerror[errno], errno);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/io b/cddl/usr.sbin/dwatch/libexec/io
new file mode 100644
index 000000000000..26c58593ead3
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/io
@@ -0,0 +1,108 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for dtrace_io(4) $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display activity related to disk I/O
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+io) : ${PROBE:=io:::start, io:::done} ;;
+ *) : ${PROBE:=io:::${PROFILE#io-}}
+esac
+
+############################################################ EVENT ACTION
+
+[ "$CUSTOM_TEST" ] || EVENT_TEST='this->devinfo.dev_name != ""'
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this bufinfo_t bufinfo;
+this devinfo_t devinfo;
+this int b_flags;
+this long bio_length;
+this string bio_cmd;
+this string bio_flags;
+this string device_entry;
+this string device_if;
+this string device_type;
+this string flow;
+
+inline string append_bio_flag[int flags, int flag] = this->bio_flags =
+ strjoin(this->bio_flags,
+ strjoin(this->bio_flags == "" ? "" : (flags & flag) == flag ? "|" : "",
+ bio_flag_string[flags & flag]));
+
+$PROBE /(struct bio *)args[0] != NULL/ /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * dtrace_io(4)
+ */
+ this->flow = probefunc == "done" ? "<-" : "->";
+
+ /*
+ * struct bio *
+ */
+ this->bufinfo = xlate <bufinfo_t> ((struct bio *)args[0]);
+ this->bio_cmd = bio_cmd_string[(int)this->bufinfo.b_cmd];
+ this->b_flags = (int)this->bufinfo.b_flags;
+ this->bio_flags = bio_flag_string[this->b_flags & BIO_ERROR];
+ this->bio_flags = strjoin(this->bio_flags, this->bufinfo.b_error ?
+ strjoin(this->bio_flags == "" ?
+ bio_flag_string[BIO_ERROR] : "",
+ strjoin("#", lltostr(this->bufinfo.b_error))) :
+ "");
+ append_bio_flag[this->b_flags, BIO_DONE];
+ append_bio_flag[this->b_flags, BIO_ONQUEUE];
+ append_bio_flag[this->b_flags, BIO_ORDERED];
+ append_bio_flag[this->b_flags, BIO_UNMAPPED];
+ append_bio_flag[this->b_flags, BIO_TRANSIENT_MAPPING];
+ append_bio_flag[this->b_flags, BIO_VLIST];
+ this->bio_flags = this->bio_flags == "" ? "-" : this->bio_flags;
+ this->bio_length = (long)this->bufinfo.b_bcount;
+
+ /*
+ * struct devstat *
+ */
+ this->devinfo = xlate <devinfo_t> ((struct devstat *)args[1]);
+ this->device_type = device_type[(int)this->devinfo.dev_type];
+ this->device_if = device_if[(int)this->devinfo.dev_type];
+ this->device_entry = strjoin(this->devinfo.dev_name,
+ lltostr(this->devinfo.dev_minor));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print disk I/O details
+ */
+ printf("%s %s %s %s %s %s %d byte%s",
+ this->flow,
+ this->device_type,
+ this->device_if,
+ this->device_entry,
+ this->bio_cmd,
+ this->bio_flags,
+ this->bio_length,
+ this->bio_length == 1 ? "" : "s");
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/ip b/cddl/usr.sbin/dwatch/libexec/ip
new file mode 100644
index 000000000000..8de385f568bf
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/ip
@@ -0,0 +1,76 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for dtrace_ip(4) $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display interface name and bytes sent/received when IP I/O occurs
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+ip) : ${PROBE:=ip:::send, ip:::receive} ;;
+ *) : ${PROBE:=ip:::${PROFILE#ip-}}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this string flow;
+this string if_name;
+this string local;
+this string remote;
+this u_char recv;
+this uint32_t length;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * dtrace_ip(4)
+ */
+ this->recv = probename == "receive" ? 1 : 0;
+ this->flow = this->recv ? "<-" : "->";
+
+ /*
+ * ipinfo_t *
+ */
+ this->length = (uint32_t)args[2]->ip_plength;
+ this->local = this->recv ? args[2]->ip_daddr : args[2]->ip_saddr;
+ this->remote = this->recv ? args[2]->ip_saddr : args[2]->ip_daddr;
+
+ /*
+ * ifinfo_t *
+ */
+ this->if_name = args[3]->if_name;
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print network I/O details
+ */
+ printf("%s %s %s %s %u byte%s",
+ this->if_name,
+ this->local,
+ this->flow,
+ this->remote,
+ this->length,
+ this->length == 1 ? "" : "s");
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/kill b/cddl/usr.sbin/dwatch/libexec/kill
new file mode 100644
index 000000000000..c30e951381c3
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/kill
@@ -0,0 +1,47 @@
+# -*- 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-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to kill(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:=syscall::$PROFILE:entry}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this int sig;
+this pid_t pid;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ this->pid = (pid_t)arg0;
+ this->sig = (int)arg1;
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print signal/pid details
+ */
+ printf("signal %i to pid %d", this->sig, this->pid);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/nanosleep b/cddl/usr.sbin/dwatch/libexec/nanosleep
new file mode 100644
index 000000000000..acc4cf352af7
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/nanosleep
@@ -0,0 +1,54 @@
+# -*- 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-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print arguments being passed to nanosleep(2) [or similar]
+#
+############################################################ PROBE
+
+: ${PROBE:=syscall::$PROFILE:entry}
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this struct timespec * rqtp;
+this time_t requested_sec;
+this long requested_nsec;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ print("<$ID>");
+}
+ /*
+ * const struct timespec *
+ */
+ this->rqtp = (struct timespec *)copyin(arg0, sizeof(struct timespec));
+ this->requested_sec = (time_t)this->rqtp->tv_sec;
+ this->requested_nsec = (long)this->rqtp->tv_nsec;
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Dump nanosleep(2) arguments
+ */
+ printf("%d.%d seconds",
+ this->requested_sec, this->requested_nsec / 100000);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/open b/cddl/usr.sbin/dwatch/libexec/open
new file mode 100644
index 000000000000..5185a97aca03
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/open
@@ -0,0 +1,57 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for open[at](2) [or similar] entry $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print path being passed to open(2), openat(2), or similar
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+open) : ${PROBE:=syscall::open:entry, syscall::openat:entry} ;;
+ *) : ${PROBE:=syscall::$PROFILE:entry}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this string path;
+this u_char at;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * Should we expect the first argument to be a file descriptor?
+ * NB: Based on probefunc ending in "at" (e.g., openat(2))
+ */
+ this->at = strstr(probefunc, "at") ==
+ (probefunc + strlen(probefunc) - 2) ? 1 : 0;
+
+ this->path = copyinstr(this->at ? arg1 : arg0);
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print path details
+ */
+ printf("%s", this->path);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/proc b/cddl/usr.sbin/dwatch/libexec/proc
new file mode 100644
index 000000000000..0f67394a84d5
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/proc
@@ -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 dtrace_proc(4) activity $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display process activity
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+proc)
+ : ${PROBE:=$( echo \
+ proc:::create, \
+ proc:::exec, \
+ proc:::exec-failure, \
+ proc:::exec-success, \
+ proc:::exit, \
+ proc:::signal-clear, \
+ proc:::signal-discard, \
+ proc:::signal-send )}
+ ;;
+proc-signal)
+ : ${PROBE:=$( echo \
+ proc:::signal-clear, \
+ proc:::signal-discard, \
+ proc:::signal-send )}
+ ;;
+proc-status)
+ : ${PROBE:=$( echo \
+ proc:::create, \
+ proc:::exec, \
+ proc:::exec-failure, \
+ proc:::exec-success, \
+ proc:::exit )}
+ ;;
+*)
+ : ${PROBE:=proc:::${PROFILE#proc-}}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this int sig;
+this pid_t pid;
+this string details;
+this string exec_arg0;
+
+inline string probealias[string name] =
+ name == "create" ? "FORK" :
+ name == "exec" ? "EXEC" :
+ name == "exec-failure" ? "FAIL" :
+ name == "exec-success" ? "INIT" :
+ name == "exit" ? "EXIT" :
+ name == "signal-clear" ? "CLEAR" :
+ name == "signal-discard" ? "DISCARD" :
+ name == "signal-send" ? "SEND" :
+ name;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ this->details = "";
+}
+
+proc:::create /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");
+}
+ $( pproc -P _create "(struct proc *)args[0]" )
+
+ /* details = "pid <pid of args[0]> -- <proc args of args[0]>" */
+ this->details = strjoin(
+ strjoin("pid ", lltostr(this->pid_create)),
+ strjoin(" -- ", this->args_create));
+}
+
+proc:::exec /* probe ID $(( $ID + 2 )) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))");}
+ this->details = this->exec_arg0 = stringof(arg0);
+}
+
+proc:::exec-failure /* probe ID $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");
+}
+ /* details = "<arg0 from proc:::exec>: <strerror of arg0> (<arg0>)" */
+ this->details = strjoin(
+ strjoin(this->exec_arg0, ": "),
+ strjoin(strerror[(int)arg0],
+ strjoin(" (", strjoin(lltostr((int)arg0), ")"))));
+}
+
+proc:::exec-success /* probe ID $(( $ID + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + 4 ))>");}
+ this->details = this->args0;
+}
+
+proc:::exit /* probe ID $(( $ID + 5 )) */
+{${TRACE:+
+ printf("<$(( $ID + 5 ))>");}
+ this->details = child_signal_string[(int)arg0];
+}
+
+proc:::signal-clear /* probe ID $(( $ID + 6 )) */
+{${TRACE:+
+ printf("<$(( $ID + 6 ))>");}
+ this->pid = (pid_t)((ksiginfo_t *)args[1])->ksi_info.si_pid;
+ this->sig = (int)arg0;
+}
+
+proc:::signal-discard, proc:::signal-send /* probe ID $(( $ID + 7 )) */
+{${TRACE:+
+ printf("<$(( $ID + 7 ))>");}
+ this->pid = (pid_t)((struct proc *)args[1])->p_pid;
+ this->sig = (int)arg2;
+}
+
+proc:::signal-clear,
+proc:::signal-discard,
+proc:::signal-send /* probe ID $(( $ID + 8 )) */
+{${TRACE:+
+ printf("<$(( $ID + 8 ))>");
+}
+ /* details = "<signal>[<num>] pid <pid>" */
+ this->details = strjoin(strjoin(signal_string[this->sig], "["),
+ strjoin(strjoin(lltostr(this->sig), "] pid "),
+ lltostr(this->pid)));
+}
+
+proc:::signal-send, proc:::signal-discard /* probe ID $(( $ID + 9 )) */
+{${TRACE:+
+ printf("<$(( $ID + 9 ))>");
+}
+ $( pproc -P _signal "(struct proc *)args[1]" )
+
+ this->details = strjoin(this->details,
+ strjoin(" -- ", this->args_signal));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 10 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print details
+ */
+ printf("%s %s", probealias[probename], this->details);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/rw b/cddl/usr.sbin/dwatch/libexec/rw
new file mode 100644
index 000000000000..32aa58c34f15
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/rw
@@ -0,0 +1,74 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for read(2), write(2), or similar entry $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display data sent/received when read(2)/write(2) occurs
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+rw) : ${PROBE:=syscall::read:entry, syscall::write:entry} ;;
+ *) : ${PROBE:=syscall::$PROFILE:entry}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this size_t nbytes;
+this string bufstr;
+this string flow;
+this void * buf;
+this void * data;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * R/W
+ */
+ this->flow = probefunc == "read" ? "<-" : "->";
+ this->buf = (void *)arg1;
+ this->nbytes = (size_t)arg2;
+
+ /*
+ * Allocate temporary memory for, copy, and NUL-terminate the data
+ */
+ this->data = alloca(this->nbytes + 1);
+ copyinto((uintptr_t)this->buf, this->nbytes, this->data);
+ bcopy("\0", (void *)((uintptr_t)this->data + this->nbytes), 1);
+
+ /*
+ * Extract string from temporary memory
+ */
+ this->bufstr = stringof(this->data);
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print read/write details
+ */
+ printf("%s \"%s\" %d byte%s",
+ this->flow,
+ this->bufstr,
+ this->nbytes,
+ this->nbytes == 1 ? "" : "s");
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/sched b/cddl/usr.sbin/dwatch/libexec/sched
new file mode 100644
index 000000000000..acbe47d92989
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/sched
@@ -0,0 +1,109 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for dtrace_sched(4) $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display CPU scheduling activity
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+sched)
+ : ${PROBE:=sched:::} ;;
+sched-cpu)
+ : ${PROBE:=sched:::off-cpu, sched:::on-cpu, sched:::remain-cpu} ;;
+sched-exec)
+ : ${PROBE:=sched:::sleep, sched:::wakeup} ;;
+sched-pri)
+ : ${PROBE:=sched:::change-pri, sched:::lend-pri} ;;
+sched-queue)
+ : ${PROBE:=sched:::dequeue, sched:::enqueue, sched:::load-change} ;;
+*)
+ : ${PROBE:=sched:::${PROFILE#sched-}}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this pid_t pid;
+this string args;
+this string details;
+this u_char curprio;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ this->args = this->args0;
+ this->details = "";
+ this->pid = this->pid0;
+}
+
+sched:::change-pri, sched:::dequeue, sched:::enqueue,
+sched:::lend-pri, sched:::off-cpu, sched:::surrender,
+sched:::tick, sched:::wakeup /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->curprio = (u_char)((struct thread *)args[0])->td_priority;
+
+ $( pproc -P _sched "(struct proc *)args[1]" )
+
+ this->args = this->args_sched;
+ this->pid = this->pid_sched;
+}
+
+sched:::enqueue /* probe ID $(( $ID + 2 )) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ /* details = "head" or "tail" */
+ this->details = (int)arg3 == 0 ? "tail" : "head";
+}
+
+sched:::change-pri, sched:::lend-pri /* probe ID $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ /* details = "<curprio> -> <arg2>" */
+ this->details = strjoin(lltostr(this->curprio),
+ strjoin("->", lltostr((uint8_t)arg2)));
+}
+
+sched:::load-change /* probe ID $(( $ID + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + 4 ))>");}
+ /* details = "CPU<arg0> queue <arg1>" */
+ this->details = strjoin(strjoin("CPU", lltostr((int)arg0)),
+ strjoin(" queue ", lltostr((int)arg1)));
+}
+
+$PROBE /* probe ID $(( $ID + 5 )) */
+{${TRACE:+
+ printf("<$(( $ID + 5 ))>");}
+ /* details += " pid <pid> -- <proc args of pid>" */
+ this->details = strjoin(this->details, this->details == "" ? "" : " ");
+ this->details = strjoin(this->details, strjoin(
+ strjoin("pid ", lltostr(this->pid)),
+ strjoin(" -- ", this->args)));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 6 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print scheduling details
+ */
+ printf("%s %s", probename, this->details);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/sendrecv b/cddl/usr.sbin/dwatch/libexec/sendrecv
new file mode 100644
index 000000000000..7227e41b5731
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/sendrecv
@@ -0,0 +1,229 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for send(2)/recv(2) $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Print details from send(2)/recv(2)
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+sendrecv)
+ : ${PROBE:=$( echo \
+ syscall::recvfrom:return, \
+ syscall::recvmsg:return, \
+ syscall::sendmsg:entry, \
+ syscall::sendto:entry )} ;;
+send)
+ : ${PROBE:=$( echo \
+ syscall::sendmsg:entry, \
+ syscall::sendto:entry )} ;;
+recv)
+ : ${PROBE:=$( echo \
+ syscall::recvfrom:return, \
+ syscall::recvmsg:return )} ;;
+recv*)
+ : ${PROBE:=syscall::$PROFILE:return} ;;
+*)
+ : ${PROBE:=syscall::$PROFILE:entry}
+esac
+
+############################################################ EVENT ACTION
+
+#[ "$CUSTOM_TEST" ] || EVENT_TEST="this->from != NULL"
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+typedef struct sainfo {
+ sa_family_t sa_family;
+ uint16_t port;
+ string addr;
+ string family;
+} sainfo_t;
+
+/*
+ * Address families from <sys/socket.h>
+ */
+#pragma D binding "1.13" address_family_string
+inline string address_family_string[sa_family_t af] =
+ af == AF_UNSPEC ? "AF_UNSPEC" :
+ af == AF_LOCAL ? "AF_UNIX" :
+ af == AF_UNIX ? "AF_UNIX" :
+ af == AF_INET ? "AF_INET" :
+ af == AF_IMPLINK ? "AF_IMPLINK" :
+ af == AF_PUP ? "AF_PUP" :
+ af == AF_CHAOS ? "AF_CHAOS" :
+ af == AF_NETBIOS ? "AF_NETBIOS" :
+ af == AF_ISO ? "AF_ISO" :
+ af == AF_OSI ? "AF_ISO" :
+ af == AF_ECMA ? "AF_ECMA" :
+ af == AF_DATAKIT ? "AF_DATAKIT" :
+ af == AF_CCITT ? "AF_CCITT" :
+ af == AF_SNA ? "AF_SNA" :
+ af == AF_DECnet ? "AF_DECnet" :
+ af == AF_DLI ? "AF_DLI" :
+ af == AF_LAT ? "AF_LAT" :
+ af == AF_HYLINK ? "AF_HYLINK" :
+ af == AF_APPLETALK ? "AF_APPLETALK" :
+ af == AF_ROUTE ? "AF_ROUTE" :
+ af == AF_LINK ? "AF_LINK" :
+ af == pseudo_AF_XTP ? "pseudo_AF_XTP" :
+ af == AF_COIP ? "AF_COIP" :
+ af == AF_CNT ? "AF_CNT" :
+ af == pseudo_AF_RTIP ? "pseudo_AF_RTIP" :
+ af == AF_IPX ? "AF_IPX" :
+ af == AF_SIP ? "AF_SIP" :
+ af == pseudo_AF_PIP ? "pseudo_AF_PIP" :
+ af == AF_ISDN ? "AF_ISDN" :
+ af == AF_E164 ? "AF_ISDN" :
+ af == pseudo_AF_KEY ? "pseudo_AF_KEY" :
+ af == AF_INET6 ? "AF_INET6" :
+ af == AF_NATM ? "AF_NATM" :
+ af == AF_ATM ? "AF_ATM" :
+ af == pseudo_AF_HDRCMPLT ? "pseudo_AF_HDRCMPLT" :
+ af == AF_NETGRAPH ? "AF_NETGRAPH" :
+ af == AF_SLOW ? "AF_SLOW" :
+ af == AF_SCLUSTER ? "AF_SCLUSTER" :
+ af == AF_ARP ? "AF_ARP" :
+ af == AF_BLUETOOTH ? "AF_BLUETOOTH" :
+ af == AF_IEEE80211 ? "AF_IEEE80211" :
+ af == AF_INET_SDP ? "AF_INET_SDP" :
+ af == AF_INET6_SDP ? "AF_INET6_SDP" :
+ af == AF_MAX ? "AF_MAX" :
+ strjoin("AF_UNKNOWN(", strjoin(lltostr(af), ")"));
+
+#pragma D binding "1.13" sa_data_size
+inline int sa_data_size = 14;
+#pragma D binding "1.13" sa_dummy_data
+inline char *sa_dummy_data = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+#pragma D binding "1.13" sa_data_addr
+inline string sa_data_addr[sa_family_t af, char data[sa_data_size]] =
+ af == AF_INET ? strjoin(
+ strjoin(strjoin(lltostr(data[2] & 0xFF), "."),
+ strjoin(lltostr(data[3] & 0xFF), ".")
+ ),
+ strjoin(strjoin(lltostr(data[4] & 0xFF), "."),
+ lltostr(data[5] & 0xFF))
+ ) :
+ "";
+
+#pragma D binding "1.13" sa_data_port
+inline uint16_t sa_data_port[sa_family_t af, char data[sa_data_size]] =
+ af == AF_INET ? (data[0] << 8) + data[1] :
+ 0;
+
+#pragma D binding "1.13" translator
+translator sainfo_t < struct sockaddr *SA > {
+ sa_family = SA == NULL ? 0 : SA->sa_family;
+ family = address_family_string[SA == NULL ? 0 : SA->sa_family];
+ addr = SA == NULL ?
+ sa_data_addr[0, sa_dummy_data] :
+ sa_data_addr[SA->sa_family, SA->sa_data];
+ port = SA == NULL ?
+ sa_data_port[0, sa_dummy_data] :
+ sa_data_port[SA->sa_family, SA->sa_data];
+};
+
+this sainfo_t sainfo;
+this ssize_t nbytes;
+this string details;
+this string flow;
+this struct msghdr * msghdr;
+this struct sockaddr * sa;
+
+inline string probeflow[string func] =
+ func == "recvfrom" ? "<-" :
+ func == "recvmsg" ? "<-" :
+ func == "recvmmsg" ? "<-" :
+ "->";
+
+inline string af_details[sa_family_t af, string addr, uint16_t port] =
+ af == AF_INET ? strjoin(addr, strjoin(":", lltostr(port))) :
+ "";
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ this->details = "";
+ this->flow = probeflow[probefunc];
+}
+
+syscall::recvfrom:entry /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->sainfo = xlate <sainfo_t> ((struct sockaddr *)(args[4] == NULL ?
+ NULL : copyin(arg4, sizeof(struct sockaddr))));
+}
+
+syscall::recvfrom:return /* probe ID $(( $ID + 2 )) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ this->nbytes = arg0;
+ this->details = strjoin("from ", strjoin(
+ strjoin(this->sainfo.family, " "),
+ af_details[this->sainfo.sa_family,
+ this->sainfo.addr, this->sainfo.port]));
+}
+
+syscall::recvmsg:entry /* probe ID $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ this->sockaddr = (struct sockaddr *)arg1;
+}
+
+syscall::recvmsg:return /this->sockaddr != NULL/ /* probe ID $(( $ID + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + 4 ))>");}
+ this->nbytes = arg0;
+ this->sainfo = xlate <sainfo_t> ((struct sockaddr *)this->sockaddr);
+ this->details = strjoin("sainfo=[", "]");
+}
+
+syscall::sendmsg:entry /* probe ID $(( $ID + 5 )) */
+{${TRACE:+
+ printf("<$(( $ID + 5 ))>");}
+ this->nbytes = arg2;
+}
+
+syscall::sendto:entry /* probe ID $(( $ID + 6 )) */
+{${TRACE:+
+ printf("<$(( $ID + 6 ))>");}
+ this->nbytes = arg2;
+ this->sainfo = xlate <sainfo_t> ((struct sockaddr *)(arg4 == NULL ?
+ NULL : copyin(arg4, sizeof(struct sockaddr))));
+ this->details = strjoin("to ", strjoin(
+ strjoin(this->sainfo.family, " "),
+ af_details[this->sainfo.sa_family,
+ this->sainfo.addr, this->sainfo.port]));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 7 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print socket details
+ */
+ printf("%s %d byte%s%s%s",
+ this->flow,
+ this->nbytes,
+ this->nbytes != 1 ? "s" : "",
+ this->details != "" ? " " : "",
+ this->details);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/tcp b/cddl/usr.sbin/dwatch/libexec/tcp
new file mode 100644
index 000000000000..344cdb4ee6e8
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/tcp
@@ -0,0 +1,210 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for dtrace_tcp(4) connections $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display local/remote TCP addresses/ports and bytes sent/received for TCP I/O
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+tcp)
+ : ${PROBE:=$( echo \
+ tcp:::accept-established, \
+ tcp:::accept-refused, \
+ tcp:::connect-established, \
+ tcp:::connect-refused, \
+ tcp:::connect-request, \
+ tcp:::receive, \
+ tcp:::send, \
+ tcp:::state-change )} ;;
+tcp-accept)
+ : ${PROBE:=tcp:::accept-established, tcp:::accept-refused} ;;
+tcp-connect)
+ : ${PROBE:=$( echo \
+ tcp:::connect-established, \
+ tcp:::connect-refused, \
+ tcp:::connect-request )} ;;
+tcp-established)
+ : ${PROBE:=tcp:::accept-established, tcp:::connect-established} ;;
+tcp-init)
+ : ${PROBE:=$( echo \
+ tcp:::accept-established, \
+ tcp:::accept-refused, \
+ tcp:::connect-established, \
+ tcp:::connect-refused, \
+ tcp:::connect-request )} ;;
+tcp-io)
+ : ${PROBE:=tcp:::send, tcp:::receive} ;;
+tcp-refused)
+ : ${PROBE:=tcp:::accept-refused, tcp:::connect-refused} ;;
+tcp-status)
+ : ${PROBE:=$( echo \
+ tcp:::accept-established, \
+ tcp:::accept-refused, \
+ tcp:::connect-established, \
+ tcp:::connect-refused, \
+ tcp:::connect-request, \
+ tcp:::state-change )} ;;
+*)
+ : ${PROBE:=tcp:::${PROFILE#tcp-}}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this int32_t from_state;
+this int32_t to_state;
+this string details;
+this string flow;
+this string local;
+this string remote;
+this u_char local6;
+this u_char remote6;
+this u_char slocal;
+this uint16_t lport;
+this uint16_t rport;
+this uint32_t length;
+
+inline string probeflow[string name] =
+ name == "accept-established" ? "<-" :
+ name == "accept-refused" ? "X-" :
+ name == "connect-refused" ? "-X" :
+ name == "connect-request" ? "-?" :
+ name == "receive" ? "<-" :
+ "->";
+
+inline u_char srclocal[string name] =
+ name == "accept-refused" ? 1 :
+ name == "connect-request" ? 1 :
+ name == "send" ? 1 :
+ 0;
+
+/*
+ * TCPSTATES from <sys/netinet/tcp_fsm.h> used by netstat(1)
+ */
+inline string tcpstate[int32_t state] =
+ state == TCPS_CLOSED ? "CLOSED" :
+ state == TCPS_LISTEN ? "LISTEN" :
+ state == TCPS_SYN_SENT ? "SYN_SENT" :
+ state == TCPS_SYN_RECEIVED ? "SYN_RCVD" :
+ state == TCPS_ESTABLISHED ? "ESTABLISHED" :
+ state == TCPS_CLOSE_WAIT ? "CLOSE_WAIT" :
+ state == TCPS_FIN_WAIT_1 ? "FIN_WAIT_1" :
+ state == TCPS_CLOSING ? "CLOSING" :
+ state == TCPS_LAST_ACK ? "LAST_ACK" :
+ state == TCPS_FIN_WAIT_2 ? "FIN_WAIT_2" :
+ state == TCPS_TIME_WAIT ? "TIME_WAIT" :
+ strjoin("UNKNOWN(", strjoin(lltostr(state), ")"));
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ this->details = "";
+
+ /*
+ * dtrace_tcp(4)
+ */
+ this->flow = probeflow[probename];
+}
+
+tcp:::accept-established,
+tcp:::accept-refused,
+tcp:::connect-established,
+tcp:::connect-refused,
+tcp:::connect-request,
+tcp:::receive,
+tcp:::send /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");
+}
+ /*
+ * dtrace_tcp(4)
+ */
+ this->slocal = srclocal[probename];
+
+ /*
+ * ipinfo_t *
+ */
+ this->local = this->slocal ? args[2]->ip_saddr : args[2]->ip_daddr;
+ this->remote = this->slocal ? args[2]->ip_daddr : args[2]->ip_saddr;
+
+ /*
+ * tcpinfo_t *
+ */
+ this->lport = this->slocal ? args[4]->tcp_sport : args[4]->tcp_dport;
+ this->rport = this->slocal ? args[4]->tcp_dport : args[4]->tcp_sport;
+
+ /*
+ * IPv6 support
+ */
+ this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
+ this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
+ this->local = strjoin(strjoin(this->local6 ? "[" : "",
+ this->local), this->local6 ? "]" : "");
+ this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
+ this->remote), this->remote6 ? "]" : "");
+}
+
+tcp:::state-change /* probe ID $(( $ID + 2 )) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");
+}
+ /*
+ * tcpsinfo_t *
+ */
+ this->local = args[3]->tcps_laddr;
+ this->lport = (uint16_t)args[3]->tcps_lport;
+ this->remote = args[3]->tcps_raddr;
+ this->rport = (uint16_t)args[3]->tcps_rport;
+ this->to_state = (int32_t)args[3]->tcps_state;
+
+ /*
+ * tcplsinfo_t *
+ */
+ this->from_state = (int32_t)args[5]->tcps_state;
+
+ /* flow = "[from state]->[to state]" */
+ this->flow = strjoin(tcpstate[this->from_state],
+ strjoin("->", tcpstate[this->to_state]));
+}
+
+tcp:::send, tcp:::receive /* pribe ID $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ this->length = (uint32_t)args[2]->ip_plength -
+ (uint8_t)args[4]->tcp_offset;
+
+ /* details = " <length> byte<s>" */
+ this->details = strjoin(
+ strjoin(" ", lltostr(this->length)),
+ strjoin(" byte", this->length == 1 ? "" : "s"));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 4 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print details
+ */
+ printf("%s:%u %s %s:%u%s",
+ this->local, this->lport,
+ this->flow,
+ this->remote, this->rport,
+ this->details);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/udp b/cddl/usr.sbin/dwatch/libexec/udp
new file mode 100644
index 000000000000..1f896a71805d
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/udp
@@ -0,0 +1,89 @@
+# -*- tab-width: 4 -*- ;; Emacs
+# vi: set filetype=sh tabstop=8 shiftwidth=8 noexpandtab :: Vi/ViM
+############################################################ IDENT(1)
+#
+# $Title: dwatch(8) module for dtrace_udp(4) $
+# $Copyright: 2014-2018 Devin Teske. All rights reserved. $
+# $FreeBSD$
+#
+############################################################ DESCRIPTION
+#
+# Display local/remote UDP addresses/ports and bytes sent/received for UDP I/O
+#
+############################################################ PROBE
+
+case "$PROFILE" in
+udp) : ${PROBE:=udp:::send, udp:::receive} ;;
+ *) : ${PROBE:=udp:::${PROFILE#udp-}}
+esac
+
+############################################################ ACTIONS
+
+exec 9<<EOF
+this string flow;
+this string local;
+this string remote;
+this u_char local6;
+this u_char recv;
+this u_char remote6;
+this uint16_t length;
+this uint16_t lport;
+this uint16_t rport;
+
+$PROBE /* probe ID $ID */
+{${TRACE:+
+ printf("<$ID>");
+}
+ /*
+ * dtrace_udp(4)
+ */
+ this->recv = probename == "receive" ? 1 : 0;
+ this->flow = this->recv ? "<-" : "->";
+
+ /*
+ * ipinfo_t *
+ */
+ this->local = this->recv ? args[2]->ip_daddr : args[2]->ip_saddr;
+ this->remote = this->recv ? args[2]->ip_saddr : args[2]->ip_daddr;
+
+ /*
+ * udpinfo_t *
+ */
+ this->length = (uint16_t)args[4]->udp_length;
+ this->lport = this->recv ? args[4]->udp_dport : args[4]->udp_sport;
+ this->rport = this->recv ? args[4]->udp_sport : args[4]->udp_dport;
+
+ /*
+ * IPv6 support
+ */
+ this->local6 = strstr(this->local, ":") != NULL ? 1 : 0;
+ this->remote6 = strstr(this->remote, ":") != NULL ? 1 : 0;
+ this->local = strjoin(strjoin(this->local6 ? "[" : "",
+ this->local), this->local6 ? "]" : "");
+ this->remote = strjoin(strjoin(this->remote6 ? "[" : "",
+ this->remote), this->remote6 ? "]" : "");
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + 1 ))
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print network I/O details
+ */
+ printf("%s:%u %s %s:%u %d byte%s",
+ this->local, this->lport,
+ this->flow,
+ this->remote, this->rport,
+ this->length,
+ this->length == 1 ? "" : "s");
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/vop_create b/cddl/usr.sbin/dwatch/libexec/vop_create
new file mode 100644
index 000000000000..3c544815b758
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/vop_create
@@ -0,0 +1,196 @@
+# -*- 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-2018 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 $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ 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 '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ gsub(/DEPTH/, DEPTH)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->nameDEPTH = "";
+ EOFDEPTH
+ )
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->fi_name == ""/ /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID $(( $ID + 2 )) (depth 1) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ 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 $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=$(( $ID + 4 )) -v MAX_DEPTH=$MAX_DEPTH '
+ { buf = buf $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ 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 $(( $ID + $MAX_DEPTH + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 3 ))>");}
+ 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
+ */
+
+/*********************************************************/
+
+$PROBE /this->fi_mount != 0/ /* probe ID $(( $ID + $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 4 ))>");
+}
+ /*
+ * Join full path
+ * NB: Up-to but not including the parent directory (joined below)
+ */
+ this->path = this->fi_mount;
+ this->path = strjoin(this->path, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ gsub(/N/, N)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->path = strjoin(this->path,
+ \ strjoin(this->nameN, this->nameN != "" ? "/" : ""));
+ EOFDEPTH
+ )
+
+ /* Join the parent directory name */
+ this->path = strjoin(this->path, strjoin(this->name =
+ (this->d_name != 0 ? this->d_name : ""),
+ this->name != "" ? "/" : ""));
+
+ /* Join the entry name */
+ this->path = strjoin(this->path,
+ this->name = (this->fi_name != 0 ? this->fi_name : ""));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print full path
+ */
+ printf("%s", this->path);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/vop_readdir b/cddl/usr.sbin/dwatch/libexec/vop_readdir
new file mode 100644
index 000000000000..7a34e420133e
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/vop_readdir
@@ -0,0 +1,188 @@
+# -*- 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-2018 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 $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ 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 '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ gsub(/DEPTH/, DEPTH)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->nameDEPTH = "";
+ EOFDEPTH
+ )
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == ""/ /* probe ID $((
+ $ID + 1
+ )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID $(( $ID + 2 )) (depth 1) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ 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 $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=$(( $ID + 4 )) -v MAX_DEPTH=$MAX_DEPTH '
+ { buf = buf $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ 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 $(( $ID + $MAX_DEPTH + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 3 ))>");}
+ 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
+ */
+
+/*********************************************************/
+
+$PROBE /this->fi_mount != 0/ /* probe ID $(( $ID + $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 4 ))>");
+}
+ /*
+ * Join full path
+ * NB: Up-to but not including the parent directory (joined below)
+ */
+ this->path = this->fi_mount;
+ this->path = strjoin(this->path, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ gsub(/N/, N)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->path = strjoin(this->path,
+ \ strjoin(this->nameN, this->nameN != "" ? "/" : ""));
+ EOFDEPTH
+ )
+
+ /* Join the parent directory name */
+ this->path = strjoin(this->path, strjoin(this->name =
+ (this->d_name != 0 ? this->d_name : ""),
+ this->name != "" ? "/" : ""));
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print full path
+ */
+ printf("%s", this->path);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/vop_rename b/cddl/usr.sbin/dwatch/libexec/vop_rename
new file mode 100644
index 000000000000..a9dbf16e73fa
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/vop_rename
@@ -0,0 +1,302 @@
+# -*- 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-2018 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 $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ 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 '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ gsub(/DEPTH/, DEPTH)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-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 $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->fncp = 0;
+}
+
+$PROBE /this->tvp == 0 || this->tfi_fs == 0 ||
+ this->tfi_fs == "devfs" || this->tfi_fs == "" ||
+ this->tfi_name == ""/ /* probe ID $(( $ID + 2 )) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ this->tncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->fncp/ /* probe ID $(( $ID + 3 )) (depth 1) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ 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 $(( $ID + 4 )) (depth 1) */
+{${TRACE:+
+ printf("<$(( $ID + 4 ))>");}
+ 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 $((
+ $ID + 5
+ )) */
+{${TRACE:+
+ printf("<$(( $ID + 5 ))>");}
+ this->fdvp = 0;
+}
+
+$PROBE /this->tname1 == 0 || this->tfi_fs == 0 ||
+ this->tfi_fs == "devfs" || this->tfi_fs == "" ||
+ this->tname1 == "/" || this->tname1 == ""/ /* probe ID $((
+ $ID + 6
+ )) */
+{${TRACE:+
+ printf("<$(( $ID + 6 ))>");}
+ this->tdvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=$(( $ID + 7 )) -v MAX_DEPTH=$MAX_DEPTH '
+ { buf = buf $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM1/, ID)
+ gsub(/IDNUM2/, ID + 1)
+ 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 $(( $ID + $MAX_DEPTH * 2 + 5 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH * 2 + 5 ))>");}
+ 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 $(( $ID + $MAX_DEPTH * 2 + 6 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH * 2 + 6 ))>");}
+ 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
+ */
+
+/*********************************************************/
+
+$PROBE /this->ffi_mount != 0 && this->tfi_mount != 0/ /* probe ID $((
+ $ID + $MAX_DEPTH * 2 + 7
+)) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH * 2 + 7 ))>");
+}
+ /*
+ * Join 'from' full path
+ * NB: Up-to but not including the parent directory (joined below)
+ */
+ this->fpath = this->ffi_mount;
+ this->fpath = strjoin(this->fpath, this->ffi_mount != 0 ? (
+ this->ffi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ gsub(/N/, N)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->fpath = strjoin(this->fpath,
+ \ strjoin(this->fnameN, this->fnameN != "" ? "/" : ""));
+ EOFDEPTH
+ )
+
+ /* Join the 'from' parent directory name */
+ this->fpath = strjoin(this->fpath, strjoin(this->fname =
+ (this->fd_name != 0 ? this->fd_name : ""),
+ this->fname != "" ? "/" : ""));
+
+ /* Join the 'from' entry name */
+ this->fpath = strjoin(this->fpath,
+ this->fname = (this->ffi_name != 0 ? this->ffi_name : ""));
+
+ /*
+ * Join 'to' full path
+ * NB: Up-to but not including the parent directory (joined below)
+ */
+ this->tpath = this->tfi_mount;
+ this->tpath = strjoin(this->tpath, this->tfi_mount != 0 ? (
+ this->tfi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ gsub(/N/, N)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->tpath = strjoin(this->tpath,
+ \ strjoin(this->tnameN, this->tnameN != "" ? "/" : ""));
+ EOFDEPTH
+ )
+
+ /* Join the 'to' parent directory name */
+ this->tpath = strjoin(this->tpath, strjoin(this->tname =
+ (this->td_name != 0 ? this->td_name : ""),
+ this->tname != "" ? "/" : ""));
+
+ /* Join the 'to' entry name */
+ this->tpath = strjoin(this->tpath,
+ this->tname = (this->tfi_name != 0 ? this->tfi_name : ""));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + $MAX_DEPTH * 2 + 8 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->ffi_mount != 0 && this->tfi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print 'from' and 'to' full paths
+ */
+ printf("%s -> %s", this->fpath, this->tpath);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/cddl/usr.sbin/dwatch/libexec/vop_symlink b/cddl/usr.sbin/dwatch/libexec/vop_symlink
new file mode 100644
index 000000000000..ca75d350af47
--- /dev/null
+++ b/cddl/usr.sbin/dwatch/libexec/vop_symlink
@@ -0,0 +1,197 @@
+# -*- 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-2018 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 $ID */
+{${TRACE:+
+ printf("<$ID>");}
+ 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 '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (DEPTH = 1; DEPTH <= MAX_DEPTH + 1; DEPTH++) {
+ gsub(/DEPTH/, DEPTH)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->nameDEPTH = "";
+ EOFDEPTH
+ )
+}
+
+$PROBE /this->vp == 0 || this->fi_fs == 0 ||
+ this->fi_fs == "devfs" || this->fi_fs == "" ||
+ this->fi_name == ""/ /* probe ID $(( $ID + 1 )) */
+{${TRACE:+
+ printf("<$(( $ID + 1 ))>");}
+ this->ncp = 0;
+}
+
+/*********************************************************/
+
+$PROBE /this->ncp/ /* probe ID $(( $ID + 2 )) (depth 1) */
+{${TRACE:+
+ printf("<$(( $ID + 2 ))>");}
+ 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 $(( $ID + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + 3 ))>");}
+ this->dvp = 0;
+}
+
+/*********************************************************/
+
+/*
+ * BEGIN Pathname-depth iterators
+ */
+
+$( awk -v ID=$(( $ID + 4 )) -v MAX_DEPTH=$MAX_DEPTH '
+ { buf = buf $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ for (DEPTH = 2; DEPTH <= MAX_DEPTH; DEPTH++) {
+ $0 = buf
+ gsub(/DEPTH/, DEPTH)
+ gsub(/IDNUM/, ID++)
+ 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 $(( $ID + $MAX_DEPTH + 3 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 3 ))>");}
+ 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
+ */
+
+/*********************************************************/
+
+$PROBE /this->fi_mount != 0/ /* probe ID $(( $ID + $MAX_DEPTH + 4 )) */
+{${TRACE:+
+ printf("<$(( $ID + $MAX_DEPTH + 4 ))>");
+}
+ /*
+ * Join full path
+ * NB: Up-to but not including the parent directory (joined below)
+ */
+ this->path = this->fi_mount;
+ this->path = strjoin(this->path, this->fi_mount != 0 ? (
+ this->fi_mount == "/" ? "" : "/"
+ ) : "/");
+ $( awk -v MAX_DEPTH=$MAX_DEPTH '
+ { sub(/^\\\t/, "\t") }
+ { buf = buf "\t" $0 "\n" }
+ END {
+ sub(/\n$/, "", buf)
+ $0 = buf
+ sub(/^[[:space:]]*/, "")
+ for (N = MAX_DEPTH + 1; N > 0; N--) {
+ gsub(/N/, N)
+ print
+ $0 = buf
+ }
+ }
+ ' <<-EOFDEPTH
+ this->path = strjoin(this->path,
+ \ strjoin(this->nameN, this->nameN != "" ? "/" : ""));
+ EOFDEPTH
+ )
+
+ /* Join the parent directory name */
+ this->path = strjoin(this->path, strjoin(this->name =
+ (this->d_name != 0 ? this->d_name : ""),
+ this->name != "" ? "/" : ""));
+
+ /* Join the entry name */
+ this->path = strjoin(this->path,
+ this->name = (this->fi_name != 0 ? this->fi_name : ""));
+}
+EOF
+ACTIONS=$( cat <&9 )
+ID=$(( $ID + $MAX_DEPTH + 5 ))
+
+############################################################ EVENT ACTION
+
+EVENT_TEST="this->fi_mount != 0"
+
+############################################################ EVENT DETAILS
+
+if [ ! "$CUSTOM_DETAILS" ]; then
+exec 9<<EOF
+ /*
+ * Print full path and target
+ */
+ printf("%s -> %s", this->path, this->target);
+EOF
+EVENT_DETAILS=$( cat <&9 )
+fi
+
+################################################################################
+# END
+################################################################################
diff --git a/etc/mtree/BSD.usr.dist b/etc/mtree/BSD.usr.dist
index eaca6694dd53..aff532744830 100644
--- a/etc/mtree/BSD.usr.dist
+++ b/etc/mtree/BSD.usr.dist
@@ -118,6 +118,8 @@
..
bsdinstall
..
+ dwatch
+ ..
hyperv
..
lpr
@@ -331,6 +333,8 @@
..
drivers
..
+ dwatch
+ ..
etc
defaults
..
diff --git a/share/dtrace/Makefile b/share/dtrace/Makefile
index efd8b08706ba..86e47bc89469 100644
--- a/share/dtrace/Makefile
+++ b/share/dtrace/Makefile
@@ -17,10 +17,7 @@ SCRIPTS= blocking \
tcpdebug \
tcpstate \
tcptrack \
- udptrack \
- watch_execve \
- watch_kill \
- watch_vop_remove
+ udptrack
SCRIPTSDIR= ${SHAREDIR}/dtrace
diff --git a/share/dtrace/watch_execve b/share/dtrace/watch_execve
deleted file mode 100755
index 1817d4b841af..000000000000
--- a/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" : "");
-}
diff --git a/share/dtrace/watch_kill b/share/dtrace/watch_kill
deleted file mode 100755
index 46f3cd8733fe..000000000000
--- a/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" : "");
-}
diff --git a/share/dtrace/watch_vop_remove b/share/dtrace/watch_vop_remove
deleted file mode 100755
index 6a5e7c4bebe8..000000000000
--- a/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" : "");
-}