ktrace.c revision 1.12 1 /* $NetBSD: ktrace.c,v 1.12 1999/07/30 14:03:55 darrenr Exp $ */
2
3 /*-
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)ktrace.c 8.2 (Berkeley) 4/28/95";
45 #else
46 __RCSID("$NetBSD: ktrace.c,v 1.12 1999/07/30 14:03:55 darrenr Exp $");
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <sys/file.h>
54 #include <sys/time.h>
55 #include <sys/uio.h>
56 #include <sys/ktrace.h>
57
58 #include <err.h>
59 #include <errno.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63
64 #include "ktrace.h"
65
66 int main __P((int, char **));
67 int rpid __P((char *));
68 void usage __P((void));
69 int do_ktrace __P((char *, int, int,int));
70 void no_ktrace __P((int));
71
72 #ifdef KTRUSS
73 extern int timestamp, decimal, fancy, tail, maxdata;
74 #endif
75
76 int
77 main(argc, argv)
78 int argc;
79 char **argv;
80 {
81 enum { NOTSET, CLEAR, CLEARALL } clear;
82 int append, ch, fd, inherit, ops, pid, pidset, trpoints;
83 char *infile, *outfile;
84
85 clear = NOTSET;
86 append = ops = pidset = inherit = 0;
87 trpoints = DEF_POINTS;
88 pid = 0; /* Appease GCC */
89
90 #ifdef KTRUSS
91 # define OPTIONS "aCce:df:g:ilm:o:p:RTt:"
92 outfile = infile = NULL;
93 #else
94 # define OPTIONS "aCcdf:g:ip:t:"
95 outfile = infile = DEF_TRACEFILE;
96 #endif
97
98 while ((ch = getopt(argc,argv, OPTIONS)) != -1)
99 switch((char)ch) {
100 case 'a':
101 append = 1;
102 break;
103 case 'C':
104 clear = CLEARALL;
105 pidset = 1;
106 break;
107 case 'c':
108 clear = CLEAR;
109 pidset = 1;
110 break;
111 case 'd':
112 ops |= KTRFLAG_DESCEND;
113 break;
114 #ifdef KTRUSS
115 case 'e':
116 setemul(optarg);
117 break;
118 case 'f':
119 infile = optarg;
120 break;
121 #else
122 case 'f':
123 infile = outfile = optarg;
124 break;
125 #endif
126 case 'g':
127 pid = -rpid(optarg);
128 pidset = 1;
129 break;
130 case 'i':
131 inherit = 1;
132 break;
133 #ifdef KTRUSS
134 case 'l':
135 tail = 1;
136 break;
137 case 'm':
138 maxdata = atoi(optarg);
139 break;
140 case 'o':
141 outfile = optarg;
142 break;
143 #endif
144 case 'p':
145 pid = rpid(optarg);
146 pidset = 1;
147 break;
148 #ifdef KTRUSS
149 case 'R':
150 timestamp = 2; /* relative timestamp */
151 break;
152 case 'T':
153 timestamp = 1;
154 break;
155 #endif
156 case 't':
157 trpoints = getpoints(optarg);
158 if (trpoints < 0) {
159 warnx("unknown facility in %s", optarg);
160 usage();
161 }
162 break;
163 default:
164 usage();
165 }
166 argv += optind;
167 argc -= optind;
168
169 if (!infile && ((pidset && *argv) || (!pidset && !*argv)))
170 usage();
171
172 #ifdef KTRUSS
173 if (infile) {
174 dumpfile(infile, 0, trpoints);
175 exit(0);
176 }
177 #endif
178 if (inherit)
179 trpoints |= KTRFAC_INHERIT;
180
181 (void)signal(SIGSYS, no_ktrace);
182 if (clear != NOTSET) {
183 if (clear == CLEARALL) {
184 ops = KTROP_CLEAR | KTRFLAG_DESCEND;
185 trpoints = ALL_POINTS;
186 pid = 1;
187 } else
188 ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
189
190 (void)do_ktrace(outfile, ops, trpoints, pid);
191 exit(0);
192 }
193
194 if (outfile && strcmp(outfile, "-")) {
195 if ((fd = open(outfile, O_CREAT | O_WRONLY |
196 (append ? 0 : O_TRUNC), DEFFILEMODE)) < 0)
197 err(1, outfile);
198 (void)close(fd);
199 }
200
201 if (*argv) {
202 if (do_ktrace(outfile, ops, trpoints, getpid()) == 1) {
203 execvp(argv[0], &argv[0]);
204 err(1, "exec of '%s' failed", argv[0]);
205 }
206 } else
207 (void)do_ktrace(outfile, ops, trpoints, pid);
208 exit(0);
209 }
210
211 int
212 rpid(p)
213 char *p;
214 {
215 static int first;
216
217 if (first++) {
218 warnx("only one -g or -p flag is permitted.");
219 usage();
220 }
221 if (!*p) {
222 warnx("illegal process id.");
223 usage();
224 }
225 return(atoi(p));
226 }
227
228 void
229 usage()
230 {
231 extern char *__progname;
232 #ifdef KTRUSS
233 # define LONG_OPTION "[-e emulation] [-m maxdata] [-o outfile] "
234 # define SHRT_OPTION "RT"
235 #else
236 # define LONG_OPTION ""
237 # define SHRT_OPTION ""
238 #endif
239 (void)fprintf(stderr,
240 "Usage:\t%s [-aCcid%s] %s[-f trfile] [-g pgid] [-p pid] [-t [cenisw+]]\n\t%s [-aCcid%s] %s[-f trfile] [-t [cenisw+]] command\n",
241 __progname, SHRT_OPTION, LONG_OPTION,
242 __progname, SHRT_OPTION, LONG_OPTION);
243 exit(1);
244 }
245
246 void
247 no_ktrace(sig)
248 int sig;
249 {
250 (void)fprintf(stderr,
251 "error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'options KTRACE'\n");
252 exit(1);
253 }
254
255 int
256 do_ktrace(tracefile, ops, trpoints, pid)
257 char *tracefile;
258 int ops;
259 int trpoints;
260 int pid;
261 {
262 int ret;
263
264 if (!tracefile || strcmp(tracefile, "-") == 0) {
265 int pi[2], dofork, fpid;
266
267 if (pipe(pi) < 0)
268 err(1, "pipe(2)");
269 fcntl(pi[0], F_SETFD, FD_CLOEXEC|fcntl(pi[0], F_GETFD, 0));
270 fcntl(pi[1], F_SETFD, FD_CLOEXEC|fcntl(pi[1], F_GETFD, 0));
271
272 dofork = (pid == getpid());
273
274 if (dofork)
275 fpid = fork();
276 else
277 fpid = pid; /* XXX: Gcc */
278 if (fpid) {
279 if (!dofork)
280 ret = fktrace(pi[1], ops, trpoints, fpid);
281 else
282 close(pi[1]);
283 #ifdef KTRUSS
284 dumpfile(NULL, pi[0], trpoints);
285 waitpid(fpid, NULL, 0);
286 #else
287 {
288 char buf[512];
289 int n, cnt = 0;
290
291 while ((n = read(pi[0], buf, sizeof(buf)))>0) {
292 write(1, buf, n);
293 cnt += n;
294 }
295 }
296 #endif
297 return 0;
298 }
299 close(pi[0]);
300 if (dofork && !fpid) {
301 ret = fktrace(pi[1], ops, trpoints, getpid());
302 return 1;
303 }
304 } else
305 ret = ktrace(tracefile, ops, trpoints, pid);
306 if (ret < 0)
307 err(1, tracefile);
308 return 1;
309 }
310