Control: reassign -1 unison-2.53 2.53.3-2 Control: retitle -1 when receiving a SIGINT, unison should send it to the process group, not just to ssh
A summary of the issue: I'm using a wrapper to ssh in order to call ssh-add before the real ssh, when needed. When I run unison and type Ctrl-C when a passphrase is asked by ssh-add, this kills unison and my wrapper, but not ssh-add. BTW, I've noticed that with svn (which uses my ssh wrapper in the same way as unison), everything is OK. So this issue is specific to the execution via unison. In my wrapper, I've replaced "ssh-add" by "strace -o ~/str.out ssh-add", so that I can now see more about the issue: with svn, ssh-add receives the SIGINT, but not with unison! In the ssh-add strace output when using svn: [...] openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 rt_sigaction(SIGALRM, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGHUP, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGINT, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGPIPE, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGQUIT, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTERM, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTSTP, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTTIN, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTTOU, {sa_handler=0x55993f0238b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f305625a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 write(4, "Enter passphrase for /home/vlefe"..., 49) = 49 read(4, 0x7ffd198c78cf, 1) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} --- rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call) write(4, "\n", 1) = 1 [...] In the ssh-add strace output when using unison: [...] openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCGETS, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 rt_sigaction(SIGALRM, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGHUP, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGINT, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGPIPE, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGQUIT, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTERM, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTSTP, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTTIN, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 rt_sigaction(SIGTTOU, {sa_handler=0x55e65c2078b0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 write(4, "Enter passphrase for /home/vlefe"..., 49) = 49 read(4, and Ctrl-C does nothing, I suppose because SIGINT is ignored here. In the unison-2.53-2.53.3 src/remote.ml file: (* Signals generated by the terminal from user input are sent to all processes in the foreground process group. This means that the ssh child process will receive SIGINT at the same time as Unison and close the connection before Unison has the chance to do cleanup with the remote end. To make matters more complicated, the ssh process must be in the foreground process group because interaction with the user is done via the terminal (not via stdin, stdout) and background processes can't read from the terminal (unless we'd set up a pty like is done for the GUI). Don't let these signals reach ssh by blocking them. The signals could be ignored instead of being blocked because ssh does not set handlers for SIGINT and SIGQUIT if they've been ignored at startup. But this triggers an error in ssh. The interactive passphrase reading function captures these signals for the purpose of restoring terminal settings (echo). When receiving a signal, and after restoring previous signal handlers, it resends the signal to itself. But now the signal is ignored and instead of terminating, the process will continue running as if passphrase reading function had returned with an empty result. Since the ssh process no longer receives the signals generated by user input we have to make sure that it terminates when Unison does. This usually happens due to its stdin and stdout being closed, except for when it is interacting with the user via terminal. To get around that, an [at_exit] handler is registered to send a SIGTERM and SIGKILL to the ssh process. (Note, for [at_exit] handlers to run, unison process must terminate normally, not be killed. For SIGINT, this means that [Sys.catch_break true] (or an alternative SIGINT handler) must be set before creating the ssh process.) *) So, in my case, unison sends SIGINT only to my ssh wrapper. It should send the signal to the process group in order to mimic what normally happens with a Ctrl-C. Then, if I type a character, e.g. "z", ssh-add gets an I/O error, but it reopens /dev/tty for the next passphrase instead of exiting. I'm not sure whether this is correct, but via Mutt, the terminal was still working for ssh-add, so that fixing the issue in unison would be the only good solution. write(4, "Enter passphrase for /home/vlefe"..., 49) = 49 read(4, "z", 1) = 1 read(4, 0x7ffc8bf3e17f, 1) = -1 EIO (Input/output error) write(4, "\n", 1) = 1 ioctl(4, TCGETS, {c_iflag=INLCR|ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(4, TCSETSF, {c_iflag=ICRNL|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = -1 EIO (Input/output error) rt_sigaction(SIGALRM, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGHUP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGQUIT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGTERM, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGTSTP, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 rt_sigaction(SIGTTOU, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f77bb25a510}, NULL, 8) = 0 close(4) = 0 openat(AT_FDCWD, "/home/vlefevre/.ssh/id_rsa-android", O_RDONLY) = 4 newfstatat(4, "", {st_mode=S_IFREG|0600, st_size=1766, ...}, AT_EMPTY_PATH) = 0 getuid() = 1000 newfstatat(4, "", {st_mode=S_IFREG|0600, st_size=1766, ...}, AT_EMPTY_PATH) = 0 read(4, "-----BEGIN RSA PRIVATE KEY-----\n"..., 4096) = 1766 read(4, "", 2330) = 0 read(4, "", 4096) = 0 close(4) = 0 ioctl(0, TCGETS, 0x7ffc8bf3e7e0) = -1 ENOTTY (Inappropriate ioctl for device) getpid() = 61437 openat(AT_FDCWD, "/dev/tty", O_RDWR) = 4 [...] -- Vincent Lefèvre <vinc...@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)