zeek/scripts/spot-trace

146 lines
4.7 KiB
Perl
Executable file

#!/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] [<path>]<name> [<filter>]\n";
$req_file = shift or die "missing argument: <name>\n",
__FILE__, " [-kqPF] [<path>]<name> [<filter>]\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 <trace name>
# returns (<trace number>, <trace PID>, <trace path>, <trace filter>)
#
# runs ps looking for a trace running with the given name. If none is
# found <trace number> 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>) {
($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 <path>, <name>, <number>, <filter>
#
# 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 <OUTFILE>;
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 <path>, <name>, <number>, <suffix>...
# returns <number>
#
# searches for a number (beginning with the target number) for which
# no files of the form <path><name>-<number><suffix> 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;
}