joes@sbcs.UUCP (Joseph Simonetti) (06/12/85)
In response to the postings I made to net.unix and net.unix-wizards concerning my System Call Trace Facility, I have received an overwhelming number of requests for my source code. I have therefore decided to post it to net.sources and net.unix-wizards. Anyone interested in the technical report which describes this package may obtain a copy by sending mail to (...!sbcs!kathy). Ask for TR # 85/13 and be sure to include your U.S. mailing address. For those of yo who sent me specific questions and comments, I hope to respond to each of you individually, please be patient. #--------CUT---------CUT---------CUT---------CUT--------# ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting README: sed 's/^Z//' >README <<\STUNKYFLUFF Z To install the systrace call the following files must be Zmodified or created. Z Note that all diffs were done using diff -c. Z Z/sys/sys/h/proc.h Add the following lines to the definitions of Z process flags in /sys/sys/h/proc.h Z Z #define SYSTRACE 0x0080000 Z #define CHILDTRACE 0x2000000 Z Z/sys/sys/kern_fork.c Add code which passes on the SYSTRACE Z and CHILDTRACE flags to newly created Z processes. Use the diffs in the file Z kern_fork.c Z Z/sys/vax/trap.c Add tests which invoke the entrytrace and Z exittrace routines on entry to and exit from Z the kernel during the performance of a system call. Z Use the diffs in the file sys-vax-trap.c Z Z/sys/sys/syscalls.c Add the character string "systrace" to the Z syscallnames table. Use the diffs located Z in the file syscalls.c, these modifications Z update the names of the system calls. Z Z/sys/sys/init_sysent.c Add the function definition int systrace() Z to the definitions of the other system call Z routines. Z Add the function name systrace with Z three arguments to the sysent table. Use the Z diffs in init_sysent.c Z Zsys-h-trace.h This is a new file which is copied into /sys/sys/h Z and contains the definitions for the parameters Z which are to be passed to the systrace call. Z Z/sys/sys/kern_trace.c The code which implements the functions systrace(), Z entrytrace() and exittrace(). Copy the file Z kern_trace.c into /sys/sys/kern_trace.c Z Z/sys/conf/files Add the line Z Z sys/kern_trace.c standard Z Z to this file. Z Z After the kernel changes proper have been made, you must Zthen create an entrypoint for systrace in the standard C library Zby following the instructions shown below. Z ZPlace the file systrace.c into the directory /usr/src/lib/libc/vax/sys. Z Z/usr/include/syscalls.h Add #define SYS_systrace 151 Z ZIn the file /usr/src/lib/libc/vax/sys/Makefile add Zsystrace.o to OBJECTS Z ZDo a cd into /usr/src/lib/libc/vax/sys and type "make systrace.o". ZCopy systrace.o into the /lib directory. Z ZDo a cd to /lib and issue the following commands Z Z ar q libc.a systrace.o Z ranlib libc.a Z Z You may now compile trace.c Z Z Move the executable to /etc/trace. Manual pages documenting Zthe systrace system call and usage of trace.c reside in the files Zsystrace.2 and trace.8 respectively. Z STUNKYFLUFF set `sum README` if test 39267 != $1 then echo README: Checksum error. Is: $1, should be: 39267. fi # # echo Extracting init_sysent.c: sed 's/^Z//' >init_sysent.c <<\STUNKYFLUFF Z*** /sys/sys/init_sysent.c Sun Sep 25 21:06:36 1983 Z--- init_sysent.c Sun Mar 17 16:58:40 1985 Z*************** Z*** 60,65 Z Z /* 2.4 processes */ Z int ptrace(); Z Z /* 2.5 terminals */ Z Z Z--- 60,66 ----- Z Z /* 2.4 processes */ Z int ptrace(); Z+ int systrace(); /* JDS systrace system call */ Z Z /* 2.5 terminals */ Z Z*************** Z*** 262,266 Z 2, setquota, /* 148 = quota */ Z 4, qquota, /* 149 = qquota */ Z 3, getsockname, /* 150 = getsockname */ Z }; Z int nsysent = sizeof (sysent) / sizeof (sysent[0]); Z Z--- 263,268 ----- Z 2, setquota, /* 148 = quota */ Z 4, qquota, /* 149 = qquota */ Z 3, getsockname, /* 150 = getsockname */ Z+ 3, systrace, /* 151 = systrace JDS */ Z }; Z int nsysent = sizeof (sysent) / sizeof (sysent[0]); STUNKYFLUFF set `sum init_sysent.c` if test 34563 != $1 then echo init_sysent.c: Checksum error. Is: $1, should be: 34563. fi # # echo Extracting kern_fork.c: sed 's/^Z//' >kern_fork.c <<\STUNKYFLUFF Z*** /sys/sys/kern_fork.c Fri Jul 29 10:07:18 1983 Z--- kern_fork.c Wed May 15 11:48:36 1985 Z*************** Z*** 132,137 Z rpp->p_stat = SIDL; Z timerclear(&rpp->p_realtimer.it_value); Z rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG)); Z if (isvfork) { Z rpp->p_flag |= SVFORK; Z rpp->p_ndx = rip->p_ndx; Z Z--- 132,139 ----- Z rpp->p_stat = SIDL; Z timerclear(&rpp->p_realtimer.it_value); Z rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG)); Z+ if (rip->p_flag & CHILDTRACE) Z+ rpp->p_flag = rpp->p_flag | SYSTRACE | CHILDTRACE; Z if (isvfork) { Z rpp->p_flag |= SVFORK; Z rpp->p_ndx = rip->p_ndx; STUNKYFLUFF set `sum kern_fork.c` if test 23257 != $1 then echo kern_fork.c: Checksum error. Is: $1, should be: 23257. fi # # echo Extracting kern_trace.c: sed 's/^Z//' >kern_trace.c <<\STUNKYFLUFF Z#include "../h/param.h" Z#include "../h/systm.h" Z#include "../h/dir.h" Z#include "../h/user.h" Z#include "../h/inode.h" Z#include "../h/fs.h" Z#include "../h/kernel.h" Z#include "../h/acct.h" Z#include "../h/nami.h" Z#include "../h/uio.h" Z#include "../h/proc.h" Z#include "../h/systrace.h" Z#include "../sys/syscalls.c" /* table of printable system call names */ Z Zstruct sysent sysent[]; /* contains argument counts for each call */ Zint nsysent; /* number of system calls defined */ Z Z Zstruct inode *tracep = NULL; Zstruct inode *savtracep = NULL; Zint tracesuspend = 2; /* % free space where tracing is suspended */ Zint traceresume = 4; /* % free space where tracing is resumed */ Z Z#define BUFSIZE 132 Z#define TMPSIZE 55 Z Zstruct { Z char line[BUFSIZE]; /* buffer for current log entry */ Z int length, /* current length of line in characters */ Z locked, /* lock flag to prevent buffer overwrite */ Z wanted; /* flag used to indicate desire to lock */ Z unsigned long bot, /* time when log file was opened */ Z mytime, /* when last elapsed time entry was written */ Z delta; /* timespan between generation of elapsed */ Z /* time entries in the trace log. */ Z } tbuf = { "\n", 0, 0, 0, }; Z Zsystrace() Z Z{ Z register struct inode *ip; Z struct proc *pfind(), *procptr; Z register struct a { Z int function; Z int pid; Z char *fname; Z } *uap = (struct a *) u.u_ap; Z Z if (suser ()) Z switch (uap->function) { Z case FILESPEC: Z if (savtracep) { Z tracep = savtracep; Z savtracep = NULL; Z } Z if (uap -> fname == NULL) { Z if (ip = tracep) { Z tlock(); Z tbuf.length = 1; Z strapp("> > >------------------ Log closed at " ); Z dumptime( time.tv_sec - tbuf.bot ); Z strapp(" ------------------< < <\n" ); Z logentry(); Z irele (ip); Z tracep = NULL; Z tunlock(); Z } Z return; Z } Z u.u_dirp = (caddr_t) uap->fname; Z ip = namei (uchar, LOOKUP, 1); Z if (ip == NULL) Z return; Z if ((ip -> i_mode & IFMT) != IFREG) { Z u.u_error = EACCES; Z iput (ip); Z return; Z } Z if (tracep && (tracep -> i_number != ip -> i_number || Z tracep -> i_dev != ip -> i_dev)) Z irele (tracep); Z tracep = ip; Z iunlock (ip); Z tbuf.mytime = time.tv_sec; tbuf.bot = time.tv_sec; Z if (uap->pid < 0) Z tbuf.delta = 0L; Z else Z tbuf.delta = (unsigned long) uap->pid; Z break; Z case ALL: Z case PIDONLY: Z case CHILDONLY: Z if (tracep == NULL && savtracep == NULL) { Z u.u_error = ENOENT; Z return; Z } Z procptr = pfind( uap->pid ); Z if (procptr == 0) { Z u.u_error = ESRCH; Z return; Z } Z if (uap->function == ALL || uap->function == PIDONLY) Z procptr->p_flag | = SYSTRACE; Z if (uap->function == ALL || uap->function == CHILDONLY) Z procptr->p_flag | = CHILDTRACE; Z break; Z case TRACEOFF: Z procptr = pfind( uap->pid ); Z if (procptr == 0) { Z u.u_error = ESRCH; Z return; Z } Z procptr->p_flag & = ~( SYSTRACE | CHILDTRACE ); Z break; Z default: Z u.u_error = EINVAL; Z } Z} Z Ztlock() Z Z{ Z while (tbuf.locked) { Z tbuf.wanted = 1; Z sleep ((caddr_t) &tbuf, PLOCK); Z } Z tbuf.locked = 1; Z} Z Ztunlock() Z Z{ Z tbuf.locked = 0; Z if (tbuf.wanted) { Z tbuf.wanted = 0; Z wakeup( (caddr_t) &tbuf); Z } Z} Z Zentrytrace( code, nargs ) Z Zunsigned code, nargs; Z Z{ Z register int i; Z char *cp; Z Z tlock(); Z timelog(); Z tbuf.length = 1; Z decout( u.u_procp->p_pid); Z strapp( " Call "); Z Z if (code >= nsysent) { Z strapp( "Undefined "); Z decout( code ); Z } Z else Z strapp( syscallnames[code] ); Z Z cp = " ( "; Z for (i= 0; i < nargs; i++) { Z strapp( cp ); Z dumparg( code, i ); Z cp = ", "; Z } Z if (i) Z strapp( " )" ); Z logentry(); Z tunlock(); Z} Z Zdumparg( code, argno ) Z Zunsigned code, argno; Z Z/* In special cases dump out the character string passed to Zthe system call, otherwise use the heuristic routine dumparg. */ Z Z{ Z switch (code) { Z Zcase 33: /* access */ Zcase 51: /* acct */ Zcase 12: /* chdir */ Zcase 15: /* chmod */ Zcase 16: /* chown */ Zcase 61: /* chroot */ Zcase 8: /* creat */ Zcase 59: /* execve */ Zcase 40: /* lstat */ Zcase 136: /* mkdir */ Zcase 14: /* mknod */ Zcase 5: /* open */ Zcase 58: /* readlink */ Zcase 137: /* rmdir */ Zcase 18: /* stat */ Zcase 85: /* swapon */ Zcase 129: /* truncate */ Zcase 22: /* umount */ Zcase 10: /* unlink */ Zcase 138: /* utimes */ Z if (argno == 0) { Z strout( argno, 0 ); Z return; Z } Z break; Zcase 9: /* link */ Zcase 21: /* mount */ Zcase 128: /* rename */ Zcase 148: /* setquota */ Zcase 57: /* symlink */ Z if (argno < 2) { Z strout( argno, 0 ); Z return; Z } Z break; Zcase 101: /* send */ Zcase 133: /* sendto */ Zcase 4: /* write */ Z if (argno == 1 ) { Z strout( argno, u.u_arg[2] ); Z return; Z } Z break; Zcase 54: /* ioctl, output second argument in hex only */ Z if (argno == 1 ) { Z hexout( u.u_arg[argno] ); Z return; Z } Z break; Z } Z /* otherwise use rules of thumb to format the argument */ Z numout( u.u_arg[argno] ); Z} Z Zexittrace(code, nargs) Z Z/* On exit output the arguments based on the system call or the Zvalue of u.u_error if nonzero */ Z Zunsigned code, nargs; Z Z{ Z if (code == 59 && u.u_error == 0) Z return; /* don't log successful execve */ Z tlock(); Z timelog(); Z tbuf.length = 1; Z decout( u.u_procp->p_pid); Z if (code >= nsysent) { Z strapp(" Undefined "); Z decout( code ); Z } Z else { Z strapp( " "); Z strapp( syscallnames[code] ); Z } Z strapp( " returns "); Z Z if (u.u_error) { Z strapp( "Error "); Z decout( u.u_error ); Z } Z else Z switch (code) { Z case 87: /* gethostname */ Z if (u.u_arg[1] > 0) Z strout( 0, 0 ); Z break; Z case 3: /* read */ Z case 58: /* readlink */ Z case 102: /* recv */ Z case 125: /* recvfrom */ Z if (u.u_r.r_val1 > 0) { Z decout( u.u_r.r_val1 ); Z strapp( " byte(s) : "); Z strout( 1, u.u_r.r_val1 ); Z } else Z numout( u.u_r.r_val1 ); Z break; Z default: Z numout( u.u_r.r_val1 ); Z } Z logentry(); Z tunlock(); Z} Z Ztimelog() Z Z/* Write a record containing the elapsed time since the log file Zwas opened. An entry is written if more than tbuf.delta seconds Zhave passed since the writing of the last elapsed time record. ZIf tbuf.delta is zero then no elapsed time entries are written. */ Z Z{ Z if (! tbuf.delta) Z return; Z if (time.tv_sec - tbuf.mytime >= tbuf.delta) { Z tbuf.mytime = time.tv_sec; Z tbuf.length = 1; Z strapp( "> > >------------------------- "); Z dumptime( tbuf.mytime - tbuf.bot ); Z strapp( " -------------------------< < <"); Z logentry(); Z } Z} Z Zdumptime( tmp ) Z Z/* Output the time as an ascii string hh:mm:ss */ Z Zunsigned long tmp; Z Z{ Z if (tmp / 3600 < 10) Z strapp( "0" ); Z decout( tmp / 3600 ); Z tmp % = 3600; Z strapp( ":" ); Z if (tmp / 60 < 10) Z strapp( "0" ); Z decout( tmp / 60 ); Z strapp( ":" ); Z if (tmp % 60 < 10) Z strapp( "0" ); Z decout( tmp % 60 ); Z} Z Zlogentry() Z Z{ Z register int i,error, usave; Z register struct inode *ip; Z register struct fs *fs; Z off_t siz; Z register char *ap = tbuf.line; Z Z if (savtracep) { Z fs = savtracep->i_fs; Z if (freespace(fs, fs->fs_minfree + traceresume) > 0) { Z tracep = savtracep; Z savtracep = NULL; Z printf("Tracing resumed\n"); Z } Z } Z if ((ip = tracep) == NULL) Z return; Z fs = tracep->i_fs; Z if (freespace(fs, fs->fs_minfree + tracesuspend) <= 0) { Z savtracep = tracep; Z tracep = NULL; Z printf("Tracing suspended\n"); Z return; Z } Z ilock(ip); Z siz = ip->i_size; Z usave = u.u_error; /* save user status */ Z u.u_error = 0; /* zero u.u_error to fake out rdwri */ Z error = Z rdwri(UIO_WRITE, ip, (caddr_t)ap, strlen(tbuf.line), siz, Z 1, (int *)0); Z u.u_error = usave; /* resture user status */ Z if (error) Z itrunc(ip, (u_long)siz); Z iunlock(ip); Z} Z Zstrout( argno, maxlen ) Z Z/* Copy a string into the trace buffer. The address of the first Zbyte is taken from u.u_arg[argno]. Z If the maximum length is given as zero then copying will Zterminate when a \0 is reached. Z If the maximum length is given as nonvero then the number Zof bytes copied will be the minimum of maxlen and TMPSIZE - 1. Z In all cases, copying will stop if a memory fault is Zencountered. */ Z Zunsigned argno; Zint maxlen; Z Z{ Z caddr_t ptr; Z int s,c; Z char tmp[TMPSIZE], *tptr = tmp; Z Z ptr = (caddr_t)u.u_arg[argno]; Z Z if (maxlen == 0 || maxlen > TMPSIZE - 1) Z s = TMPSIZE - 1; Z else Z s = maxlen; Z Z do { Z c = fubyte( ptr++ ); Z if (c == 0 && maxlen == 0 || c == -1) break; Z Z /* change newlines and tabs to blanks, all other ctrl to ? */ Z Z if (c == '\t') c = ' '; Z if (c == '\n') c = ' '; Z if (c < ' ' || c > 127) c = '?'; Z Z *tptr++ = c; Z s--; Z } while ( s > 0 ); Z *tptr = '\0'; Z strapp( "\"" ); Z strapp( tmp ); Z strapp( "\"" ); Z} Z Znumout( num ) Z Z/* append the number num to the input string. Conditionally output Zdecimal, hex or both representations based on the value of num. Z -1..DECLIMIT -> decimal only Z DECLIMIT..BOTHLIMIT OR < -1 -> decimal and hex Z > BOTHLIMIT -> hex only Z*/ Z Zint num; Z Z#define DECLIMIT 100 Z#define BOTHLIMIT 50000 Z{ Z int n; Z Z n = num; Z if (n < 0) Z n = -n; Z if (n <= BOTHLIMIT || num < -1) Z decout( num ); Z if (n > DECLIMIT && n <= BOTHLIMIT || num < -1) Z strapp( "/ "); Z if (n > DECLIMIT || num < -1) Z hexout( num ); Z} Z Zhexout( n ) Z Zunsigned n; Z Z{ Z int d; Z char tmp[20], *tptr = tmp; Z Z strapp( "Ox", 0); Z do { Z d = n & 15; Z *tptr++ = d + (d<10 ? '0' : 'a' - 10); Z n = n >> 4; Z } while (n != 0); Z *tptr = '\0'; Z reverse( tmp ); Z strapp( tmp ); Z} Z Zdecout( n ) Z Zint n; Z Z{ Z int d; Z char tmp[20], *tptr; Z Z if (n<0) { Z n = -n; Z strapp( "-" ); Z }; Z if (n == 0) { Z strapp( "0" ); Z return; Z } Z for (tptr = tmp; n != 0; n = n / 10) { Z d = n % 10; Z *tptr++ = d + '0'; Z } Z *tptr = '\0'; Z reverse( tmp ); Z strapp( tmp ); Z} Z Zreverse( str ) Z Zchar str[]; Z Z{ Z int c, i, j; Z Z for (i = 0, j = strlen( str ) - 1; i < j; i++, j-- ) { Z c = str[i]; Z str[i] = str[j]; Z str[j] = c; Z } Z} Z Zstrapp( str ) Z Z/* append str to the trace buffer, stop when the trace buffer is full Zor the end of str is reached. */ Z Zchar *str; Z Z{ Z int i = 0; Z Z while ( str[i] && tbuf.length < BUFSIZE ) Z tbuf.line [tbuf.length++] = str[i++]; Z tbuf.line [tbuf.length] = '\0'; Z} STUNKYFLUFF set `sum kern_trace.c` if test 45468 != $1 then echo kern_trace.c: Checksum error. Is: $1, should be: 45468. fi # # echo Extracting makeshar: sed 's/^Z//' >makeshar <<\STUNKYFLUFF Zcat <<XXX Z#--------CUT---------CUT---------CUT---------CUT--------# Z######################################################### Z# # Z# This is a shell archive file. To extract files: # Z# # Z# 1) Make a directory for the files. # Z# 2) Write a file, such as "file.shar", containing # Z# this archive file into the directory. # Z# 3) Type "sh file.shar". Do not use csh. # Z# # Z######################################################### ZXXX Zfor i in $* Zdo Z cat <<XXX Z# Z# Zecho Extracting $i: Zsed 's/^Z//' >$i <<\\STUNKYFLUFF ZXXX Z sed 's/^/Z/' $i Z set `sum $i` Z cat <<XXX ZSTUNKYFLUFF Zset \`sum $i\` Zif test $1 != \$1 Zthen Zecho $i: Checksum error. Is: \$1, should be: $1. Zfi ZXXX Zdone Zecho echo ALL DONE BUNKY! Zecho exit 0 STUNKYFLUFF set `sum makeshar` if test 02365 != $1 then echo makeshar: Checksum error. Is: $1, should be: 02365. fi # # echo Extracting sys-h-systrace.h: sed 's/^Z//' >sys-h-systrace.h <<\STUNKYFLUFF Z#define FILESPEC 0 Z#define ALL 1 Z#define PIDONLY 2 Z#define CHILDONLY 3 Z#define TRACEOFF 4 Z STUNKYFLUFF set `sum sys-h-systrace.h` if test 37681 != $1 then echo sys-h-systrace.h: Checksum error. Is: $1, should be: 37681. fi # # echo Extracting sys-vax-trap.c: sed 's/^Z//' >sys-vax-trap.c <<\STUNKYFLUFF Z*** /sys/vax/trap.c.orig Mon Mar 11 10:58:54 1985 Z--- sys-vax-trap.c Tue May 28 18:06:56 1985 Z*************** Z*** 221,226 Z u.u_dirp = (caddr_t)u.u_arg[0]; Z u.u_r.r_val1 = 0; Z u.u_r.r_val2 = locr0[R1]; Z if (setjmp(&u.u_qsave)) { Z if (u.u_error == 0 && u.u_eosys == JUSTRETURN) Z u.u_error = EINTR; Z Z--- 221,230 ----- Z u.u_dirp = (caddr_t)u.u_arg[0]; Z u.u_r.r_val1 = 0; Z u.u_r.r_val2 = locr0[R1]; Z+ Z+ if (u.u_procp->p_flag & SYSTRACE) /* JDS */ Z+ entrytrace( code, callp->sy_narg ); /* JDS */ Z+ Z if (setjmp(&u.u_qsave)) { Z if (u.u_error == 0 && u.u_eosys == JUSTRETURN) Z u.u_error = EINTR; Z*************** Z*** 265,270 Z locr0[R1] = u.u_r.r_val2; Z } Z done: Z p = u.u_procp; Z if (p->p_cursig || ISSIG(p)) Z psig(); Z Z--- 269,278 ----- Z locr0[R1] = u.u_r.r_val2; Z } Z done: Z+ if (u.u_procp->p_flag & SYSTRACE && /* JDS */ Z+ code != 139 ) /* do not record the */ Z+ /* getdprop return */ Z+ exittrace(code, callp-> sy_narg); /* JDS */ Z p = u.u_procp; Z if (p->p_cursig || ISSIG(p)) Z psig(); STUNKYFLUFF set `sum sys-vax-trap.c` if test 49652 != $1 then echo sys-vax-trap.c: Checksum error. Is: $1, should be: 49652. fi # # echo Extracting syscalls.c: sed 's/^Z//' >syscalls.c <<\STUNKYFLUFF Z*** /sys/sys/syscalls.c Fri Jul 29 10:07:21 1983 Z--- syscalls.c Fri May 3 17:22:16 1985 Z*************** Z*** 42,48 Z "old ftime", /* 35 = old ftime */ Z "sync", /* 36 = sync */ Z "old kill", /* 37 = old kill */ Z! "#38 -- 4.1a select", /* 38 = nosys */ Z "old setpgrp", /* 39 = old setpgrp */ Z "lstat", /* 40 = lstat */ Z "dup", /* 41 = dup */ Z Z--- 42,48 ----- Z "old ftime", /* 35 = old ftime */ Z "sync", /* 36 = sync */ Z "old kill", /* 37 = old kill */ Z! "4.1a select", /* 38 = nosys */ Z "old setpgrp", /* 39 = old setpgrp */ Z "lstat", /* 40 = lstat */ Z "dup", /* 41 = dup */ Z*************** Z*** 49,55 Z "pipe", /* 42 = pipe */ Z "old times", /* 43 = old times */ Z "old profil - nosys", /* 44 = old profil */ Z! "#45", /* 45 = nosys */ Z "old setgid", /* 46 = old setgid */ Z "getgid", /* 47 = getgid */ Z "old signal", /* 48 = old sig */ Z Z--- 49,55 ----- Z "pipe", /* 42 = pipe */ Z "old times", /* 43 = old times */ Z "old profil - nosys", /* 44 = old profil */ Z! "old times", /* 45 = nosys */ Z "old setgid", /* 46 = old setgid */ Z "getgid", /* 47 = getgid */ Z "old signal", /* 48 = old sig */ Z*************** Z*** 53,60 Z "old setgid", /* 46 = old setgid */ Z "getgid", /* 47 = getgid */ Z "old signal", /* 48 = old sig */ Z! "#49", /* 49 = reserved for USG */ Z! "#50", /* 50 = reserved for USG */ Z "acct", /* 51 = turn acct off/on */ Z "old phys - nosys", /* 52 = old set phys addr */ Z "old lock - nosys", /* 53 = old lock in core */ Z Z--- 53,60 ----- Z "old setgid", /* 46 = old setgid */ Z "getgid", /* 47 = getgid */ Z "old signal", /* 48 = old sig */ Z! "#49 - reserved", /* 49 = reserved for USG */ Z! "#50 - reserved", /* 50 = reserved for USG */ Z "acct", /* 51 = turn acct off/on */ Z "old phys - nosys", /* 52 = old set phys addr */ Z "old lock - nosys", /* 53 = old lock in core */ Z*************** Z*** 66,73 Z "execve", /* 59 = execve */ Z "umask", /* 60 = umask */ Z "chroot", /* 61 = chroot */ Z! "#62", /* 62 = nosys */ Z! "#63", /* 63 = used internally */ Z "getpagesize", /* 64 = getpagesize */ Z "mremap", /* 65 = mremap */ Z "vfork", /* 66 = vfork */ Z Z--- 66,73 ----- Z "execve", /* 59 = execve */ Z "umask", /* 60 = umask */ Z "chroot", /* 61 = chroot */ Z! "fstat", /* 62 = nosys */ Z! "#63 - used internally",/* 63 = used internally */ Z "getpagesize", /* 64 = getpagesize */ Z "mremap", /* 65 = mremap */ Z "vfork", /* 66 = vfork */ Z*************** Z*** 88,94 Z "getpgrp", /* 81 = getpgrp */ Z "setpgrp", /* 82 = setpgrp */ Z "setitimer", /* 83 = setitimer */ Z! "#84", /* 84 = nosys */ Z "old swapon", /* 85 = old swapon */ Z "getitimer", /* 86 = getitimer */ Z "gethostname", /* 87 = gethostname */ Z Z--- 88,94 ----- Z "getpgrp", /* 81 = getpgrp */ Z "setpgrp", /* 82 = setpgrp */ Z "setitimer", /* 83 = setitimer */ Z! "wait", /* 84 = nosys */ Z "old swapon", /* 85 = old swapon */ Z "getitimer", /* 86 = getitimer */ Z "gethostname", /* 87 = gethostname */ Z*************** Z*** 109,115 Z "recv", /* 102 = recv */ Z "socketaddr", /* 103 = socketaddr */ Z "bind", /* 104 = bind */ Z! "#105", /* 105 = nosys */ Z "listen", /* 106 = listen */ Z "old vtimes", /* 107 = old vtimes */ Z "sigvec", /* 108 = sigvec */ Z Z--- 109,115 ----- Z "recv", /* 102 = recv */ Z "socketaddr", /* 103 = socketaddr */ Z "bind", /* 104 = bind */ Z! "setsockopt", /* 105 = nosys */ Z "listen", /* 106 = listen */ Z "old vtimes", /* 107 = old vtimes */ Z "sigvec", /* 108 = sigvec */ Z*************** Z*** 122,128 Z #ifdef TRACE Z "vtrace", /* 115 = vtrace */ Z #else Z! "#115", /* 115 = nosys */ Z #endif Z "gettimeofday", /* 116 = gettimeofday */ Z "getrusage", /* 117 = getrusage */ Z Z--- 122,128 ----- Z #ifdef TRACE Z "vtrace", /* 115 = vtrace */ Z #else Z! "#115 - nosys", /* 115 = nosys */ Z #endif Z "gettimeofday", /* 116 = gettimeofday */ Z "getrusage", /* 117 = getrusage */ Z*************** Z*** 126,132 Z #endif Z "gettimeofday", /* 116 = gettimeofday */ Z "getrusage", /* 117 = getrusage */ Z! "#118", /* 118 = nosys */ Z "resuba", /* 119 = resuba */ Z "readv", /* 120 = readv */ Z "writev", /* 121 = writev */ Z Z--- 126,132 ----- Z #endif Z "gettimeofday", /* 116 = gettimeofday */ Z "getrusage", /* 117 = getrusage */ Z! "getsockopt", /* 118 = nosys */ Z "resuba", /* 119 = resuba */ Z "readv", /* 120 = readv */ Z "writev", /* 121 = writev */ Z*************** Z*** 155,161 Z "getrlimit", /* 144 = getrlimit */ Z "setrlimit", /* 145 = setrlimit */ Z "killpg", /* 146 = killpg */ Z! "#147", /* 147 = nosys */ Z "setquota", /* 148 = setquota */ Z "qquota", /* 149 = qquota */ Z "getsockname", /* 150 = getsockname */ Z Z--- 155,161 ----- Z "getrlimit", /* 144 = getrlimit */ Z "setrlimit", /* 145 = setrlimit */ Z "killpg", /* 146 = killpg */ Z! "#147 - nosys", /* 147 = nosys */ Z "setquota", /* 148 = setquota */ Z "qquota", /* 149 = qquota */ Z "getsockname", /* 150 = getsockname */ Z*************** Z*** 159,162 Z "setquota", /* 148 = setquota */ Z "qquota", /* 149 = qquota */ Z "getsockname", /* 150 = getsockname */ Z }; Z Z--- 159,163 ----- Z "setquota", /* 148 = setquota */ Z "qquota", /* 149 = qquota */ Z "getsockname", /* 150 = getsockname */ Z+ "systrace", /* 151 = systrace JDS */ Z }; STUNKYFLUFF set `sum syscalls.c` if test 26350 != $1 then echo syscalls.c: Checksum error. Is: $1, should be: 26350. fi # # echo Extracting systrace.2: sed 's/^Z//' >systrace.2 <<\STUNKYFLUFF Z.TH SYSTRACE 2 "18 March 1985" Z.UC 4 Z.SH NAME Zsystrace \- system call trace Z.SH SYNOPSIS Z.nf Z.ft B Z#include <sys/systrace.h> Z.PP Z.ft B Zsystrace(function, pid, name) Zint function, pid; Zchar *name; Z.fi Z.SH DESCRIPTION Z.I Systrace Zallows the superuser to selectively enable/disable the generation Zof a human readable log of the system calls made by any process. ZOptionally, periodic entries of the elapsed time between Zthe opening of the log file Zand the current time may be included in the log. The minimum Znumber of seconds between the elapsed time entries is specified Zwhen the log file is opened. Z.PP ZTwo records are written to the log file for each system call made Zby a traced process. ZThe first record contains the process-id of the traced process Zfollowed by the name of the system call and its arguments. ZArguments are formatted in a manner consistant with the particular Zsystem call. ZThe second record contains the process-id of the traced process Zfollowed by the name of the system call and the result returned Zto the user or an appropriate error status. ZFor system calls such as Z.I read Zthe actual data read will also be output to the log. Z.PP ZCharacter strings are enclosed in double quotes. ZNewline and tab characters are output as one space, control characters Zand bytes whose value exceeds 127 decimal are output as question Zmarks. ZNote that the number of characters displayed is necessarily limited Zin length. Z.PP ZIntegers from negative one to one-hundred inclusive are output Zas decimal numbers. ZIntegers greater than one-hundred but less than or equal to 50000 are Zoutput in decimal and in hexadecimal. ZIn all other cases only the hexadecimal format is used. ZThe heuristic used for integer output has proven useful in eliminating Zredundant and sometimes nonsensical data from the log without Zthe use of an inordinate number of special cases in the implementation. Z.PP ZThe Z.I function Zparameter is specified as one of the following values. Z.PP Z.RS Z FILESPEC Specify log filename Z PIDONLY Trace only the specified process Z ALL Trace the process and future children Z CHILDONLY Trace only future children Z TRACEOFF Stop tracing the specified process Z.RE Z.PP ZIf the function parameter is FILESPEC, then Z.I Pid Zspecifies the minimum number of seconds between the output of elapsed Ztime entries to the logfile. A value of zero will disable this Zfeature. Z.I Name Zis the pathname of the log file to open or NULL if the log file Zis to be closed. Note that when the log file is closed a record Zis written to the log which shows the Zelapsed time since the log file was opened. ZAlso note that closing the log file is a fast way to Zdisable the tracing of all traced processes in an emergency. Z.SH "RETURN VALUE ZIf the call succeeds a value of 0 is returned. If the call Zfails, then a value of \-1 is returned and an error code is Zplaced in the global location \fIerrno\fP. Z.SH "ERRORS ZThe specified action is taken unless one of the following are true: Z.TP 15 Z[EPERM] ZThe caller was not the super-user. Z.TP 15 Z[EINVAL] ZAn invalid function code was specified. Z.TP 15 Z[ENOENT] ZThe function code was FILESPEC and the named file did not exist. Z.TP 15 Z[ENOENT] ZThe function code was ALL, PIDONLY or CHILDONLY and no log file was Zopened by a previous call to systrace. Z.TP 15 Z[ESRCH] ZThe specified process id was not found. Z.SH BUGS ZOn return from Z.I fork Zand Z.I vfork Zthe value output to the log for the child process is nonzero since Zreturn values are obtained from the address space of the parent Z(calling) process. Z.SH SEE ALSO Ztrace(8) Z.SH AUTHOR ZJoseph D. Simonetti STUNKYFLUFF set `sum systrace.2` if test 40821 != $1 then echo systrace.2: Checksum error. Is: $1, should be: 40821. fi # # echo Extracting systrace.c: sed 's/^Z//' >systrace.c <<\STUNKYFLUFF Z/* systrace.c 4.2 SUNYSB change by J. Simonetti 03/20/85 */ Z#include "SYS.h" Z ZSYSCALL(systrace) Z ret STUNKYFLUFF set `sum systrace.c` if test 51684 != $1 then echo systrace.c: Checksum error. Is: $1, should be: 51684. fi # # echo Extracting trace.8: sed 's/^Z//' >trace.8 <<\STUNKYFLUFF Z.TH TRACE 8 "19 March 1985" Z.UC 4 Z.SH NAME Ztrace \- log system calls on a per-process basis Z.SH SYNOPSIS Z.B /etc/trace Z.B \-f Zlogfilename Z[ interval ] Z.PP Z.B /etc/trace Z.B \-p Zprocess-id Z.PP Z.B /etc/trace Z.B \-c Zprocess-id Z.PP Z.B /etc/trace Z.B \-a Zprocess-id Z.PP Z.B /etc/trace Z.B \-o Zprocess-id Z.PP Z.B /etc/trace Z.B -f Z.PP Z.B /etc/trace command arg1 arg2 ... Z.SH DESCRIPTION Z.I Trace Zuses the Z.I systrace(2) Zsystem call to control the logging of system calls made by selected Zprocesses to a user specified trace file. Z.PP ZThe Z.B \-f Zoption is used to specify the name of a file to which the system Zcall trace is to be written and an optional value giving the minimum Ztime in seconds between which records indicating the elapsed Ztime relative to when the log file was opened are Zinserted in the log. ZIf the interval is omitted then no elapsed time entries are placed Zin the log. ZIf the Z.B \-f Zoption is given without a filename then the trace file is closed Zand logging is suspended. Z.PP ZThe Z.B \-p \-c Zand Z.B \-a Zoptions enable tracing of the specified process-id only, any Zfuture children it may create or the process and its future children Zrespectively. ZThe Z.B \-o Zoption turns off tracing for the specified process only. Z.PP ZA trace of a particular unix command can be Zmade by giving the unix command line as the arguments to Z.B /etc/trace. Z.SH "SEE ALSO" Zsystrace(2) Z.SH AUTHOR ZJoseph D. Simonetti STUNKYFLUFF set `sum trace.8` if test 05748 != $1 then echo trace.8: Checksum error. Is: $1, should be: 05748. fi # # echo Extracting trace.c: sed 's/^Z//' >trace.c <<\STUNKYFLUFF Z/* This is the source code for the /etc/trace command as Zdescribed in trace(8) */ Z Z#include <stdio.h> Z#include <sys/time.h> Z#include <sys/file.h> Z#include <errno.h> Z#include <sys/systrace.h> Z Zmain(argc, argv) Z Zint argc; Zchar *argv[]; Z Z{ Z int flag, status, c, interval; Z long pid, getpid(); Z Z if (argc < 2) { Z fprintf( stderr, "%s requires at least one argument\n" Z , argv[0] ); Z exit(1); Z } Z Z if (argv[1][0] == '-') Z c = argv[1][1]; Z else { Z pid = getpid(); Z status = systrace( ALL, (int) pid, 0); Z if (status) { Z fprintf( stderr, "systrace call unsuccessful\n"); Z exit(-1); Z } Z status = execvp( argv[1], &argv[1] ); Z perror("exec error :"); Z exit(1); Z } Z Z switch (c) { Z Zcase 'f': Z if (argc >= 3) { Z if (argc == 3) Z interval = 0; Z else Z interval = atoi( &argv[3][0] ); Z openlog( argv[2], interval ); Z } Z else { Z fprintf( stderr, "Closing log file.\n" ); Z status = systrace( FILESPEC, 0, NULL ); Z } Z break; Zcase 'a': Zcase 'p': Zcase 'c': Zcase 'o': Z pid = atoi( &argv[2][0] ); Z if (c == 'a') Z flag = ALL; Z else if (c == 'p') Z flag = PIDONLY; Z else if (c == 'c') Z flag = CHILDONLY; Z else flag = TRACEOFF; Z Z switch (flag) { Z case ALL: fprintf( stderr, "Enabling trace on process %d"); Z fprintf( stderr, " and all future children\n" ); Z break; Z case PIDONLY: fprintf( stderr, "Enabling trace on process %d only\n" Z , pid ); Z break; Z case CHILDONLY: fprintf( stderr, "Enabling trace on future children "); Z fprintf( stderr, "of process %d\n", pid ); Z break; Z case TRACEOFF: fprintf( stderr, "Disabling trace on process %d" Z , pid ); Z fprintf( stderr, " and all future children\n" ); Z break; Z default: fprintf( stderr, "INTERNAL error in %s\n", argv[0] ); Z exit( -1 ); Z } Z Z status = systrace( flag, pid, 0); Z break; Zdefault: Z fprintf(stderr, "%s : invalid option\n",argv[1]); Z exit(-1); Z } Z Z if (status) { Z fprintf( stderr, "systrace call unsuccessful\n"); Z exit(-1); Z } Z exit(0); Z} Z Zopenlog( filename, interval ) Z Zchar *filename; Zint interval; Z Z{ Z struct timeval tp; Z char *st; Z FILE *fp; Z int nbytes, status; Z Z fprintf( stderr, "Opening log file "); Z if (interval) { Z fprintf( stderr, "with minimum elapsed time entries "); Z fprintf( stderr, "every %d seconds\n", interval ); Z } else Z fprintf( stderr, "with elapsed time entries disabled\n" ); Z Z fp = fopen( filename, "w" ); Z if (fp == NULL) { Z perror( filename ); Z exit(-1); Z } Z Z gettimeofday( &tp, NULL ); Z Z st = ctime( &tp.tv_sec ); Z st[24] = '\0'; Z fprintf( fp, "> > >---------- Log opened on %s ----------< < <", st); Z fclose( fp ); Z Z status = systrace( FILESPEC, interval, filename ); Z if (status) { Z fprintf( stderr, "systrace error opening log file\n" ); Z exit(-1); Z } Z} STUNKYFLUFF set `sum trace.c` if test 37197 != $1 then echo trace.c: Checksum error. Is: $1, should be: 37197. fi echo ALL DONE BUNKY! exit 0