summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--sftp-client.c35
-rw-r--r--sftp.c64
3 files changed, 83 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 4b7b656c7..bc124cc7d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
120040524
2 - (dtucker) OpenBSD CVS Sync
3 - djm@cvs.openbsd.org 2004/05/19 12:17:33
4 [sftp-client.c sftp.c]
5 gracefully abort transfers on receipt of SIGINT, also ignore SIGINT while
6 waiting for a command; ok markus@
7
120040523 820040523
2 - (djm) [sshd_config] Explain consequences of UsePAM=yes a little better in 9 - (djm) [sshd_config] Explain consequences of UsePAM=yes a little better in
3 sshd_config; ok dtucker@ 10 sshd_config; ok dtucker@
@@ -1126,4 +1133,4 @@
1126 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 1133 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
1127 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 1134 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
1128 1135
1129$Id: ChangeLog,v 1.3358 2004/05/23 06:22:27 mouring Exp $ 1136$Id: ChangeLog,v 1.3359 2004/05/24 00:12:19 dtucker Exp $
diff --git a/sftp-client.c b/sftp-client.c
index bf2eb43ac..6dcd5de74 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -20,7 +20,7 @@
20/* XXX: copy between two remote sites */ 20/* XXX: copy between two remote sites */
21 21
22#include "includes.h" 22#include "includes.h"
23RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $"); 23RCSID("$OpenBSD: sftp-client.c,v 1.49 2004/05/19 12:17:33 djm Exp $");
24 24
25#include "openbsd-compat/sys-queue.h" 25#include "openbsd-compat/sys-queue.h"
26 26
@@ -36,6 +36,7 @@ RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $");
36#include "sftp-common.h" 36#include "sftp-common.h"
37#include "sftp-client.h" 37#include "sftp-client.h"
38 38
39extern volatile sig_atomic_t interrupted;
39extern int showprogress; 40extern int showprogress;
40 41
41/* Minimum amount of data to read at at time */ 42/* Minimum amount of data to read at at time */
@@ -330,7 +331,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
330 (*dir)[0] = NULL; 331 (*dir)[0] = NULL;
331 } 332 }
332 333
333 for (;;) { 334 for (; !interrupted;) {
334 int count; 335 int count;
335 336
336 id = expected_id = conn->msg_id++; 337 id = expected_id = conn->msg_id++;
@@ -407,6 +408,13 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
407 do_close(conn, handle, handle_len); 408 do_close(conn, handle, handle_len);
408 xfree(handle); 409 xfree(handle);
409 410
411 /* Don't return partial matches on interrupt */
412 if (interrupted && dir != NULL && *dir != NULL) {
413 free_sftp_dirents(*dir);
414 *dir = xmalloc(sizeof(**dir));
415 **dir = NULL;
416 }
417
410 return(0); 418 return(0);
411} 419}
412 420
@@ -812,6 +820,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
812 char *data; 820 char *data;
813 u_int len; 821 u_int len;
814 822
823 /*
824 * Simulate EOF on interrupt: stop sending new requests and
825 * allow outstanding requests to drain gracefully
826 */
827 if (interrupted) {
828 if (num_req == 0) /* If we haven't started yet... */
829 break;
830 max_req = 0;
831 }
832
815 /* Send some more requests */ 833 /* Send some more requests */
816 while (num_req < max_req) { 834 while (num_req < max_req) {
817 debug3("Request range %llu -> %llu (%d/%d)", 835 debug3("Request range %llu -> %llu (%d/%d)",
@@ -899,8 +917,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
899 (unsigned long long)offset, 917 (unsigned long long)offset,
900 num_req); 918 num_req);
901 max_req = 1; 919 max_req = 1;
902 } 920 } else if (max_req <= conn->num_requests) {
903 else if (max_req < conn->num_requests + 1) {
904 ++max_req; 921 ++max_req;
905 } 922 }
906 } 923 }
@@ -1036,10 +1053,14 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1036 int len; 1053 int len;
1037 1054
1038 /* 1055 /*
1039 * Can't use atomicio here because it returns 0 on EOF, thus losing 1056 * Can't use atomicio here because it returns 0 on EOF,
1040 * the last block of the file 1057 * thus losing the last block of the file.
1058 * Simulate an EOF on interrupt, allowing ACKs from the
1059 * server to drain.
1041 */ 1060 */
1042 do 1061 if (interrupted)
1062 len = 0;
1063 else do
1043 len = read(local_fd, data, conn->transfer_buflen); 1064 len = read(local_fd, data, conn->transfer_buflen);
1044 while ((len == -1) && (errno == EINTR || errno == EAGAIN)); 1065 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1045 1066
diff --git a/sftp.c b/sftp.c
index a47ccf5a2..0bc68f058 100644
--- a/sftp.c
+++ b/sftp.c
@@ -16,7 +16,7 @@
16 16
17#include "includes.h" 17#include "includes.h"
18 18
19RCSID("$OpenBSD: sftp.c,v 1.45 2004/03/03 09:31:20 djm Exp $"); 19RCSID("$OpenBSD: sftp.c,v 1.46 2004/05/19 12:17:33 djm Exp $");
20 20
21#include "buffer.h" 21#include "buffer.h"
22#include "xmalloc.h" 22#include "xmalloc.h"
@@ -46,6 +46,9 @@ static pid_t sshpid = -1;
46/* This is set to 0 if the progressmeter is not desired. */ 46/* This is set to 0 if the progressmeter is not desired. */
47int showprogress = 1; 47int showprogress = 1;
48 48
49/* SIGINT received during command processing */
50volatile sig_atomic_t interrupted = 0;
51
49int remote_glob(struct sftp_conn *, const char *, int, 52int remote_glob(struct sftp_conn *, const char *, int,
50 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ 53 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
51 54
@@ -131,6 +134,24 @@ static const struct CMD cmds[] = {
131int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); 134int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);
132 135
133static void 136static void
137killchild(int signo)
138{
139 if (sshpid > 1)
140 kill(sshpid, SIGTERM);
141
142 _exit(1);
143}
144
145static void
146cmd_interrupt(int signo)
147{
148 const char msg[] = "\rInterrupt \n";
149
150 write(STDERR_FILENO, msg, sizeof(msg) - 1);
151 interrupted = 1;
152}
153
154static void
134help(void) 155help(void)
135{ 156{
136 printf("Available commands:\n"); 157 printf("Available commands:\n");
@@ -465,7 +486,7 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
465 goto out; 486 goto out;
466 } 487 }
467 488
468 for (i = 0; g.gl_pathv[i]; i++) { 489 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
469 if (infer_path(g.gl_pathv[i], &tmp)) { 490 if (infer_path(g.gl_pathv[i], &tmp)) {
470 err = -1; 491 err = -1;
471 goto out; 492 goto out;
@@ -534,7 +555,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
534 goto out; 555 goto out;
535 } 556 }
536 557
537 for (i = 0; g.gl_pathv[i]; i++) { 558 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
538 if (!is_reg(g.gl_pathv[i])) { 559 if (!is_reg(g.gl_pathv[i])) {
539 error("skipping non-regular file %s", 560 error("skipping non-regular file %s",
540 g.gl_pathv[i]); 561 g.gl_pathv[i]);
@@ -621,7 +642,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
621 642
622 qsort(d, n, sizeof(*d), sdirent_comp); 643 qsort(d, n, sizeof(*d), sdirent_comp);
623 644
624 for (n = 0; d[n] != NULL; n++) { 645 for (n = 0; d[n] != NULL && !interrupted; n++) {
625 char *tmp, *fname; 646 char *tmp, *fname;
626 647
627 tmp = path_append(path, d[n]->filename); 648 tmp = path_append(path, d[n]->filename);
@@ -673,6 +694,9 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
673 return (-1); 694 return (-1);
674 } 695 }
675 696
697 if (interrupted)
698 goto out;
699
676 /* 700 /*
677 * If the glob returns a single match, which is the same as the 701 * If the glob returns a single match, which is the same as the
678 * input glob, and it is a directory, then just list its contents 702 * 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,
706 colspace = width / columns; 730 colspace = width / columns;
707 } 731 }
708 732
709 for (i = 0; g.gl_pathv[i]; i++) { 733 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
710 char *fname; 734 char *fname;
711 735
712 fname = path_strip(g.gl_pathv[i], strip_path); 736 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,
743 if (!(lflag & LONG_VIEW) && (c != 1)) 767 if (!(lflag & LONG_VIEW) && (c != 1))
744 printf("\n"); 768 printf("\n");
745 769
770 out:
746 if (g.gl_pathc) 771 if (g.gl_pathc)
747 globfree(&g); 772 globfree(&g);
748 773
@@ -952,7 +977,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
952 case I_RM: 977 case I_RM:
953 path1 = make_absolute(path1, *pwd); 978 path1 = make_absolute(path1, *pwd);
954 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 979 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
955 for (i = 0; g.gl_pathv[i]; i++) { 980 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
956 printf("Removing %s\n", g.gl_pathv[i]); 981 printf("Removing %s\n", g.gl_pathv[i]);
957 err = do_rm(conn, g.gl_pathv[i]); 982 err = do_rm(conn, g.gl_pathv[i]);
958 if (err != 0 && err_abort) 983 if (err != 0 && err_abort)
@@ -1041,7 +1066,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1041 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1066 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1042 a.perm = n_arg; 1067 a.perm = n_arg;
1043 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1068 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1044 for (i = 0; g.gl_pathv[i]; i++) { 1069 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1045 printf("Changing mode on %s\n", g.gl_pathv[i]); 1070 printf("Changing mode on %s\n", g.gl_pathv[i]);
1046 err = do_setstat(conn, g.gl_pathv[i], &a); 1071 err = do_setstat(conn, g.gl_pathv[i], &a);
1047 if (err != 0 && err_abort) 1072 if (err != 0 && err_abort)
@@ -1052,7 +1077,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1052 case I_CHGRP: 1077 case I_CHGRP:
1053 path1 = make_absolute(path1, *pwd); 1078 path1 = make_absolute(path1, *pwd);
1054 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1079 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1055 for (i = 0; g.gl_pathv[i]; i++) { 1080 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1056 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { 1081 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1057 if (err != 0 && err_abort) 1082 if (err != 0 && err_abort)
1058 break; 1083 break;
@@ -1180,6 +1205,8 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
1180 for (;;) { 1205 for (;;) {
1181 char *cp; 1206 char *cp;
1182 1207
1208 signal(SIGINT, SIG_IGN);
1209
1183 printf("sftp> "); 1210 printf("sftp> ");
1184 1211
1185 /* XXX: use libedit */ 1212 /* XXX: use libedit */
@@ -1195,6 +1222,10 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
1195 if (cp) 1222 if (cp)
1196 *cp = '\0'; 1223 *cp = '\0';
1197 1224
1225 /* Handle user interrupts gracefully during commands */
1226 interrupted = 0;
1227 signal(SIGINT, cmd_interrupt);
1228
1198 err = parse_dispatch_command(conn, cmd, &pwd, batchmode); 1229 err = parse_dispatch_command(conn, cmd, &pwd, batchmode);
1199 if (err != 0) 1230 if (err != 0)
1200 break; 1231 break;
@@ -1206,15 +1237,6 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
1206} 1237}
1207 1238
1208static void 1239static void
1209killchild(int signo)
1210{
1211 if (sshpid > 1)
1212 kill(sshpid, signo);
1213
1214 _exit(1);
1215}
1216
1217static void
1218connect_to_server(char *path, char **args, int *in, int *out) 1240connect_to_server(char *path, char **args, int *in, int *out)
1219{ 1241{
1220 int c_in, c_out; 1242 int c_in, c_out;
@@ -1249,6 +1271,14 @@ connect_to_server(char *path, char **args, int *in, int *out)
1249 close(*out); 1271 close(*out);
1250 close(c_in); 1272 close(c_in);
1251 close(c_out); 1273 close(c_out);
1274
1275 /*
1276 * The underlying ssh is in the same process group, so we must
1277 * ignore SIGINT if we want to gracefully abort commands,
1278 * otherwise the signal will make it to the ssh process and
1279 * kill it too
1280 */
1281 signal(SIGINT, SIG_IGN);
1252 execv(path, args); 1282 execv(path, args);
1253 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 1283 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
1254 exit(1); 1284 exit(1);