Ottieni ssh per inoltrare segnali


22

Voglio essere in grado di inviare segnali (SIGINT è il più importante) tramite ssh.

Questo comando:

ssh server "sleep 1000;echo f" > foo

inizierà lo sleep sul server e dopo 1000 secondi inserirà 'f \ n' nel file foo sul mio computer locale. Se premo CTRL-C (cioè invio SIGINT a ssh), ucciderà ssh, ma non ucciderà la sospensione sul server remoto. Voglio che uccida il sonno sul server remoto.

Quindi ho provato:

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

Ma se stdin non è un terminale ottengo questo errore:

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

e quindi SIGINT non viene ancora inoltrato.

Quindi ho provato:

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

Ma poi l'output in foo non è 'f \ n' ma invece 'f \ r \ n' che è disastroso nella mia situazione (dato che il mio output è un dato binario).

In quanto sopra uso "sleep 1000; echo f", ma in realtà viene fornito dall'utente, quindi può contenere qualsiasi cosa. Tuttavia, se riusciamo a farlo funzionare per "sleep 1000; echo f", molto probabilmente possiamo farlo funzionare per tutte le situazioni realistiche.

Non mi interessa davvero ottenere uno pseudo-terminale dall'altra parte, ma non sono stato in grado di trovare nessun altro modo di ottenere ssh per inoltrare il mio SIGINT.

C'è un altro modo?

Modificare:

L'utente può dare comandi che leggono dati binari da stdin, come:

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

L'utente potrebbe fornire comandi ad alta intensità di CPU, come:

ssh server "timeout 1000 burnP6"

Edit2:

La versione che sembra funzionare per me è:

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

Grazie a digital_infinity per avermi indicato nella giusta direzione.


1
Penso che il tuo effettivo utilizzo sshdebba essere più complicato di quello che mostri come esempi, perché puoi ottenere il comportamento che desideri con un semplice riarrangiamento: sleep 1000 && ssh server "echo f" > foo(Deve essere &&, no ;, in modo che l'uccisione sleepimpedisca l' sshesecuzione del comando.) Se io ho ragione, rendi i tuoi esempi più rappresentativi del tuo reale utilizzo, in modo da poter dare una risposta migliore.
Warren Young

Corretto: sleep ed eco sono in realtà script forniti dall'utente e non letteralmente sleep ed eco. Quindi non sappiamo cosa fanno e dovremmo assumere il peggio.
Ole Tange,

Quindi ... ti verrà in mente un comando di esempio migliore, giusto? Uno in cui un semplice riarrangiamento non risolve il problema? Fai una buona domanda e mi piacerebbe vederla risposta, ma è meno probabile che tu ottenga una risposta se "quindi non farlo, allora" è una risposta ragionevole.
Warren Young

Oh a proposito ... Non farlo;)
Tim

Come evocato nella domanda: "" "In quanto sopra uso" sleep 1000; echo f ", ma in realtà è fornito dall'utente, quindi può contenere qualsiasi cosa" ""
Ole Tange

Risposte:


10

Risposta breve:

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

e interrompere il programma di CTRL + N.

Spiegazione lunga:

  1. È necessario utilizzare l' sttyopzione intrper modificare il server o il carattere di interruzione locale in modo da non scontrarsi. Nel comando sopra ho cambiato il carattere di interruzione del server in CTRL + N. È possibile modificare il carattere di interruzione locale e lasciare quello del server senza alcuna modifica.
  2. Se non si desidera che il carattere di interruzione sia presente nell'output (e in qualsiasi altro carattere di controllo), utilizzare stty -echoctl.
  3. È necessario assicurarsi che i caratteri di controllo siano attivati ​​sul server bash richiamato da sshd. In caso contrario, è possibile finire con processi ancora in attesa dopo il logout.stty isig
  4. In realtà si prende il SIGINTsegnale trap '/bin/true' SIGINTcon un'istruzione vuota. Senza la trappola non avrai nessun stdout dopo il segnale SIGINT alla tua estremità.

Sembra non gestire bene l'input binario: seq 1000 | gzip | ssh -t -t server "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
Ole Tange,

Non è possibile interrompere dalla console se si imposta l'input standard per ssh per qualcosa di diverso dalla console. In questo caso è necessario interrompere dal flusso stdin.
digital_infinity

Ho scoperto che anche questo seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > foonon funziona. Per far funzionare questo comando, dobbiamo rimuoverlo -tt. Quindi l'allocazione pseudo-terminale probabilmente prende alcuni input da stdin
digital_infinity il

Ho provato il codice uu. In questa versione non funziona: cat foo.gz | perl -ne 'print pack ("u", $ _)' | ssh -t -t server 'perl -ne "print unpack (\" u \ ", \ $ _)" | zcat | gzip | perl -ne "print pack (\" u \ ", \ $ _)" '| perl -ne 'print unpack ("u", $ _)'> foo2.gz
Ole Tange

1
Ho questo: (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. Sebbene il carattere di interruzione non funzioni, è necessario un metodo di trasmissione per il carattere di interruzione mentre lo stdin è occupato .
digital_infinity

3

Ho provato tutte le soluzioni e questo è stato il migliore:

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


Ciò non interrompe il sleepprocesso in caso di perdita della connessione.
azzurrato

Quando la connessione viene persa, lo stdin viene interrotto sbloccando il gatto che ucciderà il gruppo di processi. Se quel segnale INTerrupt è abbastanza buono per il tuo compito è una domanda diversa.
Eric Woodruff,

Dovrebbe essere abbastanza buono per il sleep, non dovrebbe? Ho aggiunto alcuni date >> /tmp/killeddopo il cat, ma non è stato attivato. C'è qualche timeout coinvolto? Sto usando Zsh normalmente, ma l'ho anche provato con bash come shell di login remoto.
azzurrato

Penso che tu sia in balia del timeout della connessione.
Eric Woodruff,

Ci sono impostazioni per controllarlo? Per il lato client -o ServerAliveInterval=3 -o ServerAliveCountMax=2consente di rilevarlo rapidamente, ma c'è qualcosa per il lato server?
azzurrato

2

Penso che potresti trovare il PID del processo che stai eseguendo sul server e inviare un segnale usando un altro sshcomando (come questo:) ssh server "kill -2 PID".

Uso questo metodo per inviare segnali di riconfigurazione ad applicazioni in esecuzione su una macchina diversa (le mie applicazioni catturano SIGUSR1 e leggono un file di configurazione). Nel mio caso, trovare il PID è facile, perché ho nomi di processo univoci e posso trovare il PID inviando una psrichiesta tramite ssh.


Non vedo un modo a prova di proiettile per trovare il PID del programma in esecuzione su remoto. Ricorda che è stato dato dall'utente. Potrebbe essere: server ssh 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange,

1

La soluzione si è evoluta in 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

----- sul terminale locale

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

Ciao! Penso che potresti rendere la tua risposta molto più utile spiegando, nel dettaglio che ritieni pertinente, come funziona. Non esitate a modificarlo per inserire nuove informazioni.
dhag,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.