#!/opt/default/bin/perl -w # change the above to whatever your perl v5 binary is. # post2ascii.pl by David Petrou (dpetrou@cs.cmu.edu). this version # written on friday, july 21, 2000. # this script converts Drew Roselli's (drew@cs.berkeley.edu) traces # from http://tracehost.cs.berkeley.edu:traces.html/ to human readable # format. The traces are described in the UC Berkeley Computer # Science Division technical report UCB//CSD-98-1029. # the traces are distributed as gzip'd files even though they may not # have the '.gz' extension. instead of uncompressing the traces, i # run this script like this 'zcat | post2ascii.pl'. zcat may be named # gzcat on your system. # this code adds a new field called global_fid which is a unique # number per dev and fid combination. # usage: # post2ascii.pl [-p|-v|-n] < tracefile # -p = print concise output # -v = print verbose output # -n = use names for things like syscalls, etc. # Note: you need -p or -v for anything to be output if you don't have # anything in the user provided function # the function "user_provided_function" is called for every line of # the trace. here you can put your filtering and printing logic. # scroll down and check it out. use strict; use Getopt::Long; use constant true => 1; use constant false => 0; use constant UNKNOWN_FILE => -9; my $progname = $0; my %syscall_name_map = ( 1 => "EXIT", 2 => "FORK", 3 => "SREAD", 4 => "SWRITE", 5 => "OPEN", 6 => "CLOSE", 8 => "CREAT", 9 => "LINK", 10 => "UNLINK", 11 => "EXECV", 12 => "CHDIR", 15 => "CHMOD", 16 => "CHOWN", 19 => "LSEEK", 21 => "SMOUNT", 22 => "UMOUNT", 30 => "UTIME", 33 => "ACCESS", 36 => "SYNC", 38 => "STAT", 40 => "LSTAT", 41 => "DUP", 55 => "REBOOT", 56 => "SYMLINK", 58 => "RDLINK", 59 => "EXECVE", 61 => "CHROOT", 62 => "FCNTL", 66 => "VFORK", 71 => "MMAP", 73 => "MUNMAP", 90 => "DUP2", 92 => "FSTAT", 95 => "FSYNC", 120 => "READV", 121 => "WRITEV", 123 => "FCHOWN", 124 => "FCHMOD", 128 => "RENAME", 129 => "TRUNC", 130 => "FTRUNC", 136 => "MKDIR", 137 => "RMDIR", 155 => "LOCKF", 178 => "LSYNC", 195 => "GETDIRENTRIES", 198 => "VFSMOUNT", 235 => "GETACL", 236 => "FGETACL", 237 => "SETACL", 238 => "FSETACL", 249 => "GETACCESS", 250 => "FSCTL", 267 => "TSYNC", 272 => "FCHDIR", ); my %arg_template_map = ( "NullArgs" => "", "DevFid" => "NN", "TruncArgs" => "NNN", "CloseArgs" => "NNN", "ReadWriteArgs" => "NNNN", "LockfArgs" => "NNNN", "ForkArgs" => "NN", "OpenArgs" => 'N' x 12, ); my %syscall_arg_map; map { $syscall_arg_map{$_} = "NullArgs" } ( "EXIT", "SYNC", "REBOOT", "LSYNC" ); map { $syscall_arg_map{$_} = "DevFid" } ( "MUNMAP", "FSTAT", "FSYNC", "FCHDIR", "FCHOWN", "FCHMOD", "GETDIRENTRIES", "FGETACL", "FSETACL", "MMAP", "TSYNC", "SMOUNT", "UNLINK", "EXECV", "CHDIR", "CHMOD", "CHOWN", "UMOUNT", "UTIME", "ACCESS", "STAT", "LSTAT", "RDLINK", "VFSMOUNT", "EXECVE", "CHROOT", "MKDIR", "RMDIR", "GETACL", "SETACL", "GETACCESS", "LINK", "RENAME", "SYMLINK" ); map { $syscall_arg_map{$_} = "TruncArgs" } ( "TRUNC", "FTRUNC" ); map { $syscall_arg_map{$_} = "CloseArgs" } ( "CLOSE" ); map { $syscall_arg_map{$_} = "ReadWriteArgs" } ( "SREAD", "READV", "SWRITE", "WRITEV" ); map { $syscall_arg_map{$_} = "LockfArgs" } ( "LOCKF" ); map { $syscall_arg_map{$_} = "ForkArgs" } ( "FORK", "VFORK" ); map { $syscall_arg_map{$_} = "OpenArgs" } ( "OPEN", "CREAT" ); my %closemode_map = ( 1 => "CLOSE_HOST", 2 => "CLOSE_PS", 3 => "CLOSE_DESC", ); my %lockf_function_map = ( 0 => "LOCKF_ULOCK", 1 => "LOCKF_LOCK", 2 => "LOCKF_TLOCK", 3 => "LOCKF_TEST", ); my %ftype_map = ( 1 => "FTYPE_REG", 2 => "FTYPE_DIR", 5 => "FTYPE_SYMLINK", 10 => "FTYPE_EMPTYDIR", ); my %fstype_map = ( 1 => "FSTYPE_UFS", 2 => "FSTYPE_NFS", 3 => "FSTYPE_DUX", ); my %mode_map = ( 0000000 => "RDONLYMODE", # not in drew's C sources 0000001 => "WRONLYMODE", 0000002 => "RDWRMODE", # not in drew's C sources 0000010 => "APPENDMODE", 0000400 => "CREATMODE", 0001000 => "TRUNCMODE", 0000003 => "ACCMODE", # why is this in here? it's the rdwr mask ); use vars qw { %reverse_mode_map $rdwr_mask }; foreach my $key (keys %mode_map) { $reverse_mode_map{$mode_map{$key}} = $key; } $rdwr_mask = $reverse_mode_map{"RDONLYMODE"} | $reverse_mode_map{"WRONLYMODE"} | $reverse_mode_map{"RDWRMODE"}; use vars qw( $packed_header $packed_args $read_return ); use vars qw( $syscall_arg_type $header_template $signize_header_template $header_length $arg_template $signize_arg_template $num_args ); use vars qw( $time $last_time $host_id $user_id $process_id $syscall $syscall_name $arg_len @args $fid $dev $global_fid $size $closemode $closemode_name $offset $bytes $lockf_function $lockf_function_name $fpid $childFlag $fd $ftype $ftype_name $fstype $fstype_name $uid $nlink $ctime $mtime $atime $mode $mode_name ); use vars qw ( %dev_fid_map $next_global_fid $dev_fid_key ); use vars qw ( $command_arg_print_simple $command_arg_print_verbose $command_arg_use_names ); use vars qw ( $num_mode_bits $mode_bit_template $all_modes @all_modes_vec ); ###################################################################### ## user_provided_function ###################################################################### sub user_provided_function { # here's where you put your filtering and printing code. an example # is provided. these are the variables that are defined for you to # use: $time, $host_id, $user_id, $process_id, $syscall, # $syscall_name, $fid, $dev, $global_fid, $size, $closemode, # $closemode_name, $offset, $bytes, $lockf_function, # $lockf_function_name, $fpid, $childFlag, $fd, $ftype, $ftype_name, # $fstype, $fstype_name, $uid, $nlink, $ctime, $mtime, $atime, $mode, # $mode_name. variables ending in "_name" are textual representations # of the variable without this suffix. # this example prints out a line for just reads to known files. if(($syscall_name ne "SREAD") && ($syscall_name ne "READV")) { return; } if($fid == UNKNOWN_FILE) { return; } print "$time $global_fid $offset $bytes\n"; } $header_template = 'NNNNnn'; $signize_header_template = 'iiiiss'; $header_length = (4 * 4) + (2 * 2); $num_mode_bits = 32; $mode_bit_template = 'b' x $num_mode_bits; $all_modes = 0; foreach my $key (keys %mode_map) { $all_modes |= $key; } $next_global_fid = 0; $last_time = 0; &parse_args; while(1) { $read_return = read STDIN, $packed_header, $header_length; die "couldn't read header" if(!defined($read_return)); last if($read_return == 0); die "bad header read" if($read_return != $header_length); ($time, $host_id, $user_id, $process_id, $syscall, $arg_len) = unpack($header_template, $packed_header); # this signize stuff is to turn values into 32-bit signed # integers. without doing this, they are unsigned. you'll see # this below for arguments as well. $packed_header = pack $signize_header_template, $time, $host_id, $user_id, $process_id, $syscall, $arg_len; ($time, $host_id, $user_id, $process_id, $syscall, $arg_len) = unpack($signize_header_template, $packed_header); # turns out traced times sometimes go negative. negating them # seems to be the right thing. die "bad time (negative): $time" # if($time < 0); if($time < 0) { $time = -$time; } die "bad time (decreased): $time" if($time < $last_time); $last_time = $time; die "bad host_id (negative): $host_id" if($host_id < 0); die "bad user_id (negative): $time" if($user_id < 0); die "bad process_id (negative): $process_id" if($process_id < 0); die "bad syscall_num (negative): $syscall" if($syscall < 0); $syscall_name = $syscall_name_map{$syscall}; die "bad syscall_num (non-existent): $syscall" if(!defined($syscall_name)); die "bad syscall_num (not elided): $syscall" if(($syscall_name eq "LSEEK") || ($syscall_name eq "DUP") || ($syscall_name eq "DUP2") || ($syscall_name eq "FCNTL") || ($syscall_name eq "FSCTL")); die "bad arg_len (negative): $arg_len" if($arg_len < 0); # following works even if $arg_len is 0... $read_return = read STDIN, $packed_args, $arg_len; die "couldn't read args" if(!defined($read_return)); die "bad args read" if($read_return != $arg_len); $syscall_arg_type = $syscall_arg_map{$syscall_name}; $arg_template = $arg_template_map{$syscall_arg_type}; $num_args = length $arg_template; @args = unpack($arg_template, $packed_args); $signize_arg_template = ""; for(my $i = 0; $i < $num_args; $i++) { if(substr($arg_template, $i, 1) eq 'N') { $signize_arg_template .= 'i'; } elsif(substr($arg_template, $i, 1) eq 'n') { $signize_arg_template .= 's'; } else { die "shouldn't happen."; } } $packed_args = pack $signize_arg_template, @args; @args = unpack($signize_arg_template, $packed_args); # now let's extract arguments if(($syscall_arg_type eq "DevFid") || ($syscall_arg_type eq "TruncArgs") || ($syscall_arg_type eq "CloseArgs") || ($syscall_arg_type eq "ReadWriteArgs") || ($syscall_arg_type eq "LockfArgs") || ($syscall_arg_type eq "OpenArgs")) { $dev = $args[0]; $fid = $args[1]; $dev_fid_key = $dev . $fid; if(!defined($dev_fid_map{$dev_fid_key})) { $dev_fid_map{$dev_fid_key} = $next_global_fid; $next_global_fid++; } $global_fid = $dev_fid_map{$dev_fid_key}; } if($syscall_arg_type eq "TruncArgs") { $size = $args[2] } if($syscall_arg_type eq "CloseArgs") { $closemode = $args[2]; $closemode_name = $closemode_map{$closemode}; die "bad closemode: $closemode" if(!defined($closemode_name)); } if($syscall_arg_type eq "ReadWriteArgs") { $offset = $args[2]; $bytes = $args[3]; } if($syscall_arg_type eq "LockfArgs") { $lockf_function = $args[2]; $lockf_function_name = $lockf_function_map{$lockf_function}; if(!defined($lockf_function_name)) { # put this here because i was getting values like 1536 and 1792 $lockf_function_name = "LOCKF_UNKNOWN"; } $size = $args[3]; } if($syscall_arg_type eq "ForkArgs") { $fpid = $args[0]; $childFlag = $args[1]; } if($syscall_arg_type eq "OpenArgs") { $fd = $args[2]; $ftype = $args[3]; $ftype_name = $ftype_map{$ftype}; die "bad ftype: $ftype" if(!defined($ftype_name)); $fstype = $args[4]; $fstype_name = $fstype_map{$fstype}; die "bad fstype: $fstype" if(!defined($fstype_name)); $uid = $args[5]; $size = $args[6]; $nlink = $args[7]; $ctime = $args[8]; $mtime = $args[9]; $atime = $args[10]; my $int_mode = $args[11]; $mode = sprintf("0%o", $int_mode); my $just_access_mode = $rdwr_mask & $int_mode; if(($just_access_mode != $reverse_mode_map{"RDONLYMODE"}) && ($just_access_mode != $reverse_mode_map{"WRONLYMODE"}) && ($just_access_mode != $reverse_mode_map{"RDWRMODE"})) { # i want to die here, and remove ACCMODE from above, but # the traces contain ACCMODE for some reason. # die "mode # $mode is open for too many things"; } $mode_name = ""; $mode_name .= $mode_map{$just_access_mode}; my $just_mode_options = (~$rdwr_mask) & $int_mode; foreach my $key (keys %mode_map) { if($just_mode_options & $key) { $mode_name .= "|$mode_map{$key}"; $just_mode_options &= (~$key); } } if($just_mode_options != 0) { # needed to put this here because i got 02401 $mode_name .= "UNKNOWN_MODE"; } } # now let's print stuff if($command_arg_print_simple || $command_arg_print_verbose) { use vars qw ( $print_syscall $print_closemode $print_lockf_function $print_ftype $print_fstype $print_mode ); $print_syscall = ($command_arg_use_names ? $syscall_name : $syscall); print "$time $host_id $user_id $process_id $print_syscall" if($command_arg_print_simple); print "t=$time, hid=$host_id, uid=$user_id, pid=$process_id, " ."sys=$print_syscall" if($command_arg_print_verbose); if(($syscall_arg_type eq "DevFid") || ($syscall_arg_type eq "TruncArgs") || ($syscall_arg_type eq "CloseArgs") || ($syscall_arg_type eq "ReadWriteArgs") || ($syscall_arg_type eq "LockfArgs") || ($syscall_arg_type eq "OpenArgs")) { print " $dev $fid $global_fid" if($command_arg_print_simple); print ", dev=$dev, fid=$fid, gfid=$global_fid" if($command_arg_print_verbose); } if($syscall_arg_type eq "TruncArgs") { print " $size" if($command_arg_print_simple); print ", size=$size" if($command_arg_print_verbose); } if($syscall_arg_type eq "CloseArgs") { $print_closemode = ($command_arg_use_names ? $closemode_name : $closemode); print " $print_closemode" if($command_arg_print_simple); print ", cmod=$print_closemode" if($command_arg_print_verbose); } if($syscall_arg_type eq "ReadWriteArgs") { print " $offset $bytes" if($command_arg_print_simple); print ", ofst=$offset, byts=$bytes" if($command_arg_print_verbose); } if($syscall_arg_type eq "LockfArgs") { $print_lockf_function = ($command_arg_use_names ? $lockf_function_name : $lockf_function); print " $lockf_function $size" if($command_arg_print_simple); print ", lckf=$lockf_function, siz=$size" if($command_arg_print_verbose); } if($syscall_arg_type eq "ForkArgs") { print " $fpid $childFlag" if($command_arg_print_simple); print ", fpd=$fpid, cFlg=$childFlag" if($command_arg_print_verbose); } if($syscall_arg_type eq "OpenArgs") { $print_ftype = ($command_arg_use_names ? $ftype_name : $ftype); $print_fstype = ($command_arg_use_names ? $fstype_name : $fstype); $print_mode = ($command_arg_use_names ? $mode_name : $mode); print " $fd $print_ftype $print_fstype $uid $size $nlink $ctime " . "$mtime $atime $print_mode" if($command_arg_print_simple); print ", fd=$fd, ftyp=$print_ftype, fstp=$print_fstype, uid=$uid, " . "siz=$size, nlnk=$nlink, ctm=$ctime, mtm=$mtime, " . "atm=$atime, mode=$print_mode" if($command_arg_print_verbose); } print "\n"; } &user_provided_function; } sub parse_args { use vars qw( $opt_p $opt_v $opt_n ); $Getopt::Long::ignorecase = false; if(&GetOptions("p", "v", "n") == false) { &usage; } $command_arg_print_simple = $opt_p; $command_arg_print_verbose = $opt_v; $command_arg_use_names = $opt_n; &usage if(@ARGV != 0); } sub usage { print "usage: $progname [-p|-v|-n|-f] < tracefile\n"; print "Options:\n"; print " -p print concise output\n"; print " -v print verbose output\n"; print " -n if printing, print names for things like syscalls\n"; print "Note: you need -p or -v for anything to be output if you don't\n" . "have anything in the user provided function.\n"; exit; }