
Parece que puede haber un problema en el openssh
. En el bash
shell, si redirijo stderr
a stdout
él, se bloqueará para siempre, así que tengo que KeyboardInterrupt
:
$ ssh -fTNF './config' -MS './sockd5/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' 2>&1 | cat -A; echo OK
ControlSocket ./sockd5/ctrl_socket already exists, disabling multiplexing^M$
^C
El mismo comando sin la redirección funciona bien:
$ ssh -fTNF './config' -MS './sockd/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' | cat -A; echo OK
ControlSocket ./sockd/ctrl_socket already exists, disabling multiplexing
OK
¿Por qué está pasando esto? ¿Existe alguna solución?
Respuesta1
Cuando ssh -f
"pasa a segundo plano" después de haberse conectado y autenticado en el host, continuará manteniendo abiertos los identificadores de su stdin, stdout y stderr originales, por lo que si esos identificadores estaban conectados a través de tuberías a otros procesos (como su stdout + stderr están en su ejemplo de cat -A
), tendrá el efecto de mantener vivos esos procesos, incluso si ya no son necesarios.
ssh
se demoniza a sí mismo llamando aldaemon(3)
función de biblioteca, pero la llama con noclose = 1
, evitando que redirija stdin/stderr/stdout desde /dev/null
.
Esto se solucionó parcialmente en versiones recientes de openssh
(para el proceso de control maestro: stdin y stdout en2010, el estándar en2016; para el proceso de sesión: la salida estándar en2017), pero si tiene que ejecutar un ssh anterior, o necesita que deje de aferrarse a stderr también, la única "solución" puede ser usar un LD_PRELOAD
truco que anule la daemon(3)
función con un contenedor que llame al original con noclose = 0
.
$ cat daemon-force-close.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int daemon(int nochdir, int noclose){
static int (*orig)(int, int);
if(!orig && !(*(void**)&orig = dlsym(RTLD_NEXT, "daemon")))
errx(1, "%s", dlerror());
return orig(nochdir, 0);
}
$ cc -shared -Wall -O2 daemon-force-close.c -ldl -o daemon-force-close.so
$ LD_PRELOAD=./daemon-force-close.so \
ssh -Nf dummy@localhost -MS ./ctlsock 2>&1 | cat -A
dummy@localhost's password:
$
[no Ctrl-C needed]
$ ssh -S ~/w/c/ctlsock dummy@localhost
Last login: Tue May 28 21:04:26 2019 from ::1
...
Respuesta2
¿Por qué está pasando esto?
Es cat
algo que debe terminarse antes de que el shell llegue a echo
. Está "bloqueando para siempre" porque las cat
vidas.
¿Existe alguna solución?
En Bash, usaría la sustitución de procesos para ejecutar cat
que no se bloquee. Con cat
fuera del camino, entonces es fácil echo OK
solo si está realmente bien (con &&
o $?
). Ejemplo:
ssh -f … > >(cat -A) 2>&1 && echo OK; echo "The script goes on."
Ahora cat
funciona antes y después ssh
de pasar a segundo plano, pero el script continúa tan pronto como ssh
lo hace (o tan pronto como ssh
falla sin pasar a segundo plano).