Home | History | Annotate | Line # | Download | only in dist
      1 #!/bin/sh
      2 #
      3 # statsnoop - snoop file stats as they occur.
      4 #             Written using DTrace (Solaris 10 3/05).
      5 #
      6 # $Id: statsnoop,v 1.2 2015/10/07 02:22:29 christos Exp $
      7 #
      8 # USAGE:	statsnoop [-a|-A|-ceghlsvxZ] [-f pathname] [-t syscall]
      9 #		          [-n name] [-p PID]
     10 #
     11 #		statsnoop	# default output
     12 #
     13 #		-a		# print most data
     14 #		-A		# dump all data, space delimited
     15 #		-c		# print cwd of process
     16 #		-e		# print errno value
     17 #		-g		# print command arguments
     18 #		-l		# print syscall type
     19 #		-s		# print start time, us
     20 #		-v		# print start time, string
     21 #		-x		# only print failed stats
     22 #		-Z		# print zonename
     23 #		-f pathname	# file pathname to snoop
     24 #		-n name		# command name to snoop
     25 #		-p PID		# process ID to snoop
     26 #		-t syscall	# stat syscall to trace
     27 #	eg,
     28 #		statsnoop -v			# human readable timestamps
     29 #		statsnoop -S			# syscall type
     30 #		statsnoop -e			# see error codes
     31 #		statsnoop -f /etc/passwd	# snoop this file only
     32 # 	
     33 # FIELDS:
     34 #		ZONE		Zone name
     35 #		UID		User ID
     36 #		PID		Process ID
     37 #		PPID		Parent Process ID
     38 #		FD		file descriptor (-1 for error)
     39 #		ERR		errno value (see /usr/include/sys/errno.h)
     40 #		TYPE		syscall type
     41 #		CWD		current working directory of process
     42 #		PATH		pathname for file stat
     43 #		COMM		command name for the process
     44 #		ARGS		argument listing for the process
     45 #		TIME		timestamp for the stat event, us
     46 #		STRTIME		timestamp for the stat event, string
     47 #
     48 # SEE ALSO: truss, BSM auditing.
     49 #
     50 # COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
     51 #
     52 # CDDL HEADER START
     53 #
     54 #  The contents of this file are subject to the terms of the
     55 #  Common Development and Distribution License, Version 1.0 only
     56 #  (the "License").  You may not use this file except in compliance
     57 #  with the License.
     58 #
     59 #  You can obtain a copy of the license at Docs/cddl1.txt
     60 #  or http://www.opensolaris.org/os/licensing.
     61 #  See the License for the specific language governing permissions
     62 #  and limitations under the License.
     63 #
     64 # CDDL HEADER END
     65 #
     66 # Author: Brendan Gregg  [Sydney, Australia]
     67 #
     68 # 09-Sep-2007	Brendan Gregg	Created this.
     69 # 
     70 
     71 
     72 ##############################
     73 # --- Process Arguments ---
     74 #
     75 
     76 ### Default variables
     77 opt_dump=0; opt_file=0; opt_time=0; opt_timestr=0; opt_args=0
     78 opt_zone=0; opt_cwd=0; opt_failonly=0; opt_err=0; filter=0; pathname=.
     79 opt_name=0; opt_pid=0; opt_type=0; opt_trace=0; pname=.; pid=0; trace=.
     80 
     81 ### Process options
     82 while getopts aAcef:ghln:p:st:vxZ name
     83 do
     84 	case $name in
     85 	a)	opt_time=1; opt_timestr=1; opt_args=1; opt_err=1 ;;
     86 	A)	opt_dump=1 ;;
     87 	c)	opt_cwd=1 ;;
     88 	e)	opt_err=1 ;;
     89 	g)	opt_args=1 ;;
     90 	f)	opt_file=1; pathname=$OPTARG ;;
     91 	l)	opt_type=1 ;;
     92 	n)	opt_name=1; pname=$OPTARG ;;
     93 	p)	opt_pid=1; pid=$OPTARG ;;
     94 	s)	opt_time=1 ;;
     95 	t)	opt_trace=1; trace=$OPTARG ;;
     96 	v)	opt_timestr=1 ;;
     97 	x)	opt_failonly=1 ;;
     98 	Z)	opt_zone=1 ;;
     99 	h|?)	cat <<-END >&2
    100 		USAGE: statsnoop [-a|-A|-ceghlsvxZ] [-f pathname] [-t syscall]
    101 		                 [-n execname] [-p PID]
    102 		       statsnoop                # default output
    103 		                -a              # print most data
    104 		                -A              # dump all data, space delimited
    105 		                -c              # print cwd of process
    106 		                -e              # print errno value
    107 		                -g              # print command arguments
    108 		                -l              # print syscall type
    109 		                -s              # print start time, us
    110 		                -v              # print start time, string
    111 		                -x              # only print failed stats
    112 		                -Z              # print zonename
    113 		                -f pathname	# pathname name to snoop
    114 		                -n name		# process name to snoop
    115 		                -p PID		# process ID to snoop
    116 		                -t syscall	# stat syscall to trace
    117 		  eg,
    118 		       statsnoop -v             # human readable timestamps
    119 		       statsnoop -e             # see error codes
    120 		       statsnoop -f /etc/motd   # snoop this file only
    121 		END
    122 		exit 1
    123 	esac
    124 done
    125 
    126 ### Option logic
    127 if [ $opt_dump -eq 1 ]; then
    128 	opt_zone=0; opt_cwd=0; opt_time=0; opt_timestr=0; opt_type=0
    129 	opt_args=2 
    130 fi
    131 if [ $opt_name -eq 1 -o $opt_pid -eq 1 -o $opt_trace -eq 1 ]; then
    132 	filter=1
    133 fi
    134 
    135 
    136 #################################
    137 # --- Main Program, DTrace ---
    138 #
    139 /usr/sbin/dtrace -n '
    140  /*
    141   * Command line arguments
    142   */
    143  inline int OPT_dump 	 = '$opt_dump';
    144  inline int OPT_file 	 = '$opt_file';
    145  inline int OPT_args 	 = '$opt_args';
    146  inline int OPT_cwd	 = '$opt_cwd';
    147  inline int OPT_err	 = '$opt_err';
    148  inline int OPT_zone 	 = '$opt_zone';
    149  inline int OPT_time 	 = '$opt_time';
    150  inline int OPT_timestr	 = '$opt_timestr';
    151  inline int OPT_type	 = '$opt_type';
    152  inline int OPT_failonly = '$opt_failonly';
    153  inline int OPT_pid	 = '$opt_pid';
    154  inline int OPT_name	 = '$opt_name';
    155  inline int OPT_trace	 = '$opt_trace';
    156  inline int FILTER 	 = '$filter';
    157  inline int PID		 = '$pid';
    158  inline string PATHNAME	 = "'$pathname'";
    159  inline string NAME	 = "'$pname'";
    160  inline string TRACE	 = "'$trace'";
    161 
    162  #pragma D option quiet
    163  #pragma D option switchrate=10hz
    164 
    165  /*
    166   * Print header
    167   */
    168  dtrace:::BEGIN 
    169  {
    170 	/* print optional headers */
    171  	OPT_time ? printf("%-14s ", "TIME") : 1;
    172  	OPT_timestr ? printf("%-20s ", "STRTIME") : 1;
    173  	OPT_zone ? printf("%-10s ", "ZONE") : 1;
    174 
    175 	/* print dump headers */
    176 	OPT_dump ? printf("%s %s %s %s %s %s %s %s %s %s %s", "ZONE",
    177 	    "TIME", "UID", "PID", "PPID", "COMM", "FD", "ERR", "CWD", 
    178 	    "PATH", "ARGS") : printf("%5s %6s ","UID","PID");
    179 	
    180 	/* print main headers */
    181 	OPT_args == 0 ? printf("%-12s ", "COMM") : 1;
    182 	OPT_dump == 0 ? printf("%3s ", "FD") : 1;
    183 	OPT_err ? printf("%3s ", "ERR") : 1;
    184 	OPT_cwd ? printf("%-20s ", "CWD") : 1;
    185 	OPT_type ? printf("%-8s ", "TYPE") : 1;
    186 	OPT_dump == 0 ? printf("%-20s ", "PATH") : 1;
    187 	OPT_args == 1 ? printf("%s", "ARGS") : 1;
    188 	printf("\n");
    189  }
    190 
    191  /*
    192   * Print stat event
    193   */
    194  syscall::stat:entry, 
    195  syscall::lstat:entry,
    196  syscall::fstat:entry
    197  {
    198 	/* default is to trace unless filtering */
    199 	self->ok = FILTER ? 0 : 1;
    200 
    201 	/* check each filter */
    202 	(OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
    203 	(OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
    204 	(OPT_trace == 1 && TRACE == probefunc) ? self->ok = 1 : 1;
    205  }
    206 
    207  syscall::stat:entry,
    208  syscall::lstat:entry
    209  /self->ok/
    210  {
    211 	self->pathp = arg0;
    212  }
    213 
    214  syscall::stat:return
    215  syscall::lstat:return
    216  /self->ok/
    217  {
    218 	self->path = copyinstr(self->pathp);
    219  }
    220 
    221  syscall::fstat:return
    222  /self->ok/
    223  {
    224 	self->path = strjoin("fd=", lltostr(arg0));
    225 	/* curthread->l_proc->p_fd->fd_dt->dt_ff[arg0]; */
    226  }
    227 
    228  syscall::stat:return,
    229  syscall::lstat:return,
    230  syscall::fstat:return
    231  /self->ok && (! OPT_failonly || (int)arg0 < 0) && 
    232      ((OPT_file == 0) || (OPT_file == 1 && PATHNAME == copyinstr(self->pathp)))/
    233  {
    234 	/* print optional fields */
    235  	OPT_time ? printf("%-14d ", timestamp/1000) : 1;
    236  	OPT_timestr ? printf("%-20Y ", walltimestamp) : 1;
    237  	OPT_zone ? printf("%-10s ", zonename) : 1;
    238 
    239 	/* print dump fields */
    240 	OPT_dump ? printf("%s %d %d %d %d %s %d %d %s %s %S", zonename,
    241 	    timestamp/1000, uid, pid, ppid, execname, (int)arg0, errno,
    242 	    cwd, self->path, curpsinfo->pr_psargs) :
    243 	    printf("%5d %6d ", uid, pid);
    244 
    245 	/* print main fields */
    246 	OPT_args == 0 ? printf("%-12.12s ", execname) : 1;
    247 	OPT_dump == 0 ? printf("%3d ", (int)arg0) : 1;
    248 	OPT_err ? printf("%3d ", errno) : 1;
    249 	OPT_cwd ? printf("%-20s ", cwd) : 1;
    250 	OPT_type ? printf("%-8s ", probefunc) : 1;
    251 	OPT_dump == 0 ? printf("%-20s ", self->path) : 1;
    252 /*	OPT_args == 1 ? printf("%S", curpsinfo->pr_psargs) : 1; */
    253 	printf("\n");
    254 
    255 	/* cleanup */
    256 	self->path = 0;
    257 	self->ok = 0;
    258  }
    259 
    260  /* 
    261   * Cleanup 
    262   */
    263  syscall::stat:return,
    264  syscall::lstat:return
    265 /*
    266  syscall::fstat:return
    267 */
    268  /self->ok/
    269  {
    270 	self->path = 0;
    271 	self->ok = 0;
    272  }
    273 '
    274