#!/usr/bin/perl require 5.002; use Cwd; use File::Basename; use Getopt::Std; $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/sbin"; my($req_file, $req_name, $req_path, $req_filter); my($trace_number, $trace_pid, $trace_path, $trace_filter); getopts('kqPF') or die __FILE__, " [-kqPF] [] []\n"; $req_file = shift or die "missing argument: \n", __FILE__, " [-kqPF] [] []\n"; ($req_name, $req_path) = fileparse($req_file); if ($req_name ne $req_file) { chdir $req_path; $req_path = cwd."/"; } else { $req_path = ""; } $req_filter = join " ", @ARGV; ($trace_number, $trace_pid, $trace_path, $trace_filter) = scan_ps($req_name); if ($trace_number) { if ($opt_k) { kill('TERM', $trace_pid) or die __FILE__, ": couldn't kill ", $trace_pid, "\n"; $opt_q or print STDERR "killed ", $trace_pid, "\n"; exit; } $req_path = $trace_path unless ($req_path); if ($req_path ne $trace_path) { if ($opt_P) { $opt_q or print STDERR "changing path from: ", $trace_path, "\nto: ", $req_path, "\n"; } else { die __FILE__, ": paths don't match\n", $req_path, " != ", $trace_path, "\n"; } } $req_filter = $trace_filter unless ($req_filter); if ($req_filter ne $trace_filter) { if ($opt_F) { $opt_q or print STDERR "changing filter from:\n", $trace_filter, "\nto:\n", $req_filter, "\n"; } else { die __FILE__, ": filters don't match\n", $req_filter, "\n!=\n", $trace_filter, "\n"; } } start_trace($req_path, $req_name, ++$trace_number, $req_filter); kill('TERM', $trace_pid) or die __FILE__, ": couldn't kill ", $trace_pid, "\n"; } else { die __FILE__, ": no such trace as ", $req_name, "\n" if ($opt_k); $req_path = cwd."/" unless ($req_path); $req_filter or die __FILE__, ": no filter specified\n"; start_trace($req_path, $req_name, 1, $req_filter); } # scan_ps # returns (, , , ) # # runs ps looking for a trace running with the given name. If none is # found returns 0. Otherwise the process info is # returned. If mor than one trace with the given name are found, the # program terminates with an error. # sub scan_ps { my($trace_name) = @_; my($trace_number, $trace_filter, $trace_pid, $trace_path); my($ps_pid, $ps_tt, $ps_stat, $ps_time, $ps_cmd, $ps_cmd1, $ps_cmd2, $ps_cmd3, $ps_cmd4, $ps_filter); my($ps_name, $ps_path, $ps_suffix); open PS, "ps -axww |" or die __FILE__, ": can't run ps\n"; while () { ($ps_pid, $ps_tt, $ps_stat, $ps_time, $ps_cmd, $ps_cmd1, $ps_cmd2, $ps_cmd3, $ps_cmd4, $ps_cmd5, $ps_cmd6, $ps_filter) = split(" ", $_, 12); if ($ps_cmd eq "tcpdump" && $ps_cmd3 eq "-w" && $ps_cmd5 eq "-s" && $ps_cmd6 == "8192") { $ps_cmd6 = 0; ($ps_name, $ps_path, $ps_suffix) = fileparse($ps_cmd4, '-\d+\.trace'); if ($ps_name eq $trace_name && $ps_suffix =~ /-(\d+)\.trace/) { if ($trace_pid) { die __FILE__, ": more than one $trace_name trace running\n"; } $trace_number = $1; $trace_filter = $ps_filter; chomp $trace_filter; $trace_pid = $ps_pid; $trace_path = $ps_path; } } } return ($trace_number, $trace_pid, $trace_path, $trace_filter); } # start_trace , , , # # fork off a new process running this trace. Nothing is returned. # Any failure terminates the program. # sub start_trace { my($path, $name, $number, $filter) = @_; my($pid); $number = next_file($path, $name, $number, ".trace", ".out"); $opt_q or print STDERR "starting ", $path.$name."-".$number, "\n"; if ($pid = fork) { sleep 3; unless ($opt_q) { open OUTFILE, $path.$name."-".$number.".out" or die __FILE__, ": no ", $path.$name."-".$number.".out\n"; print ; close OUTFILE; } return; } elsif (defined $pid) { exec "/bin/sh", "-c", "tcpdump -i em0 -w ".$path.$name."-".$number.".trace -s 8192 '".$filter. "' > ".$path.$name."-".$number.".out 2>&1 &"; die __FILE__, ": couldn't exec\n"; } else { die __FILE__, ": couldn't fork\n"; } } # next_file , , , ... # returns # # searches for a number (beginning with the target number) for which # no files of the form - exists. # As many suffixes as needed can be passed in. The resulting number # is returned. # sub next_file { my($path, $name, $number, @suffixes) = @_; ++$number until grep (-e $path.$name."-".$number.$_, @suffixes) == 0; return $number; }