11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1988, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3193523Sdwmalonestatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1988, 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 36110401Scharnier#if 0 371590Srgrimes#ifndef lint 381590Srgrimesstatic char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93"; 39110401Scharnier#endif /* not lint */ 4016509Sjraynard#endif 41110401Scharnier 4293523Sdwmalone#include <sys/cdefs.h> 4393523Sdwmalone__FBSDID("$FreeBSD$"); 4493523Sdwmalone 451590Srgrimes#include <sys/param.h> 46226504Sdes#include <sys/file.h> 471590Srgrimes#include <sys/stat.h> 481590Srgrimes#include <sys/time.h> 491590Srgrimes#include <sys/uio.h> 501590Srgrimes#include <sys/ktrace.h> 5116509Sjraynard 5216509Sjraynard#include <err.h> 53226504Sdes#include <errno.h> 54226504Sdes#include <inttypes.h> 551590Srgrimes#include <stdio.h> 5693523Sdwmalone#include <stdlib.h> 5716509Sjraynard#include <unistd.h> 5816509Sjraynard 591590Srgrimes#include "ktrace.h" 601590Srgrimes 6195649Smarkmstatic char def_tracefile[] = DEF_TRACEFILE; 6295649Smarkm 63226504Sdesstatic enum clear { NOTSET, CLEAR, CLEARALL } clear = NOTSET; 64226504Sdesstatic int pid; 65226504Sdes 6693523Sdwmalonestatic void no_ktrace(int); 67226504Sdesstatic void set_pid_clear(const char *, enum clear); 6893523Sdwmalonestatic void usage(void); 692354Sats 7093523Sdwmaloneint 7195649Smarkmmain(int argc, char *argv[]) 721590Srgrimes{ 73226504Sdes int append, ch, fd, inherit, ops, trpoints; 7493523Sdwmalone const char *tracefile; 7516844Sjoerg mode_t omask; 7623894Sjoerg struct stat sb; 771590Srgrimes 78226504Sdes append = ops = inherit = 0; 791590Srgrimes trpoints = DEF_POINTS; 8095649Smarkm tracefile = def_tracefile; 8124360Simp while ((ch = getopt(argc,argv,"aCcdf:g:ip:t:")) != -1) 821590Srgrimes switch((char)ch) { 831590Srgrimes case 'a': 841590Srgrimes append = 1; 851590Srgrimes break; 861590Srgrimes case 'C': 87226504Sdes set_pid_clear("1", CLEARALL); 881590Srgrimes break; 891590Srgrimes case 'c': 90226504Sdes set_pid_clear(NULL, CLEAR); 911590Srgrimes break; 921590Srgrimes case 'd': 931590Srgrimes ops |= KTRFLAG_DESCEND; 941590Srgrimes break; 951590Srgrimes case 'f': 961590Srgrimes tracefile = optarg; 971590Srgrimes break; 981590Srgrimes case 'g': 99226504Sdes set_pid_clear(optarg, NOTSET); 100226504Sdes pid = -pid; 1011590Srgrimes break; 1021590Srgrimes case 'i': 1031590Srgrimes inherit = 1; 1041590Srgrimes break; 1051590Srgrimes case 'p': 106226504Sdes set_pid_clear(optarg, NOTSET); 1071590Srgrimes break; 1081590Srgrimes case 't': 1091590Srgrimes trpoints = getpoints(optarg); 1101590Srgrimes if (trpoints < 0) { 11116509Sjraynard warnx("unknown facility in %s", optarg); 1121590Srgrimes usage(); 1131590Srgrimes } 1141590Srgrimes break; 1151590Srgrimes default: 1161590Srgrimes usage(); 1171590Srgrimes } 118226504Sdes 1191590Srgrimes argv += optind; 1201590Srgrimes argc -= optind; 121226504Sdes 122226504Sdes /* must have either -[Cc], a pid or a command */ 123226504Sdes if (clear == NOTSET && pid == 0 && argc == 0) 1241590Srgrimes usage(); 125226504Sdes /* can't have both a pid and a command */ 126226504Sdes /* (note that -C sets pid to 1) */ 127226504Sdes if (pid != 0 && argc > 0) { 128226504Sdes usage(); 129226504Sdes } 130226504Sdes 1311590Srgrimes if (inherit) 1321590Srgrimes trpoints |= KTRFAC_INHERIT; 1331590Srgrimes 13416509Sjraynard (void)signal(SIGSYS, no_ktrace); 1351590Srgrimes if (clear != NOTSET) { 1361590Srgrimes if (clear == CLEARALL) { 1371590Srgrimes ops = KTROP_CLEAR | KTRFLAG_DESCEND; 1381590Srgrimes trpoints = ALL_POINTS; 139226504Sdes } else { 140226504Sdes ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE; 141226504Sdes } 1421590Srgrimes if (ktrace(tracefile, ops, trpoints, pid) < 0) 14362894Skris err(1, "%s", tracefile); 1441590Srgrimes exit(0); 1451590Srgrimes } 1461590Srgrimes 14716844Sjoerg omask = umask(S_IRWXG|S_IRWXO); 14823894Sjoerg if (append) { 149156715Srwatson if ((fd = open(tracefile, O_CREAT | O_WRONLY | O_NONBLOCK, 150156715Srwatson DEFFILEMODE)) < 0) 15162894Skris err(1, "%s", tracefile); 15223894Sjoerg if (fstat(fd, &sb) != 0 || sb.st_uid != getuid()) 153110401Scharnier errx(1, "refuse to append to %s not owned by you", 15423894Sjoerg tracefile); 155156715Srwatson if (!(S_ISREG(sb.st_mode))) 156156715Srwatson errx(1, "%s not regular file", tracefile); 15723894Sjoerg } else { 15823894Sjoerg if (unlink(tracefile) == -1 && errno != ENOENT) 15923894Sjoerg err(1, "unlink %s", tracefile); 16023894Sjoerg if ((fd = open(tracefile, O_CREAT | O_EXCL | O_WRONLY, 16123894Sjoerg DEFFILEMODE)) < 0) 16262894Skris err(1, "%s", tracefile); 16323894Sjoerg } 16416844Sjoerg (void)umask(omask); 1651590Srgrimes (void)close(fd); 1661590Srgrimes 167219043Sdchagin trpoints |= PROC_ABI_POINTS; 168219043Sdchagin 169226504Sdes if (argc > 0) { 1701590Srgrimes if (ktrace(tracefile, ops, trpoints, getpid()) < 0) 17162894Skris err(1, "%s", tracefile); 172226504Sdes execvp(*argv, argv); 173226504Sdes err(1, "exec of '%s' failed", *argv); 1741590Srgrimes } 175226504Sdes if (ktrace(tracefile, ops, trpoints, pid) < 0) 17662894Skris err(1, "%s", tracefile); 1771590Srgrimes exit(0); 1781590Srgrimes} 1791590Srgrimes 180226504Sdesstatic void 181226504Sdesset_pid_clear(const char *p, enum clear cl) 1821590Srgrimes{ 183226504Sdes intmax_t n; 184226504Sdes char *e; 1851590Srgrimes 186226504Sdes if (clear != NOTSET && cl != NOTSET) { 187226504Sdes /* either -c and -C or either of them twice */ 188226504Sdes warnx("only one -c or -C flag is permitted"); 1891590Srgrimes usage(); 1901590Srgrimes } 191226504Sdes if ((clear == CLEARALL && p != NULL) || (cl == CLEARALL && pid != 0)) { 192226504Sdes /* both -C and a pid or pgid */ 193226504Sdes warnx("the -C flag may not be combined with -g or -p"); 1941590Srgrimes usage(); 1951590Srgrimes } 196226504Sdes if (p != NULL && pid != 0) { 197226504Sdes /* either -p and -g or either of them twice */ 198226504Sdes warnx("only one -g or -p flag is permitted"); 199226504Sdes usage(); 200226504Sdes } 201226504Sdes if (p != NULL) { 202226504Sdes errno = 0; 203226504Sdes n = strtoimax(p, &e, 10); 204226504Sdes /* 205226504Sdes * 1) not a number, or outside the range of an intmax_t 206226504Sdes * 2) inside the range of intmax_t but outside the range 207226504Sdes * of an int, keeping in mind that the pid may be 208226504Sdes * negated if it's actually a pgid. 209226504Sdes */ 210226504Sdes if (*e != '\0' || n < 1 || errno == ERANGE || 211226504Sdes n > (intmax_t)INT_MAX || n > -(intmax_t)INT_MIN) { 212226504Sdes warnx("invalid process or group id"); 213226504Sdes usage(); 214226504Sdes } 215226504Sdes pid = n; 216226504Sdes } 217226504Sdes if (cl != NOTSET) 218226504Sdes if ((clear = cl) == CLEARALL) 219226504Sdes pid = 1; 2201590Srgrimes} 2211590Srgrimes 22293523Sdwmalonestatic void 22395649Smarkmusage(void) 2241590Srgrimes{ 225226504Sdes 226226504Sdes fprintf(stderr, "%s\n%s\n", 227226504Sdes "usage: ktrace [-aCcdi] [-f trfile] [-g pgrp | -p pid] [-t trstr]", 228226504Sdes " ktrace [-adi] [-f trfile] [-t trstr] command"); 2291590Srgrimes exit(1); 2301590Srgrimes} 23116509Sjraynard 23293523Sdwmalonestatic void 23395649Smarkmno_ktrace(int sig __unused) 23416509Sjraynard{ 235226504Sdes 236226504Sdes fprintf(stderr, "error:\t%s\n\t%s\n", 237226504Sdes "ktrace() system call not supported in the running kernel", 238226504Sdes "re-compile kernel with 'options KTRACE'"); 23916509Sjraynard exit(1); 24016509Sjraynard} 241