]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - cddl/contrib/dtracetoolkit/Apps/shellsnoop
Clean up the handling of errors from vm_pager_get_pages(). Mostly, this
[FreeBSD/FreeBSD.git] / cddl / contrib / dtracetoolkit / Apps / shellsnoop
1 #!/bin/sh
2 #
3 # shellsnoop - A program to print read/write details from shells,
4 #              such as keystrokes and command outputs.
5 #              Written using DTrace (Solaris 10 3/05).
6 #
7 # This program sounds somewhat dangerous (snooping keystrokes), but is
8 # no more so than /usr/bin/truss, and both need root or dtrace privileges to
9 # run. In fact, less dangerous, as we only print visible text (not password
10 # text, for example). Having said that, it goes without saying that this
11 # program shouldn't be used for breeching privacy of other users.
12 #
13 # This was written as a tool to demonstrate the capabilities of DTrace.
14 #
15 # $Id: shellsnoop 19 2007-09-12 07:47:59Z brendan $
16 #
17 # USAGE:        shellsnoop [-hqsv] [-p PID] [-u UID]
18 #
19 #               -q              # quiet, only print data
20 #               -s              # include start time, us
21 #               -v              # include start time, string
22 #               -p PID          # process ID to snoop
23 #               -u UID          # user ID to snoop
24 #  eg,
25 #               shellsnoop              # default output
26 #               shellsnoop -v           # human readable timestamps
27 #               shellsnoop -p 1892      # snoop this PID only
28 #               shellsnoop -qp 1892     # watch this PID data only
29 #       
30 # FIELDS:
31 #               UID             User ID
32 #               PID             process ID
33 #               PPID            parent process ID
34 #               COMM            command name
35 #               DIR             direction (R read, W write)
36 #               TEXT            text contained in the read/write
37 #               TIME            timestamp for the command, us
38 #               STRTIME         timestamp for the command, string
39 #
40 # SEE ALSO: ttywatcher
41 #
42 # COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
43 #
44 # CDDL HEADER START
45 #
46 #  The contents of this file are subject to the terms of the
47 #  Common Development and Distribution License, Version 1.0 only
48 #  (the "License").  You may not use this file except in compliance
49 #  with the License.
50 #
51 #  You can obtain a copy of the license at Docs/cddl1.txt
52 #  or http://www.opensolaris.org/os/licensing.
53 #  See the License for the specific language governing permissions
54 #  and limitations under the License.
55 #
56 # CDDL HEADER END
57 #
58 # Author: Brendan Gregg  [Sydney, Australia]
59 #
60 # 28-Mar-2004   Brendan Gregg   Created this.
61 # 21-Jan-2005      "      "     Wrapped in sh to provide options.
62 # 30-Nov-2005      "      "     Fixed trailing buffer text bug.
63 # 30-Nov-2005      "      "     Fixed sh no keystroke text in quiet bug.
64 # 30-Nov-2005      "      "     Last update.
65
66
67
68 ##############################
69 # --- Process Arguments ---
70 #
71 opt_pid=0; opt_uid=0; opt_time=0; opt_timestr=0; opt_quiet=0; opt_debug=0
72 filter=0; pid=0; uid=0
73
74 while getopts dhp:qsu:v name
75 do
76         case $name in
77         d)      opt_debug=1 ;;
78         p)      opt_pid=1; pid=$OPTARG ;;
79         q)      opt_quiet=1 ;;
80         s)      opt_time=1 ;;
81         u)      opt_uid=1; uid=$OPTARG ;;
82         v)      opt_timestr=1 ;;
83         h|?)    cat <<-END >&2
84                 USAGE: shellsnoop [-hqsv] [-p PID] [-u UID]
85                        shellsnoop               # default output
86                                 -q              # quiet, only print data
87                                 -s              # include start time, us
88                                 -v              # include start time, string
89                                 -p PID          # process ID to snoop
90                                 -u UID          # user ID to snoop
91                 END
92                 exit 1
93         esac
94 done
95
96 if [ $opt_quiet -eq 1 ]; then
97         opt_time=0; opt_timestr=0
98 fi
99 if [ $opt_pid -eq 1 -o $opt_uid -eq 1 ]; then
100         filter=1
101 fi
102
103
104 #################################
105 # --- Main Program, DTrace ---
106 #
107 dtrace -n '
108  /*
109   * Command line arguments
110   */
111  inline int OPT_debug   = '$opt_debug';
112  inline int OPT_quiet   = '$opt_quiet';
113  inline int OPT_pid     = '$opt_pid';
114  inline int OPT_uid     = '$opt_uid';
115  inline int OPT_time    = '$opt_time';
116  inline int OPT_timestr = '$opt_timestr';
117  inline int FILTER      = '$filter';
118  inline int PID         = '$pid';
119  inline int UID         = '$uid';
120  
121  #pragma D option quiet
122  #pragma D option switchrate=20hz
123  
124  /*
125   * Print header
126   */
127  dtrace:::BEGIN /OPT_time == 1/
128  { 
129         printf("%-14s ","TIME");
130  }
131  dtrace:::BEGIN /OPT_timestr == 1/
132  { 
133         printf("%-20s ","STRTIME");
134  }
135  dtrace:::BEGIN /OPT_quiet == 0/
136  {
137         printf("%5s %5s %8s %3s  %s\n", "PID", "PPID", "CMD", "DIR", "TEXT");
138  }
139
140  /*
141   * Remember this PID is a shell child
142   */
143  syscall::execve:entry
144  /execname == "sh"   || execname == "ksh"  || execname == "csh"  || 
145   execname == "tcsh" || execname == "zsh"  || execname == "bash"/
146  {
147         child[pid] = 1;
148  
149  }
150  syscall::execve:entry
151  /(OPT_pid == 1 && PID != ppid) || (OPT_uid == 1 && UID != uid)/
152  {
153         /* forget if filtered */
154         child[pid] = 0;
155  }
156
157  /*
158   * Print shell keystrokes
159   */
160  syscall::write:entry, syscall::read:entry
161  /(execname == "sh"   || execname == "ksh"  || execname == "csh"  ||
162   execname == "tcsh" || execname == "zsh"  || execname == "bash")
163   && (arg0 >= 0 && arg0 <= 2)/
164  {
165         self->buf = arg1;
166  }
167  syscall::write:entry, syscall::read:entry
168  /(OPT_pid == 1 && PID != pid) || (OPT_uid == 1 && UID != uid)/
169  {
170         self->buf = 0;
171  }
172  syscall::write:return, syscall::read:return
173  /self->buf && child[pid] == 0 && OPT_time == 1/
174  {
175         printf("%-14d ", timestamp/1000);
176  }
177  syscall::write:return, syscall::read:return
178  /self->buf && child[pid] == 0 && OPT_timestr == 1/
179  {
180         printf("%-20Y ", walltimestamp);
181  }
182  syscall::write:return, syscall::read:return
183  /self->buf && child[pid] == 0 && OPT_quiet == 0/
184  {
185         this->text = (char *)copyin(self->buf, arg0);
186         this->text[arg0] = '\'\\0\'';
187  
188         printf("%5d %5d %8s %3s  %s\n", pid, curpsinfo->pr_ppid, execname, 
189             probefunc == "read" ? "R" : "W", stringof(this->text));
190  }
191  syscall::write:return
192  /self->buf && child[pid] == 0 && OPT_quiet == 1/
193  {
194         this->text = (char *)copyin(self->buf, arg0);
195         this->text[arg0] = '\'\\0\'';
196         printf("%s", stringof(this->text));
197  }
198  syscall::read:return
199  /self->buf && execname == "sh" && child[pid] == 0 && OPT_quiet == 1/
200  {
201         this->text = (char *)copyin(self->buf, arg0);
202         this->text[arg0] = '\'\\0\'';
203         printf("%s", stringof(this->text));
204  }
205  syscall::write:return, syscall::read:return
206  /self->buf && child[pid] == 0/
207  {
208         self->buf = 0;
209  }
210
211  /*
212   * Print command output
213   */
214  syscall::write:entry, syscall::read:entry
215  /child[pid] == 1 && (arg0 == 1 || arg0 == 2)/
216  {
217         self->buf = arg1;
218  }
219  syscall::write:return, syscall::read:return
220  /self->buf && OPT_time == 1/
221  {
222         printf("%-14d ", timestamp/1000);
223  }
224  syscall::write:return, syscall::read:return
225  /self->buf && OPT_timestr == 1/
226  {
227         printf("%-20Y ", walltimestamp);
228  }
229  syscall::write:return, syscall::read:return
230  /self->buf && OPT_quiet == 0/
231  {
232         this->text = (char *)copyin(self->buf, arg0);
233         this->text[arg0] = '\'\\0\'';
234  
235         printf("%5d %5d %8s %3s  %s", pid, curpsinfo->pr_ppid, execname,
236             probefunc == "read" ? "R" : "W", stringof(this->text));
237  
238         /* here we check if a newline is needed */
239         this->length = strlen(this->text);
240         printf("%s", this->text[this->length - 1] == '\'\\n\'' ? "" : "\n");
241         self->buf = 0;
242  }
243  syscall::write:return, syscall::read:return
244  /self->buf && OPT_quiet == 1/
245  {
246         this->text = (char *)copyin(self->buf, arg0);
247         this->text[arg0] = '\'\\0\'';
248         printf("%s", stringof(this->text));
249         self->buf = 0;
250  }
251
252  /*
253   *  Cleanup
254   */
255  syscall::exit:entry
256  {
257         child[pid] = 0;
258
259         /* debug */
260         this->parent = (char *)curthread->td_proc->p_pptr->p_comm;
261         OPT_debug == 1 ? printf("PID %d CMD %s exited. (%s)\n",
262          pid, execname, stringof(this->parent)) : 1;
263  }
264 '