Отримати ssh для передачі сигналів


22

Я хочу мати можливість передавати сигнали (SIGINT є найважливішим) через ssh.

Ця команда:

ssh server "sleep 1000;echo f" > foo

почне спати на сервері, і через 1000 секунд він помістить 'f \ n' у файл foo на моїй локальній машині. Якщо я натискаю 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", але насправді, що постачається користувачем, він може містити що завгодно. Однак, якщо ми можемо змусити його працювати на «сон 1000; відлуння», ми, швидше за все, можемо змусити його працювати у всіх реалістичних ситуаціях.

Мені справді не байдуже отримати псевдотермінал на іншому кінці, але мені не вдалося знайти іншого способу отримання ssh для пересилання мого SIGINT.

Чи є інший спосіб?

Редагувати:

Користувач може дати команди, які читають бінарні дані зі stdin, такі як:

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команду.) Якщо я Право, будь ласка, зробіть ваші приклади більш репрезентативними щодо вашого фактичного використання, щоб можна було дати кращу відповідь.
Warren Young

Правильно: сон і відлуння - це фактично сценарії, що надаються користувачем, а не буквально уві сні та відлуння. Тож ми не знаємо, що вони роблять, і повинні вважати найгірше.
Оле Танге

Отож ... ви придумаєте кращий приклад команди, правда? Той, де проста перестановка не вирішує проблему? Ви ставите гарне запитання, і я хотів би, щоб на нього відповіли, але ви рідше отримаєте відповідь, якщо "так не робіть цього, тоді" є розумною відповіддю.
Warren Young

О, до речі ... Не робіть цього;)
Тім

Як зазначено в запитанні: "" "У вищевикладеному я використовую" сон 1000; ехо 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 на своєму кінці.

Здається, не дуже добре поводитися з бінарним входом: seq 1000 | gzip | ssh -t -t сервер "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; сон 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 'пакет друку ("u", $ _)' | ssh -t -t сервер 'perl -ne' розпакувати друк (\ "u \", \ $ _) "| zcat | gzip | perl -ne "пакет друку (\" u \ ", \ $ _)" '| perl -ne 'print unpack ("u", $ _)'> foo2.gz
Ole Tange

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. Хоча символ переривання не працює - нам потрібен якийсь метод передачі для символу переривання, поки stdin зайнятий .
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.


Я не бачу способу виявлення пулі, щоб знайти PID програми, яку запускають на віддалений. Пам'ятайте, що це дається користувачем. Це може бути: ssh server '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

Привіт! Я думаю, ви могли б зробити свою відповідь набагато кориснішою, пояснивши якомога детальніше, як вам здається, як вона працює. Не соромтесь відредагувати його, щоб вставити нову інформацію.
даг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.