Obtenga ssh para reenviar señales

22

Quiero poder enviar señales (SIGINT es lo más importante) a través de ssh.

Este comando:

ssh server "sleep 1000;echo f" > foo

comenzará a dormir en el servidor y después de 1000 segundos colocará 'f \ n' en el archivo foo en mi máquina local. Si presiono CTRL-C (es decir, enviar SIGINT a ssh) matará ssh, pero no matará el modo de suspensión en el servidor remoto. Quiero que mate el sueño en el servidor remoto.

Entonces intenté:

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

Pero si stdin no es un terminal me sale este error:

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

y luego SIGINT todavía no se reenvía.

Entonces intenté:

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

Pero entonces la salida en foo no es 'f \ n' sino 'f \ r \ n', lo cual es desastroso en mi situación (ya que mi salida son datos binarios).

En lo anterior utilizo "sleep 1000; echo f", pero en realidad lo proporciona el usuario, por lo que puede contener cualquier cosa. Sin embargo, si podemos hacer que funcione para "dormir 1000; echo f", lo más probable es que funcione para todas las situaciones realistas.

Realmente no me importa obtener un pseudo terminal en el otro extremo, pero no he podido encontrar ninguna otra forma de obtener ssh para reenviar mi SIGINT.

¿Hay otra manera?

Editar:

El usuario podría dar comandos que lean datos binarios de stdin, como:

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

El usuario podría dar comandos que requieran un uso intensivo de la CPU, como:

ssh server "timeout 1000 burnP6"

Edit2:

La versión que parece funcionar para mí es:

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

Gracias a digital_infinity por señalarme en la dirección correcta.

Ole Tange
fuente
1
Creo que su uso real de sshdebe ser más complicado de lo que muestra como ejemplos, porque puede obtener el comportamiento que desea con una simple reorganización: sleep 1000 && ssh server "echo f" > foo(Tiene que ser &&, no ;, para que matar sleepevite que el sshcomando se ejecute). Tengo razón, haga que sus ejemplos sean más representativos de su uso real, de modo que se pueda dar una mejor respuesta.
Warren Young
Correcto: el sueño y el eco son en realidad scripts proporcionados por el usuario y no literalmente sueño y eco. Entonces no sabemos lo que hacen y debemos asumir lo peor.
Ole Tange
Entonces ... vas a encontrar un mejor ejemplo de comando, ¿verdad? ¿Una donde una simple reorganización no soluciona el problema? Usted hace una buena pregunta, y me gustaría verla respondida, pero es menos probable que obtenga una respuesta si "entonces no lo haga" es una respuesta razonable.
Warren Young
Ah, por cierto ... No hagas eso;)
Tim
Como elaboró ​​en la pregunta: "" "En lo anterior utilizo" sleep 1000; echo f ", pero en realidad es proporcionado por el usuario, por lo que puede contener cualquier cosa" ""
Ole Tange

Respuestas:

10

Respuesta corta:

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

y pare el programa con CTRL + N.

Larga explicación:

  1. Debe usar la sttyopción intrpara cambiar su servidor o el carácter de interrupción local para que no choquen entre sí. En el comando anterior, he cambiado el carácter de interrupción del servidor a CTRL + N. Puede cambiar su carácter de interrupción local y dejar el del servidor sin ningún cambio.
  2. Si no desea que el carácter de interrupción esté en su salida (y cualquier otro carácter de control), use stty -echoctl.
  3. Debe asegurarse de que los caracteres de control estén activados en la bash del servidor invocada por sshd. Si no lo hace, puede terminar con los procesos aún pendientes después de cerrar sesión.stty isig
  4. Realmente captas la SIGINTseñal trap '/bin/true' SIGINTcon una declaración vacía. Sin la trampa no tendrás ningún stdout después de la señal SIGINT de tu parte.
digital_infinity
fuente
Parece que no trata bien con la entrada binaria: seq 1000 | gzip | ssh -t -t server "stty isig intr ^ N -echoctl; trap '/ bin / true' SIGINT; sleep 1; zcat | bzip2" | bzcat> foo;
Ole Tange
No puede interrumpir por consola si configura la entrada estándar para ssh para algo que no sea consola. En este caso, debe interrumpir el flujo stdin.
digital_infinity
Descubrí que esto seq 1000 | gzip | ssh -tt dell-test "zcat|bzip2" | bzcat > footampoco funciona. Para que este comando funcione, debemos eliminarlo -tt. Por lo tanto, la asignación de pseudo terminal probablemente toma algo de entrada de stdin
digital_infinity
Probé el uuencode. En esta versión no funciona: cat foo.gz | perl -ne 'paquete de impresión ("u", $ _)' | ssh -t -t server 'perl -ne "imprimir descomprimir (\" u \ ", \ $ _)" | zcat | gzip | perl -ne "paquete de impresión (\" u \ ", \ $ _)" '| perl -ne 'print unpack ("u", $ _)'> foo2.gz
Ole Tange
1
Tengo esto: (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. Aunque el carácter de interrupción no funciona, necesitamos algún método de transmisión para el carácter de interrupción mientras stdin está ocupado .
digital_infinity
3

Probé todas las soluciones y esta fue la mejor:

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

Eric Woodruff
fuente
Eso no detiene el sleepproceso en caso de que se pierda la conexión.
azulado
Cuando se pierde la conexión, el stdin se rompe desbloqueando el gato que matará al grupo de proceso. Si esa señal INTerrupt es lo suficientemente buena para su tarea es una pregunta diferente.
Eric Woodruff
Debería ser lo suficientemente bueno para el sleep, ¿no? He agregado algunos date >> /tmp/killeddespués del cat, pero no se activó. ¿Hay algún tiempo de espera involucrado? Estoy usando Zsh normalmente, pero también lo probé con bash como shell de inicio de sesión remoto.
azulado
Creo que estás a merced del tiempo de espera de la conexión.
Eric Woodruff
¿Hay configuraciones para controlar esto? Para el lado del cliente -o ServerAliveInterval=3 -o ServerAliveCountMax=2permite detectarlo rápidamente, pero ¿hay algo para el lado del servidor?
azulado
2

Creo que podría encontrar el PID del proceso que está ejecutando en el servidor y enviar una señal con otro sshcomando (como este:) ssh server "kill -2 PID".

Utilizo este método para enviar señales de reconfiguración a aplicaciones que se ejecutan en una máquina diferente (mis aplicaciones capturan SIGUSR1 y leen un archivo de configuración). En mi caso, encontrar PID es fácil, porque tengo nombres de proceso únicos y puedo encontrar el PID enviando una pssolicitud a través de ssh.

saeedn
fuente
No veo una forma a prueba de balas para encontrar el PID del programa que se ejecuta en forma remota. Recuerde que es dado por el usuario. Podría ser: servidor ssh 'exec $ (echo fyrrc 1000 | / usr / games / rot13)'
Ole Tange
1

La solución evolucionó a 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)
Ole Tange
fuente
0

----- command.sh

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

----- en la terminal local

sleep 864000 | ssh -T server command.sh > foo
huésped
fuente
¡Hola! Creo que podría hacer que su respuesta sea mucho más útil al explicar, con todo el detalle que considere relevante, cómo funciona. No dude en editarlo para insertar nueva información.
dhag