]> andersk Git - openssh.git/commitdiff
- djm@cvs.openbsd.org 2004/05/19 12:17:33
authordtucker <dtucker>
Mon, 24 May 2004 00:12:19 +0000 (00:12 +0000)
committerdtucker <dtucker>
Mon, 24 May 2004 00:12:19 +0000 (00:12 +0000)
     [sftp-client.c sftp.c]
     gracefully abort transfers on receipt of SIGINT, also ignore SIGINT while
     waiting for a command; ok markus@

ChangeLog
sftp-client.c
sftp.c

index 05e65cd7d052bf5d19560b121ae25794e7c5f0f0..7e46aecb768ba07e5b71a1dc61a4848694f20726 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+20040524
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2004/05/19 12:17:33
+     [sftp-client.c sftp.c]
+     gracefully abort transfers on receipt of SIGINT, also ignore SIGINT while
+     waiting for a command; ok markus@
+
 20040523
  - (djm) [sshd_config] Explain consequences of UsePAM=yes a little better in 
    sshd_config; ok dtucker@
index bf2eb43accd9667ef816e30b49f9b1b85e175a8f..6dcd5de74695ccbfa067d7d32c2ccfafb8a10062 100644 (file)
@@ -20,7 +20,7 @@
 /* XXX: copy between two remote sites */
 
 #include "includes.h"
-RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $");
+RCSID("$OpenBSD: sftp-client.c,v 1.49 2004/05/19 12:17:33 djm Exp $");
 
 #include "openbsd-compat/sys-queue.h"
 
@@ -36,6 +36,7 @@ RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $");
 #include "sftp-common.h"
 #include "sftp-client.h"
 
+extern volatile sig_atomic_t interrupted;
 extern int showprogress;
 
 /* Minimum amount of data to read at at time */
@@ -330,7 +331,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
                (*dir)[0] = NULL;
        }
 
-       for (;;) {
+       for (; !interrupted;) {
                int count;
 
                id = expected_id = conn->msg_id++;
@@ -407,6 +408,13 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
        do_close(conn, handle, handle_len);
        xfree(handle);
 
+       /* Don't return partial matches on interrupt */
+       if (interrupted && dir != NULL && *dir != NULL) {
+               free_sftp_dirents(*dir);
+               *dir = xmalloc(sizeof(**dir));
+               **dir = NULL;
+       }
+
        return(0);
 }
 
@@ -812,6 +820,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
                char *data;
                u_int len;
 
+               /*
+                * Simulate EOF on interrupt: stop sending new requests and 
+                * allow outstanding requests to drain gracefully
+                */
+               if (interrupted) {
+                       if (num_req == 0) /* If we haven't started yet... */
+                               break;
+                       max_req = 0;
+               }
+
                /* Send some more requests */
                while (num_req < max_req) {
                        debug3("Request range %llu -> %llu (%d/%d)",
@@ -899,8 +917,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
                                            (unsigned long long)offset,
                                            num_req);
                                        max_req = 1;
-                               }
-                               else if (max_req < conn->num_requests + 1) {
+                               } else if (max_req <= conn->num_requests) {
                                        ++max_req;
                                }
                        }
@@ -1036,10 +1053,14 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
                int len;
 
                /*
-                * Can't use atomicio here because it returns 0 on EOF, thus losing
-                * the last block of the file
+                * Can't use atomicio here because it returns 0 on EOF, 
+                * thus losing the last block of the file.
+                * Simulate an EOF on interrupt, allowing ACKs from the 
+                * server to drain.
                 */
-               do
+               if (interrupted)
+                       len = 0;
+               else do
                        len = read(local_fd, data, conn->transfer_buflen);
                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
 
diff --git a/sftp.c b/sftp.c
index a47ccf5a2ae7bbad822d4a2d78ccfb0c4a148bff..0bc68f05875b0a8ed964009cfb0c36602d2dd5f7 100644 (file)
--- a/sftp.c
+++ b/sftp.c
@@ -16,7 +16,7 @@
 
 #include "includes.h"
 
-RCSID("$OpenBSD: sftp.c,v 1.45 2004/03/03 09:31:20 djm Exp $");
+RCSID("$OpenBSD: sftp.c,v 1.46 2004/05/19 12:17:33 djm Exp $");
 
 #include "buffer.h"
 #include "xmalloc.h"
@@ -46,6 +46,9 @@ static pid_t sshpid = -1;
 /* This is set to 0 if the progressmeter is not desired. */
 int showprogress = 1;
 
+/* SIGINT received during command processing */
+volatile sig_atomic_t interrupted = 0;
+
 int remote_glob(struct sftp_conn *, const char *, int,
     int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
 
@@ -130,6 +133,24 @@ static const struct CMD cmds[] = {
 
 int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);
 
+static void
+killchild(int signo)
+{
+       if (sshpid > 1)
+               kill(sshpid, SIGTERM);
+
+       _exit(1);
+}
+
+static void
+cmd_interrupt(int signo)
+{
+       const char msg[] = "\rInterrupt  \n";
+
+       write(STDERR_FILENO, msg, sizeof(msg) - 1);
+       interrupted = 1;
+}
+
 static void
 help(void)
 {
@@ -465,7 +486,7 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
                goto out;
        }
 
-       for (i = 0; g.gl_pathv[i]; i++) {
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                if (infer_path(g.gl_pathv[i], &tmp)) {
                        err = -1;
                        goto out;
@@ -534,7 +555,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
                goto out;
        }
 
-       for (i = 0; g.gl_pathv[i]; i++) {
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                if (!is_reg(g.gl_pathv[i])) {
                        error("skipping non-regular file %s",
                            g.gl_pathv[i]);
@@ -621,7 +642,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
 
        qsort(d, n, sizeof(*d), sdirent_comp);
 
-       for (n = 0; d[n] != NULL; n++) {
+       for (n = 0; d[n] != NULL && !interrupted; n++) {
                char *tmp, *fname;
 
                tmp = path_append(path, d[n]->filename);
@@ -673,6 +694,9 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
                return (-1);
        }
 
+       if (interrupted)
+               goto out;
+
        /*
         * If the glob returns a single match, which is the same as the
         * input glob, and it is a directory, then just list its contents
@@ -706,7 +730,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
                colspace = width / columns;
        }
 
-       for (i = 0; g.gl_pathv[i]; i++) {
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                char *fname;
 
                fname = path_strip(g.gl_pathv[i], strip_path);
@@ -743,6 +767,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
        if (!(lflag & LONG_VIEW) && (c != 1))
                printf("\n");
 
+ out:
        if (g.gl_pathc)
                globfree(&g);
 
@@ -952,7 +977,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
        case I_RM:
                path1 = make_absolute(path1, *pwd);
                remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
-               for (i = 0; g.gl_pathv[i]; i++) {
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                        printf("Removing %s\n", g.gl_pathv[i]);
                        err = do_rm(conn, g.gl_pathv[i]);
                        if (err != 0 && err_abort)
@@ -1041,7 +1066,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
                a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
                a.perm = n_arg;
                remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
-               for (i = 0; g.gl_pathv[i]; i++) {
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                        printf("Changing mode on %s\n", g.gl_pathv[i]);
                        err = do_setstat(conn, g.gl_pathv[i], &a);
                        if (err != 0 && err_abort)
@@ -1052,7 +1077,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
        case I_CHGRP:
                path1 = make_absolute(path1, *pwd);
                remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
-               for (i = 0; g.gl_pathv[i]; i++) {
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                        if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
                                if (err != 0 && err_abort)
                                        break;
@@ -1180,6 +1205,8 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
        for (;;) {
                char *cp;
 
+               signal(SIGINT, SIG_IGN);
+
                printf("sftp> ");
 
                /* XXX: use libedit */
@@ -1195,6 +1222,10 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
                if (cp)
                        *cp = '\0';
 
+               /* Handle user interrupts gracefully during commands */
+               interrupted = 0;
+               signal(SIGINT, cmd_interrupt);
+
                err = parse_dispatch_command(conn, cmd, &pwd, batchmode);
                if (err != 0)
                        break;
@@ -1205,15 +1236,6 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
        return (err >= 0 ? 0 : -1);
 }
 
-static void
-killchild(int signo)
-{
-       if (sshpid > 1)
-               kill(sshpid, signo);
-
-       _exit(1);
-}
-
 static void
 connect_to_server(char *path, char **args, int *in, int *out)
 {
@@ -1249,6 +1271,14 @@ connect_to_server(char *path, char **args, int *in, int *out)
                close(*out);
                close(c_in);
                close(c_out);
+
+               /*
+                * The underlying ssh is in the same process group, so we must
+                * ignore SIGINT if we want to gracefully abort commands, 
+                * otherwise the signal will make it to the ssh process and 
+                * kill it too
+                */
+               signal(SIGINT, SIG_IGN);
                execv(path, args);
                fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
                exit(1);
This page took 1.350732 seconds and 5 git commands to generate.