1139815Simp#!/bin/sh
2206361Sjoel#
375332Sbp# opensnoop - snoop file opens as they occur.
475332Sbp#             Written using DTrace (Solaris 10 3/05).
575332Sbp#
675332Sbp# $Id: opensnoop 3 2007-08-01 10:50:08Z brendan $
775332Sbp#
875332Sbp# USAGE:	opensnoop [-a|-A|-ceghsvxZ] [-f pathname] [-n name] [-p PID]
975332Sbp#
1075332Sbp#		opensnoop	# default output
1175332Sbp#
1275332Sbp#		-a		# print most data
1375332Sbp#		-A		# dump all data, space delimited
1475332Sbp#		-c		# print cwd of process
1575332Sbp#		-e		# print errno value
1675332Sbp#		-g		# print command arguments
1775332Sbp#		-s		# print start time, us
1875332Sbp#		-v		# print start time, string
1975332Sbp#		-x		# only print failed opens
2075332Sbp#		-Z		# print zonename
2175332Sbp#		-f pathname	# file pathname to snoop
2275332Sbp#		-n name		# command name to snoop
2375332Sbp#		-p PID		# process ID to snoop
2475332Sbp#	eg,
2575332Sbp#		opensnoop -v			# human readable timestamps
26116189Sobrien#		opensnoop -e			# see error codes
27116189Sobrien#		opensnoop -f /etc/passwd	# snoop this file only
28116189Sobrien# 	
29116189Sobrien# FIELDS:
3075332Sbp#		ZONE		Zone name
3175332Sbp#		UID		User ID
3275332Sbp#		PID		Process ID
3375332Sbp#		PPID		Parent Process ID
3475332Sbp#		FD		file descriptor (-1 for error)
35120492Sfjoe#		ERR		errno value (see /usr/include/sys/errno.h)
36185652Sjhb#		CWD		print current working directory of process
37120492Sfjoe#		PATH		pathname for file open
3875332Sbp#		COMM		command name for the process
3975332Sbp#		ARGS		argument listing for the process
4075332Sbp#		TIME		timestamp for the open event, us
4175332Sbp#		STRTIME		timestamp for the open event, string
4275332Sbp#
4375332Sbp# SEE ALSO: truss, BSM auditing.
4475332Sbp#
45151897Srwatson# COPYRIGHT: Copyright (c) 2006 Brendan Gregg.
46227293Sed#
4775332Sbp# CDDL HEADER START
48120492Sfjoe#
4975332Sbp#  The contents of this file are subject to the terms of the
50185652Sjhb#  Common Development and Distribution License, Version 1.0 only
51185652Sjhb#  (the "License").  You may not use this file except in compliance
5275332Sbp#  with the License.
5375332Sbp#
5475332Sbp#  You can obtain a copy of the license at Docs/cddl1.txt
5575332Sbp#  or http://www.opensolaris.org/os/licensing.
5675332Sbp#  See the License for the specific language governing permissions
5775332Sbp#  and limitations under the License.
5875332Sbp#
5975332Sbp# CDDL HEADER END
6075332Sbp#
6175332Sbp# Author: Brendan Gregg  [Sydney, Australia]
6275332Sbp#
6375332Sbp# 09-May-2004	Brendan Gregg	Created this.
6475332Sbp# 21-Jan-2005	   "	  "	Wrapped in sh to provide options.
6575332Sbp# 08-May-2005	   "      "	Rewritten for performance.
6675332Sbp# 14-May-2005	   "      "	Added errno.
6775332Sbp# 28-Jun-2005	   "      "	Added cwd, zonename.
6875332Sbp# 17-Sep-2005	   "      "	Increased switchrate, fixed page fault bug.
6975332Sbp# 16-Jan-2006	   "	  "	Added -n, -p.
7075332Sbp# 16-Jan-2006	   "	  "	Last update.
7175332Sbp# 
7275332Sbp
7375332Sbp
7475332Sbp##############################
7575332Sbp# --- Process Arguments ---
7675332Sbp#
7775332Sbp
7875332Sbp### Default variables
7975332Sbpopt_dump=0; opt_file=0; opt_time=0; opt_timestr=0; opt_args=0
8075332Sbpopt_zone=0; opt_cwd=0; opt_failonly=0; opt_err=0; filter=0; pathname=.
8175332Sbpopt_name=0; opt_pid=0; pname=.; pid=0
8275332Sbp
8375332Sbp### Process options
8475332Sbpwhile getopts aAcef:ghn:p:svxZ name
8575332Sbpdo
86185652Sjhb	case $name in
87236899Smjg	a)	opt_time=1; opt_timestr=1; opt_args=1; opt_err=1 ;;
88236899Smjg	A)	opt_dump=1 ;;
89236899Smjg	c)	opt_cwd=1 ;;
9075332Sbp	e)	opt_err=1 ;;
91236899Smjg	g)	opt_args=1 ;;
92185652Sjhb	f)	opt_file=1; pathname=$OPTARG ;;
93185652Sjhb	n)	opt_name=1; pname=$OPTARG ;;
94185652Sjhb	p)	opt_pid=1; pid=$OPTARG ;;
9575332Sbp	s)	opt_time=1 ;;
96185652Sjhb	v)	opt_timestr=1 ;;
97185652Sjhb	x)	opt_failonly=1 ;;
9875332Sbp	Z)	opt_zone=1 ;;
9975332Sbp	h|?)	cat <<-END >&2
10075332Sbp		USAGE: opensnoop [-a|-A|-ceghsvxZ] [-f pathname]
10175332Sbp		                 [-n name] [-p PID]
10275332Sbp		       opensnoop                # default output
10375332Sbp		                -a              # print most data
10475332Sbp		                -A              # dump all data, space delimited
10575332Sbp		                -c              # print cwd of process
10675332Sbp		                -e              # print errno value
10775332Sbp		                -g              # print command arguments
10875332Sbp		                -s              # print start time, us
109185652Sjhb		                -v              # print start time, string
11075332Sbp		                -x              # only print failed opens
11175332Sbp		                -Z              # print zonename
11275332Sbp		                -f pathname	# pathname name to snoop
11375332Sbp		                -n name		# process name to snoop
11475332Sbp		                -p PID		# process ID to snoop
11575332Sbp		  eg,
11675332Sbp		       opensnoop -v             # human readable timestamps
11775332Sbp		       opensnoop -e             # see error codes
11875332Sbp		       opensnoop -f /etc/motd   # snoop this file only
11975332Sbp		END
12075332Sbp		exit 1
12175332Sbp	esac
12275332Sbpdone
12375332Sbp
12475332Sbp### Option logic
12575332Sbpif [ $opt_dump -eq 1 ]; then
12675332Sbp	opt_zone=0; opt_cwd=0; opt_time=0; opt_timestr=0; opt_args=2 
12775332Sbpfi
12875332Sbpif [ $opt_name -eq 1 -o $opt_pid -eq 1 ]; then
12975332Sbp	filter=1
13075332Sbpfi
13175332Sbp
13275332Sbp
13375332Sbp#################################
13475332Sbp# --- Main Program, DTrace ---
13575332Sbp#
13675332Sbp/usr/sbin/dtrace -n '
13775332Sbp /*
138235712Skevlo  * Command line arguments
13975332Sbp  */
14075332Sbp inline int OPT_dump 	 = '$opt_dump';
14175332Sbp inline int OPT_file 	 = '$opt_file';
14275332Sbp inline int OPT_args 	 = '$opt_args';
14375332Sbp inline int OPT_cwd	 = '$opt_cwd';
14475332Sbp inline int OPT_err	 = '$opt_err';
14575332Sbp inline int OPT_zone 	 = '$opt_zone';
14675332Sbp inline int OPT_time 	 = '$opt_time';
14775332Sbp inline int OPT_timestr	 = '$opt_timestr';
14875332Sbp inline int OPT_failonly = '$opt_failonly';
14975332Sbp inline int OPT_pid	 = '$opt_pid';
15075332Sbp inline int OPT_name	 = '$opt_name';
15175332Sbp inline int FILTER 	 = '$filter';
15275332Sbp inline int PID		 = '$pid';
15375332Sbp inline string PATHNAME	 = "'$pathname'";
15475332Sbp inline string NAME	 = "'$pname'";
15575332Sbp 
15675332Sbp #pragma D option quiet
15775332Sbp #pragma D option switchrate=10hz
15875332Sbp 
15975332Sbp /*
16075332Sbp  * Print header
16175332Sbp  */
16275332Sbp dtrace:::BEGIN 
16375332Sbp {
16475332Sbp	/* 
16575332Sbp	 * ternary operators are used to improve performance. 
16675332Sbp	 * OPT_args is unusual in that it can have one of three values.
16775332Sbp	 */
16875332Sbp 
16975332Sbp	/* print optional headers */
17075332Sbp 	OPT_time ? printf("%-14s ", "TIME") : 1;
171267980Sjhb 	OPT_timestr ? printf("%-20s ", "STRTIME") : 1;
172267980Sjhb 	OPT_zone ? printf("%-10s ", "ZONE") : 1;
17375332Sbp
17475332Sbp	/* print dump headers */
17575332Sbp	OPT_dump ? printf("%s %s %s %s %s %s %s %s %s %s %s", "ZONE",
17675332Sbp	    "TIME", "UID", "PID", "PPID", "COMM", "FD", "ERR", "CWD", 
17775332Sbp	    "PATH", "ARGS") : printf("%5s %6s ","UID","PID");
17875332Sbp	
17975332Sbp	/* print main headers */
18075332Sbp	OPT_args == 0 ? printf("%-12s ", "COMM") : 1;
18175332Sbp	OPT_dump == 0 ? printf("%3s ", "FD") : 1;
18275332Sbp	OPT_err ? printf("%3s ", "ERR") : 1;
18375332Sbp	OPT_cwd ? printf("%-20s ", "CWD") : 1;
18475332Sbp	OPT_dump == 0 ? printf("%-20s ", "PATH") : 1;
18575332Sbp	OPT_args == 1 ? printf("%s", "ARGS") : 1;
18675332Sbp	printf("\n");
18775332Sbp }
18875332Sbp
18975332Sbp /*
19075332Sbp  * Print open event
19175332Sbp  */
19275332Sbp syscall::open:entry
19375332Sbp {
19475332Sbp	/* save pathname */
19575332Sbp	self->pathp = arg0;
19675332Sbp
19775332Sbp	/* default is to trace unless filtering */
19875332Sbp	self->ok = FILTER ? 0 : 1;
199111119Simp
20075332Sbp	/* check each filter */
20175332Sbp	(OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
20275332Sbp	(OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
20375332Sbp	/* OPT_file is checked on return to ensure pathp is mapped */
20475332Sbp }
20575332Sbp
20675332Sbp syscall::open:return
20775332Sbp /self->ok && (! OPT_failonly || (int)arg0 < 0) && 
20875332Sbp ((OPT_file == 0) || (OPT_file == 1 && PATHNAME == copyinstr(self->pathp)))/
20975332Sbp {
21075332Sbp	/* print optional fields */
21175332Sbp 	OPT_time ? printf("%-14d ", timestamp/1000) : 1;
21275332Sbp 	OPT_timestr ? printf("%-20Y ", walltimestamp) : 1;
21375332Sbp 	OPT_zone ? printf("%-10s ", zonename) : 1;
21475332Sbp
21575332Sbp	/* print dump fields */
21675332Sbp	OPT_dump ? printf("%s %d %d %d %d %s %d %d %s %s %S", zonename,
21775332Sbp	    timestamp/1000, uid, pid, ppid, execname, (int)arg0, errno,
21875332Sbp	    cwd, copyinstr(self->pathp), curpsinfo->pr_psargs) :
21975332Sbp	    printf("%5d %6d ", uid, pid);
22075332Sbp
22175332Sbp	/* print main fields */
22275332Sbp	OPT_args == 0 ? printf("%-12s ", execname) : 1;
22375332Sbp	OPT_dump == 0 ? printf("%3d ", (int)arg0) : 1;
22475332Sbp	OPT_err ? printf("%3d ", errno) : 1;
22575332Sbp	OPT_cwd ? printf("%-20s ", cwd) : 1;
22675332Sbp	OPT_dump == 0 ? printf("%-20s ", copyinstr(self->pathp)) : 1;
22775332Sbp	OPT_args == 1 ? printf("%S", curpsinfo->pr_psargs) : 1;
22875332Sbp	printf("\n");
22975332Sbp
23075332Sbp	/* cleanup */
23175332Sbp	self->pathp = 0;
23275332Sbp	self->ok = 0;
23375332Sbp }
23475332Sbp
23575332Sbp /* 
23675332Sbp  * Cleanup 
23775332Sbp  */
23875332Sbp syscall::open:return
23975332Sbp /self->ok/
24075332Sbp {
24175332Sbp	self->pathp = 0;
24275332Sbp	self->ok = 0;
24375332Sbp }
24475332Sbp'
24575332Sbp