In the editline(3) branch of the sftp(1) event loop, handle SIGINT
authorschwarze <schwarze@openbsd.org>
Thu, 12 Aug 2021 09:59:00 +0000 (09:59 +0000)
committerschwarze <schwarze@openbsd.org>
Thu, 12 Aug 2021 09:59:00 +0000 (09:59 +0000)
rather than ignoring it, such that the user can use Ctrl-C to discard
the currently edited command line and get a fresh prompt, just like
in ftp(1), bc(1), and in shells.

It is critical to not use ssl_signal() for this particular case
because that function unconditionally sets SA_RESTART, but here we
need the signal to interrupt the read(2) in the el_gets(3) event loop.

OK dtucker@ deraadt@

usr.bin/ssh/sftp.c

index 7a82302..8b4c090 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.210 2021/08/07 00:12:09 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.211 2021/08/12 09:59:00 schwarze Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -230,6 +230,13 @@ cmd_interrupt(int signo)
        errno = olderrno;
 }
 
+/* ARGSUSED */
+static void
+read_interrupt(int signo)
+{
+       interrupted = 1;
+}
+
 /*ARGSUSED*/
 static void
 sigchld_handler(int sig)
@@ -2168,9 +2175,8 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
                const char *line;
                int count = 0;
 
-               ssh_signal(SIGINT, SIG_IGN);
-
                if (el == NULL) {
+                       ssh_signal(SIGINT, SIG_IGN);
                        if (interactive)
                                printf("sftp> ");
                        if (fgets(cmd, sizeof(cmd), infile) == NULL) {
@@ -2179,9 +2185,21 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
                                break;
                        }
                } else {
+                       struct sigaction sa;
+
+                       interrupted = 0;
+                       memset(&sa, 0, sizeof(sa));
+                       sa.sa_handler = read_interrupt;
+                       if (sigaction(SIGINT, &sa, NULL) == -1) {
+                               debug3("sigaction(%s): %s",
+                                   strsignal(SIGINT), strerror(errno));
+                               break;
+                       }
                        if ((line = el_gets(el, &count)) == NULL ||
                            count <= 0) {
                                printf("\n");
+                               if (interrupted)
+                                       continue;
                                break;
                        }
                        history(hl, &hev, H_ENTER, line);