diff options
Diffstat (limited to 'sftp-int.c')
-rw-r--r-- | sftp-int.c | 197 |
1 files changed, 130 insertions, 67 deletions
diff --git a/sftp-int.c b/sftp-int.c index 6a2012910..6987de9a3 100644 --- a/sftp-int.c +++ b/sftp-int.c | |||
@@ -25,7 +25,7 @@ | |||
25 | /* XXX: recursive operations */ | 25 | /* XXX: recursive operations */ |
26 | 26 | ||
27 | #include "includes.h" | 27 | #include "includes.h" |
28 | RCSID("$OpenBSD: sftp-int.c,v 1.49 2002/09/12 00:13:06 djm Exp $"); | 28 | RCSID("$OpenBSD: sftp-int.c,v 1.57 2003/03/05 22:33:43 markus Exp $"); |
29 | 29 | ||
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
@@ -47,6 +47,9 @@ extern size_t copy_buffer_len; | |||
47 | /* Number of concurrent outstanding requests */ | 47 | /* Number of concurrent outstanding requests */ |
48 | extern int num_requests; | 48 | extern int num_requests; |
49 | 49 | ||
50 | /* This is set to 0 if the progressmeter is not desired. */ | ||
51 | int showprogress = 1; | ||
52 | |||
50 | /* Seperators for interactive commands */ | 53 | /* Seperators for interactive commands */ |
51 | #define WHITESPACE " \t\r\n" | 54 | #define WHITESPACE " \t\r\n" |
52 | 55 | ||
@@ -73,13 +76,14 @@ extern int num_requests; | |||
73 | #define I_SHELL 20 | 76 | #define I_SHELL 20 |
74 | #define I_SYMLINK 21 | 77 | #define I_SYMLINK 21 |
75 | #define I_VERSION 22 | 78 | #define I_VERSION 22 |
79 | #define I_PROGRESS 23 | ||
76 | 80 | ||
77 | struct CMD { | 81 | struct CMD { |
78 | const char *c; | 82 | const char *c; |
79 | const int n; | 83 | const int n; |
80 | }; | 84 | }; |
81 | 85 | ||
82 | const struct CMD cmds[] = { | 86 | static const struct CMD cmds[] = { |
83 | { "bye", I_QUIT }, | 87 | { "bye", I_QUIT }, |
84 | { "cd", I_CHDIR }, | 88 | { "cd", I_CHDIR }, |
85 | { "chdir", I_CHDIR }, | 89 | { "chdir", I_CHDIR }, |
@@ -100,6 +104,7 @@ const struct CMD cmds[] = { | |||
100 | { "ls", I_LS }, | 104 | { "ls", I_LS }, |
101 | { "lumask", I_LUMASK }, | 105 | { "lumask", I_LUMASK }, |
102 | { "mkdir", I_MKDIR }, | 106 | { "mkdir", I_MKDIR }, |
107 | { "progress", I_PROGRESS }, | ||
103 | { "put", I_PUT }, | 108 | { "put", I_PUT }, |
104 | { "mput", I_PUT }, | 109 | { "mput", I_PUT }, |
105 | { "pwd", I_PWD }, | 110 | { "pwd", I_PWD }, |
@@ -132,6 +137,7 @@ help(void) | |||
132 | printf("ls [path] Display remote directory listing\n"); | 137 | printf("ls [path] Display remote directory listing\n"); |
133 | printf("lumask umask Set local umask to 'umask'\n"); | 138 | printf("lumask umask Set local umask to 'umask'\n"); |
134 | printf("mkdir path Create remote directory\n"); | 139 | printf("mkdir path Create remote directory\n"); |
140 | printf("progress Toggle display of progress meter\n"); | ||
135 | printf("put local-path [remote-path] Upload file\n"); | 141 | printf("put local-path [remote-path] Upload file\n"); |
136 | printf("pwd Display remote working directory\n"); | 142 | printf("pwd Display remote working directory\n"); |
137 | printf("exit Quit sftp\n"); | 143 | printf("exit Quit sftp\n"); |
@@ -375,6 +381,17 @@ is_dir(char *path) | |||
375 | } | 381 | } |
376 | 382 | ||
377 | static int | 383 | static int |
384 | is_reg(char *path) | ||
385 | { | ||
386 | struct stat sb; | ||
387 | |||
388 | if (stat(path, &sb) == -1) | ||
389 | fatal("stat %s: %s", path, strerror(errno)); | ||
390 | |||
391 | return(S_ISREG(sb.st_mode)); | ||
392 | } | ||
393 | |||
394 | static int | ||
378 | remote_is_dir(struct sftp_conn *conn, char *path) | 395 | remote_is_dir(struct sftp_conn *conn, char *path) |
379 | { | 396 | { |
380 | Attrib *a; | 397 | Attrib *a; |
@@ -425,7 +442,6 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
425 | err = -1; | 442 | err = -1; |
426 | goto out; | 443 | goto out; |
427 | } | 444 | } |
428 | printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); | ||
429 | err = do_download(conn, g.gl_pathv[0], abs_dst, pflag); | 445 | err = do_download(conn, g.gl_pathv[0], abs_dst, pflag); |
430 | goto out; | 446 | goto out; |
431 | } | 447 | } |
@@ -489,6 +505,12 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
489 | 505 | ||
490 | /* Only one match, dst may be file, directory or unspecified */ | 506 | /* Only one match, dst may be file, directory or unspecified */ |
491 | if (g.gl_pathv[0] && g.gl_matchc == 1) { | 507 | if (g.gl_pathv[0] && g.gl_matchc == 1) { |
508 | if (!is_reg(g.gl_pathv[0])) { | ||
509 | error("Can't upload %s: not a regular file", | ||
510 | g.gl_pathv[0]); | ||
511 | err = 1; | ||
512 | goto out; | ||
513 | } | ||
492 | if (tmp_dst) { | 514 | if (tmp_dst) { |
493 | /* If directory specified, append filename */ | 515 | /* If directory specified, append filename */ |
494 | if (remote_is_dir(conn, tmp_dst)) { | 516 | if (remote_is_dir(conn, tmp_dst)) { |
@@ -507,7 +529,6 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
507 | } | 529 | } |
508 | abs_dst = make_absolute(abs_dst, pwd); | 530 | abs_dst = make_absolute(abs_dst, pwd); |
509 | } | 531 | } |
510 | printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst); | ||
511 | err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag); | 532 | err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag); |
512 | goto out; | 533 | goto out; |
513 | } | 534 | } |
@@ -521,6 +542,11 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
521 | } | 542 | } |
522 | 543 | ||
523 | for (i = 0; g.gl_pathv[i]; i++) { | 544 | for (i = 0; g.gl_pathv[i]; i++) { |
545 | if (!is_reg(g.gl_pathv[i])) { | ||
546 | error("skipping non-regular file %s", | ||
547 | g.gl_pathv[i]); | ||
548 | continue; | ||
549 | } | ||
524 | if (infer_path(g.gl_pathv[i], &tmp)) { | 550 | if (infer_path(g.gl_pathv[i], &tmp)) { |
525 | err = -1; | 551 | err = -1; |
526 | goto out; | 552 | goto out; |
@@ -550,7 +576,7 @@ sdirent_comp(const void *aa, const void *bb) | |||
550 | SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; | 576 | SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; |
551 | SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; | 577 | SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; |
552 | 578 | ||
553 | return (strcmp(a->filename, b->filename)); | 579 | return (strcmp(a->filename, b->filename)); |
554 | } | 580 | } |
555 | 581 | ||
556 | /* sftp ls.1 replacement for directories */ | 582 | /* sftp ls.1 replacement for directories */ |
@@ -563,7 +589,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
563 | if ((n = do_readdir(conn, path, &d)) != 0) | 589 | if ((n = do_readdir(conn, path, &d)) != 0) |
564 | return (n); | 590 | return (n); |
565 | 591 | ||
566 | /* Count entries for sort */ | 592 | /* Count entries for sort */ |
567 | for (n = 0; d[n] != NULL; n++) | 593 | for (n = 0; d[n] != NULL; n++) |
568 | ; | 594 | ; |
569 | 595 | ||
@@ -571,7 +597,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
571 | 597 | ||
572 | for (n = 0; d[n] != NULL; n++) { | 598 | for (n = 0; d[n] != NULL; n++) { |
573 | char *tmp, *fname; | 599 | char *tmp, *fname; |
574 | 600 | ||
575 | tmp = path_append(path, d[n]->filename); | 601 | tmp = path_append(path, d[n]->filename); |
576 | fname = path_strip(tmp, strip_path); | 602 | fname = path_strip(tmp, strip_path); |
577 | xfree(tmp); | 603 | xfree(tmp); |
@@ -589,7 +615,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
589 | /* XXX - multicolumn display would be nice here */ | 615 | /* XXX - multicolumn display would be nice here */ |
590 | printf("%s\n", fname); | 616 | printf("%s\n", fname); |
591 | } | 617 | } |
592 | 618 | ||
593 | xfree(fname); | 619 | xfree(fname); |
594 | } | 620 | } |
595 | 621 | ||
@@ -599,7 +625,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
599 | 625 | ||
600 | /* sftp ls.1 replacement which handles path globs */ | 626 | /* sftp ls.1 replacement which handles path globs */ |
601 | static int | 627 | static int |
602 | do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | 628 | do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, |
603 | int lflag) | 629 | int lflag) |
604 | { | 630 | { |
605 | glob_t g; | 631 | glob_t g; |
@@ -609,23 +635,23 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
609 | 635 | ||
610 | memset(&g, 0, sizeof(g)); | 636 | memset(&g, 0, sizeof(g)); |
611 | 637 | ||
612 | if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, | 638 | if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, |
613 | NULL, &g)) { | 639 | NULL, &g)) { |
614 | error("Can't ls: \"%s\" not found", path); | 640 | error("Can't ls: \"%s\" not found", path); |
615 | return (-1); | 641 | return (-1); |
616 | } | 642 | } |
617 | 643 | ||
618 | /* | 644 | /* |
619 | * If the glob returns a single match, which is the same as the | 645 | * If the glob returns a single match, which is the same as the |
620 | * input glob, and it is a directory, then just list its contents | 646 | * input glob, and it is a directory, then just list its contents |
621 | */ | 647 | */ |
622 | if (g.gl_pathc == 1 && | 648 | if (g.gl_pathc == 1 && |
623 | strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) { | 649 | strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) { |
624 | if ((a = do_lstat(conn, path, 1)) == NULL) { | 650 | if ((a = do_lstat(conn, path, 1)) == NULL) { |
625 | globfree(&g); | 651 | globfree(&g); |
626 | return (-1); | 652 | return (-1); |
627 | } | 653 | } |
628 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && | 654 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
629 | S_ISDIR(a->perm)) { | 655 | S_ISDIR(a->perm)) { |
630 | globfree(&g); | 656 | globfree(&g); |
631 | return (do_ls_dir(conn, path, strip_path, lflag)); | 657 | return (do_ls_dir(conn, path, strip_path, lflag)); |
@@ -640,8 +666,8 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
640 | if (lflag) { | 666 | if (lflag) { |
641 | /* | 667 | /* |
642 | * XXX: this is slow - 1 roundtrip per path | 668 | * XXX: this is slow - 1 roundtrip per path |
643 | * A solution to this is to fork glob() and | 669 | * A solution to this is to fork glob() and |
644 | * build a sftp specific version which keeps the | 670 | * build a sftp specific version which keeps the |
645 | * attribs (which currently get thrown away) | 671 | * attribs (which currently get thrown away) |
646 | * that the server returns as well as the filenames. | 672 | * that the server returns as well as the filenames. |
647 | */ | 673 | */ |
@@ -666,7 +692,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
666 | } | 692 | } |
667 | 693 | ||
668 | static int | 694 | static int |
669 | parse_args(const char **cpp, int *pflag, int *lflag, | 695 | parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, |
670 | unsigned long *n_arg, char **path1, char **path2) | 696 | unsigned long *n_arg, char **path1, char **path2) |
671 | { | 697 | { |
672 | const char *cmd, *cp = *cpp; | 698 | const char *cmd, *cp = *cpp; |
@@ -678,10 +704,17 @@ parse_args(const char **cpp, int *pflag, int *lflag, | |||
678 | /* Skip leading whitespace */ | 704 | /* Skip leading whitespace */ |
679 | cp = cp + strspn(cp, WHITESPACE); | 705 | cp = cp + strspn(cp, WHITESPACE); |
680 | 706 | ||
681 | /* Ignore blank lines */ | 707 | /* Ignore blank lines and lines which begin with comment '#' char */ |
682 | if (!*cp) | 708 | if (*cp == '\0' || *cp == '#') |
683 | return(-1); | 709 | return (0); |
684 | 710 | ||
711 | /* Check for leading '-' (disable error processing) */ | ||
712 | *iflag = 0; | ||
713 | if (*cp == '-') { | ||
714 | *iflag = 1; | ||
715 | cp++; | ||
716 | } | ||
717 | |||
685 | /* Figure out which command we have */ | 718 | /* Figure out which command we have */ |
686 | for (i = 0; cmds[i].c; i++) { | 719 | for (i = 0; cmds[i].c; i++) { |
687 | int cmdlen = strlen(cmds[i].c); | 720 | int cmdlen = strlen(cmds[i].c); |
@@ -703,7 +736,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, | |||
703 | cmdnum = I_SHELL; | 736 | cmdnum = I_SHELL; |
704 | } else if (cmdnum == -1) { | 737 | } else if (cmdnum == -1) { |
705 | error("Invalid command."); | 738 | error("Invalid command."); |
706 | return(-1); | 739 | return (-1); |
707 | } | 740 | } |
708 | 741 | ||
709 | /* Get arguments and parse flags */ | 742 | /* Get arguments and parse flags */ |
@@ -803,6 +836,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, | |||
803 | case I_LPWD: | 836 | case I_LPWD: |
804 | case I_HELP: | 837 | case I_HELP: |
805 | case I_VERSION: | 838 | case I_VERSION: |
839 | case I_PROGRESS: | ||
806 | break; | 840 | break; |
807 | default: | 841 | default: |
808 | fatal("Command not implemented"); | 842 | fatal("Command not implemented"); |
@@ -813,10 +847,11 @@ parse_args(const char **cpp, int *pflag, int *lflag, | |||
813 | } | 847 | } |
814 | 848 | ||
815 | static int | 849 | static int |
816 | parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | 850 | parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, |
851 | int err_abort) | ||
817 | { | 852 | { |
818 | char *path1, *path2, *tmp; | 853 | char *path1, *path2, *tmp; |
819 | int pflag, lflag, cmdnum, i; | 854 | int pflag, lflag, iflag, cmdnum, i; |
820 | unsigned long n_arg; | 855 | unsigned long n_arg; |
821 | Attrib a, *aa; | 856 | Attrib a, *aa; |
822 | char path_buf[MAXPATHLEN]; | 857 | char path_buf[MAXPATHLEN]; |
@@ -824,14 +859,22 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | |||
824 | glob_t g; | 859 | glob_t g; |
825 | 860 | ||
826 | path1 = path2 = NULL; | 861 | path1 = path2 = NULL; |
827 | cmdnum = parse_args(&cmd, &pflag, &lflag, &n_arg, | 862 | cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg, |
828 | &path1, &path2); | 863 | &path1, &path2); |
829 | 864 | ||
865 | if (iflag != 0) | ||
866 | err_abort = 0; | ||
867 | |||
830 | memset(&g, 0, sizeof(g)); | 868 | memset(&g, 0, sizeof(g)); |
831 | 869 | ||
832 | /* Perform command */ | 870 | /* Perform command */ |
833 | switch (cmdnum) { | 871 | switch (cmdnum) { |
872 | case 0: | ||
873 | /* Blank line */ | ||
874 | break; | ||
834 | case -1: | 875 | case -1: |
876 | /* Unrecognized command */ | ||
877 | err = -1; | ||
835 | break; | 878 | break; |
836 | case I_GET: | 879 | case I_GET: |
837 | err = process_get(conn, path1, path2, *pwd, pflag); | 880 | err = process_get(conn, path1, path2, *pwd, pflag); |
@@ -853,8 +896,9 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | |||
853 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 896 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
854 | for (i = 0; g.gl_pathv[i]; i++) { | 897 | for (i = 0; g.gl_pathv[i]; i++) { |
855 | printf("Removing %s\n", g.gl_pathv[i]); | 898 | printf("Removing %s\n", g.gl_pathv[i]); |
856 | if (do_rm(conn, g.gl_pathv[i]) == -1) | 899 | err = do_rm(conn, g.gl_pathv[i]); |
857 | err = -1; | 900 | if (err != 0 && err_abort) |
901 | break; | ||
858 | } | 902 | } |
859 | break; | 903 | break; |
860 | case I_MKDIR: | 904 | case I_MKDIR: |
@@ -900,15 +944,14 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | |||
900 | do_globbed_ls(conn, *pwd, *pwd, lflag); | 944 | do_globbed_ls(conn, *pwd, *pwd, lflag); |
901 | break; | 945 | break; |
902 | } | 946 | } |
903 | 947 | ||
904 | /* Strip pwd off beginning of non-absolute paths */ | 948 | /* Strip pwd off beginning of non-absolute paths */ |
905 | tmp = NULL; | 949 | tmp = NULL; |
906 | if (*path1 != '/') | 950 | if (*path1 != '/') |
907 | tmp = *pwd; | 951 | tmp = *pwd; |
908 | 952 | ||
909 | path1 = make_absolute(path1, *pwd); | 953 | path1 = make_absolute(path1, *pwd); |
910 | 954 | err = do_globbed_ls(conn, path1, tmp, lflag); | |
911 | do_globbed_ls(conn, path1, tmp, lflag); | ||
912 | break; | 955 | break; |
913 | case I_LCHDIR: | 956 | case I_LCHDIR: |
914 | if (chdir(path1) == -1) { | 957 | if (chdir(path1) == -1) { |
@@ -942,62 +985,70 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | |||
942 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 985 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
943 | for (i = 0; g.gl_pathv[i]; i++) { | 986 | for (i = 0; g.gl_pathv[i]; i++) { |
944 | printf("Changing mode on %s\n", g.gl_pathv[i]); | 987 | printf("Changing mode on %s\n", g.gl_pathv[i]); |
945 | do_setstat(conn, g.gl_pathv[i], &a); | 988 | err = do_setstat(conn, g.gl_pathv[i], &a); |
989 | if (err != 0 && err_abort) | ||
990 | break; | ||
946 | } | 991 | } |
947 | break; | 992 | break; |
948 | case I_CHOWN: | 993 | case I_CHOWN: |
949 | path1 = make_absolute(path1, *pwd); | ||
950 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | ||
951 | for (i = 0; g.gl_pathv[i]; i++) { | ||
952 | if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) | ||
953 | continue; | ||
954 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | ||
955 | error("Can't get current ownership of " | ||
956 | "remote file \"%s\"", g.gl_pathv[i]); | ||
957 | continue; | ||
958 | } | ||
959 | printf("Changing owner on %s\n", g.gl_pathv[i]); | ||
960 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
961 | aa->uid = n_arg; | ||
962 | do_setstat(conn, g.gl_pathv[i], aa); | ||
963 | } | ||
964 | break; | ||
965 | case I_CHGRP: | 994 | case I_CHGRP: |
966 | path1 = make_absolute(path1, *pwd); | 995 | path1 = make_absolute(path1, *pwd); |
967 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); | 996 | remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); |
968 | for (i = 0; g.gl_pathv[i]; i++) { | 997 | for (i = 0; g.gl_pathv[i]; i++) { |
969 | if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) | 998 | if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { |
970 | continue; | 999 | if (err != 0 && err_abort) |
1000 | break; | ||
1001 | else | ||
1002 | continue; | ||
1003 | } | ||
971 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | 1004 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
972 | error("Can't get current ownership of " | 1005 | error("Can't get current ownership of " |
973 | "remote file \"%s\"", g.gl_pathv[i]); | 1006 | "remote file \"%s\"", g.gl_pathv[i]); |
974 | continue; | 1007 | if (err != 0 && err_abort) |
1008 | break; | ||
1009 | else | ||
1010 | continue; | ||
975 | } | 1011 | } |
976 | printf("Changing group on %s\n", g.gl_pathv[i]); | ||
977 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | 1012 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
978 | aa->gid = n_arg; | 1013 | if (cmdnum == I_CHOWN) { |
979 | do_setstat(conn, g.gl_pathv[i], aa); | 1014 | printf("Changing owner on %s\n", g.gl_pathv[i]); |
1015 | aa->uid = n_arg; | ||
1016 | } else { | ||
1017 | printf("Changing group on %s\n", g.gl_pathv[i]); | ||
1018 | aa->gid = n_arg; | ||
1019 | } | ||
1020 | err = do_setstat(conn, g.gl_pathv[i], aa); | ||
1021 | if (err != 0 && err_abort) | ||
1022 | break; | ||
980 | } | 1023 | } |
981 | break; | 1024 | break; |
982 | case I_PWD: | 1025 | case I_PWD: |
983 | printf("Remote working directory: %s\n", *pwd); | 1026 | printf("Remote working directory: %s\n", *pwd); |
984 | break; | 1027 | break; |
985 | case I_LPWD: | 1028 | case I_LPWD: |
986 | if (!getcwd(path_buf, sizeof(path_buf))) | 1029 | if (!getcwd(path_buf, sizeof(path_buf))) { |
987 | error("Couldn't get local cwd: %s", | 1030 | error("Couldn't get local cwd: %s", strerror(errno)); |
988 | strerror(errno)); | 1031 | err = -1; |
989 | else | 1032 | break; |
990 | printf("Local working directory: %s\n", | 1033 | } |
991 | path_buf); | 1034 | printf("Local working directory: %s\n", path_buf); |
992 | break; | 1035 | break; |
993 | case I_QUIT: | 1036 | case I_QUIT: |
994 | return(-1); | 1037 | /* Processed below */ |
1038 | break; | ||
995 | case I_HELP: | 1039 | case I_HELP: |
996 | help(); | 1040 | help(); |
997 | break; | 1041 | break; |
998 | case I_VERSION: | 1042 | case I_VERSION: |
999 | printf("SFTP protocol version %u\n", sftp_proto_version(conn)); | 1043 | printf("SFTP protocol version %u\n", sftp_proto_version(conn)); |
1000 | break; | 1044 | break; |
1045 | case I_PROGRESS: | ||
1046 | showprogress = !showprogress; | ||
1047 | if (showprogress) | ||
1048 | printf("Progress meter enabled\n"); | ||
1049 | else | ||
1050 | printf("Progress meter disabled\n"); | ||
1051 | break; | ||
1001 | default: | 1052 | default: |
1002 | fatal("%d is not implemented", cmdnum); | 1053 | fatal("%d is not implemented", cmdnum); |
1003 | } | 1054 | } |
@@ -1009,20 +1060,23 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | |||
1009 | if (path2) | 1060 | if (path2) |
1010 | xfree(path2); | 1061 | xfree(path2); |
1011 | 1062 | ||
1012 | /* If an error occurs in batch mode we should abort. */ | 1063 | /* If an unignored error occurs in batch mode we should abort. */ |
1013 | if (infile != stdin && err > 0) | 1064 | if (err_abort && err != 0) |
1014 | return -1; | 1065 | return (-1); |
1066 | else if (cmdnum == I_QUIT) | ||
1067 | return (1); | ||
1015 | 1068 | ||
1016 | return(0); | 1069 | return (0); |
1017 | } | 1070 | } |
1018 | 1071 | ||
1019 | void | 1072 | int |
1020 | interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | 1073 | interactive_loop(int fd_in, int fd_out, char *file1, char *file2) |
1021 | { | 1074 | { |
1022 | char *pwd; | 1075 | char *pwd; |
1023 | char *dir = NULL; | 1076 | char *dir = NULL; |
1024 | char cmd[2048]; | 1077 | char cmd[2048]; |
1025 | struct sftp_conn *conn; | 1078 | struct sftp_conn *conn; |
1079 | int err; | ||
1026 | 1080 | ||
1027 | conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); | 1081 | conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); |
1028 | if (conn == NULL) | 1082 | if (conn == NULL) |
@@ -1039,7 +1093,8 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1039 | if (remote_is_dir(conn, dir) && file2 == NULL) { | 1093 | if (remote_is_dir(conn, dir) && file2 == NULL) { |
1040 | printf("Changing to: %s\n", dir); | 1094 | printf("Changing to: %s\n", dir); |
1041 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); | 1095 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
1042 | parse_dispatch_command(conn, cmd, &pwd); | 1096 | if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) |
1097 | return (-1); | ||
1043 | } else { | 1098 | } else { |
1044 | if (file2 == NULL) | 1099 | if (file2 == NULL) |
1045 | snprintf(cmd, sizeof cmd, "get %s", dir); | 1100 | snprintf(cmd, sizeof cmd, "get %s", dir); |
@@ -1047,12 +1102,14 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1047 | snprintf(cmd, sizeof cmd, "get %s %s", dir, | 1102 | snprintf(cmd, sizeof cmd, "get %s %s", dir, |
1048 | file2); | 1103 | file2); |
1049 | 1104 | ||
1050 | parse_dispatch_command(conn, cmd, &pwd); | 1105 | err = parse_dispatch_command(conn, cmd, &pwd, 1); |
1051 | xfree(dir); | 1106 | xfree(dir); |
1052 | return; | 1107 | xfree(pwd); |
1108 | return (err); | ||
1053 | } | 1109 | } |
1054 | xfree(dir); | 1110 | xfree(dir); |
1055 | } | 1111 | } |
1112 | |||
1056 | #if HAVE_SETVBUF | 1113 | #if HAVE_SETVBUF |
1057 | setvbuf(stdout, NULL, _IOLBF, 0); | 1114 | setvbuf(stdout, NULL, _IOLBF, 0); |
1058 | setvbuf(infile, NULL, _IOLBF, 0); | 1115 | setvbuf(infile, NULL, _IOLBF, 0); |
@@ -1061,6 +1118,7 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1061 | setlinebuf(infile); | 1118 | setlinebuf(infile); |
1062 | #endif | 1119 | #endif |
1063 | 1120 | ||
1121 | err = 0; | ||
1064 | for (;;) { | 1122 | for (;;) { |
1065 | char *cp; | 1123 | char *cp; |
1066 | 1124 | ||
@@ -1077,8 +1135,13 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1077 | if (cp) | 1135 | if (cp) |
1078 | *cp = '\0'; | 1136 | *cp = '\0'; |
1079 | 1137 | ||
1080 | if (parse_dispatch_command(conn, cmd, &pwd)) | 1138 | err = parse_dispatch_command(conn, cmd, &pwd, infile != stdin); |
1139 | if (err != 0) | ||
1081 | break; | 1140 | break; |
1082 | } | 1141 | } |
1083 | xfree(pwd); | 1142 | xfree(pwd); |
1143 | |||
1144 | /* err == 1 signifies normal "quit" exit */ | ||
1145 | return (err >= 0 ? 0 : -1); | ||
1084 | } | 1146 | } |
1147 | |||