Получить SSH для пересылки сигналов

22

Я хочу иметь возможность отправлять сигналы (SIGINT является наиболее важным) через SSH.

Эта команда:

ssh server "sleep 1000;echo f" > foo

начнет спать на сервере и через 1000 секунд поместит 'f \ n' в файл foo на моей локальной машине. Если я нажму CTRL-C (то есть отправлю SIGINT в ssh), это убьет ssh, но не остановит sleep на удаленном сервере. Я хочу, чтобы это убило сон на удаленном сервере.

Итак, я попробовал:

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», но на самом деле он предоставляется пользователем, поэтому он может содержать все, что угодно. Однако, если мы можем заставить его работать для «сна 1000; эхо f», мы, скорее всего, можем заставить его работать для всех реалистичных ситуаций.

Я действительно не беспокоюсь о получении псевдо-терминала на другом конце, но я не смог найти какой-либо другой способ заставить ssh переслать мой SIGINT.

Есть ли другой способ?

Редактировать:

Пользователь может давать команды, которые читают двоичные данные из стандартного ввода, такие как:

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

Пользователь может давать команды, которые интенсивно используют процессор, такие как:

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 за указание в правильном направлении.

Оле Танге
источник
1
Я думаю, что ваше фактическое использование sshдолжно быть более сложным, чем то, что вы показываете в качестве примеров, потому что вы можете получить желаемое поведение с помощью простой перестановки: sleep 1000 && ssh server "echo f" > foo(Должно быть &&, нет ;, так что убийство sleepпрепятствует выполнению sshкоманды.) Если я Правильно, пожалуйста, сделайте ваши примеры более репрезентативными для вашего фактического использования, чтобы можно было дать лучший ответ.
Уоррен Янг
Правильно: sleep и echo на самом деле являются пользовательскими скриптами, а не в буквальном смысле sleep и echo. Поэтому мы не знаем, что они делают, и должны предполагать худшее.
Оле Танге
Оооо ... ты собираешься придумать лучший пример команды, верно? Тот, где простая перестановка не решает проблему? Вы задаете хороший вопрос, и я хотел бы, чтобы на него ответили, но вы вряд ли получите ответ, если «так не делайте этого, тогда» - разумный ответ.
Уоррен Янг
О, кстати ... Не делай этого;)
Тим
Как изложено в вопросе: «» «В приведенном выше описании я использую« sleep 1000; echo f », но в действительности он предоставляется пользователем, поэтому он может содержать все что угодно» «»
Ole Tange

Ответы:

10

Краткий ответ:

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. Вы должны убедиться, что управляющие символы включены на сервере bash, вызываемом sshd. Если вы этого не сделаете, вы можете закончить процессами, которые все еще остаются после выхода из системы.stty isig
  4. Вы на самом деле поймать SIGINTсигнал trap '/bin/true' SIGINTс пустым заявлением. Без ловушки у вас не будет никакого стандартного сигнала после сигнала SIGINT на вашем конце.
digital_infinity
источник
Кажется, с двоичным вводом не очень-то хорошо справиться: seq 1000 | GZIP | ssh -t -t сервер "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
Оле Танге
Вы не можете прервать консоль, если вы установили стандартный ввод для ssh для чего-то другого, чем консоль. В этом случае вы должны прервать поток stdin.
digital_infinity
Я обнаружил, что это seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > fooтоже не работает. Чтобы эта команда работала, нам нужно удалить -tt. Таким образом, для выделения псевдотерминала, вероятно, потребуется некоторая информация от stdin
digital_infinity
Я попробовал uuencode. В этой версии это не работает: cat foo.gz | perl -ne 'print pack ("u", $ _)' | ssh -t -t server 'perl -ne "печать распаковать (\" u \ ", \ $ _)" | Zcat | GZIP | perl -ne "print pack (\" u \ ", \ $ _)" '| perl -ne 'print unpack ("u", $ _)'> foo2.gz
Оле Танге
1
У меня есть это: (sleep 1; seq 1000 ) | gzip | uuencode bin | ssh -tt dell-test "stty isig intr ^N -echoctl -echo ; trap '/bin/true' SIGINT; sleep 1; uudecode -o /dev/stdout | zcat |bzip2 | uuencode bin2 " | uudecode -o /dev/stdout | bzcat >foo. Хотя символ прерывания не работает - нам нужен какой-то метод передачи для символа прерывания, когда стандартный ввод занят .
digital_infinity
3

Я перепробовал все решения, и это было лучшим:

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

/programming/3235180/starting-a-process-over-ssh-using-bash-and-then-killing-it-on-sigint/25882610#25882610

Эрик Вудрафф
источник
Это не останавливает sleepпроцесс в случае потери соединения.
синеватый
Когда соединение потеряно, stdin разрывается, разблокируя кошку, которая убивает группу процессов. Достаточно ли хорош этот сигнал INTerrupt для вашей задачи - это другой вопрос.
Эрик Вудрафф
Это должно быть достаточно хорошо для sleep, не так ли? Я добавил некоторые date >> /tmp/killedпосле cat, но это не сработало. Есть ли тайм-аут? Я использую Zsh нормально, но также протестировал его с bash в качестве оболочки удаленного входа.
голубоглазый
Я думаю, что вы находитесь в зависимости от времени ожидания соединения.
Эрик Вудрафф
Есть ли настройки для управления этим? Для клиентской стороны -o ServerAliveInterval=3 -o ServerAliveCountMax=2позволяет быстро его обнаружить, но есть ли что-то для серверной стороны?
голубоглазый
2

Я думаю, что вы можете найти PID процесса, который вы запускаете на сервере, и отправить сигнал, используя другую sshкоманду (например, так:) ssh server "kill -2 PID".

Я использую этот метод для отправки сигналов реконфигурации приложениям, работающим на другом компьютере (мои приложения перехватывают SIGUSR1 и читают файл конфигурации). В моем случае найти PID легко, потому что у меня есть уникальные имена процессов, и я могу найти PID, отправив psзапрос через ssh.

saeedn
источник
Я не вижу пуленепробиваемого способа найти PID программы, запущенной на удаленном компьютере. Помните, что это дано пользователем. Это может быть: ssh сервер 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange
1

Решение превратилось в http://www.gnu.org/software/parallel/parallel_design.html#Remote-Ctrl-C-and-standard-error-stderr

$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)
Оле Танге
источник
0

----- 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
гость
источник
Здравствуй! Я думаю, что вы могли бы сделать свой ответ намного более полезным, объяснив, настолько подробно, насколько вы считаете уместным, как он работает. Не стесняйтесь редактировать его, чтобы вставить новую информацию.
дхаг