web-dev-qa-db-ja.com

sshにシグナルを転送させる

Sshを介してシグナル(SIGINTが最も重要)を送信できるようにしたい。

このコマンド:

ssh server "sleep 1000;echo f" > foo

サーバーでスリープを開始し、1000秒後にローカルマシンのファイルfooに「f\n」を配置します。 CTRL-Cを押すと(つまり、SIGINTをsshに送信)、sshは強制終了されますが、リモートサーバーのスリープは強制終了されません。リモートサーバーのスリープを強制終了したい。

だから私は試した:

ssh server -t "sleep 1000;echo f" > foo

しかし、stdinがターミナルでない場合、次のエラーが発生します。

Pseudo-terminal will not be allocated because stdin is not a terminal.

その後、SIGINTはまだ転送されません。

だから私は試した:

ssh server -t -t "sleep 1000;echo f" > output

しかし、fooの出力は 'f\n'ではなく 'f\r\n'です。これは私の状況では悲惨です(私の出力はバイナリデータであるため)。

上記では「sleep 1000; echo f」を使用していますが、実際にはユーザーが指定するため、何でも含めることができます。ただし、「sleep 1000; echo f」で機能させることができれば、現実的なすべての状況で機能させることができます。

私は実際にはもう一方の端で疑似端末を取得することには関心がありませんが、sshにSIGINTを転送させる他の方法を見つけることができませんでした。

別の方法はありますか?

編集:

ユーザーは、次のようなstdinからバイナリデータを読み取るコマンドを与えることができます。

seq 1000 | gzip | ssh server "zcat|bzip2; sleep 1000" | bzcat > foo

ユーザーは、CPUを多用する次のようなコマンドを与えることができます。

ssh server "timeout 1000 burnP6"

Edit2:

私にとってうまくいくように見えるバージョンは次のとおりです:

your_preprocessing |
  uuencode a | ssh -tt -oLogLevel=quiet server "stty isig -echoctl -echo ; uudecode -o - |
your_command |
  uuencode a" | uudecode -o - |
your_postprocessing

私を正しい方向に向けてくれたdigital_infinityに感謝します。

22
Ole Tange

短い答え:

ssh -t fs "stty isig intr ^N -echoctl ; trap '/bin/true' SIGINT; sleep 1000; echo f" > foo

cTRL + Nでプログラムを停止します。

長い説明:

  1. sttyオプションintrを使用して、サーバーまたはローカル割り込み文字を変更して、互いに衝突しないようにする必要があります。上記のコマンドで、サーバーの割り込み文字をCTRL + Nに変更しました。ローカルの割り込み文字を変更し、サーバーの文字を変更せずに残すことができます。
  2. 割り込み文字(およびその他の制御文字)を出力に含めたくない場合は、stty -echoctlを使用します。
  3. Sshdによって呼び出されたサーバーbashで制御文字がオンになっていることを確認する必要があります。そうしないと、ログアウトした後もプロセスが停止する可能性があります。 stty isig
  4. あなたは実際に空のステートメントでtrap '/bin/true' SIGINTによってSIGINT信号をキャッチします。トラップがないと、SIGINTシグナルの後にstdoutがなくなります。
10

私はすべての解決策を試しましたが、これが最高でした:

ssh Host "sleep 99 < <(cat; kill -INT 0)" <&1

https://stackoverflow.com/questions/3235180/starting-a-process-over-ssh-using-bash-and-then-killing-it-on-sigint/25882610#2588261

3
Eric Woodruff

ソリューションは https://www.gnu.org/software/parallel/parallel_design.html#The-remote-system-wrapper に進化しました

$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
    # Make own process group to be able to kill HUP it later
    setpgrp;
    exec $ENV{Shell}, "-c", ($bashfunc."@ARGV");
    die "exec: $!\n";
}
do {
    # Parent is not init (ppid=1), so sshd is alive
    # Exponential sleep up to 1 sec
    $s = $s < 1 ? 0.001 + $s * 1.03 : $s;
    select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)
2
Ole Tange

サーバー上で実行しているプロセスのPIDを見つけて、別のsshコマンドを使用してシグナルを送信できると思います(次のような:ssh server "kill -2 PID")。

この方法を使用して、別のマシンで実行されているアプリケーションに再構成信号を送信します(私のアプリケーションはSIGUSR1をキャッチして構成ファイルを読み取ります)。私の場合、一意のプロセス名があり、ps経由でsshリクエストを送信してPIDを見つけることができるため、PIDを見つけるのは簡単です。

2
saeedn

----- command.sh

#! /bin/sh
trap 'trap - EXIT; kill 0; exit' EXIT
(sleep 1000;echo f) &
read ans

-----ローカル端末上

sleep 864000 | ssh -T server command.sh > foo
0
guest