1 /* $NetBSD: ktrace.c,v 1.23 2001/05/04 07:09:55 simonb 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.23 2001/05/04 07:09:55 simonb 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 #include <sys/socket.h> 58 59 #include <err.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 65 #include "ktrace.h" 66 67 #ifdef KTRUSS 68 #include <string.h> 69 #include "setemul.h" 70 #endif 71 72 int main __P((int, char **)); 73 int rpid __P((char *)); 74 void usage __P((void)); 75 int do_ktrace __P((const char *, int, int,int)); 76 void no_ktrace __P((int)); 77 78 #ifdef KTRUSS 79 extern int timestamp, decimal, fancy, tail, maxdata; 80 #endif 81 82 int 83 main(argc, argv) 84 int argc; 85 char **argv; 86 { 87 enum { NOTSET, CLEAR, CLEARALL } clear; 88 int append, ch, fd, inherit, ops, pid, pidset, synclog, trpoints; 89 const char *infile, *outfile; 90 #ifdef KTRUSS 91 const char *emul_name = "netbsd"; 92 #endif 93 94 clear = NOTSET; 95 append = ops = pidset = inherit = synclog = 0; 96 trpoints = DEF_POINTS; 97 pid = 0; /* Appease GCC */ 98 99 #ifdef KTRUSS 100 # define OPTIONS "aCce:df:g:ilm:o:p:RTt:" 101 outfile = infile = NULL; 102 #else 103 # define OPTIONS "aCcdf:g:ip:st:" 104 outfile = infile = DEF_TRACEFILE; 105 #endif 106 107 while ((ch = getopt(argc,argv, OPTIONS)) != -1) 108 switch((char)ch) { 109 case 'a': 110 append = 1; 111 break; 112 case 'C': 113 clear = CLEARALL; 114 pidset = 1; 115 break; 116 case 'c': 117 clear = CLEAR; 118 pidset = 1; 119 break; 120 case 'd': 121 ops |= KTRFLAG_DESCEND; 122 break; 123 #ifdef KTRUSS 124 case 'e': 125 emul_name = strdup(optarg); /* it's safer to copy it */ 126 break; 127 case 'f': 128 infile = optarg; 129 break; 130 #else 131 case 'f': 132 infile = outfile = optarg; 133 break; 134 #endif 135 case 'g': 136 pid = -rpid(optarg); 137 pidset = 1; 138 break; 139 case 'i': 140 inherit = 1; 141 break; 142 #ifdef KTRUSS 143 case 'l': 144 tail = 1; 145 break; 146 case 'm': 147 maxdata = atoi(optarg); 148 break; 149 case 'o': 150 outfile = optarg; 151 break; 152 #endif 153 case 'p': 154 pid = rpid(optarg); 155 pidset = 1; 156 break; 157 #ifdef KTRUSS 158 case 'R': 159 timestamp = 2; /* relative timestamp */ 160 break; 161 #else 162 case 's': 163 synclog = 1; 164 break; 165 #endif 166 #ifdef KTRUSS 167 case 'T': 168 timestamp = 1; 169 break; 170 #endif 171 case 't': 172 trpoints = getpoints(optarg); 173 if (trpoints < 0) { 174 warnx("unknown facility in %s", optarg); 175 usage(); 176 } 177 break; 178 default: 179 usage(); 180 } 181 argv += optind; 182 argc -= optind; 183 184 if (!infile && ((pidset && *argv) || (!pidset && !*argv))) 185 usage(); 186 187 #ifdef KTRUSS 188 if (infile) { 189 dumpfile(infile, 0, trpoints); 190 exit(0); 191 } 192 193 setemul(emul_name, 0, 0); 194 #endif 195 196 /* 197 * For cleaner traces, initialize malloc now rather 198 * than in a traced subprocess. 199 */ 200 free(malloc(1)); 201 202 if (inherit) 203 trpoints |= KTRFAC_INHERIT; 204 205 (void)signal(SIGSYS, no_ktrace); 206 if (clear != NOTSET) { 207 if (clear == CLEARALL) { 208 ops = KTROP_CLEAR | KTRFLAG_DESCEND; 209 trpoints = ALL_POINTS; 210 pid = 1; 211 } else 212 ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE; 213 214 (void)do_ktrace(outfile, ops, trpoints, pid); 215 exit(0); 216 } 217 218 if (outfile && strcmp(outfile, "-")) { 219 if ((fd = open(outfile, O_CREAT | O_WRONLY | 220 (append ? 0 : O_TRUNC) | (synclog ? 0 : O_SYNC), 221 DEFFILEMODE)) < 0) 222 err(1, "%s", outfile); 223 (void)close(fd); 224 } 225 226 if (*argv) { 227 #ifdef KTRUSS 228 if (do_ktrace(outfile, ops, trpoints, getpid()) == 1) { 229 execvp(argv[0], &argv[0]); 230 err(1, "exec of '%s' failed", argv[0]); 231 } 232 #else 233 (void) do_ktrace(outfile, ops, trpoints, getpid()); 234 execvp(argv[0], &argv[0]); 235 err(1, "exec of '%s' failed", argv[0]); 236 #endif 237 } else 238 (void)do_ktrace(outfile, ops, trpoints, pid); 239 exit(0); 240 } 241 242 int 243 rpid(p) 244 char *p; 245 { 246 static int first; 247 248 if (first++) { 249 warnx("only one -g or -p flag is permitted."); 250 usage(); 251 } 252 if (!*p) { 253 warnx("illegal process id."); 254 usage(); 255 } 256 return(atoi(p)); 257 } 258 259 void 260 usage() 261 { 262 #ifdef KTRUSS 263 # define LONG_OPTION "[-e emulation] [-m maxdata] [-o outfile] " 264 # define SHRT_OPTION "RT" 265 #else 266 # define LONG_OPTION "" 267 # define SHRT_OPTION "" 268 #endif 269 (void)fprintf(stderr, 270 "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", 271 getprogname(), SHRT_OPTION, LONG_OPTION, 272 getprogname(), SHRT_OPTION, LONG_OPTION); 273 exit(1); 274 } 275 276 void 277 no_ktrace(sig) 278 int sig; 279 { 280 (void)fprintf(stderr, 281 "error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'options KTRACE'\n"); 282 exit(1); 283 } 284 285 int 286 do_ktrace(tracefile, ops, trpoints, pid) 287 const char *tracefile; 288 int ops; 289 int trpoints; 290 int pid; 291 { 292 int ret; 293 294 if (!tracefile || strcmp(tracefile, "-") == 0) { 295 int pi[2], dofork, fpid; 296 297 if (pipe(pi) < 0) 298 err(1, "pipe(2)"); 299 fcntl(pi[0], F_SETFD, FD_CLOEXEC|fcntl(pi[0], F_GETFD, 0)); 300 fcntl(pi[1], F_SETFD, FD_CLOEXEC|fcntl(pi[1], F_GETFD, 0)); 301 302 dofork = (pid == getpid()); 303 304 #ifdef KTRUSS 305 if (dofork) 306 fpid = fork(); 307 else 308 fpid = pid; /* XXX: Gcc */ 309 #else 310 if (dofork) 311 fpid = fork(); 312 else 313 fpid = 0; /* XXX: Gcc */ 314 #endif 315 #ifdef KTRUSS 316 if (fpid) 317 #else 318 if (!dofork || !fpid) 319 #endif 320 { 321 if (!dofork) 322 #ifdef KTRUSS 323 ret = fktrace(pi[1], ops, trpoints, fpid); 324 #else 325 ret = fktrace(pi[1], ops, trpoints, pid); 326 #endif 327 else 328 close(pi[1]); 329 #ifdef KTRUSS 330 dumpfile(NULL, pi[0], trpoints); 331 waitpid(fpid, NULL, 0); 332 #else 333 { 334 char buf[512]; 335 int n, cnt = 0; 336 337 while ((n = read(pi[0], buf, sizeof(buf)))>0) { 338 write(1, buf, n); 339 cnt += n; 340 } 341 } 342 if (dofork) 343 _exit(0); 344 #endif 345 return 0; 346 } 347 close(pi[0]); 348 #ifdef KTRUSS 349 if (dofork && !fpid) { 350 ret = fktrace(pi[1], ops, trpoints, getpid()); 351 return 1; 352 } 353 #else 354 ret = fktrace(pi[1], ops, trpoints, pid); 355 #endif 356 } else 357 ret = ktrace(tracefile, ops, trpoints, pid); 358 if (ret < 0) 359 err(1, "%s", tracefile); 360 return 1; 361 } 362