patch to fix non-echo tty on scp SIGINT

Adam Wiggins hiro at dusk.org
Mon Nov 22 22:04:07 EST 2004


A long-time missing feature (or bug, depending on how you look at it) is
that a Ctrl-C at the password prompt in scp does not restore the
terminal settings, thus dropping you to the command prompt without any
keyboard echo.  (A "reset" command will fix it.)  This is a pretty
regular occurance for me, and some others I've talked to - usually when
you realize that the scp command you typed has a typo and decide to
abort.

Strangely, ssh handles this correctly, but scp does not.  The single
handler in scp.c is killchild(), which should pass the SIGINT along to
the ssh process, which would restore the terminal.  However this doesn't
work for some reason I couldn't discern - perhaps the ssh process is
invoked in such a way that it doesn't have access to the terminal
settings?

I created the attached patch which fixes the problem by saving the
terminal settings at the start of program execution and restoring them
on SIGINT.  Although this is slightly hacky I think it is good general
practice to leave the terminal in the same state that it began in.  Even
if the ssh process were hardlocked this would still restore the
terminal.

Adam

-------------- next part --------------
--- openssh-3.9p1/scp.c 2004-08-13 04:19:38.000000000 -0700
+++ openssh-3.9p1-ttyfix/scp.c  2004-11-22 00:54:45.679885981 -0800
@@ -105,12 +105,19 @@
 /* This is used to store the pid of ssh_program */
 pid_t do_cmd_pid = -1;

+/* Save terminal state for restore on exit */
+static struct termios _saved_tio;
+
 static void
 killchild(int signo)
 {
        if (do_cmd_pid > 1)
                kill(do_cmd_pid, signo);

+       /* restore the terminal to its original state */
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+               perror("tcsetattr");
+
        _exit(1);
 }

@@ -218,6 +225,11 @@
        extern char *optarg;
        extern int optind;

+       if (tcgetattr(fileno(stdin), &_saved_tio) == -1) {
+               perror("tcgetattr");
+               return 0;
+       }
+
        __progname = ssh_get_progname(argv[0]);

        args.list = NULL;


More information about the openssh-unix-dev mailing list