[net.sources] Source Code for the System Call Trace Facility

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