您好我正在尝试记录用户从我的服务器执行的所有操作。我有一个脚本替换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
所以最后仍有这两个过程无关紧要。
答案 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;
...