diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | sftp-client.c | 35 | ||||
-rw-r--r-- | sftp.c | 64 |
3 files changed, 83 insertions, 25 deletions
@@ -1,3 +1,10 @@ | |||
1 | 20040524 | ||
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 | |||
1 | 20040523 | 8 | 20040523 |
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" |
23 | RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $"); | 23 | RCSID("$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 | ||
39 | extern volatile sig_atomic_t interrupted; | ||
39 | extern int showprogress; | 40 | extern 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 | ||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | 18 | ||
19 | RCSID("$OpenBSD: sftp.c,v 1.45 2004/03/03 09:31:20 djm Exp $"); | 19 | RCSID("$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. */ |
47 | int showprogress = 1; | 47 | int showprogress = 1; |
48 | 48 | ||
49 | /* SIGINT received during command processing */ | ||
50 | volatile sig_atomic_t interrupted = 0; | ||
51 | |||
49 | int remote_glob(struct sftp_conn *, const char *, int, | 52 | int 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[] = { | |||
131 | int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); | 134 | int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); |
132 | 135 | ||
133 | static void | 136 | static void |
137 | killchild(int signo) | ||
138 | { | ||
139 | if (sshpid > 1) | ||
140 | kill(sshpid, SIGTERM); | ||
141 | |||
142 | _exit(1); | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | cmd_interrupt(int signo) | ||
147 | { | ||
148 | const char msg[] = "\rInterrupt \n"; | ||
149 | |||
150 | write(STDERR_FILENO, msg, sizeof(msg) - 1); | ||
151 | interrupted = 1; | ||
152 | } | ||
153 | |||
154 | static void | ||
134 | help(void) | 155 | help(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 | ||
1208 | static void | 1239 | static void |
1209 | killchild(int signo) | ||
1210 | { | ||
1211 | if (sshpid > 1) | ||
1212 | kill(sshpid, signo); | ||
1213 | |||
1214 | _exit(1); | ||
1215 | } | ||
1216 | |||
1217 | static void | ||
1218 | connect_to_server(char *path, char **args, int *in, int *out) | 1240 | connect_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); |