diff options
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 217 |
1 files changed, 130 insertions, 87 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.142 2013/02/08 00:41:12 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.148 2013/07/25 00:56:52 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -38,6 +38,9 @@ | |||
38 | #ifdef HAVE_LIBGEN_H | 38 | #ifdef HAVE_LIBGEN_H |
39 | #include <libgen.h> | 39 | #include <libgen.h> |
40 | #endif | 40 | #endif |
41 | #ifdef HAVE_LOCALE_H | ||
42 | # include <locale.h> | ||
43 | #endif | ||
41 | #ifdef USE_LIBEDIT | 44 | #ifdef USE_LIBEDIT |
42 | #include <histedit.h> | 45 | #include <histedit.h> |
43 | #else | 46 | #else |
@@ -76,12 +79,18 @@ int batchmode = 0; | |||
76 | /* PID of ssh transport process */ | 79 | /* PID of ssh transport process */ |
77 | static pid_t sshpid = -1; | 80 | static pid_t sshpid = -1; |
78 | 81 | ||
82 | /* Suppress diagnositic messages */ | ||
83 | int quiet = 0; | ||
84 | |||
79 | /* This is set to 0 if the progressmeter is not desired. */ | 85 | /* This is set to 0 if the progressmeter is not desired. */ |
80 | int showprogress = 1; | 86 | int showprogress = 1; |
81 | 87 | ||
82 | /* When this option is set, we always recursively download/upload directories */ | 88 | /* When this option is set, we always recursively download/upload directories */ |
83 | int global_rflag = 0; | 89 | int global_rflag = 0; |
84 | 90 | ||
91 | /* When this option is set, we resume download if possible */ | ||
92 | int global_aflag = 0; | ||
93 | |||
85 | /* When this option is set, the file transfers will always preserve times */ | 94 | /* When this option is set, the file transfers will always preserve times */ |
86 | int global_pflag = 0; | 95 | int global_pflag = 0; |
87 | 96 | ||
@@ -145,6 +154,7 @@ extern char *__progname; | |||
145 | #define I_SYMLINK 21 | 154 | #define I_SYMLINK 21 |
146 | #define I_VERSION 22 | 155 | #define I_VERSION 22 |
147 | #define I_PROGRESS 23 | 156 | #define I_PROGRESS 23 |
157 | #define I_REGET 26 | ||
148 | 158 | ||
149 | struct CMD { | 159 | struct CMD { |
150 | const char *c; | 160 | const char *c; |
@@ -184,6 +194,7 @@ static const struct CMD cmds[] = { | |||
184 | { "put", I_PUT, LOCAL }, | 194 | { "put", I_PUT, LOCAL }, |
185 | { "pwd", I_PWD, REMOTE }, | 195 | { "pwd", I_PWD, REMOTE }, |
186 | { "quit", I_QUIT, NOARGS }, | 196 | { "quit", I_QUIT, NOARGS }, |
197 | { "reget", I_REGET, REMOTE }, | ||
187 | { "rename", I_RENAME, REMOTE }, | 198 | { "rename", I_RENAME, REMOTE }, |
188 | { "rm", I_RM, REMOTE }, | 199 | { "rm", I_RM, REMOTE }, |
189 | { "rmdir", I_RMDIR, REMOTE }, | 200 | { "rmdir", I_RMDIR, REMOTE }, |
@@ -215,7 +226,7 @@ cmd_interrupt(int signo) | |||
215 | const char msg[] = "\rInterrupt \n"; | 226 | const char msg[] = "\rInterrupt \n"; |
216 | int olderrno = errno; | 227 | int olderrno = errno; |
217 | 228 | ||
218 | write(STDERR_FILENO, msg, sizeof(msg) - 1); | 229 | (void)write(STDERR_FILENO, msg, sizeof(msg) - 1); |
219 | interrupted = 1; | 230 | interrupted = 1; |
220 | errno = olderrno; | 231 | errno = olderrno; |
221 | } | 232 | } |
@@ -233,6 +244,7 @@ help(void) | |||
233 | " filesystem containing 'path'\n" | 244 | " filesystem containing 'path'\n" |
234 | "exit Quit sftp\n" | 245 | "exit Quit sftp\n" |
235 | "get [-Ppr] remote [local] Download file\n" | 246 | "get [-Ppr] remote [local] Download file\n" |
247 | "reget remote [local] Resume download file\n" | ||
236 | "help Display this help text\n" | 248 | "help Display this help text\n" |
237 | "lcd path Change local directory to 'path'\n" | 249 | "lcd path Change local directory to 'path'\n" |
238 | "lls [ls-options [path]] Display local directory listing\n" | 250 | "lls [ls-options [path]] Display local directory listing\n" |
@@ -306,7 +318,7 @@ local_do_ls(const char *args) | |||
306 | /* XXX: quoting - rip quoting code from ftp? */ | 318 | /* XXX: quoting - rip quoting code from ftp? */ |
307 | snprintf(buf, len, _PATH_LS " %s", args); | 319 | snprintf(buf, len, _PATH_LS " %s", args); |
308 | local_do_shell(buf); | 320 | local_do_shell(buf); |
309 | xfree(buf); | 321 | free(buf); |
310 | } | 322 | } |
311 | } | 323 | } |
312 | 324 | ||
@@ -337,15 +349,15 @@ make_absolute(char *p, char *pwd) | |||
337 | /* Derelativise */ | 349 | /* Derelativise */ |
338 | if (p && p[0] != '/') { | 350 | if (p && p[0] != '/') { |
339 | abs_str = path_append(pwd, p); | 351 | abs_str = path_append(pwd, p); |
340 | xfree(p); | 352 | free(p); |
341 | return(abs_str); | 353 | return(abs_str); |
342 | } else | 354 | } else |
343 | return(p); | 355 | return(p); |
344 | } | 356 | } |
345 | 357 | ||
346 | static int | 358 | static int |
347 | parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, | 359 | parse_getput_flags(const char *cmd, char **argv, int argc, |
348 | int *rflag) | 360 | int *aflag, int *pflag, int *rflag) |
349 | { | 361 | { |
350 | extern int opterr, optind, optopt, optreset; | 362 | extern int opterr, optind, optopt, optreset; |
351 | int ch; | 363 | int ch; |
@@ -353,9 +365,12 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, | |||
353 | optind = optreset = 1; | 365 | optind = optreset = 1; |
354 | opterr = 0; | 366 | opterr = 0; |
355 | 367 | ||
356 | *rflag = *pflag = 0; | 368 | *aflag = *rflag = *pflag = 0; |
357 | while ((ch = getopt(argc, argv, "PpRr")) != -1) { | 369 | while ((ch = getopt(argc, argv, "aPpRr")) != -1) { |
358 | switch (ch) { | 370 | switch (ch) { |
371 | case 'a': | ||
372 | *aflag = 1; | ||
373 | break; | ||
359 | case 'p': | 374 | case 'p': |
360 | case 'P': | 375 | case 'P': |
361 | *pflag = 1; | 376 | *pflag = 1; |
@@ -513,7 +528,7 @@ pathname_is_dir(char *pathname) | |||
513 | 528 | ||
514 | static int | 529 | static int |
515 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | 530 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
516 | int pflag, int rflag) | 531 | int pflag, int rflag, int resume) |
517 | { | 532 | { |
518 | char *abs_src = NULL; | 533 | char *abs_src = NULL; |
519 | char *abs_dst = NULL; | 534 | char *abs_dst = NULL; |
@@ -547,7 +562,7 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
547 | tmp = xstrdup(g.gl_pathv[i]); | 562 | tmp = xstrdup(g.gl_pathv[i]); |
548 | if ((filename = basename(tmp)) == NULL) { | 563 | if ((filename = basename(tmp)) == NULL) { |
549 | error("basename %s: %s", tmp, strerror(errno)); | 564 | error("basename %s: %s", tmp, strerror(errno)); |
550 | xfree(tmp); | 565 | free(tmp); |
551 | err = -1; | 566 | err = -1; |
552 | goto out; | 567 | goto out; |
553 | } | 568 | } |
@@ -563,24 +578,28 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
563 | } else { | 578 | } else { |
564 | abs_dst = xstrdup(filename); | 579 | abs_dst = xstrdup(filename); |
565 | } | 580 | } |
566 | xfree(tmp); | 581 | free(tmp); |
567 | 582 | ||
568 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); | 583 | resume |= global_aflag; |
584 | if (!quiet && resume) | ||
585 | printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); | ||
586 | else if (!quiet && !resume) | ||
587 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); | ||
569 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 588 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
570 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, | 589 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
571 | pflag || global_pflag, 1) == -1) | 590 | pflag || global_pflag, 1, resume) == -1) |
572 | err = -1; | 591 | err = -1; |
573 | } else { | 592 | } else { |
574 | if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, | 593 | if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, |
575 | pflag || global_pflag) == -1) | 594 | pflag || global_pflag, resume) == -1) |
576 | err = -1; | 595 | err = -1; |
577 | } | 596 | } |
578 | xfree(abs_dst); | 597 | free(abs_dst); |
579 | abs_dst = NULL; | 598 | abs_dst = NULL; |
580 | } | 599 | } |
581 | 600 | ||
582 | out: | 601 | out: |
583 | xfree(abs_src); | 602 | free(abs_src); |
584 | globfree(&g); | 603 | globfree(&g); |
585 | return(err); | 604 | return(err); |
586 | } | 605 | } |
@@ -632,7 +651,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
632 | tmp = xstrdup(g.gl_pathv[i]); | 651 | tmp = xstrdup(g.gl_pathv[i]); |
633 | if ((filename = basename(tmp)) == NULL) { | 652 | if ((filename = basename(tmp)) == NULL) { |
634 | error("basename %s: %s", tmp, strerror(errno)); | 653 | error("basename %s: %s", tmp, strerror(errno)); |
635 | xfree(tmp); | 654 | free(tmp); |
636 | err = -1; | 655 | err = -1; |
637 | goto out; | 656 | goto out; |
638 | } | 657 | } |
@@ -648,9 +667,10 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
648 | } else { | 667 | } else { |
649 | abs_dst = make_absolute(xstrdup(filename), pwd); | 668 | abs_dst = make_absolute(xstrdup(filename), pwd); |
650 | } | 669 | } |
651 | xfree(tmp); | 670 | free(tmp); |
652 | 671 | ||
653 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | 672 | if (!quiet) |
673 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | ||
654 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 674 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
655 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, | 675 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
656 | pflag || global_pflag, 1) == -1) | 676 | pflag || global_pflag, 1) == -1) |
@@ -663,10 +683,8 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
663 | } | 683 | } |
664 | 684 | ||
665 | out: | 685 | out: |
666 | if (abs_dst) | 686 | free(abs_dst); |
667 | xfree(abs_dst); | 687 | free(tmp_dst); |
668 | if (tmp_dst) | ||
669 | xfree(tmp_dst); | ||
670 | globfree(&g); | 688 | globfree(&g); |
671 | return(err); | 689 | return(err); |
672 | } | 690 | } |
@@ -714,7 +732,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
714 | /* Add any subpath that also needs to be counted */ | 732 | /* Add any subpath that also needs to be counted */ |
715 | tmp = path_strip(path, strip_path); | 733 | tmp = path_strip(path, strip_path); |
716 | m += strlen(tmp); | 734 | m += strlen(tmp); |
717 | xfree(tmp); | 735 | free(tmp); |
718 | 736 | ||
719 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) | 737 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) |
720 | width = ws.ws_col; | 738 | width = ws.ws_col; |
@@ -740,7 +758,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
740 | 758 | ||
741 | tmp = path_append(path, d[n]->filename); | 759 | tmp = path_append(path, d[n]->filename); |
742 | fname = path_strip(tmp, strip_path); | 760 | fname = path_strip(tmp, strip_path); |
743 | xfree(tmp); | 761 | free(tmp); |
744 | 762 | ||
745 | if (lflag & LS_LONG_VIEW) { | 763 | if (lflag & LS_LONG_VIEW) { |
746 | if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { | 764 | if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { |
@@ -752,7 +770,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
752 | lname = ls_file(fname, &sb, 1, | 770 | lname = ls_file(fname, &sb, 1, |
753 | (lflag & LS_SI_UNITS)); | 771 | (lflag & LS_SI_UNITS)); |
754 | printf("%s\n", lname); | 772 | printf("%s\n", lname); |
755 | xfree(lname); | 773 | free(lname); |
756 | } else | 774 | } else |
757 | printf("%s\n", d[n]->longname); | 775 | printf("%s\n", d[n]->longname); |
758 | } else { | 776 | } else { |
@@ -764,7 +782,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
764 | c++; | 782 | c++; |
765 | } | 783 | } |
766 | 784 | ||
767 | xfree(fname); | 785 | free(fname); |
768 | } | 786 | } |
769 | 787 | ||
770 | if (!(lflag & LS_LONG_VIEW) && (c != 1)) | 788 | if (!(lflag & LS_LONG_VIEW) && (c != 1)) |
@@ -834,7 +852,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
834 | lname = ls_file(fname, g.gl_statv[i], 1, | 852 | lname = ls_file(fname, g.gl_statv[i], 1, |
835 | (lflag & LS_SI_UNITS)); | 853 | (lflag & LS_SI_UNITS)); |
836 | printf("%s\n", lname); | 854 | printf("%s\n", lname); |
837 | xfree(lname); | 855 | free(lname); |
838 | } else { | 856 | } else { |
839 | printf("%-*s", colspace, fname); | 857 | printf("%-*s", colspace, fname); |
840 | if (c >= columns) { | 858 | if (c >= columns) { |
@@ -843,7 +861,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
843 | } else | 861 | } else |
844 | c++; | 862 | c++; |
845 | } | 863 | } |
846 | xfree(fname); | 864 | free(fname); |
847 | } | 865 | } |
848 | 866 | ||
849 | if (!(lflag & LS_LONG_VIEW) && (c != 1)) | 867 | if (!(lflag & LS_LONG_VIEW) && (c != 1)) |
@@ -1112,8 +1130,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1112 | } | 1130 | } |
1113 | 1131 | ||
1114 | static int | 1132 | static int |
1115 | parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, | 1133 | parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, |
1116 | int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) | 1134 | int *pflag, int *rflag, int *sflag, unsigned long *n_arg, |
1135 | char **path1, char **path2) | ||
1117 | { | 1136 | { |
1118 | const char *cmd, *cp = *cpp; | 1137 | const char *cmd, *cp = *cpp; |
1119 | char *cp2, **argv; | 1138 | char *cp2, **argv; |
@@ -1157,14 +1176,15 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, | |||
1157 | } | 1176 | } |
1158 | 1177 | ||
1159 | /* Get arguments and parse flags */ | 1178 | /* Get arguments and parse flags */ |
1160 | *lflag = *pflag = *rflag = *hflag = *n_arg = 0; | 1179 | *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0; |
1161 | *path1 = *path2 = NULL; | 1180 | *path1 = *path2 = NULL; |
1162 | optidx = 1; | 1181 | optidx = 1; |
1163 | switch (cmdnum) { | 1182 | switch (cmdnum) { |
1164 | case I_GET: | 1183 | case I_GET: |
1184 | case I_REGET: | ||
1165 | case I_PUT: | 1185 | case I_PUT: |
1166 | if ((optidx = parse_getput_flags(cmd, argv, argc, | 1186 | if ((optidx = parse_getput_flags(cmd, argv, argc, |
1167 | pflag, rflag)) == -1) | 1187 | aflag, pflag, rflag)) == -1) |
1168 | return -1; | 1188 | return -1; |
1169 | /* Get first pathname (mandatory) */ | 1189 | /* Get first pathname (mandatory) */ |
1170 | if (argc - optidx < 1) { | 1190 | if (argc - optidx < 1) { |
@@ -1179,6 +1199,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, | |||
1179 | /* Destination is not globbed */ | 1199 | /* Destination is not globbed */ |
1180 | undo_glob_escape(*path2); | 1200 | undo_glob_escape(*path2); |
1181 | } | 1201 | } |
1202 | if (*aflag && cmdnum == I_PUT) { | ||
1203 | /* XXX implement resume for uploads */ | ||
1204 | error("Resume is not supported for uploads"); | ||
1205 | return -1; | ||
1206 | } | ||
1182 | break; | 1207 | break; |
1183 | case I_LINK: | 1208 | case I_LINK: |
1184 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) | 1209 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) |
@@ -1287,7 +1312,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1287 | int err_abort) | 1312 | int err_abort) |
1288 | { | 1313 | { |
1289 | char *path1, *path2, *tmp; | 1314 | char *path1, *path2, *tmp; |
1290 | int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0; | 1315 | int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; |
1316 | int rflag = 0, sflag = 0; | ||
1291 | int cmdnum, i; | 1317 | int cmdnum, i; |
1292 | unsigned long n_arg = 0; | 1318 | unsigned long n_arg = 0; |
1293 | Attrib a, *aa; | 1319 | Attrib a, *aa; |
@@ -1296,9 +1322,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1296 | glob_t g; | 1322 | glob_t g; |
1297 | 1323 | ||
1298 | path1 = path2 = NULL; | 1324 | path1 = path2 = NULL; |
1299 | cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, | 1325 | cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag, |
1300 | &sflag, &n_arg, &path1, &path2); | 1326 | &rflag, &sflag, &n_arg, &path1, &path2); |
1301 | |||
1302 | if (iflag != 0) | 1327 | if (iflag != 0) |
1303 | err_abort = 0; | 1328 | err_abort = 0; |
1304 | 1329 | ||
@@ -1313,8 +1338,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1313 | /* Unrecognized command */ | 1338 | /* Unrecognized command */ |
1314 | err = -1; | 1339 | err = -1; |
1315 | break; | 1340 | break; |
1341 | case I_REGET: | ||
1342 | aflag = 1; | ||
1343 | /* FALLTHROUGH */ | ||
1316 | case I_GET: | 1344 | case I_GET: |
1317 | err = process_get(conn, path1, path2, *pwd, pflag, rflag); | 1345 | err = process_get(conn, path1, path2, *pwd, pflag, |
1346 | rflag, aflag); | ||
1318 | break; | 1347 | break; |
1319 | case I_PUT: | 1348 | case I_PUT: |
1320 | err = process_put(conn, path1, path2, *pwd, pflag, rflag); | 1349 | err = process_put(conn, path1, path2, *pwd, pflag, rflag); |
@@ -1335,7 +1364,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1335 | path1 = make_absolute(path1, *pwd); | 1364 | path1 = make_absolute(path1, *pwd); |
1336 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 1365 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
1337 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 1366 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
1338 | printf("Removing %s\n", g.gl_pathv[i]); | 1367 | if (!quiet) |
1368 | printf("Removing %s\n", g.gl_pathv[i]); | ||
1339 | err = do_rm(conn, g.gl_pathv[i]); | 1369 | err = do_rm(conn, g.gl_pathv[i]); |
1340 | if (err != 0 && err_abort) | 1370 | if (err != 0 && err_abort) |
1341 | break; | 1371 | break; |
@@ -1359,24 +1389,24 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1359 | break; | 1389 | break; |
1360 | } | 1390 | } |
1361 | if ((aa = do_stat(conn, tmp, 0)) == NULL) { | 1391 | if ((aa = do_stat(conn, tmp, 0)) == NULL) { |
1362 | xfree(tmp); | 1392 | free(tmp); |
1363 | err = 1; | 1393 | err = 1; |
1364 | break; | 1394 | break; |
1365 | } | 1395 | } |
1366 | if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { | 1396 | if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { |
1367 | error("Can't change directory: Can't check target"); | 1397 | error("Can't change directory: Can't check target"); |
1368 | xfree(tmp); | 1398 | free(tmp); |
1369 | err = 1; | 1399 | err = 1; |
1370 | break; | 1400 | break; |
1371 | } | 1401 | } |
1372 | if (!S_ISDIR(aa->perm)) { | 1402 | if (!S_ISDIR(aa->perm)) { |
1373 | error("Can't change directory: \"%s\" is not " | 1403 | error("Can't change directory: \"%s\" is not " |
1374 | "a directory", tmp); | 1404 | "a directory", tmp); |
1375 | xfree(tmp); | 1405 | free(tmp); |
1376 | err = 1; | 1406 | err = 1; |
1377 | break; | 1407 | break; |
1378 | } | 1408 | } |
1379 | xfree(*pwd); | 1409 | free(*pwd); |
1380 | *pwd = tmp; | 1410 | *pwd = tmp; |
1381 | break; | 1411 | break; |
1382 | case I_LS: | 1412 | case I_LS: |
@@ -1431,7 +1461,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1431 | a.perm = n_arg; | 1461 | a.perm = n_arg; |
1432 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 1462 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
1433 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 1463 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
1434 | printf("Changing mode on %s\n", g.gl_pathv[i]); | 1464 | if (!quiet) |
1465 | printf("Changing mode on %s\n", g.gl_pathv[i]); | ||
1435 | err = do_setstat(conn, g.gl_pathv[i], &a); | 1466 | err = do_setstat(conn, g.gl_pathv[i], &a); |
1436 | if (err != 0 && err_abort) | 1467 | if (err != 0 && err_abort) |
1437 | break; | 1468 | break; |
@@ -1460,10 +1491,14 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1460 | } | 1491 | } |
1461 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | 1492 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
1462 | if (cmdnum == I_CHOWN) { | 1493 | if (cmdnum == I_CHOWN) { |
1463 | printf("Changing owner on %s\n", g.gl_pathv[i]); | 1494 | if (!quiet) |
1495 | printf("Changing owner on %s\n", | ||
1496 | g.gl_pathv[i]); | ||
1464 | aa->uid = n_arg; | 1497 | aa->uid = n_arg; |
1465 | } else { | 1498 | } else { |
1466 | printf("Changing group on %s\n", g.gl_pathv[i]); | 1499 | if (!quiet) |
1500 | printf("Changing group on %s\n", | ||
1501 | g.gl_pathv[i]); | ||
1467 | aa->gid = n_arg; | 1502 | aa->gid = n_arg; |
1468 | } | 1503 | } |
1469 | err = do_setstat(conn, g.gl_pathv[i], aa); | 1504 | err = do_setstat(conn, g.gl_pathv[i], aa); |
@@ -1504,10 +1539,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1504 | 1539 | ||
1505 | if (g.gl_pathc) | 1540 | if (g.gl_pathc) |
1506 | globfree(&g); | 1541 | globfree(&g); |
1507 | if (path1) | 1542 | free(path1); |
1508 | xfree(path1); | 1543 | free(path2); |
1509 | if (path2) | ||
1510 | xfree(path2); | ||
1511 | 1544 | ||
1512 | /* If an unignored error occurs in batch mode we should abort. */ | 1545 | /* If an unignored error occurs in batch mode we should abort. */ |
1513 | if (err_abort && err != 0) | 1546 | if (err_abort && err != 0) |
@@ -1617,8 +1650,8 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1617 | complete_display(list, 0); | 1650 | complete_display(list, 0); |
1618 | 1651 | ||
1619 | for (y = 0; list[y] != NULL; y++) | 1652 | for (y = 0; list[y] != NULL; y++) |
1620 | xfree(list[y]); | 1653 | free(list[y]); |
1621 | xfree(list); | 1654 | free(list); |
1622 | return count; | 1655 | return count; |
1623 | } | 1656 | } |
1624 | 1657 | ||
@@ -1631,7 +1664,7 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1631 | list[count] = NULL; | 1664 | list[count] = NULL; |
1632 | 1665 | ||
1633 | if (count == 0) { | 1666 | if (count == 0) { |
1634 | xfree(list); | 1667 | free(list); |
1635 | return 0; | 1668 | return 0; |
1636 | } | 1669 | } |
1637 | 1670 | ||
@@ -1641,8 +1674,8 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1641 | complete_display(list, 0); | 1674 | complete_display(list, 0); |
1642 | 1675 | ||
1643 | for (y = 0; list[y]; y++) | 1676 | for (y = 0; list[y]; y++) |
1644 | xfree(list[y]); | 1677 | free(list[y]); |
1645 | xfree(list); | 1678 | free(list); |
1646 | 1679 | ||
1647 | if (tmp != NULL) { | 1680 | if (tmp != NULL) { |
1648 | tmplen = strlen(tmp); | 1681 | tmplen = strlen(tmp); |
@@ -1663,7 +1696,7 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1663 | if (y > 0 && el_insertstr(el, argterm) == -1) | 1696 | if (y > 0 && el_insertstr(el, argterm) == -1) |
1664 | fatal("el_insertstr failed."); | 1697 | fatal("el_insertstr failed."); |
1665 | } | 1698 | } |
1666 | xfree(tmp); | 1699 | free(tmp); |
1667 | } | 1700 | } |
1668 | 1701 | ||
1669 | return count; | 1702 | return count; |
@@ -1694,8 +1727,9 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1694 | char *file, int remote, int lastarg, char quote, int terminated) | 1727 | char *file, int remote, int lastarg, char quote, int terminated) |
1695 | { | 1728 | { |
1696 | glob_t g; | 1729 | glob_t g; |
1697 | char *tmp, *tmp2, ins[3]; | 1730 | char *tmp, *tmp2, ins[8]; |
1698 | u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; | 1731 | u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; |
1732 | int clen; | ||
1699 | const LineInfo *lf; | 1733 | const LineInfo *lf; |
1700 | 1734 | ||
1701 | /* Glob from "file" location */ | 1735 | /* Glob from "file" location */ |
@@ -1727,7 +1761,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1727 | if (tmp[tmplen] == '/') | 1761 | if (tmp[tmplen] == '/') |
1728 | pwdlen = tmplen + 1; /* track last seen '/' */ | 1762 | pwdlen = tmplen + 1; /* track last seen '/' */ |
1729 | } | 1763 | } |
1730 | xfree(tmp); | 1764 | free(tmp); |
1731 | 1765 | ||
1732 | if (g.gl_matchc == 0) | 1766 | if (g.gl_matchc == 0) |
1733 | goto out; | 1767 | goto out; |
@@ -1742,7 +1776,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1742 | 1776 | ||
1743 | tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); | 1777 | tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); |
1744 | tmp = path_strip(tmp2, isabs ? NULL : remote_path); | 1778 | tmp = path_strip(tmp2, isabs ? NULL : remote_path); |
1745 | xfree(tmp2); | 1779 | free(tmp2); |
1746 | 1780 | ||
1747 | if (tmp == NULL) | 1781 | if (tmp == NULL) |
1748 | goto out; | 1782 | goto out; |
@@ -1764,10 +1798,13 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1764 | tmp2 = tmp + filelen - cesc; | 1798 | tmp2 = tmp + filelen - cesc; |
1765 | len = strlen(tmp2); | 1799 | len = strlen(tmp2); |
1766 | /* quote argument on way out */ | 1800 | /* quote argument on way out */ |
1767 | for (i = 0; i < len; i++) { | 1801 | for (i = 0; i < len; i += clen) { |
1802 | if ((clen = mblen(tmp2 + i, len - i)) < 0 || | ||
1803 | (size_t)clen > sizeof(ins) - 2) | ||
1804 | fatal("invalid multibyte character"); | ||
1768 | ins[0] = '\\'; | 1805 | ins[0] = '\\'; |
1769 | ins[1] = tmp2[i]; | 1806 | memcpy(ins + 1, tmp2 + i, clen); |
1770 | ins[2] = '\0'; | 1807 | ins[clen + 1] = '\0'; |
1771 | switch (tmp2[i]) { | 1808 | switch (tmp2[i]) { |
1772 | case '\'': | 1809 | case '\'': |
1773 | case '"': | 1810 | case '"': |
@@ -1804,7 +1841,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1804 | if (i > 0 && el_insertstr(el, ins) == -1) | 1841 | if (i > 0 && el_insertstr(el, ins) == -1) |
1805 | fatal("el_insertstr failed."); | 1842 | fatal("el_insertstr failed."); |
1806 | } | 1843 | } |
1807 | xfree(tmp); | 1844 | free(tmp); |
1808 | 1845 | ||
1809 | out: | 1846 | out: |
1810 | globfree(&g); | 1847 | globfree(&g); |
@@ -1816,7 +1853,8 @@ static unsigned char | |||
1816 | complete(EditLine *el, int ch) | 1853 | complete(EditLine *el, int ch) |
1817 | { | 1854 | { |
1818 | char **argv, *line, quote; | 1855 | char **argv, *line, quote; |
1819 | u_int argc, carg, cursor, len, terminated, ret = CC_ERROR; | 1856 | int argc, carg; |
1857 | u_int cursor, len, terminated, ret = CC_ERROR; | ||
1820 | const LineInfo *lf; | 1858 | const LineInfo *lf; |
1821 | struct complete_ctx *complete_ctx; | 1859 | struct complete_ctx *complete_ctx; |
1822 | 1860 | ||
@@ -1830,7 +1868,7 @@ complete(EditLine *el, int ch) | |||
1830 | memcpy(line, lf->buffer, cursor); | 1868 | memcpy(line, lf->buffer, cursor); |
1831 | line[cursor] = '\0'; | 1869 | line[cursor] = '\0'; |
1832 | argv = makeargv(line, &carg, 1, "e, &terminated); | 1870 | argv = makeargv(line, &carg, 1, "e, &terminated); |
1833 | xfree(line); | 1871 | free(line); |
1834 | 1872 | ||
1835 | /* Get all the arguments on the line */ | 1873 | /* Get all the arguments on the line */ |
1836 | len = lf->lastchar - lf->buffer; | 1874 | len = lf->lastchar - lf->buffer; |
@@ -1842,7 +1880,7 @@ complete(EditLine *el, int ch) | |||
1842 | /* Ensure cursor is at EOL or a argument boundary */ | 1880 | /* Ensure cursor is at EOL or a argument boundary */ |
1843 | if (line[cursor] != ' ' && line[cursor] != '\0' && | 1881 | if (line[cursor] != ' ' && line[cursor] != '\0' && |
1844 | line[cursor] != '\n') { | 1882 | line[cursor] != '\n') { |
1845 | xfree(line); | 1883 | free(line); |
1846 | return ret; | 1884 | return ret; |
1847 | } | 1885 | } |
1848 | 1886 | ||
@@ -1870,7 +1908,7 @@ complete(EditLine *el, int ch) | |||
1870 | ret = CC_REDISPLAY; | 1908 | ret = CC_REDISPLAY; |
1871 | } | 1909 | } |
1872 | 1910 | ||
1873 | xfree(line); | 1911 | free(line); |
1874 | return ret; | 1912 | return ret; |
1875 | } | 1913 | } |
1876 | #endif /* USE_LIBEDIT */ | 1914 | #endif /* USE_LIBEDIT */ |
@@ -1922,31 +1960,30 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) | |||
1922 | dir = make_absolute(dir, remote_path); | 1960 | dir = make_absolute(dir, remote_path); |
1923 | 1961 | ||
1924 | if (remote_is_dir(conn, dir) && file2 == NULL) { | 1962 | if (remote_is_dir(conn, dir) && file2 == NULL) { |
1925 | printf("Changing to: %s\n", dir); | 1963 | if (!quiet) |
1964 | printf("Changing to: %s\n", dir); | ||
1926 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); | 1965 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
1927 | if (parse_dispatch_command(conn, cmd, | 1966 | if (parse_dispatch_command(conn, cmd, |
1928 | &remote_path, 1) != 0) { | 1967 | &remote_path, 1) != 0) { |
1929 | xfree(dir); | 1968 | free(dir); |
1930 | xfree(remote_path); | 1969 | free(remote_path); |
1931 | xfree(conn); | 1970 | free(conn); |
1932 | return (-1); | 1971 | return (-1); |
1933 | } | 1972 | } |
1934 | } else { | 1973 | } else { |
1935 | /* XXX this is wrong wrt quoting */ | 1974 | /* XXX this is wrong wrt quoting */ |
1936 | if (file2 == NULL) | 1975 | snprintf(cmd, sizeof cmd, "get%s %s%s%s", |
1937 | snprintf(cmd, sizeof cmd, "get %s", dir); | 1976 | global_aflag ? " -a" : "", dir, |
1938 | else | 1977 | file2 == NULL ? "" : " ", |
1939 | snprintf(cmd, sizeof cmd, "get %s %s", dir, | 1978 | file2 == NULL ? "" : file2); |
1940 | file2); | ||
1941 | |||
1942 | err = parse_dispatch_command(conn, cmd, | 1979 | err = parse_dispatch_command(conn, cmd, |
1943 | &remote_path, 1); | 1980 | &remote_path, 1); |
1944 | xfree(dir); | 1981 | free(dir); |
1945 | xfree(remote_path); | 1982 | free(remote_path); |
1946 | xfree(conn); | 1983 | free(conn); |
1947 | return (err); | 1984 | return (err); |
1948 | } | 1985 | } |
1949 | xfree(dir); | 1986 | free(dir); |
1950 | } | 1987 | } |
1951 | 1988 | ||
1952 | setlinebuf(stdout); | 1989 | setlinebuf(stdout); |
@@ -2004,8 +2041,8 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) | |||
2004 | if (err != 0) | 2041 | if (err != 0) |
2005 | break; | 2042 | break; |
2006 | } | 2043 | } |
2007 | xfree(remote_path); | 2044 | free(remote_path); |
2008 | xfree(conn); | 2045 | free(conn); |
2009 | 2046 | ||
2010 | #ifdef USE_LIBEDIT | 2047 | #ifdef USE_LIBEDIT |
2011 | if (el != NULL) | 2048 | if (el != NULL) |
@@ -2112,6 +2149,7 @@ main(int argc, char **argv) | |||
2112 | 2149 | ||
2113 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 2150 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
2114 | sanitise_stdfd(); | 2151 | sanitise_stdfd(); |
2152 | setlocale(LC_CTYPE, ""); | ||
2115 | 2153 | ||
2116 | __progname = ssh_get_progname(argv[0]); | 2154 | __progname = ssh_get_progname(argv[0]); |
2117 | memset(&args, '\0', sizeof(args)); | 2155 | memset(&args, '\0', sizeof(args)); |
@@ -2126,7 +2164,7 @@ main(int argc, char **argv) | |||
2126 | infile = stdin; | 2164 | infile = stdin; |
2127 | 2165 | ||
2128 | while ((ch = getopt(argc, argv, | 2166 | while ((ch = getopt(argc, argv, |
2129 | "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { | 2167 | "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { |
2130 | switch (ch) { | 2168 | switch (ch) { |
2131 | /* Passed through to ssh(1) */ | 2169 | /* Passed through to ssh(1) */ |
2132 | case '4': | 2170 | case '4': |
@@ -2143,6 +2181,8 @@ main(int argc, char **argv) | |||
2143 | addargs(&args, "%s", optarg); | 2181 | addargs(&args, "%s", optarg); |
2144 | break; | 2182 | break; |
2145 | case 'q': | 2183 | case 'q': |
2184 | ll = SYSLOG_LEVEL_ERROR; | ||
2185 | quiet = 1; | ||
2146 | showprogress = 0; | 2186 | showprogress = 0; |
2147 | addargs(&args, "-%c", ch); | 2187 | addargs(&args, "-%c", ch); |
2148 | break; | 2188 | break; |
@@ -2164,6 +2204,9 @@ main(int argc, char **argv) | |||
2164 | case '2': | 2204 | case '2': |
2165 | sshver = 2; | 2205 | sshver = 2; |
2166 | break; | 2206 | break; |
2207 | case 'a': | ||
2208 | global_aflag = 1; | ||
2209 | break; | ||
2167 | case 'B': | 2210 | case 'B': |
2168 | copy_buffer_len = strtol(optarg, &cp, 10); | 2211 | copy_buffer_len = strtol(optarg, &cp, 10); |
2169 | if (copy_buffer_len == 0 || *cp != '\0') | 2212 | if (copy_buffer_len == 0 || *cp != '\0') |
@@ -2178,7 +2221,7 @@ main(int argc, char **argv) | |||
2178 | (infile = fopen(optarg, "r")) == NULL) | 2221 | (infile = fopen(optarg, "r")) == NULL) |
2179 | fatal("%s (%s).", strerror(errno), optarg); | 2222 | fatal("%s (%s).", strerror(errno), optarg); |
2180 | showprogress = 0; | 2223 | showprogress = 0; |
2181 | batchmode = 1; | 2224 | quiet = batchmode = 1; |
2182 | addargs(&args, "-obatchmode yes"); | 2225 | addargs(&args, "-obatchmode yes"); |
2183 | break; | 2226 | break; |
2184 | case 'p': | 2227 | case 'p': |
@@ -2275,7 +2318,7 @@ main(int argc, char **argv) | |||
2275 | if (conn == NULL) | 2318 | if (conn == NULL) |
2276 | fatal("Couldn't initialise connection to server"); | 2319 | fatal("Couldn't initialise connection to server"); |
2277 | 2320 | ||
2278 | if (!batchmode) { | 2321 | if (!quiet) { |
2279 | if (sftp_direct == NULL) | 2322 | if (sftp_direct == NULL) |
2280 | fprintf(stderr, "Connected to %s.\n", host); | 2323 | fprintf(stderr, "Connected to %s.\n", host); |
2281 | else | 2324 | else |