mike928 has asked for the wisdom of the Perl Monks concerning the following question:

Hi there!

I want to write a script that

- captures the output of tcpdump

- deposits the PID of the tcpdump process in $pid

- kills the tcpdump after some time

I tried running this code:

#!/usr/local/bin/perl -w use warnings; use strict; $|=1; my $output; my $pid; $pid = open (STDIN,"sudo /usr/sbin/tcpdump -n -e -i mon_wlan0 -c 100|" +); while ($output=<>){ print "$output\n"; } print "pid = $pid\n";

while running top | grep tcpdump on another terminal

but the PID returned by the script is different(larger) from the one in the terminal

So my questions are:

---why do i have 2 process id-s? (parent&child maybe?)

---how do i fix the script to be able to stop the tcpdump with kill -9 $pid before the packet counter expires ?

Any help would be appreciated. Thank you!

Replies are listed 'Best First'.
Re: capture output of tcpdump and PID
by thargas (Deacon) on May 22, 2012 at 18:48 UTC

    Answering the first question first, you do indeed have two processes; that's what the | does in the open. See doc:perlopentut.

    I'm not sure what want with the second one. If you mean that you want to stop after a specified amount of time, then you could just use alarm() to set a timer for the desired amount of time and exit the loop at that point. Like (untested):

    my $done = 0; local $SIG{ALRM} = sub { $done = 1; }; alarm 10; # or whatever while (not $done and $output = <STDIN>) { print $output; # don't need newline as it's there already }

      Thanks, i also tried another way to stop the process, and it's quite simple... i just close(LABEL)

      I also tried the alarm code, and it works

      The alarm code isn't somehow similar to this:

      open (CAPTURE,"sudo /usr/sbin/tcpdump -i wlan0 |"); $startTime = time(); while ( $line = <CAPTURE> ) { ### some code $endTime = time(); $t = $endTime - $startTime; if($t>10) { close(CAPTURE); last; } }

      how could i pause at regular intervals the tcpdump process to switch between wifi channels 1, 6, 11 without stopping (closing) the pipe ?

      Any idea would be appreciated

        How do you set/change the channel? If you do it by giving tcpdump an argument, then I suspect you're out of luck. You'll just have to stop the process and restart it with the new channel setting. If the channel can be changed with some other utility while tcpdump is running, then it should be fairly simple: read from the pipe until you want to change it (maybe based on how much time has elapsed since you started), and then run the other utility, then continue reading from the pipe. There may be some buffered output from tcpdump already waiting at the moment you change the channel. If that's a problem, you may have to do something more fancy.

        Aaron B.
        Available for small or large Perl jobs; see my home node.

        The problem with just adding the time-comparison to the loop is that if nothing comes from tcpdump, the loop hangs waiting for something and your timeout code is never invokes. At least not until after something does come in. Perhaps this is not an issue in your case.
Re: capture output of tcpdump and PID
by zentara (Cardinal) on May 22, 2012 at 21:00 UTC
    Try IPC::Open3, this works for me as a basic example.
    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; my $pid = open3(\*WRITE, \*READ, 0, "/usr/sbin/tcpdump -i wlan0 "); #if \*ERROR is 0 (false), STDERR is sent to STDOUT print "pid $pid\n"; while(1){ select(undef,undef,undef,.01); # small delay if( sysread \*READ,$output,1024 ){ print "$output\n"; }else{ print "finished\n"; exit; } }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh