Your usage of "&" in the command is not only unnecessary (the fork already runs "in the background"), it also
is the primary reason your code doesn't work. Otherwise, your approach to create a new process group is perfectly fine, in case you need or want to kill an entire tree of child processes.
Compare the following (I replaced tcpdump with a simple sleep, which is irrelevant to the discussion):
#!/usr/bin/perl -w
use strict;
sub ps { system "ps Tf -o pid,ppid,pgrp,sid,cmd"; }
$SIG{CHLD} = 'IGNORE';
my $snoop = fork();
if ( $snoop == 0 ){
setpgrp;
system("sleep 20 &");
exit;
}
ps();
sleep 1;
print "PID: $snoop\n";
printf "PGRP: %d\n", getpgrp($snoop);
kill -1, getpgrp($snoop);
ps();
__END__
PID PPID PGRP SID CMD
2360 2358 2360 2360 bash -rcfile .bashrc
19529 2360 19529 2360 \_ /usr/bin/perl -w ./964597.pl
19531 19529 19529 2360 \_ ps Tf -o pid,ppid,pgrp,sid,cmd
19533 1 19530 2360 sleep 20
PID: 19530
PGRP: -1
PID PPID PGRP SID CMD
2360 2358 2360 2360 bash -rcfile .bashrc
19529 2360 19529 2360 \_ /usr/bin/perl -w ./964597.pl
19534 19529 19529 2360 \_ ps Tf -o pid,ppid,pgrp,sid,cmd
19533 1 19530 2360 sleep 20
#!/usr/bin/perl -w
use strict;
sub ps { system "ps Tf -o pid,ppid,pgrp,sid,cmd"; }
$SIG{CHLD} = 'IGNORE';
my $snoop = fork();
if ( $snoop == 0 ){
setpgrp;
system("sleep 20 ;");
exit;
}
ps();
sleep 1;
print "PID: $snoop\n";
printf "PGRP: %d\n", getpgrp($snoop);
kill -1, getpgrp($snoop);
ps();
__END__
PID PPID PGRP SID CMD
2360 2358 2360 2360 bash -rcfile .bashrc
19537 2360 19537 2360 \_ /usr/bin/perl -w ./964597.pl
19538 19537 19538 2360 \_ /usr/bin/perl -w ./964597.pl
19540 19538 19538 2360 | \_ sh -c sleep 20 ;
19541 19540 19538 2360 | \_ sleep 20
19539 19537 19537 2360 \_ ps Tf -o pid,ppid,pgrp,sid,cmd
PID: 19538
PGRP: 19538
PID PPID PGRP SID CMD
2360 2358 2360 2360 bash -rcfile .bashrc
19537 2360 19537 2360 \_ /usr/bin/perl -w ./964597.pl
19542 19537 19537 2360 \_ ps Tf -o pid,ppid,pgrp,sid,cmd
As you can see in the first example, the child process (sleep) dissociates, i.e. the original process (your $snoop PID) is no longer alive, so getpgrp($snoop) fails, and you effectively kill nothing...
In the second example, however, without using "&"1, things work as intended. I.e., you have created a new process group (19538 here), which you are then killing successfully.
That said, unless you actually are running multiple child processes, there is no need to use the process group technique. As long as you can make sure that tcpdump is the only and immediate child process (for example using exec, as noted by halfcountplus (but without your "&" !)), killing that process directly would work without a problem.
BTW, to check whether a process is running, you can send it the "0" pseudo signal, e.g.
printf "child%s alive\n", kill(0, $snoop) ? "":" not";
___
1note that I'm using a ";" here in place of the "&", because the example is also meant to show that using an extra process group to kill multiple processes in one go, is working just fine. Without a shell meta character in the command (the semicolon in this case), Perl would optimize away the extra shell, so there would only be a single child process, which kind of defeats the purpose of using a process group...
|