diff -u --new-file -r strace-4.2/Makefile.in strace-4.2-ioctldefs/Makefile.in
--- strace-4.2/Makefile.in	Sat Nov 27 20:56:12 1999
+++ strace-4.2-ioctldefs/Makefile.in	Thu Apr 20 11:31:37 2000
@@ -50,7 +50,8 @@
 ALL_SUBDIRS = test linux linux/alpha linux/powerpc sunos4 svr4
 OBJ = strace.o version.o syscall.o util.o \
 	desc.o file.o ipc.o io.o ioctl.o mem.o net.o process.o bjm.o \
-	resource.o signal.o sock.o system.o term.o time.o proc.o stream.o
+	resource.o signal.o sock.o system.o term.o time.o proc.o stream.o \
+	ioctldefs.o
 
 all: strace
 
@@ -104,3 +105,4 @@
 system.o: system.c defs.h config.h
 time.o: time.c defs.h config.h
 util.o: util.c defs.h config.h
+ioctldefs.o: defs.h
diff -u --new-file -r strace-4.2/README-ioctl.defs strace-4.2-ioctldefs/README-ioctl.defs
--- strace-4.2/README-ioctl.defs	Wed Dec 31 19:00:00 1969
+++ strace-4.2-ioctldefs/README-ioctl.defs	Thu Apr 20 22:06:48 2000
@@ -0,0 +1,101 @@
+Ioctl.Defs Functionality in Strace
+==================================
+
+Tom Rothamel <tom-10975@onegeek.org>
+
+The -I <file> option causes strace to interprate the file given as a
+list of ioctl names and a list of commands for printing the structure
+pointed to by the third argument of the corresponding ioctl. This
+helps the debugging of ioctl calls in programs.
+
+Each line of the file should consist of one of the following.
+- An ioctl name, as printed out by strace, followed by a format string
+  used to print out the ioctl. (This can look something like
+  "SNDCTL_DSP_GETOSPACE dddd".)
+- A line beginning with a '#', marking a comment. ("# Comment")
+- A blank line.
+
+Invalid lines will cause a warning message to be printed at load
+time. Invalid format codes will cause a warning message to be printed
+at run time.
+
+The table that follows is the list of data printing commands. Each
+entry contains a short description of the output format, as well as
+which data types this is useful for.
+
+d	Print out a normal-size integer as a decimal number. (int)
+ld	Print out a long integer as a decimal number. (long)
+x	Print out a normal-size integer as a hex number. (int)
+lx	Print out a long integer as a hex number. (long)
+h	Print out a short integer as a decimal number. (short)
+C	Print out a char as a decimal integer. (char)
+c	Print out a char as a character code. (char)
+p	Print out a pointer. (void *, foo *, bar **, etc...)
+s	Print out a string pointed to by a char *. (char *)
+<num>S	Print out a string array in this structure of length num.
+	(char string[<num>])
+{	Start the definition of a sub-structure that will be printed 
+	provided the pointer to it is not NULL. The definition ends
+	with a '}'. Please note that this is only used for pointers to
+	structures... complete structures should be included in the
+	structure definition.
+-	Disable the automatic insertion of padding to the
+	command list. Normally, strace will try to take into account the
+	alignment restrictions on structure members imposed by your
+	processor/compiler. If this is given, these padding bytes will
+	need to be inserted manually using the '_' command. This will
+	need to be repeated in each sub-structure definition. ({} pair.)
++	Re-enable the automatic insertion of padding into the command 
+	list.
+_	Insert a byte of padding. This should only be used if the
+	automatic insertion of padding is turned off.
+[	Prints a literal '[', useful for indicating the start of included
+	arrays.
+]	Prints a literal ']', useful for indicating the end of included 
+	arrays.
+
+For example, if NEW_IOCTL takes a struct foo, and the following
+definitions are in the appropriate header:
+
+	struct bar {
+		int a;
+		int b;
+	};
+
+	struct foo {
+		char *name;
+		char id[20];
+		struct bar bar1;
+		struct bar *bar2;
+		struct bar *bar3;
+	};
+
+then in the ioctl.defs file one should place.
+
+	NEW_IOCTL s20Sii{ii}{ii}
+
+
+h2ioctldefs.pl
+==============
+
+Included in this distribution is a perl script, h2ioctldefs.pl, that 
+attempts to convert a header file from the linux kernel distribution
+into an ioctl.defs file. It's quite limited in what it can convert,
+but it still provides a fairly decent first shot at conversion.
+
+It takes two arguments. The first is a c file that includes the header
+and everything needed to compile it, the second is the h file
+itself. h2ioctldefs first uses pstruct to scan the files for
+structures that may be used by the ioctls, then it looks for _IOW,
+_IOR, and _IOWR definition that indicate ioctls. It then outputs a
+file in the appropriate format.
+
+
+ioctl.defs.oss-sound
+====================
+
+This is a sample ioctl.defs file, that includes information for the
+OSS sound ioctls under Linux.
+
+
+For more information, please email Tom Rothamel <tom-10975@onegeek.org>
\ No newline at end of file
diff -u --new-file -r strace-4.2/defs.h strace-4.2-ioctldefs/defs.h
--- strace-4.2/defs.h	Thu Dec 23 10:08:17 1999
+++ strace-4.2-ioctldefs/defs.h	Thu Apr 20 11:31:37 2000
@@ -290,6 +290,7 @@
 extern int nprocs;
 extern int max_strlen;
 extern struct tcb *tcp_last;
+extern int ioctldef_wanted;
 
 #ifdef __STDC__
 #define P(args) args
@@ -350,6 +351,9 @@
 extern int sock_ioctl P((struct tcb *, long, long));
 extern int proc_ioctl P((struct tcb *, int, int));
 extern int stream_ioctl P((struct tcb *, int, int));
+
+extern int ioctldef_dump P((struct tcb *, long, long));
+extern void ioctldef_load P((char *));
 
 extern void tv_tv P((struct timeval *, int, int));
 extern int tv_nz P((struct timeval *));
diff -u --new-file -r strace-4.2/h2ioctldefs.pl strace-4.2-ioctldefs/h2ioctldefs.pl
--- strace-4.2/h2ioctldefs.pl	Wed Dec 31 19:00:00 1969
+++ strace-4.2-ioctldefs/h2ioctldefs.pl	Thu Apr 20 17:27:50 2000
@@ -0,0 +1,190 @@
+#!/usr/bin/perl -w
+
+# This doesn't handle properly:
+# - Arrays of structs.
+# - Unsigned numbers. (It converts to signed.)
+# - Bitfields.
+#
+# Occasionally, pstruct can't figure out what type a type is. In that case,
+# padding is emitted to skip the member.
+
+sub getsmcode {
+	my $type = shift;
+	my $number = shift;
+	my $totsize = shift;
+	my $name = shift;
+
+	# We don't support unsigned, so remove it now.
+	$type =~ s/unsigned//g;
+	$type =~ s/signed//g;
+
+	# Now, fix the spacing again,
+	$type =~ s/^\s+//;
+	$type =~ s/\s+$//;
+	$type =~ s/\s+/ /g;
+
+	if ($type eq "char" && $number > 0) {
+		return $number . "S";
+	}
+
+	my $code;
+
+	if ($type =~ /struct (\w+)$/) {
+		if ($number > 1) {
+			print STDERR "Warning: Handling $name:\n";
+			print STDERR "Warning: Arrays of struct $1 don't work right.\n";
+		}
+		return ""; # We'll pick up the members later.
+	}
+
+	if ($type eq "char *") {
+		$code = 's';
+	} elsif ($type =~ /\*/) {
+		$code = 'p';
+	} elsif ($type eq "long long int") {
+		$code = 'ld';
+	} elsif ($type eq "long long") {
+		$code = 'ld';
+	} elsif ($type eq "long int") {
+		$code = 'ld';
+	} elsif ($type eq "long") {
+		$code = 'ld';
+	} elsif ($type eq "short int") {
+		$code = 'h';
+	} elsif ($type eq "short") {
+		$code = 'h';
+	} elsif ($type eq "int") {
+		$code = 'd';
+	} elsif ($type eq "char") {
+		$code = 'C';
+	} else {
+		print STDERR "Warning: Handling $name:\n";
+		print STDERR "Warning: I don't know how to handle type '$type'.\n";
+		print STDERR "Warning: Replacing with $totsize bytes of padding.\n";
+		return "_" x $totsize;
+	}
+
+	if ($number > 1) {
+		$code = '[' . $code x $number . ']';
+	}
+
+
+	return $code;
+#	print $type, "\n";
+}
+
+my $structfile = $ARGV[0];
+my $ioctlfile = $ARGV[1] || $structfile;
+
+die "Not enough arguments" unless $ioctlfile;
+
+open(PSTRUCT, "pstruct $structfile|") or die "Couldn't open '$structfile'";
+
+my $struct = "not a real struct";
+my %structdefs = ();
+
+while ($_ = <PSTRUCT>) {
+	chomp;
+	
+	if (/^struct (.+) \{/) {
+		$struct = $1;
+#		print STDERR "\n", $struct, "\n";
+		next;
+	}
+
+	if (/^\}/) {
+		$struct = "not a real struct";
+		next;
+	}
+
+	next if $struct eq "complex int";
+	next if $struct eq "not a real struct";
+
+#	print STDERR $_, "\n";
+
+
+	if (/\s+(.*?)\s+([^\s]+)(\[(\d+)\])\s+(\d+)\s+(\d+)$/) {
+		$structdefs{$struct} .= getsmcode($1, $4, $6, $2);
+		next;
+	}
+
+	if (/\s+(.*?)\s+([^\s]+)\s+(\d+)\s+(\d+)$/) {
+		$structdefs{$struct} .= getsmcode($1, 0, $4, $2);
+		next;
+	}
+
+	print STDERR "Warning: Can't handle $_\n";
+}
+
+close PSTRUCT;
+
+open IO, "<$ioctlfile";
+
+
+
+
+sub gotioctl {
+	my $name = shift;
+	my $arg = shift;
+
+	$arg =~ s/struct//;
+	$arg =~ s/^\s+//;
+	$arg =~ s/\s+$//;
+	$arg =~ s/\s+//;
+
+	my $num = 0;
+
+	if ($arg =~ /^(.*)\[(\d+)\]$/) {
+		$arg = $1;
+		$num = $2;
+	}
+	
+	print "# $name takes as an argument $arg\n";
+
+	if (exists $structdefs{$arg}) {
+		$code = $structdefs{$arg};
+		if ($num > 1) {
+			$code = '[' . $code x $num . ']';
+		}
+	} else {
+		$code = getsmcode($arg, $num, 0, $name);
+	}
+
+	print $name, " ", $code, "\n\n";
+
+}
+
+while (<IO>) {
+	chomp;
+
+	next unless (/^\#define/);
+
+	s{/\*.*?\*/}{}g;
+	s/\s+/ /g;
+	s/ $//;
+	s/ \(/\(/g;
+
+	s/(\s+)_SIO/$1_IO/;
+
+#	print $_, "\n";
+	
+	if (/^\#define (\w+) _IOW\([^,]+,[^,]+,([^,]+)\)$/) {
+		gotioctl($1, $2);
+		next;
+	}
+
+	if (/^\#define (\w+) _IOR\([^,]+,[^,]+,([^,]+)\)$/) {
+		gotioctl($1, $2);
+		next;
+	}
+
+	if (/^\#define (\w+) _IOWR\([^,]+,[^,]+,([^,]+)\)$/) {
+		gotioctl($1, $2);
+		next;
+	}
+	       
+
+
+}
+
+
diff -u --new-file -r strace-4.2/ioctl.c strace-4.2-ioctldefs/ioctl.c
--- strace-4.2/ioctl.c	Thu Dec 23 09:20:15 1999
+++ strace-4.2-ioctldefs/ioctl.c	Thu Apr 20 11:31:37 2000
@@ -121,6 +121,11 @@
 	default:
 		break;
 	}
+
+	if (ioctldef_wanted) {
+		return ioctldef_dump(tcp, code, arg);
+	}
+	
 	return 0;
 }
 
diff -u --new-file -r strace-4.2/ioctl.defs.oss-sound strace-4.2-ioctldefs/ioctl.defs.oss-sound
--- strace-4.2/ioctl.defs.oss-sound	Wed Dec 31 19:00:00 1969
+++ strace-4.2-ioctldefs/ioctl.defs.oss-sound	Thu Apr 20 18:03:15 2000
@@ -0,0 +1,296 @@
+# ioctl.defs.sample file
+#
+# This is a useful sample of ioctl.defs. It implements all of the ioctls
+# defined in soundcard.h (That is, the OSS sound control ioctls.) It was
+# created by first running h2ioctldefs.pl on soundcard.h, and then going
+# in manually to look for duplicate name for the ioctls, as well as adding
+# in some of the ioctls that aren't defined using the _SIO macros.
+
+
+# SNDCTL_SYNTH_INFO takes as an argument synth_info
+SNDCTL_SYNTH_INFO 30Sdddddddd[ddddddddddddddddddd]
+
+# SNDCTL_SEQ_CTRLRATE takes as an argument int
+SNDCTL_SEQ_CTRLRATE d
+
+# SNDCTL_SEQ_GETOUTCOUNT takes as an argument int
+SNDCTL_SEQ_GETOUTCOUNT d
+
+# SNDCTL_SEQ_GETINCOUNT takes as an argument int
+SNDCTL_SEQ_GETINCOUNT d
+
+# SNDCTL_SEQ_PERCMODE takes as an argument int
+SNDCTL_SEQ_PERCMODE d
+
+# SNDCTL_FM_LOAD_INSTR takes as an argument sbi_instrument
+SNDCTL_FM_LOAD_INSTR hhd________________________________
+
+# SNDCTL_SEQ_TESTMIDI takes as an argument int
+SNDCTL_SEQ_TESTMIDI d
+
+# SNDCTL_SEQ_RESETSAMPLES takes as an argument int
+SNDCTL_SEQ_RESETSAMPLES d
+
+# SNDCTL_SEQ_NRSYNTHS takes as an argument int
+SNDCTL_SEQ_NRSYNTHS d
+
+# SNDCTL_SEQ_NRMIDIS takes as an argument int
+SNDCTL_SEQ_NRMIDIS d
+
+# SNDCTL_MIDI_INFO takes as an argument midi_info
+SNDCTL_MIDI_INFO 30Sddd[dddddddddddddddddd]
+
+# SNDCTL_SEQ_THRESHOLD takes as an argument int
+SNDCTL_SEQ_THRESHOLD d
+
+# SNDCTL_SYNTH_MEMAVL takes as an argument int
+SNDCTL_SYNTH_MEMAVL d
+
+# SNDCTL_FM_4OP_ENABLE takes as an argument int
+SNDCTL_FM_4OP_ENABLE d
+
+# SNDCTL_SEQ_OUTOFBAND takes as an argument seq_event_rec
+SNDCTL_SEQ_OUTOFBAND 8S
+
+# SNDCTL_SEQ_GETTIME takes as an argument int
+SNDCTL_SEQ_GETTIME d
+
+# SNDCTL_SYNTH_ID takes as an argument synth_info
+SNDCTL_SYNTH_ID 30Sdddddddd[ddddddddddddddddddd]
+
+# SNDCTL_SYNTH_CONTROL takes as an argument synth_control
+SNDCTL_SYNTH_CONTROL d4000S
+
+# SNDCTL_SYNTH_REMOVESAMPLE takes as an argument remove_sample
+SNDCTL_SYNTH_REMOVESAMPLE ddd
+
+# SNDCTL_TMR_TIMEBASE takes as an argument int
+SNDCTL_TMR_TIMEBASE d
+
+# SNDCTL_TMR_TEMPO takes as an argument int
+SNDCTL_TMR_TEMPO d
+
+# SNDCTL_TMR_SOURCE takes as an argument int
+SNDCTL_TMR_SOURCE d
+
+# SNDCTL_TMR_METRONOME takes as an argument int
+SNDCTL_TMR_METRONOME d
+
+# SNDCTL_TMR_SELECT takes as an argument int
+SNDCTL_TMR_SELECT d
+
+# SNDCTL_MIDI_PRETIME takes as an argument int
+SNDCTL_MIDI_PRETIME d
+
+# SNDCTL_MIDI_MPUMODE takes as an argument int
+SNDCTL_MIDI_MPUMODE d
+
+# SNDCTL_MIDI_MPUCMD takes as an argument mpu_command_rec
+SNDCTL_MIDI_MPUCMD 
+
+# SNDCTL_DSP_SPEED takes as an argument int
+SNDCTL_DSP_SPEED d
+
+# SNDCTL_DSP_STEREO takes as an argument int
+SNDCTL_DSP_STEREO d
+
+# SNDCTL_DSP_GETBLKSIZE takes as an argument int
+SNDCTL_DSP_GETBLKSIZE d
+
+# SNDCTL_DSP_CHANNELS takes as an argument int
+SNDCTL_DSP_CHANNELS d
+
+# SOUND_PCM_WRITE_FILTER takes as an argument int
+SOUND_PCM_WRITE_FILTER d
+
+# SNDCTL_DSP_SUBDIVIDE takes as an argument int
+SNDCTL_DSP_SUBDIVIDE d
+
+# SNDCTL_DSP_SETFRAGMENT takes as an argument int
+SNDCTL_DSP_SETFRAGMENT d
+
+# SNDCTL_DSP_GETFMTS takes as an argument int
+SNDCTL_DSP_GETFMTS d
+
+# SNDCTL_DSP_SETFMT takes as an argument int
+SNDCTL_DSP_SETFMT d
+
+# SNDCTL_DSP_GETOSPACE takes as an argument audio_buf_info
+SNDCTL_DSP_GETOSPACE dddd
+
+# SNDCTL_DSP_GETISPACE takes as an argument audio_buf_info
+SNDCTL_DSP_GETISPACE dddd
+
+# SNDCTL_DSP_GETCAPS takes as an argument int
+SNDCTL_DSP_GETCAPS d
+
+# SNDCTL_DSP_GETTRIGGER takes as an argument int
+SNDCTL_DSP_GETTRIGGER d
+
+# SNDCTL_DSP_SETTRIGGER takes as an argument int
+SNDCTL_DSP_SETTRIGGER d
+
+# SNDCTL_DSP_GETIPTR takes as an argument count_info
+SNDCTL_DSP_GETIPTR ddd
+
+# SNDCTL_DSP_GETOPTR takes as an argument count_info
+SNDCTL_DSP_GETOPTR ddd
+
+# SNDCTL_DSP_MAPINBUF takes as an argument buffmem_desc
+SNDCTL_DSP_MAPINBUF pd
+
+# SNDCTL_DSP_MAPOUTBUF takes as an argument buffmem_desc
+SNDCTL_DSP_MAPOUTBUF pd
+
+# SNDCTL_DSP_GETODELAY takes as an argument int
+SNDCTL_DSP_GETODELAY d
+
+# SNDCTL_DSP_PROFILE takes as an argument int
+SNDCTL_DSP_PROFILE d
+
+# SOUND_PCM_READ_RATE takes as an argument int
+SOUND_PCM_READ_RATE d
+
+# SOUND_PCM_READ_CHANNELS takes as an argument int
+SOUND_PCM_READ_CHANNELS d
+
+# SOUND_PCM_READ_BITS takes as an argument int
+SOUND_PCM_READ_BITS d
+
+# SOUND_PCM_READ_FILTER takes as an argument int
+SOUND_PCM_READ_FILTER d
+
+# SNDCTL_COPR_LOAD takes as an argument copr_buffer
+SNDCTL_COPR_LOAD dddd4000S
+
+# SNDCTL_COPR_RDATA takes as an argument copr_debug_buf
+SNDCTL_COPR_RDATA ddddd
+
+# SNDCTL_COPR_RCODE takes as an argument copr_debug_buf
+SNDCTL_COPR_RCODE ddddd
+
+# SNDCTL_COPR_WDATA takes as an argument copr_debug_buf
+SNDCTL_COPR_WDATA ddddd
+
+# SNDCTL_COPR_WCODE takes as an argument copr_debug_buf
+SNDCTL_COPR_WCODE ddddd
+
+# SNDCTL_COPR_RUN takes as an argument copr_debug_buf
+SNDCTL_COPR_RUN ddddd
+
+# SNDCTL_COPR_HALT takes as an argument copr_debug_buf
+SNDCTL_COPR_HALT ddddd
+
+# SNDCTL_COPR_SENDMSG takes as an argument copr_msg
+SNDCTL_COPR_SENDMSG d4000S
+
+# SNDCTL_COPR_RCVMSG takes as an argument copr_msg
+SNDCTL_COPR_RCVMSG d4000S
+
+# SOUND_MIXER_INFO takes as an argument mixer_info
+SOUND_MIXER_INFO 16S32Sd[dddddddddd]
+
+# SOUND_OLD_MIXER_INFO takes as an argument _old_mixer_info
+SOUND_OLD_MIXER_INFO 16S32S
+
+# SOUND_MIXER_ACCESS takes as an argument mixer_record
+SOUND_MIXER_ACCESS 
+
+# SOUND_MIXER_AGC takes as an argument int
+SOUND_MIXER_AGC d
+
+# SOUND_MIXER_3DSE takes as an argument int
+SOUND_MIXER_3DSE d
+
+# SOUND_MIXER_PRIVATE1 takes as an argument int
+SOUND_MIXER_PRIVATE1 d
+
+# SOUND_MIXER_PRIVATE2 takes as an argument int
+SOUND_MIXER_PRIVATE2 d
+
+# SOUND_MIXER_PRIVATE3 takes as an argument int
+SOUND_MIXER_PRIVATE3 d
+
+# SOUND_MIXER_PRIVATE4 takes as an argument int
+SOUND_MIXER_PRIVATE4 d
+
+# SOUND_MIXER_PRIVATE5 takes as an argument int
+SOUND_MIXER_PRIVATE5 d
+
+# SOUND_MIXER_GETLEVELS takes as an argument mixer_vol_table
+SOUND_MIXER_GETLEVELS d32S[dddddddddddddddddddddddddddddddd]
+
+# SOUND_MIXER_SETLEVELS takes as an argument mixer_vol_table
+SOUND_MIXER_SETLEVELS d32S[dddddddddddddddddddddddddddddddd]
+
+# OSS_GETVERSION takes as an argument int
+OSS_GETVERSION d
+
+
+# The following are aliases for some of the ioctls given above.
+SNDCTL_DSP_SAMPLESIZE d
+SOUND_PCM_WRITE_CHANNELS d
+SOUND_PCM_WRITE_BITS d
+SOUND_PCM_WRITE_RATE d
+SOUND_PCM_SUBDIVIDE d
+SOUND_PCM_SETFRAGMENT d
+SOUND_PCM_GETFMTS d
+SOUND_PCM_SETFMT d
+SOUND_PCM_GETOSPACE dddd
+SOUND_PCM_GETISPACE dddd
+SOUND_PCM_GETCAPS d
+SOUND_PCM_GETTRIGGER d
+SOUND_PCM_SETTRIGGER d
+SOUND_PCM_GETIPTR ddd
+SOUND_PCM_GETOPTR ddd
+SOUND_PCM_MAPINBUF pd
+SOUND_PCM_MAPOUTBUF pd
+
+# The following are not defined with the varios _SIO macros, but instead are
+# defined using MIXER_READ and MIXER_WRITE.
+SOUND_MIXER_READ_VOLUME	d
+SOUND_MIXER_READ_BASS d
+SOUND_MIXER_READ_TREBLE d
+SOUND_MIXER_READ_SYNTH d
+SOUND_MIXER_READ_PCM d
+SOUND_MIXER_READ_SPEAKER d
+SOUND_MIXER_READ_LINE d
+SOUND_MIXER_READ_MIC d
+SOUND_MIXER_READ_CD d
+SOUND_MIXER_READ_IMIX d
+SOUND_MIXER_READ_ALTPCM d
+SOUND_MIXER_READ_RECLEV d
+SOUND_MIXER_READ_IGAIN d
+SOUND_MIXER_READ_OGAIN d
+SOUND_MIXER_READ_LINE1 d
+SOUND_MIXER_READ_LINE2 d
+SOUND_MIXER_READ_LINE3 d
+SOUND_MIXER_READ_MUTE d
+SOUND_MIXER_READ_ENHANCE d
+SOUND_MIXER_READ_LOUD d
+SOUND_MIXER_READ_RECSRC d
+SOUND_MIXER_READ_DEVMASK d
+SOUND_MIXER_READ_RECMASK d
+SOUND_MIXER_READ_STEREODEVS d
+SOUND_MIXER_READ_CAPS d
+SOUND_MIXER_WRITE_VOLUME d
+SOUND_MIXER_WRITE_BASS d
+SOUND_MIXER_WRITE_TREBLE d
+SOUND_MIXER_WRITE_SYNTH d
+SOUND_MIXER_WRITE_PCM d
+SOUND_MIXER_WRITE_SPEAKER d
+SOUND_MIXER_WRITE_LINE d
+SOUND_MIXER_WRITE_MIC d
+SOUND_MIXER_WRITE_CD d
+SOUND_MIXER_WRITE_IMIX d
+SOUND_MIXER_WRITE_ALTPCM d
+SOUND_MIXER_WRITE_RECLEV d
+SOUND_MIXER_WRITE_IGAIN d
+SOUND_MIXER_WRITE_OGAIN d
+SOUND_MIXER_WRITE_LINE1 d
+SOUND_MIXER_WRITE_LINE2 d
+SOUND_MIXER_WRITE_LINE3 d
+SOUND_MIXER_WRITE_MUTE d
+SOUND_MIXER_WRITE_ENHANCE d
+SOUND_MIXER_WRITE_LOUD d
+SOUND_MIXER_WRITE_RECSRC d
diff -u --new-file -r strace-4.2/ioctldefs.c strace-4.2-ioctldefs/ioctldefs.c
--- strace-4.2/ioctldefs.c	Wed Dec 31 19:00:00 1969
+++ strace-4.2-ioctldefs/ioctldefs.c	Thu Apr 20 22:04:47 2000
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2000 Tom Rothamel <tom-10979@onegeek.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Changes on 2000-04-20:
+ * - Added out-of-memory checking to malloc, strdup, and realloc calls.
+ * - Added diagnosis of invalid format codes.
+ */
+ 
+
+#include "defs.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <malloc.h>
+
+struct ioctl_dump_info {
+	char *name;
+	char *pspec;
+};
+
+typedef struct ioctl_dump_info IDI;
+
+int idialloc = 0;
+int idinum = 0;
+IDI **iditab = NULL;
+
+/* Safe memory allocation functions */
+
+static char *safe_strdup(char *s) {
+	char *ns;
+
+	ns = strdup(s);
+	if (!ns) {
+		fprintf(stderr, "safe_strdup: out of memory.");
+		exit(-1);
+	}
+
+	return ns;
+}
+
+static void *safe_malloc(size_t size) {
+	void *m;
+
+	m = malloc(size);
+	if (!m) {
+		fprintf(stderr, "safe_malloc: out of memory.");
+		exit(-1);
+	}
+
+	return m;
+}
+
+static void *safe_realloc(void *m, size_t size) {
+
+	m = realloc(m, size);
+	if (!m) {
+		fprintf(stderr, "safe_realloc: out of memory.");
+		exit(-1);
+	}
+
+	return m;
+}
+	
+
+/* Create a new idi, strduping the strings given. */
+IDI *idi_new(name, pspec)
+char *name;
+char *pspec;
+{
+	IDI *idi;
+
+	idi = safe_malloc(sizeof(IDI));
+	idi->name = safe_strdup(name);
+	idi->pspec = safe_strdup(pspec);
+
+	return idi;
+}
+
+/* Frees an idi, and associated strings. */
+void idi_free(idi)
+IDI *idi;
+{
+	free(idi->name);
+	free(idi->pspec);
+	free(idi);
+}
+
+/* Creates a new idi and adds it to the iditab. */
+void idi_add(name, pspec)
+char *name;
+char *pspec;
+{
+	IDI *idi;
+
+	idi = idi_new(name, pspec);
+
+	if (idialloc < idinum + 1) {
+		idialloc = 2 * (idinum + 1);
+		iditab = safe_realloc(iditab, idialloc * sizeof(IDI *));
+	}
+
+	iditab[idinum++] = idi;
+}
+
+/* Compares two idis by name. */
+int idi_compare(idi1, idi2)
+IDI **idi1;
+IDI **idi2;
+{
+	return strcmp((*idi1)->name, (*idi2)->name);
+}
+
+/* Compares a string and an idi. */
+int idi_strcompare(s, idi2)
+char *s;
+IDI **idi2;
+{
+	return strcmp(s, (*idi2)->name);
+}
+
+/* Sort the iditab. */ 
+void iditab_sort()
+{
+	if (!iditab) return;
+	
+	qsort(iditab, idinum, sizeof(IDI *),
+	      (int (*)(const void *, const void *)) idi_compare);
+}
+
+/* Search the iditab. */
+char *iditab_search(s)
+char *s;
+{
+	IDI **idi;
+
+	if (!iditab) return NULL;
+	
+	idi = bsearch(s, iditab, idinum , sizeof(IDI *),
+		      (int (*)(const void *, const void *)) idi_strcompare);
+
+	if (!idi) return NULL;
+
+	return (*idi)->pspec;
+}
+	
+/* Prints the iditab. Really for debugging use only.*/
+void iditab_print()
+{
+	int i;
+
+	for (i = 0; i < idinum; i++) {
+		printf("IDI: %d %p name = %s pspec = %s\n", i, iditab[i], 
+		       iditab[i]->name, iditab[i]->pspec);
+	}
+}
+
+/* Frees the iditab. */
+void iditab_free()
+{
+	int i;
+
+	if (!iditab) return;	
+
+	for (i = 0; i < idinum; i++) {
+		idi_free(iditab[i]);
+	}
+
+	iditab = 0;
+	idialloc = 0;
+	iditab = NULL;
+}
+
+/* Removes comments from the string */
+void iop_strcomment(s)
+char *s;
+{
+	while (*s) {
+		if (*s == '#') {
+			*s = 0;
+			return;
+		}
+
+		s++;
+	}
+}
+
+/* Tries to split a string into parts on whitespace. If it can do so, it
+   returns the second half, and it replaces the first whitespace character
+   with a NUL. Otherwise, it returns NULL. */
+char *iop_strsplit(s)
+char *s;
+{
+	while (*s) {
+		if (isspace(*s)) break;
+		s++;
+	}
+
+	if (!*s) return NULL;
+
+	*s = 0;
+	s++;
+	
+	while (*s) {
+		if (!isspace(*s)) break;
+		s++;
+	}
+
+	if (!*s) return NULL;
+	return s;
+}
+
+/* Removes newilines from a line. */
+void iop_chomp(s)
+char *s;
+{
+	while (*s) {
+		if (*s == '\n') *s = 0;
+		s++;
+	}
+}
+
+/* Load in the file containing the pspecs for the different ioctls. */
+void ioctldef_load(fn)
+char *fn;
+{
+	FILE *f;
+	char buf[256];
+	char *pspec;
+	int line = 0;
+	
+	f = fopen(fn, "r");
+	if (!f) {
+		fprintf(stderr, "Couldn't open ioctl def file '%s'.\n",
+			fn);
+		exit(-1);
+	}
+
+	while (fgets(buf, 256, f)) {
+		line++;
+		iop_chomp(buf);
+		iop_strcomment(buf);
+		pspec = iop_strsplit(buf);
+
+		if (!*buf) continue;
+		if (!pspec) {
+			fprintf(stderr, "%s line %d is invalid.\n", fn, line);
+			continue;
+		}
+		
+		idi_add(buf, pspec);
+	}
+	
+	fclose(f);
+
+	iditab_sort();
+}
+
+/* Prints an int found at addr. fmt is a format string containing a
+   printf-style specifier for an int. */
+void iout_printint(tcp, fmt, addr)
+struct tcb *tcp;
+char *fmt;
+long addr;
+{
+	long i = 0;
+
+	if (umoven(tcp, addr, sizeof(long), (char *) &i) == -1) {
+		tprintf("(err: getting int)");
+		return;
+	}
+
+	tprintf(fmt, i);
+}
+
+/* Ditto the above, but for a short integer rather than an int or long. */
+void iout_shortint(tcp, fmt, addr)
+struct tcb *tcp;
+char *fmt;
+long addr;
+{
+	short i = 0;
+
+	if (umoven(tcp, addr, sizeof(short), (char *) &i) == -1) {
+		tprintf("(err: getting int)");
+		return;
+	}
+
+	tprintf(fmt, i);
+}
+
+/* This prints out a char * and the string that it points to. */
+void iout_charptr(tcp, addr)
+struct tcb *tcp;
+long addr;
+{
+	long straddr;
+
+	if(umoven(tcp, addr, sizeof(char *), (char *) &straddr) == -1) {
+		tprintf("(err: getting char *)");
+		return;
+	}
+
+	if (!straddr) {
+		tprintf("NULL");
+	}
+
+	tprintf("%p = ", (void *) straddr);	
+	printstr(tcp, straddr, -1);
+}
+
+/* This prints out a single character, as per a format. */
+void iout_char(tcp, fmt, addr)
+struct tcb *tcp;
+char *fmt;
+long addr;
+{
+	char i;
+		
+	if (umoven(tcp, addr, sizeof(char), (char *) &i) == -1) {
+		tprintf("(err: getting char)");
+		return;
+	}
+
+	tprintf(fmt, i);
+}
+
+/* The strategy for padding:
+
+   We assume that if we create a structure that has first a single char
+   and then another type, the offset of that second member is the alignment
+   that that type must be at in a structure. Using the alignment, it's simple
+   to calculate the number of padding bytes needed.
+
+   I've only tested this on the ix86, but it works there. (It may break if
+   the compiler used to compile strace and the traced program differs.)
+*/
+
+#define pads(n,t) struct pad_ ## n { char a; t b; }
+
+pads(char, char);
+pads(int, int);
+pads(short, short);
+pads(long, long);
+pads(charptr, char *);
+pads(voidptr, void *);
+
+/* This macro attempts to handle the padding that the compiler puts
+   into structures. Cross fingers and hope it works on your platform. */
+#define pad(n) { \
+	int align; \
+	\
+	if (smartpad) { \
+		align = offsetof(struct pad_ ## n, b); \
+		/* tprintf(" " # n "(%d %ld %ld) ", align, addr % align, align - (addr % align)); */  \
+		if (addr % align) addr += align - (addr % align); \
+	} \
+}
+
+#define reset longf = 0; width = 0
+#define comma if (needcomma++) { tprintf(", "); }
+
+char *iout_runstruct(struct tcb *tcp, char *s, long addr);
+
+/* This runs a printspec on a known-valid structure. All of the
+   formatting codes are defined in the big switch in this function. */
+char *iout_runstr(tcp, s, addr)
+struct tcb *tcp;
+char *s;
+unsigned long addr;
+{
+	int needcomma = 0;
+	int smartpad = 1;
+	int longf = 0;
+	int width = 0;
+	unsigned long naddr;
+	char c;
+	
+	while ((c = *s)) {
+		switch(*s++) {
+		case '+':
+			smartpad = 1;
+			break;
+		case '-':
+			smartpad = 0;
+			break;
+		case '_':
+			addr += 1;
+			break;
+		case 'l':
+			longf = 1;
+			break;
+
+		case 'c':
+			comma;
+			pad(char);
+			iout_char(tcp, "'%c'", addr);
+			addr += 1;
+			reset;
+			break;			
+		case 'C':
+			comma;
+			pad(char);
+			iout_char(tcp, "%d", addr);
+			addr += 1;
+			reset;
+			break;
+		case 'h':
+			comma;
+			pad(short);
+			iout_shortint(tcp, "%hd", addr);
+			addr += sizeof(short int);
+			reset;
+			break;
+		case 'd':
+			comma;
+			if (longf) {
+				pad(long);
+				iout_printint(tcp, "%ld", addr);
+				addr += sizeof(long);
+			} else {
+				pad(int);
+				iout_printint(tcp, "%d", addr);
+				addr += sizeof(int);
+			}
+			reset;
+			break;
+		case 'x':
+			comma;
+			if (longf) {
+				pad(long);
+				iout_printint(tcp, "%#lx", addr);
+				addr += sizeof(long);
+			} else {
+				pad(int);
+				iout_printint(tcp, "%#x", addr);
+				addr += sizeof(int);
+			}
+			reset;				
+			break;
+		case 'p':
+			comma;
+			pad(voidptr);
+			iout_printint(tcp, "%p", addr);
+			addr += sizeof(void *);
+			reset;
+			break;
+		case 's':
+			comma;
+			pad(charptr);
+			iout_charptr(tcp, addr);
+			addr += sizeof(char *);
+			reset;
+			break;
+		case 'S':
+			comma;
+			if (width == 0) {
+				tprintf("(err: no string size)");
+			} else {
+				/* This handles the null-termination for us. */
+				printpathn(tcp, addr, width);
+			}
+			addr += width;
+			reset;
+			break;
+		case '{':
+			comma;
+			pad(voidptr);
+			if (umoven(tcp, addr, sizeof(void *), (char *) &naddr) == -1) {
+				tprintf("(err: couldn't get struct *)");
+				break;
+			}
+			s = iout_runstruct(tcp, s, naddr);
+			addr += sizeof(void *);
+			reset;
+			break;
+		case '}':
+			return s;
+		case '[':
+			comma;
+			needcomma = 0;
+			tprintf("[");
+			break;
+		case ']':
+			tprintf("]");
+			needcomma = 1;
+			break;			
+		default:
+			tprintf("(err: unknown format character '%c'.)", c);
+		}
+
+		if (c >= '0' && c <= '9') {
+			width *= 10;
+			width += (c - '0');
+		}
+	}				
+
+	return s;
+}
+
+/* This checks to see if a structure is valid. If it is (ie. the pointer to
+   it isn't NULL), it prints it. Otherwise, it skips over it in the printspec.
+*/
+char *iout_runstruct(tcp, s, addr)
+struct tcb *tcp;
+char *s;
+long addr;
+{
+	char *rv;
+	int braced;
+	char c;
+	
+	if (addr == 0) {
+		tprintf("NULL");
+
+		braced = 0;
+		while ((c = *s++)) {
+			if (c == '{') {
+				braced++;
+			}
+			if (c == '}') {
+				braced--;
+				if (braced < 0) return s;
+			}
+		}
+
+		return s;
+	}
+
+	tprintf("%#lx = {", addr);
+	rv = iout_runstr(tcp, s, addr);
+	tprintf("}");
+
+	return rv;
+}
+
+
+/* This function looks up the ioctl name in the iditab. If it's there,
+   it dispatches a pointer to the structure to runstruct so that it can
+   be printed according to the printspec. */
+int ioctldef_dump(tcp, dump, arg)
+struct tcb *tcp;
+long dump;
+long arg;
+{
+	char *name;
+	char name_buf[20];
+	char *pspec;
+	
+	if (entering(tcp)) return 0;
+
+	if (!(name = ioctl_lookup(dump))) {
+		sprintf(name_buf, "%#lx", dump);
+		name = name_buf;
+	}
+
+	pspec = iditab_search(name);
+	if (!pspec) return 0;
+
+	tprintf(", ");
+	iout_runstruct(tcp, pspec, tcp->u_arg[2]);
+	
+	return 1;
+}
+
+
diff -u --new-file -r strace-4.2/strace.1 strace-4.2-ioctldefs/strace.1
--- strace-4.2/strace.1	Thu Dec 23 09:20:15 1999
+++ strace-4.2-ioctldefs/strace.1	Thu Apr 20 11:31:37 2000
@@ -66,6 +66,9 @@
 .BI \-u username
 ]
 [
+.BI \-I ioctl-defs-file
+]
+[
 .I command
 [
 .I arg
@@ -436,6 +439,14 @@
 .BR write (2)
 system call which is controlled by the option
 .BR "\-e trace=write" .
+.TP
+.BI "\-I " filename
+This causes strace to read in 
+.I filename
+and use the definitions contained within to print the third argument
+of ioctls. (Please see the file README-ioctl.defs that came with the
+strace distribution for more details, including the format of this
+file.)
 .TP
 .BI "\-o " filename
 Write the trace output to the file
diff -u --new-file -r strace-4.2/strace.c strace-4.2-ioctldefs/strace.c
--- strace-4.2/strace.c	Thu Dec 23 09:20:15 1999
+++ strace-4.2-ioctldefs/strace.c	Thu Apr 20 11:31:37 2000
@@ -70,6 +70,8 @@
 extern char version[];
 extern char **environ;
 
+int ioctldef_wanted = 0;
+
 static struct tcb *pid2tcb P((int pid));
 static int trace P((void));
 static void cleanup P((void));
@@ -137,6 +139,7 @@
 -a column -- alignment COLUMN for printing syscall results (default %d)\n\
 -e expr -- a qualifying expression: option=[!]all or option=[!]val1[,val2]...\n\
    options: trace, abbrev, verbose, raw, signal, read, or write\n\
+-I file -- use information from FILE to print ioctls.\n\
 -o file -- send trace output to FILE instead of stderr\n\
 -O overhead -- set overhead for tracing syscalls to OVERHEAD usecs\n\
 -p pid -- trace process with process id PID, may be repeated\n\
@@ -179,7 +182,7 @@
 	set_sortby(DEFAULT_SORTBY);
 	set_personality(DEFAULT_PERSONALITY);
 	while ((c = getopt(argc, argv,
-		"+cdfFhiqrtTvVxa:e:o:O:p:s:S:u:")) != EOF) {
+		"+cdfFhiqrtTvVxa:e:I:o:O:p:s:S:u:")) != EOF) {
 		switch (c) {
 		case 'c':
 			cflag++;
@@ -228,6 +231,10 @@
 			break;
 		case 'e':
 			qualify(optarg);
+			break;
+		case 'I':
+			ioctldef_load(optarg);
+			ioctldef_wanted = 1;
 			break;
 		case 'o':
 			outfname = strdup(optarg);
