Fix markup. Fix backslashes to surive roff.
[netbsd-mini2440.git] / usr.bin / ktrace / ktrace.c
blob0721946eaa4045411a42c5dd85970369f82a694b
1 /* $NetBSD: ktrace.c,v 1.42.6.1 2008/12/29 01:14:15 christos Exp $ */
3 /*-
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)ktrace.c 8.2 (Berkeley) 4/28/95";
41 #else
42 __RCSID("$NetBSD: ktrace.c,v 1.42.6.1 2008/12/29 01:14:15 christos Exp $");
43 #endif
44 #endif /* not lint */
46 #include <sys/param.h>
47 #include <sys/stat.h>
48 #include <sys/wait.h>
49 #include <sys/file.h>
50 #include <sys/time.h>
51 #include <sys/uio.h>
52 #include <sys/ktrace.h>
53 #include <sys/socket.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 #include <signal.h>
63 #include "ktrace.h"
65 #ifdef KTRUSS
66 #include "setemul.h"
67 #endif
69 int main(int, char *[]);
70 static int rpid(char *);
71 static void usage(void);
72 static int do_ktrace(const char *, int, int, int, int, int);
73 static void no_ktrace(int);
74 static void fset(int fd, int flag);
75 static void fclear(int fd, int flag);
77 #ifdef KTRUSS
78 extern int timestamp, decimal, fancy, tail, maxdata;
79 #endif
81 int
82 main(int argc, char *argv[])
84 enum { NOTSET, CLEAR, CLEARALL } clear;
85 int block, append, ch, fd, trset, ops, pid, pidset, synclog, trpoints;
86 int vers;
87 const char *outfile;
88 #ifdef KTRUSS
89 const char *infile;
90 const char *emul_name = "netbsd";
91 #endif
93 clear = NOTSET;
94 append = ops = pidset = trset = synclog = 0;
95 trpoints = 0;
96 block = 1;
97 vers = 2;
98 pid = 0; /* Appease GCC */
100 #ifdef KTRUSS
101 # define OPTIONS "aCce:df:g:ilm:no:p:RTt:v:"
102 outfile = infile = NULL;
103 #else
104 # define OPTIONS "aCcdf:g:ip:st:v:"
105 outfile = DEF_TRACEFILE;
106 #endif
108 while ((ch = getopt(argc, argv, OPTIONS)) != -1)
109 switch (ch) {
110 case 'a':
111 append = 1;
112 break;
113 case 'C':
114 clear = CLEARALL;
115 pidset = 1;
116 break;
117 case 'c':
118 clear = CLEAR;
119 pidset = 1;
120 break;
121 case 'd':
122 ops |= KTRFLAG_DESCEND;
123 break;
124 #ifdef KTRUSS
125 case 'e':
126 emul_name = strdup(optarg); /* it's safer to copy it */
127 break;
128 case 'f':
129 infile = optarg;
130 break;
131 #else
132 case 'f':
133 outfile = optarg;
134 break;
135 #endif
136 case 'g':
137 pid = -rpid(optarg);
138 pidset = 1;
139 break;
140 case 'i':
141 trpoints |= KTRFAC_INHERIT;
142 break;
143 #ifdef KTRUSS
144 case 'l':
145 tail = 1;
146 break;
147 case 'm':
148 maxdata = atoi(optarg);
149 break;
150 case 'o':
151 outfile = optarg;
152 break;
153 #endif
154 case 'n':
155 block = 0;
156 break;
157 case 'p':
158 pid = rpid(optarg);
159 pidset = 1;
160 break;
161 #ifdef KTRUSS
162 case 'R':
163 timestamp = 2; /* relative timestamp */
164 break;
165 #else
166 case 's':
167 synclog = 1;
168 break;
169 #endif
170 #ifdef KTRUSS
171 case 'T':
172 timestamp = 1;
173 break;
174 #endif
175 case 't':
176 trset = 1;
177 trpoints = getpoints(trpoints, optarg);
178 if (trpoints < 0) {
179 warnx("unknown facility in %s", optarg);
180 usage();
182 break;
183 case 'v':
184 vers = atoi(optarg);
185 break;
186 default:
187 usage();
189 argv += optind;
190 argc -= optind;
192 if (!trset)
193 trpoints |= clear == NOTSET ? DEF_POINTS : ALL_POINTS;
195 if ((pidset && *argv) || (!pidset && !*argv)) {
196 #ifdef KTRUSS
197 if (!infile)
198 #endif
199 usage();
202 #ifdef KTRUSS
203 if (clear == CLEAR && outfile == NULL && pid == 0)
204 usage();
206 if (infile) {
207 dumpfile(infile, 0, trpoints);
208 exit(0);
211 setemul(emul_name, 0, 0);
212 #endif
215 * For cleaner traces, initialize malloc now rather
216 * than in a traced subprocess.
218 free(malloc(1));
220 (void)signal(SIGSYS, no_ktrace);
221 if (clear != NOTSET) {
222 if (clear == CLEARALL) {
223 ops = KTROP_CLEAR | KTRFLAG_DESCEND;
224 trpoints = ALL_POINTS;
225 pid = 1;
226 } else
227 ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
229 (void)do_ktrace(outfile, vers, ops, trpoints, pid, block);
230 exit(0);
233 if (outfile && strcmp(outfile, "-")) {
234 if ((fd = open(outfile, O_CREAT | O_WRONLY |
235 (append ? 0 : O_TRUNC) | (synclog ? 0 : O_SYNC),
236 DEFFILEMODE)) < 0)
237 err(EXIT_FAILURE, "%s", outfile);
238 (void)close(fd);
241 if (*argv) {
242 #ifdef KTRUSS
243 if (do_ktrace(outfile, vers, ops, trpoints, getpid(), block) == 1) {
244 execvp(argv[0], &argv[0]);
245 err(EXIT_FAILURE, "exec of '%s' failed", argv[0]);
247 #else
248 (void)do_ktrace(outfile, vers, ops, trpoints, getpid(), block);
249 execvp(argv[0], &argv[0]);
250 err(EXIT_FAILURE, "exec of '%s' failed", argv[0]);
251 #endif
252 } else
253 (void)do_ktrace(outfile, vers, ops, trpoints, pid, block);
254 return 0;
257 static int
258 rpid(char *p)
260 static int first;
262 if (first++) {
263 warnx("only one -g or -p flag is permitted.");
264 usage();
266 if (!*p) {
267 warnx("illegal process id.");
268 usage();
270 return (atoi(p));
273 static void
274 fset(int fd, int flag)
276 int oflag = fcntl(fd, F_GETFL, 0);
278 if (oflag == -1)
279 err(EXIT_FAILURE, "Cannot get file flags");
280 if (fcntl(fd, F_SETFL, oflag | flag) == -1)
281 err(EXIT_FAILURE, "Cannot set file flags");
284 static void
285 fclear(int fd, int flag)
287 int oflag = fcntl(fd, F_GETFL, 0);
289 if (oflag == -1)
290 err(EXIT_FAILURE, "Cannot get file flags");
291 if (fcntl(fd, F_SETFL, oflag & ~flag) == -1)
292 err(EXIT_FAILURE, "Cannot set file flags");
295 static void
296 usage(void)
299 #define TRPOINTS "[AaceilmnsUuvw+-]"
300 #ifdef KTRUSS
301 (void)fprintf(stderr, "usage:\t%s "
302 "[-aCcdilnRT] [-e emulation] [-f infile] [-g pgrp] "
303 "[-m maxdata]\n\t "
304 "[-o outfile] [-p pid] [-t " TRPOINTS "]\n", getprogname());
305 (void)fprintf(stderr, "\t%s "
306 "[-adinRT] [-e emulation] [-m maxdata] [-o outfile]\n\t "
307 "[-t " TRPOINTS "] [-v vers] command\n",
308 getprogname());
309 #else
310 (void)fprintf(stderr, "usage:\t%s "
311 "[-aCcdins] [-f trfile] [-g pgrp] [-p pid] [-t " TRPOINTS "]\n",
312 getprogname());
313 (void)fprintf(stderr, "\t%s "
314 "[-adis] [-f trfile] [-t " TRPOINTS "] command\n",
315 getprogname());
316 #endif
317 exit(1);
320 static const char *ktracefile = NULL;
321 static void
322 /*ARGSUSED*/
323 no_ktrace(int sig)
326 if (ktracefile)
327 (void)unlink(ktracefile);
328 (void)errx(EXIT_FAILURE,
329 "ktrace(2) system call not supported in the running"
330 " kernel; re-compile kernel with `options KTRACE'");
333 static int
334 do_ktrace(const char *tracefile, int vers, int ops, int trpoints, int pid,
335 int block)
337 int ret;
338 ops |= vers << KTRFAC_VER_SHIFT;
340 if (KTROP(ops) == KTROP_SET &&
341 (!tracefile || strcmp(tracefile, "-") == 0)) {
342 int pi[2], dofork;
344 if (pipe(pi) < 0)
345 err(EXIT_FAILURE, "pipe(2)");
347 fset(pi[0], FD_CLOEXEC);
348 fset(pi[1], FD_CLOEXEC);
349 dofork = (pid == getpid());
351 if (dofork) {
352 #ifdef KTRUSS
354 * Create a child process and trace it.
356 pid = fork();
357 if (pid == -1)
358 err(EXIT_FAILURE, "fork");
359 else if (pid == 0) {
360 pid = getpid();
361 goto trace_and_exec;
363 #else
364 int fpid;
367 * Create a dumper process and we will be
368 * traced.
370 fpid = fork();
371 if (fpid == -1)
372 err(EXIT_FAILURE, "fork");
373 else if (fpid != 0)
374 goto trace_and_exec;
375 #endif
376 (void)close(pi[1]);
377 } else {
378 ret = fktrace(pi[1], ops, trpoints, pid);
379 if (ret == -1)
380 err(EXIT_FAILURE, "fd %d, pid %d",
381 pi[1], pid);
382 if (block)
383 fclear(pi[1], O_NONBLOCK);
385 #ifdef KTRUSS
386 dumpfile(NULL, pi[0], trpoints);
387 waitpid(pid, NULL, 0);
388 #else
390 char buf[BUFSIZ];
391 int n;
393 while ((n =
394 read(pi[0], buf, sizeof(buf))) > 0)
395 if (write(STDOUT_FILENO, buf, (size_t)n) == -1)
396 warn("write failed");
398 if (dofork)
399 _exit(0);
400 #endif
401 return 0;
403 trace_and_exec:
404 (void)close(pi[0]);
405 ret = fktrace(pi[1], ops, trpoints, pid);
406 if (ret == -1)
407 err(EXIT_FAILURE, "fd %d, pid %d", pi[1], pid);
408 if (block)
409 fclear(pi[1], O_NONBLOCK);
410 } else {
411 ret = ktrace(ktracefile = tracefile, ops, trpoints, pid);
412 if (ret == -1)
413 err(EXIT_FAILURE, "file %s, pid %d",
414 tracefile != NULL ? tracefile : "NULL", pid);
416 return 1;