ktrace.c revision 1.33
1/*	$OpenBSD: ktrace.c,v 1.33 2016/07/18 09:36:50 guenther Exp $	*/
2/*	$NetBSD: ktrace.c,v 1.4 1995/08/31 23:01:44 jtc Exp $	*/
3
4/*-
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/param.h>	/* MAXCOMLEN */
34#include <sys/signal.h>
35#include <sys/stat.h>
36#include <sys/time.h>
37#include <sys/uio.h>
38#include <sys/ktrace.h>
39
40#include <err.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "ktrace.h"
49#include "extern.h"
50
51extern char *__progname;
52
53static int rpid(const char *);
54static void no_ktrace(int);
55static void usage(void);
56
57int	is_ltrace;
58
59int
60main(int argc, char *argv[])
61{
62	enum { NOTSET, CLEAR, CLEARALL } clear;
63	int append, ch, fd, inherit, ops, pidset, trpoints;
64	pid_t pid;
65	char *tracefile, *tracespec;
66	mode_t omask;
67	struct stat sb;
68
69	is_ltrace = strcmp(__progname, "ltrace") == 0;
70
71	clear = NOTSET;
72	append = ops = pidset = inherit = pid = 0;
73	trpoints = is_ltrace ? KTRFAC_USER : DEF_POINTS;
74	tracefile = DEF_TRACEFILE;
75	tracespec = NULL;
76
77	if (is_ltrace) {
78		while ((ch = getopt(argc, argv, "af:it:u:")) != -1)
79			switch ((char)ch) {
80			case 'a':
81				append = 1;
82				break;
83			case 'f':
84				tracefile = optarg;
85				break;
86			case 'i':
87				inherit = 1;
88				break;
89			case 't':
90				trpoints = getpoints(optarg, KTRFAC_USER);
91				if (trpoints < 0) {
92					warnx("unknown facility in %s", optarg);
93					usage();
94				}
95				break;
96			case 'u':
97				tracespec = optarg;
98				break;
99			default:
100				usage();
101			}
102	} else {
103		while ((ch = getopt(argc, argv, "aBCcdf:g:ip:t:")) != -1)
104			switch ((char)ch) {
105			case 'a':
106				append = 1;
107				break;
108			case 'B':
109				putenv("LD_BIND_NOW=");
110				break;
111			case 'C':
112				clear = CLEARALL;
113				pidset = 1;
114				break;
115			case 'c':
116				clear = CLEAR;
117				break;
118			case 'd':
119				ops |= KTRFLAG_DESCEND;
120				break;
121			case 'f':
122				tracefile = optarg;
123				break;
124			case 'g':
125				pid = -rpid(optarg);
126				pidset = 1;
127				break;
128			case 'i':
129				inherit = 1;
130				break;
131			case 'p':
132				pid = rpid(optarg);
133				pidset = 1;
134				break;
135			case 't':
136				trpoints = getpoints(optarg, DEF_POINTS);
137				if (trpoints < 0) {
138					warnx("unknown facility in %s", optarg);
139					usage();
140				}
141				break;
142			default:
143				usage();
144			}
145	}
146
147	argv += optind;
148	argc -= optind;
149
150	if ((pidset && *argv) || (!pidset && !*argv && clear != CLEAR))
151		usage();
152
153	if (inherit)
154		trpoints |= KTRFAC_INHERIT;
155
156	(void)signal(SIGSYS, no_ktrace);
157	if (clear != NOTSET) {
158		if (clear == CLEARALL) {
159			ops = KTROP_CLEAR | KTRFLAG_DESCEND;
160			trpoints = ALL_POINTS;
161			pid = 1;
162		} else
163			ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
164
165		if (ktrace(tracefile, ops, trpoints, pid) < 0) {
166			if (errno == ESRCH)
167				err(1, "%d", pid);
168			err(1, "%s", tracefile);
169		}
170		exit(0);
171	}
172
173	omask = umask(S_IRWXG|S_IRWXO);
174	if (append) {
175		if ((fd = open(tracefile, O_CREAT | O_WRONLY, DEFFILEMODE)) < 0)
176			err(1, "%s", tracefile);
177		if (fstat(fd, &sb) != 0 || sb.st_uid != getuid())
178			errx(1, "Refuse to append to %s: not owned by you.",
179			    tracefile);
180	} else {
181		if (unlink(tracefile) == -1 && errno != ENOENT)
182			err(1, "unlink %s", tracefile);
183		if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY,
184		    DEFFILEMODE)) < 0)
185			err(1, "%s", tracefile);
186	}
187	(void)umask(omask);
188	(void)close(fd);
189
190	if (*argv) {
191		if (is_ltrace) {
192			if (setenv("LD_TRACE_PLT", inherit ? "i" : "", 1) < 0)
193				err(1, "setenv(LD_TRACE_PLT)");
194			if (tracespec &&
195			    setenv("LD_TRACE_PLTSPEC", tracespec, 1) < 0)
196				err(1, "setenv(LD_TRACE_PLTSPEC)");
197		}
198		if (ktrace(tracefile, ops, trpoints, getpid()) < 0)
199			err(1, "%s", tracefile);
200		execvp(argv[0], &argv[0]);
201		err(1, "exec of '%s' failed", argv[0]);
202	}
203	else if (ktrace(tracefile, ops, trpoints, pid) < 0) {
204		if (errno == ESRCH)
205			err(1, "%d", pid);
206		err(1, "%s", tracefile);
207	}
208	exit(0);
209}
210
211static int
212rpid(const char *p)
213{
214	const char *errstr;
215	static int first;
216	pid_t pid;
217
218	if (first++) {
219		warnx("only one -g or -p flag is permitted.");
220		usage();
221	}
222	if (!*p) {
223		warnx("illegal process id.");
224		usage();
225	}
226	pid = strtonum(p, 1, INT_MAX, &errstr);
227	if (errstr) {
228		warnx("illegal process id: %s", errstr);
229		usage();
230	}
231	return pid;
232}
233
234static void
235usage(void)
236{
237	if (is_ltrace)
238		fprintf(stderr, "usage: %s [-ai] [-f trfile] [-t trstr]"
239		    " [-u trspec] command\n",
240		    __progname);
241	else
242		fprintf(stderr, "usage: %s [-aBCcdi] [-f trfile] [-g pgid]"
243		    " [-p pid] [-t trstr]\n"
244		    "       %s [-adi] [-f trfile] [-t trstr] command\n",
245		    __progname, __progname);
246	exit(1);
247}
248
249/* ARGSUSED */
250static void
251no_ktrace(int signo)
252{
253	char buf[8192];
254
255	snprintf(buf, sizeof(buf),
256"error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'option KTRACE'\n");
257	write(STDERR_FILENO, buf, strlen(buf));
258	_exit(1);
259}
260