1 /* $NetBSD: ktrace.c,v 1.24 2001/09/02 23:18:01 assar 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.24 2001/09/02 23:18:01 assar 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 *outfile; 90 #ifdef KTRUSS 91 const char *infile; 92 const char *emul_name = "netbsd"; 93 #endif 94 95 clear = NOTSET; 96 append = ops = pidset = inherit = synclog = 0; 97 trpoints = DEF_POINTS; 98 pid = 0; /* Appease GCC */ 99 100 #ifdef KTRUSS 101 # define OPTIONS "aCce:df:g:ilm:o:p:RTt:" 102 outfile = infile = NULL; 103 #else 104 # define OPTIONS "aCcdf:g:ip:st:" 105 outfile = DEF_TRACEFILE; 106 #endif 107 108 while ((ch = getopt(argc,argv, OPTIONS)) != -1) 109 switch((char)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 inherit = 1; 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 'p': 155 pid = rpid(optarg); 156 pidset = 1; 157 break; 158 #ifdef KTRUSS 159 case 'R': 160 timestamp = 2; /* relative timestamp */ 161 break; 162 #else 163 case 's': 164 synclog = 1; 165 break; 166 #endif 167 #ifdef KTRUSS 168 case 'T': 169 timestamp = 1; 170 break; 171 #endif 172 case 't': 173 trpoints = getpoints(optarg); 174 if (trpoints < 0) { 175 warnx("unknown facility in %s", optarg); 176 usage(); 177 } 178 break; 179 default: 180 usage(); 181 } 182 argv += optind; 183 argc -= optind; 184 185 if ((pidset && *argv) || (!pidset && !*argv)) { 186 #ifdef KTRUSS 187 if(!infile) 188 #endif 189 usage(); 190 } 191 192 #ifdef KTRUSS 193 if (infile) { 194 dumpfile(infile, 0, trpoints); 195 exit(0); 196 } 197 198 setemul(emul_name, 0, 0); 199 #endif 200 201 /* 202 * For cleaner traces, initialize malloc now rather 203 * than in a traced subprocess. 204 */ 205 free(malloc(1)); 206 207 if (inherit) 208 trpoints |= KTRFAC_INHERIT; 209 210 (void)signal(SIGSYS, no_ktrace); 211 if (clear != NOTSET) { 212 if (clear == CLEARALL) { 213 ops = KTROP_CLEAR | KTRFLAG_DESCEND; 214 trpoints = ALL_POINTS; 215 pid = 1; 216 } else 217 ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE; 218 219 (void)do_ktrace(outfile, ops, trpoints, pid); 220 exit(0); 221 } 222 223 if (outfile && strcmp(outfile, "-")) { 224 if ((fd = open(outfile, O_CREAT | O_WRONLY | 225 (append ? 0 : O_TRUNC) | (synclog ? 0 : O_SYNC), 226 DEFFILEMODE)) < 0) 227 err(1, "%s", outfile); 228 (void)close(fd); 229 } 230 231 if (*argv) { 232 #ifdef KTRUSS 233 if (do_ktrace(outfile, ops, trpoints, getpid()) == 1) { 234 execvp(argv[0], &argv[0]); 235 err(1, "exec of '%s' failed", argv[0]); 236 } 237 #else 238 (void) do_ktrace(outfile, ops, trpoints, getpid()); 239 execvp(argv[0], &argv[0]); 240 err(1, "exec of '%s' failed", argv[0]); 241 #endif 242 } else 243 (void)do_ktrace(outfile, ops, trpoints, pid); 244 exit(0); 245 } 246 247 int 248 rpid(p) 249 char *p; 250 { 251 static int first; 252 253 if (first++) { 254 warnx("only one -g or -p flag is permitted."); 255 usage(); 256 } 257 if (!*p) { 258 warnx("illegal process id."); 259 usage(); 260 } 261 return(atoi(p)); 262 } 263 264 void 265 usage() 266 { 267 #ifdef KTRUSS 268 # define LONG_OPTION "[-e emulation] [-m maxdata] [-o outfile] " 269 # define SHRT_OPTION "RT" 270 #else 271 # define LONG_OPTION "" 272 # define SHRT_OPTION "" 273 #endif 274 (void)fprintf(stderr, 275 "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", 276 getprogname(), SHRT_OPTION, LONG_OPTION, 277 getprogname(), SHRT_OPTION, LONG_OPTION); 278 exit(1); 279 } 280 281 void 282 no_ktrace(sig) 283 int sig; 284 { 285 (void)fprintf(stderr, 286 "error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'options KTRACE'\n"); 287 exit(1); 288 } 289 290 int 291 do_ktrace(tracefile, ops, trpoints, pid) 292 const char *tracefile; 293 int ops; 294 int trpoints; 295 int pid; 296 { 297 int ret; 298 299 if (!tracefile || strcmp(tracefile, "-") == 0) { 300 int pi[2], dofork, fpid; 301 302 if (pipe(pi) < 0) 303 err(1, "pipe(2)"); 304 fcntl(pi[0], F_SETFD, FD_CLOEXEC|fcntl(pi[0], F_GETFD, 0)); 305 fcntl(pi[1], F_SETFD, FD_CLOEXEC|fcntl(pi[1], F_GETFD, 0)); 306 307 dofork = (pid == getpid()); 308 309 #ifdef KTRUSS 310 if (dofork) 311 fpid = fork(); 312 else 313 fpid = pid; /* XXX: Gcc */ 314 #else 315 if (dofork) 316 fpid = fork(); 317 else 318 fpid = 0; /* XXX: Gcc */ 319 #endif 320 #ifdef KTRUSS 321 if (fpid) 322 #else 323 if (!dofork || !fpid) 324 #endif 325 { 326 if (!dofork) 327 #ifdef KTRUSS 328 ret = fktrace(pi[1], ops, trpoints, fpid); 329 #else 330 ret = fktrace(pi[1], ops, trpoints, pid); 331 #endif 332 else 333 close(pi[1]); 334 #ifdef KTRUSS 335 dumpfile(NULL, pi[0], trpoints); 336 waitpid(fpid, NULL, 0); 337 #else 338 { 339 char buf[512]; 340 int n, cnt = 0; 341 342 while ((n = read(pi[0], buf, sizeof(buf)))>0) { 343 write(1, buf, n); 344 cnt += n; 345 } 346 } 347 if (dofork) 348 _exit(0); 349 #endif 350 return 0; 351 } 352 close(pi[0]); 353 #ifdef KTRUSS 354 if (dofork && !fpid) { 355 ret = fktrace(pi[1], ops, trpoints, getpid()); 356 return 1; 357 } 358 #else 359 ret = fktrace(pi[1], ops, trpoints, pid); 360 #endif 361 } else 362 ret = ktrace(tracefile, ops, trpoints, pid); 363 if (ret < 0) 364 err(1, "%s", tracefile); 365 return 1; 366 } 367