我需要在后台通过$ ssh->系统执行命令,并且记录下这应该像本地"系统"命令:
'As for "system" builtin, "SIGINT" and "SIGQUIT" signals are blocked. (see "system" in perlfunc).'
实际上,这似乎并不正确,因为当接收到SIGINT时,子节点中的$ ssh->系统会立即终止,即使我明确地想要" IGNORE"它首先:
use warnings;
use strict;
use POSIX ":sys_wait_h";
use Net::OpenSSH;
my $CTRLC=0;
$SIG{CHLD}='IGNORE';
sub _int_handler {
$CTRLC++;
print "CTRL-C was pressed $CTRLC times!!!\n";
}
$SIG{INT}='IGNORE';
my $SSH=Net::OpenSSH->new('testhost',
forward_agent => 1,
master_stderr_discard => 1,
master_opts => [ -o =>"PasswordAuthentication=no"]);
$SIG{INT}=\&_int_handler;
sub _ssh {
$SIG{INT}='IGNORE';
$SSH->system('sleep 3; sleep 3');
# system('sleep 3; sleep 3');
print "Exiting Child!\n";
exit 0;
}
print "Starting shell ...\n";
_ssh if not (my $PID=fork);
print $PID, "\n";
waitpid ($PID,0);
运行此代码并尝试在第一次"睡眠3"之后中断。正在启动," $ SSH->系统"电话会立即结束。
但是,如果您使用本地"系统"而在下面的语句中,SIGINT被正确捕获。
在我发现的Net :: OpenSSH的源代码中,$ SIG {INT}也明确地设置为" IGNORE"在"系统"子。我不知道为什么这不起作用。
我会感谢任何可能的解决方案,如果它意味着以不同的方式做事。最后,我只想远程执行命令并仍然保护它们免受CTRL-C的攻击。</ p>
谢谢,
Mazze
更新
感谢您输入@salva。我进一步剥离了东西,最后它似乎是&#34; -S&#34; ssh的旗帜:
$SIG{INT}='IGNORE';
# system('ssh -S /tmp/mysock lnx0001a -- sleep 3');
system('ssh lnx0001a -- sleep 3');
&#34; -S / tmp / mysock&#34;正在使用变体,ssh似乎是可中断的,而不是其他。有没有人可以解释一下? 我应该为此发布一个新的独立问题吗?
再次感谢,
Mazze
更新2:
我把事情搞得更多,现在这完全没有任何perl范围。你可以在你的shell中做到这一点:
$ trap '' INT
$ ssh lnx0001a -- sleep 3
现在不能打断。 但是,在我的情况下,以下内容仍然是可以中断的:
$ ssh -S /tmp/mysock lnx0001a -- sleep 3
使用CTRL-C,会立即中断。与root用户的情况与我的情况相同,但其他同事不会在其用户身上看到此行为。我们比较了@ ENV,但我们没有发现可能导致不同行为的原因。
你怎么样:&#34; -S&#34;版本可以在&#34;陷阱&#39;&#39; INT&#34;在你的壳? (显然,您必须先为/ tmp / mysock创建一个主会话。)
此致
Mazze
答案 0 :(得分:4)
问题是当你在控制台上按CTRL-C时,内核会向进程组的所有进程发送一个信号(参见Prevent control-c from sending SIGINT to all process group children)。
我认为你在行为上看到的差异实际上是由子进程的差异引起的,有些是重置信号标志,而有些则没有。
无论如何,我将添加对在不同进程组中运行SSH进程的支持。在模块RT上添加错误报告,所以我不要忘记它。
更新:以下实验显示OpenSSH system
方法和内置版的行为方式相同:
my @cmd = $SSH->make_remote_command("sleep 3 && echo hello");
warn "running command @cmd\n";
local $SIG{INT} = 'IGNORE';
system @cmd;
如果运行它,即使INT信号处理程序设置为ssh
,您也会看到信号到达并中止IGNORE
进程。
更新2 :经过一些实验,我发现问题实际上存在于后台运行的主SSH进程上。除非您使用密码验证,否则它也会在进程组中挂起,因此会获得INT信号。
我正在添加一个新选项,明确要求将主服务器作为一个新的流程组运行,但由于选项数量很多,这部分代码非常复杂,所以这不是一件容易的事。
更新3 :我发布了一个新的development version (0.61_15)模块。
现在,你可以......
my $ssh = Net::OpenSSH->new($host, master_setpgrp => 1, ...);
$ssh->system({setpgrp => 1}, "sleep 10; echo uninterruptible");
...希望没有SIGINT进入主进程或从进程SSH进程。
请报告您可能发现的任何问题!
答案 1 :(得分:1)
在您的情况下,通过将PERL_SIGNALS的环境变量设置为“不安全”,最好获得pre-Perl-5.8信号行为。
从Perl 5.8.1开始,这里描述了信号的正常方法:perlipc: Deferred Signals (Safe Signals)
但您可能想要的是直接行为,例如:perlrun: PERL_SIGNALS
所以,问题的解决方案可能是这个:
$ENV{'PERL_SIGNALS'} = 'unsafe';
你的代码中的:)
我在这里尝试过,到目前为止工作。但是这种方法可能存在缺点,因为我不知道你的程序是否会因此而面临不同的问题。