Home | History | Annotate | Line # | Download | only in dist
      1 #!/bin/sh
      2 #
      3 # rwsnoop - snoop read/write events.
      4 #           Originally written using DTrace (Solaris 10 3/05).
      5 #
      6 # This is measuring reads and writes at the application level. This matches
      7 # the syscalls read, and write.
      8 #
      9 # $Id: rwsnoop,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $
     10 #
     11 # USAGE:	rwsnoop [-jPtvZ] [-n name] [-p pid]
     12 # 
     13 #		rwsnoop		# default output
     14 #
     15 #		-P		# print parent process ID
     16 #		-t		# print timestamp, us
     17 #		-v		# print time, string
     18 #		-J		# print jail ID
     19 #		-n name		# this process name only
     20 #		-p PID		# this PID only
     21 #	eg,
     22 #		rwsnoop -J		# print jail ID
     23 #		rwsnoop -n bash 	# monitor processes named "bash"
     24 #		rwsnoop > out.txt	# recommended
     25 #
     26 # NOTE:
     27 # 	rwsnoop usually prints plenty of output, which itself will cause
     28 #	more output. It can be better to redirect the output of rwsnoop
     29 #	to a file to prevent this.
     30 #
     31 # FIELDS:
     32 #		TIME		Timestamp, us
     33 #		TIMESTR		Time, string
     34 #		JAIL		JAIL ID
     35 #		UID		User ID
     36 #		PID		Process ID
     37 #		PPID		Parent Process ID
     38 #		CMD		Process name
     39 #		D		Direction, Read or Write
     40 #		BYTES		Total bytes during sample, -1 for error
     41 #		FILE		Filename, if file based
     42 #
     43 # Reads and writes that are not file based, for example with sockets, will
     44 # print "<unknown>" as the filename.
     45 #
     46 # SEE ALSO:	rwtop
     47 #
     48 # COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
     49 #
     50 # CDDL HEADER START
     51 #
     52 #  The contents of this file are subject to the terms of the
     53 #  Common Development and Distribution License, Version 1.0 only
     54 #  (the "License").  You may not use this file except in compliance
     55 #  with the License.
     56 #
     57 #  You can obtain a copy of the license at Docs/cddl1.txt
     58 #  or http://www.opensolaris.org/os/licensing.
     59 #  See the License for the specific language governing permissions
     60 #  and limitations under the License.
     61 #
     62 # CDDL HEADER END
     63 #
     64 # TODO:
     65 #  Track readv and writev.
     66 #
     67 # Author: Brendan Gregg  [Sydney, Australia]
     68 #
     69 # 24-Jul-2005   Brendan Gregg   Created this.
     70 # 17-Sep-2005	   "      "	Increased switchrate.
     71 # 17-Sep-2005	   "      "	Last update.
     72 # 26-Jul-2014   George Neville-Neil	Port to FreeBSD
     73 #
     74 
     75 
     76 ##############################
     77 # --- Process Arguments ---
     78 #
     79 
     80 ### default variables
     81 opt_name=0; opt_pid=0; opt_jailid=0; opt_time=0; opt_timestr=0
     82 opt_bytes=1; filter=0; pname=.; pid=0; opt_ppid=0;
     83 
     84 ### process options
     85 while getopts n:Pp:jtvZ name
     86 do
     87 	case $name in
     88 	n)	opt_name=1; pname=$OPTARG ;;
     89 	p)	opt_pid=1; pid=$OPTARG ;;
     90 	P)	opt_ppid=1 ;;
     91 	t)	opt_time=1 ;;
     92 	v)	opt_timestr=1 ;;
     93 	J)	opt_jailid=1 ;;
     94 	h|?)	cat <<-END >&2
     95 		USAGE: rwsnoop [-jPtvZ] [-n name] [-p pid]
     96  
     97 		                -P       # print parent process ID
     98 		                -t       # print timestamp, us
     99 		                -v       # print time, string
    100 		                -J       # print jail ID
    101 		                -n name  # this process name only
    102 		                -p PID   # this PID only
    103 		   eg,
    104 		        rwsnoop          # default output
    105 		        rwsnoop -J       # print jail ID
    106 		        rwsnoop -n bash  # monitor processes named "bash"
    107 		END
    108 		exit 1
    109 	esac
    110 done
    111 
    112 shift $(( $OPTIND - 1 ))
    113 
    114 ### option logic
    115 if [ $opt_name -ne 0 ]; then
    116 	filter=1
    117 fi
    118 
    119 if [ $opt_pid -ne 0 ]; then
    120 	filter=1
    121 fi
    122 
    123 #################################
    124 # --- Main Program, DTrace ---
    125 #
    126 /usr/sbin/dtrace -n '
    127  /*
    128   * Command line arguments
    129   */
    130  inline int OPT_jailid 	= '$opt_jailid';
    131  inline int OPT_bytes 	= '$opt_bytes';
    132  inline int OPT_name 	= '$opt_name';
    133  inline int OPT_ppid 	= '$opt_ppid';
    134  inline int OPT_pid 	= '$opt_pid';
    135  inline int OPT_time 	= '$opt_time';
    136  inline int OPT_timestr	= '$opt_timestr';
    137  inline int FILTER 	= '$filter';
    138  inline int PID		= '$pid';
    139  inline string NAME 	= "'$pname'";
    140  
    141  #pragma D option quiet
    142  #pragma D option switchrate=10hz
    143 
    144  /*
    145   * Print header
    146   */
    147  dtrace:::BEGIN 
    148  {
    149 	/* print header */
    150 	OPT_time    ? printf("%-14s ", "TIME") : 1;
    151 	OPT_timestr ? printf("%-20s ", "TIMESTR") : 1;
    152 	OPT_jailid    ? printf("%5s ", "JAILID") : 1;
    153 	OPT_ppid    ? printf("%6s ", "PPID") : 1;
    154 	printf("%5s %6s %-12s %4s %1s %7s\n",
    155 	    "UID", "PID", "CMD", "FD", "D", "BYTES");
    156  }
    157 
    158  /*
    159   * Check event is being traced
    160   */
    161  syscall::*read:entry,
    162  syscall::*write:entry
    163  /pid != $pid/
    164  { 
    165 	/* default is to trace unless filtering, */
    166 	self->ok = FILTER ? 0 : 1;
    167 
    168 	/* check each filter, */
    169 	(OPT_name == 1 && NAME == execname)? self->ok = 1 : 1;
    170 	(OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
    171 
    172 	/* save file descriptor */
    173 	self->fd = self->ok ? arg0 : 0;
    174  }
    175 
    176  /*
    177   * Save read details
    178   */
    179  syscall::*read:return
    180  /self->ok/
    181  {
    182 	self->rw = "R";
    183 	self->size = arg0;
    184  }
    185 
    186  /*
    187   * Save write details
    188   */
    189  syscall::*write:entry
    190  /self->ok/
    191  {
    192 	self->rw = "W";
    193 	self->size = arg2;
    194  }
    195 
    196  /*
    197   * Process event
    198   */
    199  syscall::*read:return,
    200  syscall::*write:entry
    201  /self->ok/
    202  {
    203 	/*
    204 	 * Fetch filename
    205          * XXX Not yet implemented.
    206 	 */
    207 /*
    208 
    209 	this->filistp = curthread->t_procp->p_user.u_finfo.fi_list;
    210 	this->ufentryp = (uf_entry_t *)((uint64_t)this->filistp +
    211 	    (uint64_t)self->fd * (uint64_t)sizeof(uf_entry_t));
    212 	this->filep = this->ufentryp->uf_file;
    213 	this->vnodep = this->filep != 0 ? this->filep->f_vnode : 0;
    214 	self->vpath = this->vnodep ? (this->vnodep->v_path != 0 ? 
    215 	    cleanpath(this->vnodep->v_path) : "<unknown>") : "<unknown>";
    216 */
    217 	/*
    218 	 * Print details
    219 	 */
    220 	OPT_time    ? printf("%-14d ", timestamp / 1000) : 1;
    221 	OPT_timestr ? printf("%-20Y ", walltimestamp) : 1;
    222 	OPT_jailid    ? printf("%5d ", curpsinfo->pr_jailid) : 1;
    223 	OPT_ppid    ? printf("%6d ", ppid) : 1;
    224 	printf("%5d %6d %-12.12s %4d %1s %7d\n",
    225 	    uid, pid, execname, self->fd, self->rw, (int)self->size);
    226 	
    227 	self->ok = 0;
    228 	self->fd = 0;
    229 	self->rw = 0;
    230 	self->size = 0;
    231 	self->vpath = 0;
    232  }
    233 '
    234