Perl fork exec,系统在父母和杀害孩子

时间:2014-11-26 09:43:41

标签: perl ssh exec fork kill

您好我正在尝试记录用户从我的服务器执行的所有操作。我有一个脚本替换ssh并记录所有内容。

问题是当用户停止ssh会话时,记录操作的子进程不会被杀死。

my $pid = fork();
die "unable to fork: $!" unless defined($pid);
if (!$pid) {  # child
    exec("tail -f $logfile | logger -t $ENV{SUDO_USER}:$target ");
    die "unable to exec: $!";
}

$show_cmd && print "% $cmd\n" ;
system $cmd or die "exec() failed: $!\n" ;
printf "Session end pid to kill %d\n", $pid;
kill 1, $pid;
waitpid $pid, 0;
printf "End of the script.\n";

我也把

$SIG{CHLD} = "IGNORE";

如果我删除了指令系统(启动用户的原始ssh命令的指令),则该孩子被杀死,但这也使我的脚本无用。

如何成功终止流程?

编辑: 当系统命令结束脚本继续时,执行printf,并打印孩子的pid。

EDIT2:

这是ssh会话期间的'ps faux'

root      4976  [...]   \_ /usr/bin/perl -w /usr/bin/ssh **.**.**.62
root      4977  [...]      \_ sh -c tail -f /var/log/log-session/2014-11-26.155910.*******:root@**.**.**.62 | logger -t *********:root@**.**.**.62
root      4979  [...]      |   \_ tail -f /var/log/log-session/2014-11-26.155910.*********:root@**.**.**.62
root      4980  [...]      |   \_ logger -t ********:root@**.**.**.62
root      4978  [...]      \_ sh -c /usr/bin/realssh -o UserKnownHostsFile=/etc/ssh/known_hosts_Securite -i /etc/ssh/id_dsa_Securite **.**.**.62 | ...
root      4981  [...]         \_ /usr/bin/realssh -o UserKnownHostsFile=/etc/ssh/known_hosts_Securite -i /etc/ssh/id_dsa_Securite **.**.**.62
root      4982  [...]         \_ /usr/bin/tee -a /var/log/log-session/2014-11-26.155910.********:root@**.**.**.62

会话结束时:来自用户的^ D

Connection to **.**.**.62 closed.
Session end pid to kill: 4977
End of the script.

'ps faux'的结果:

 root      4979  [...]        tail -f /var/log/log-session/2014-11-26.155910.*********:root@**.**.**.62
 root      4980  [...]        logger -t ********:root@**.**.**.62

所以最后仍有这两个过程无关紧要。

2 个答案:

答案 0 :(得分:2)

我认为问题是杀死所有进程树和 That SO answer solves the problem

我对子进程有这个

setpgrp(0, 0);

将kill指令更改为

kill 9, -$pid;

现在看起来像这样

my $pid = fork();
die "unable to fork: $!" unless defined($pid);
if (!$pid) {  # child
    setpgrp(0, 0);
    exec("tail -f $logfile | logger -t $ENV{SUDO_USER}:$target ");
    die "unable to exec: $!";
}

$show_cmd && print "% $cmd\n" ;
system $cmd or die "exec() failed: $!\n" ;
printf "Session end pid to kill %d\n", $pid;
kill 9, -$pid;
waitpid $pid, 0;
printf "End of the script.\n";

感谢您的帮助

答案 1 :(得分:1)

这行

会有问题
system $cmd or die "exec() failed: $!\n" ;

因为当命令成功返回时, system 返回值将为0。因此,在杀死孩子之前,你的程序会在这里过早退出。

看看这个答案: Perl: After a successful system call, "or die" command still ends script

我认为您应该以不同的方式处理检查用户命令已成功执行的方式,或者只是确保将退出值和输出传播给用户。

你可以这样:

system($cmd);

if ($? == -1) {
    print "failed to execute: $!\n";
    kill 1, $pid;
    exit($?);
} elsif ($? & 127) {
    printf "child died with signal %d, %s coredump\n", ($? & 127),  ($? & 128) ? 'with' : 'without';
    kill 1, $pid;
    exit(3);
}
my $exitval =  $? >> 8;
...