1235368Sgnn#!/usr/bin/sh 2235368Sgnn# 3235368Sgnn# statsnoop - snoop file stats as they occur. 4235368Sgnn# Written using DTrace (Solaris 10 3/05). 5235368Sgnn# 6235368Sgnn# $Id: statsnoop 65 2007-10-04 11:09:40Z brendan $ 7235368Sgnn# 8235368Sgnn# USAGE: statsnoop [-a|-A|-ceghlsvxZ] [-f pathname] [-t syscall] 9235368Sgnn# [-n name] [-p PID] 10235368Sgnn# 11235368Sgnn# statsnoop # default output 12235368Sgnn# 13235368Sgnn# -a # print most data 14235368Sgnn# -A # dump all data, space delimited 15235368Sgnn# -c # print cwd of process 16235368Sgnn# -e # print errno value 17235368Sgnn# -g # print command arguments 18235368Sgnn# -l # print syscall type 19235368Sgnn# -s # print start time, us 20235368Sgnn# -v # print start time, string 21235368Sgnn# -x # only print failed stats 22235368Sgnn# -Z # print zonename 23235368Sgnn# -f pathname # file pathname to snoop 24235368Sgnn# -n name # command name to snoop 25235368Sgnn# -p PID # process ID to snoop 26235368Sgnn# -t syscall # stat syscall to trace 27235368Sgnn# eg, 28235368Sgnn# statsnoop -v # human readable timestamps 29235368Sgnn# statsnoop -S # syscall type 30235368Sgnn# statsnoop -e # see error codes 31235368Sgnn# statsnoop -f /etc/passwd # snoop this file only 32235368Sgnn# 33235368Sgnn# FIELDS: 34235368Sgnn# ZONE Zone name 35235368Sgnn# UID User ID 36235368Sgnn# PID Process ID 37235368Sgnn# PPID Parent Process ID 38235368Sgnn# FD file descriptor (-1 for error) 39235368Sgnn# ERR errno value (see /usr/include/sys/errno.h) 40235368Sgnn# TYPE syscall type 41235368Sgnn# CWD current working directory of process 42235368Sgnn# PATH pathname for file stat 43235368Sgnn# COMM command name for the process 44235368Sgnn# ARGS argument listing for the process 45235368Sgnn# TIME timestamp for the stat event, us 46235368Sgnn# STRTIME timestamp for the stat event, string 47235368Sgnn# 48235368Sgnn# SEE ALSO: truss, BSM auditing. 49235368Sgnn# 50235368Sgnn# COPYRIGHT: Copyright (c) 2007 Brendan Gregg. 51235368Sgnn# 52235368Sgnn# CDDL HEADER START 53235368Sgnn# 54235368Sgnn# The contents of this file are subject to the terms of the 55235368Sgnn# Common Development and Distribution License, Version 1.0 only 56235368Sgnn# (the "License"). You may not use this file except in compliance 57235368Sgnn# with the License. 58235368Sgnn# 59235368Sgnn# You can obtain a copy of the license at Docs/cddl1.txt 60235368Sgnn# or http://www.opensolaris.org/os/licensing. 61235368Sgnn# See the License for the specific language governing permissions 62235368Sgnn# and limitations under the License. 63235368Sgnn# 64235368Sgnn# CDDL HEADER END 65235368Sgnn# 66235368Sgnn# Author: Brendan Gregg [Sydney, Australia] 67235368Sgnn# 68235368Sgnn# 09-Sep-2007 Brendan Gregg Created this. 69235368Sgnn# 70235368Sgnn 71235368Sgnn 72235368Sgnn############################## 73235368Sgnn# --- Process Arguments --- 74235368Sgnn# 75235368Sgnn 76235368Sgnn### Default variables 77235368Sgnnopt_dump=0; opt_file=0; opt_time=0; opt_timestr=0; opt_args=0 78235368Sgnnopt_zone=0; opt_cwd=0; opt_failonly=0; opt_err=0; filter=0; pathname=. 79235368Sgnnopt_name=0; opt_pid=0; opt_type=0; opt_trace=0; pname=.; pid=0; trace=. 80235368Sgnn 81235368Sgnn### Process options 82235368Sgnnwhile getopts aAcef:ghln:p:st:vxZ name 83235368Sgnndo 84235368Sgnn case $name in 85235368Sgnn a) opt_time=1; opt_timestr=1; opt_args=1; opt_err=1 ;; 86235368Sgnn A) opt_dump=1 ;; 87235368Sgnn c) opt_cwd=1 ;; 88235368Sgnn e) opt_err=1 ;; 89235368Sgnn g) opt_args=1 ;; 90235368Sgnn f) opt_file=1; pathname=$OPTARG ;; 91235368Sgnn l) opt_type=1 ;; 92235368Sgnn n) opt_name=1; pname=$OPTARG ;; 93235368Sgnn p) opt_pid=1; pid=$OPTARG ;; 94235368Sgnn s) opt_time=1 ;; 95235368Sgnn t) opt_trace=1; trace=$OPTARG ;; 96235368Sgnn v) opt_timestr=1 ;; 97235368Sgnn x) opt_failonly=1 ;; 98235368Sgnn Z) opt_zone=1 ;; 99235368Sgnn h|?) cat <<-END >&2 100235368Sgnn USAGE: statsnoop [-a|-A|-ceghlsvxZ] [-f pathname] [-t syscall] 101235368Sgnn [-n execname] [-p PID] 102235368Sgnn statsnoop # default output 103235368Sgnn -a # print most data 104235368Sgnn -A # dump all data, space delimited 105235368Sgnn -c # print cwd of process 106235368Sgnn -e # print errno value 107235368Sgnn -g # print command arguments 108235368Sgnn -l # print syscall type 109235368Sgnn -s # print start time, us 110235368Sgnn -v # print start time, string 111235368Sgnn -x # only print failed stats 112235368Sgnn -Z # print zonename 113235368Sgnn -f pathname # pathname name to snoop 114235368Sgnn -n name # process name to snoop 115235368Sgnn -p PID # process ID to snoop 116235368Sgnn -t syscall # stat syscall to trace 117235368Sgnn eg, 118235368Sgnn statsnoop -v # human readable timestamps 119235368Sgnn statsnoop -e # see error codes 120235368Sgnn statsnoop -f /etc/motd # snoop this file only 121235368Sgnn END 122235368Sgnn exit 1 123235368Sgnn esac 124235368Sgnndone 125235368Sgnn 126235368Sgnn### Option logic 127235368Sgnnif [ $opt_dump -eq 1 ]; then 128235368Sgnn opt_zone=0; opt_cwd=0; opt_time=0; opt_timestr=0; opt_type=0 129235368Sgnn opt_args=2 130235368Sgnnfi 131235368Sgnnif [ $opt_name -eq 1 -o $opt_pid -eq 1 -o $opt_trace -eq 1 ]; then 132235368Sgnn filter=1 133235368Sgnnfi 134235368Sgnn 135235368Sgnn 136235368Sgnn################################# 137235368Sgnn# --- Main Program, DTrace --- 138235368Sgnn# 139235368Sgnn/usr/sbin/dtrace -n ' 140235368Sgnn /* 141235368Sgnn * Command line arguments 142235368Sgnn */ 143235368Sgnn inline int OPT_dump = '$opt_dump'; 144235368Sgnn inline int OPT_file = '$opt_file'; 145235368Sgnn inline int OPT_args = '$opt_args'; 146235368Sgnn inline int OPT_cwd = '$opt_cwd'; 147235368Sgnn inline int OPT_err = '$opt_err'; 148235368Sgnn inline int OPT_zone = '$opt_zone'; 149235368Sgnn inline int OPT_time = '$opt_time'; 150235368Sgnn inline int OPT_timestr = '$opt_timestr'; 151235368Sgnn inline int OPT_type = '$opt_type'; 152235368Sgnn inline int OPT_failonly = '$opt_failonly'; 153235368Sgnn inline int OPT_pid = '$opt_pid'; 154235368Sgnn inline int OPT_name = '$opt_name'; 155235368Sgnn inline int OPT_trace = '$opt_trace'; 156235368Sgnn inline int FILTER = '$filter'; 157235368Sgnn inline int PID = '$pid'; 158235368Sgnn inline string PATHNAME = "'$pathname'"; 159235368Sgnn inline string NAME = "'$pname'"; 160235368Sgnn inline string TRACE = "'$trace'"; 161235368Sgnn 162235368Sgnn #pragma D option quiet 163235368Sgnn #pragma D option switchrate=10hz 164235368Sgnn 165235368Sgnn /* 166235368Sgnn * Print header 167235368Sgnn */ 168235368Sgnn dtrace:::BEGIN 169235368Sgnn { 170235368Sgnn /* print optional headers */ 171235368Sgnn OPT_time ? printf("%-14s ", "TIME") : 1; 172235368Sgnn OPT_timestr ? printf("%-20s ", "STRTIME") : 1; 173235368Sgnn OPT_zone ? printf("%-10s ", "ZONE") : 1; 174235368Sgnn 175235368Sgnn /* print dump headers */ 176235368Sgnn OPT_dump ? printf("%s %s %s %s %s %s %s %s %s %s %s", "ZONE", 177235368Sgnn "TIME", "UID", "PID", "PPID", "COMM", "FD", "ERR", "CWD", 178235368Sgnn "PATH", "ARGS") : printf("%5s %6s ","UID","PID"); 179235368Sgnn 180235368Sgnn /* print main headers */ 181235368Sgnn OPT_args == 0 ? printf("%-12s ", "COMM") : 1; 182235368Sgnn OPT_dump == 0 ? printf("%3s ", "FD") : 1; 183235368Sgnn OPT_err ? printf("%3s ", "ERR") : 1; 184235368Sgnn OPT_cwd ? printf("%-20s ", "CWD") : 1; 185235368Sgnn OPT_type ? printf("%-8s ", "TYPE") : 1; 186235368Sgnn OPT_dump == 0 ? printf("%-20s ", "PATH") : 1; 187235368Sgnn OPT_args == 1 ? printf("%s", "ARGS") : 1; 188235368Sgnn printf("\n"); 189235368Sgnn } 190235368Sgnn 191235368Sgnn /* 192235368Sgnn * Print stat event 193235368Sgnn */ 194235368Sgnn syscall::stat:entry, syscall::stat64:entry, syscall::xstat:entry, 195235368Sgnn syscall::lstat:entry, syscall::lstat64:entry, syscall::lxstat:entry, 196235368Sgnn syscall::fstat:entry, syscall::fstat64:entry, syscall::fxstat:entry 197235368Sgnn { 198235368Sgnn /* default is to trace unless filtering */ 199235368Sgnn self->ok = FILTER ? 0 : 1; 200235368Sgnn 201235368Sgnn /* check each filter */ 202235368Sgnn (OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1; 203235368Sgnn (OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1; 204235368Sgnn (OPT_trace == 1 && TRACE == probefunc) ? self->ok = 1 : 1; 205235368Sgnn } 206235368Sgnn 207235368Sgnn syscall::stat:entry, syscall::stat64:entry, 208235368Sgnn syscall::lstat:entry, syscall::lstat64:entry, syscall::lxstat:entry 209235368Sgnn /self->ok/ 210235368Sgnn { 211235368Sgnn self->pathp = arg0; 212235368Sgnn } 213235368Sgnn 214235368Sgnn syscall::xstat:entry 215235368Sgnn /self->ok/ 216235368Sgnn { 217235368Sgnn self->pathp = arg1; 218235368Sgnn } 219235368Sgnn 220235368Sgnn syscall::stat:return, syscall::stat64:return, syscall::xstat:return, 221235368Sgnn syscall::lstat:return, syscall::lstat64:return, syscall::lxstat:return 222235368Sgnn /self->ok/ 223235368Sgnn { 224235368Sgnn self->path = copyinstr(self->pathp); 225235368Sgnn self->pathp = 0; 226235368Sgnn } 227235368Sgnn 228235368Sgnn syscall::fstat:return, syscall::fstat64:entry, syscall::fxstat:entry 229235368Sgnn /self->ok/ 230235368Sgnn { 231235368Sgnn self->filep = curthread->t_procp->p_user.u_finfo.fi_list[arg0].uf_file; 232235368Sgnn } 233235368Sgnn 234235368Sgnn syscall::fstat:return, syscall::fstat64:return, syscall::fxstat:return 235235368Sgnn /self->ok/ 236235368Sgnn { 237235368Sgnn this->vnodep = self->filep != 0 ? self->filep->f_vnode : 0; 238235368Sgnn self->path = this->vnodep ? (this->vnodep->v_path != 0 ? 239235368Sgnn cleanpath(this->vnodep->v_path) : "<unknown>") : "<unknown>"; 240235368Sgnn self->filep = 0; 241235368Sgnn } 242235368Sgnn 243235368Sgnn syscall::stat:return, syscall::stat64:return, syscall::xstat:return, 244235368Sgnn syscall::lstat:return, syscall::lstat64:return, syscall::lxstat:return, 245235368Sgnn syscall::fstat:return, syscall::fstat64:return, syscall::fxstat:return 246235368Sgnn /self->ok && (! OPT_failonly || (int)arg0 < 0) && 247235368Sgnn ((OPT_file == 0) || (OPT_file == 1 && PATHNAME == copyinstr(self->pathp)))/ 248235368Sgnn { 249235368Sgnn /* print optional fields */ 250235368Sgnn OPT_time ? printf("%-14d ", timestamp/1000) : 1; 251235368Sgnn OPT_timestr ? printf("%-20Y ", walltimestamp) : 1; 252235368Sgnn OPT_zone ? printf("%-10s ", zonename) : 1; 253235368Sgnn 254235368Sgnn /* print dump fields */ 255235368Sgnn OPT_dump ? printf("%s %d %d %d %d %s %d %d %s %s %S", zonename, 256235368Sgnn timestamp/1000, uid, pid, ppid, execname, (int)arg0, errno, 257235368Sgnn cwd, self->path, curpsinfo->pr_psargs) : 258235368Sgnn printf("%5d %6d ", uid, pid); 259235368Sgnn 260235368Sgnn /* print main fields */ 261235368Sgnn OPT_args == 0 ? printf("%-12.12s ", execname) : 1; 262235368Sgnn OPT_dump == 0 ? printf("%3d ", (int)arg0) : 1; 263235368Sgnn OPT_err ? printf("%3d ", errno) : 1; 264235368Sgnn OPT_cwd ? printf("%-20s ", cwd) : 1; 265235368Sgnn OPT_type ? printf("%-8s ", probefunc) : 1; 266235368Sgnn OPT_dump == 0 ? printf("%-20s ", self->path) : 1; 267235368Sgnn OPT_args == 1 ? printf("%S", curpsinfo->pr_psargs) : 1; 268235368Sgnn printf("\n"); 269235368Sgnn 270235368Sgnn /* cleanup */ 271235368Sgnn self->path = 0; 272235368Sgnn self->ok = 0; 273235368Sgnn } 274235368Sgnn 275235368Sgnn /* 276235368Sgnn * Cleanup 277235368Sgnn */ 278235368Sgnn syscall::stat:return, syscall::stat64:return, syscall::xstat:return, 279235368Sgnn syscall::lstat:return, syscall::lstat64:return, syscall::lxstat:return, 280235368Sgnn syscall::fstat:return, syscall::fstat64:return, syscall::fxstat:return 281235368Sgnn /self->ok/ 282235368Sgnn { 283235368Sgnn self->path = 0; 284235368Sgnn self->ok = 0; 285235368Sgnn } 286235368Sgnn' 287