diff options
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 104 |
1 files changed, 82 insertions, 22 deletions
@@ -16,7 +16,13 @@ | |||
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | 18 | ||
19 | RCSID("$OpenBSD: sftp.c,v 1.56 2004/07/11 17:48:47 deraadt Exp $"); | 19 | RCSID("$OpenBSD: sftp.c,v 1.62 2005/02/20 22:59:06 djm Exp $"); |
20 | |||
21 | #ifdef USE_LIBEDIT | ||
22 | #include <histedit.h> | ||
23 | #else | ||
24 | typedef void EditLine; | ||
25 | #endif | ||
20 | 26 | ||
21 | #include "buffer.h" | 27 | #include "buffer.h" |
22 | #include "xmalloc.h" | 28 | #include "xmalloc.h" |
@@ -144,8 +150,10 @@ int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); | |||
144 | static void | 150 | static void |
145 | killchild(int signo) | 151 | killchild(int signo) |
146 | { | 152 | { |
147 | if (sshpid > 1) | 153 | if (sshpid > 1) { |
148 | kill(sshpid, SIGTERM); | 154 | kill(sshpid, SIGTERM); |
155 | waitpid(sshpid, NULL, 0); | ||
156 | } | ||
149 | 157 | ||
150 | _exit(1); | 158 | _exit(1); |
151 | } | 159 | } |
@@ -154,9 +162,11 @@ static void | |||
154 | cmd_interrupt(int signo) | 162 | cmd_interrupt(int signo) |
155 | { | 163 | { |
156 | const char msg[] = "\rInterrupt \n"; | 164 | const char msg[] = "\rInterrupt \n"; |
165 | int olderrno = errno; | ||
157 | 166 | ||
158 | write(STDERR_FILENO, msg, sizeof(msg) - 1); | 167 | write(STDERR_FILENO, msg, sizeof(msg) - 1); |
159 | interrupted = 1; | 168 | interrupted = 1; |
169 | errno = olderrno; | ||
160 | } | 170 | } |
161 | 171 | ||
162 | static void | 172 | static void |
@@ -256,7 +266,7 @@ path_strip(char *path, char *strip) | |||
256 | return (xstrdup(path)); | 266 | return (xstrdup(path)); |
257 | 267 | ||
258 | len = strlen(strip); | 268 | len = strlen(strip); |
259 | if (strip != NULL && strncmp(path, strip, len) == 0) { | 269 | if (strncmp(path, strip, len) == 0) { |
260 | if (strip[len - 1] != '/' && path[len] == '/') | 270 | if (strip[len - 1] != '/' && path[len] == '/') |
261 | len++; | 271 | len++; |
262 | return (xstrdup(path + len)); | 272 | return (xstrdup(path + len)); |
@@ -738,12 +748,14 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
738 | { | 748 | { |
739 | glob_t g; | 749 | glob_t g; |
740 | int i, c = 1, colspace = 0, columns = 1; | 750 | int i, c = 1, colspace = 0, columns = 1; |
741 | Attrib *a; | 751 | Attrib *a = NULL; |
742 | 752 | ||
743 | memset(&g, 0, sizeof(g)); | 753 | memset(&g, 0, sizeof(g)); |
744 | 754 | ||
745 | if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, | 755 | if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, |
746 | NULL, &g)) { | 756 | NULL, &g) || (g.gl_pathc && !g.gl_matchc)) { |
757 | if (g.gl_pathc) | ||
758 | globfree(&g); | ||
747 | error("Can't ls: \"%s\" not found", path); | 759 | error("Can't ls: \"%s\" not found", path); |
748 | return (-1); | 760 | return (-1); |
749 | } | 761 | } |
@@ -752,19 +764,21 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
752 | goto out; | 764 | goto out; |
753 | 765 | ||
754 | /* | 766 | /* |
755 | * If the glob returns a single match, which is the same as the | 767 | * If the glob returns a single match and it is a directory, |
756 | * input glob, and it is a directory, then just list its contents | 768 | * then just list its contents. |
757 | */ | 769 | */ |
758 | if (g.gl_pathc == 1 && | 770 | if (g.gl_matchc == 1) { |
759 | strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) { | 771 | if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) { |
760 | if ((a = do_lstat(conn, path, 1)) == NULL) { | ||
761 | globfree(&g); | 772 | globfree(&g); |
762 | return (-1); | 773 | return (-1); |
763 | } | 774 | } |
764 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && | 775 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
765 | S_ISDIR(a->perm)) { | 776 | S_ISDIR(a->perm)) { |
777 | int err; | ||
778 | |||
779 | err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); | ||
766 | globfree(&g); | 780 | globfree(&g); |
767 | return (do_ls_dir(conn, path, strip_path, lflag)); | 781 | return (err); |
768 | } | 782 | } |
769 | } | 783 | } |
770 | 784 | ||
@@ -784,7 +798,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
784 | colspace = width / columns; | 798 | colspace = width / columns; |
785 | } | 799 | } |
786 | 800 | ||
787 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 801 | for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) { |
788 | char *fname; | 802 | char *fname; |
789 | 803 | ||
790 | fname = path_strip(g.gl_pathv[i], strip_path); | 804 | fname = path_strip(g.gl_pathv[i], strip_path); |
@@ -801,7 +815,8 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
801 | * that the server returns as well as the filenames. | 815 | * that the server returns as well as the filenames. |
802 | */ | 816 | */ |
803 | memset(&sb, 0, sizeof(sb)); | 817 | memset(&sb, 0, sizeof(sb)); |
804 | a = do_lstat(conn, g.gl_pathv[i], 1); | 818 | if (a == NULL) |
819 | a = do_lstat(conn, g.gl_pathv[i], 1); | ||
805 | if (a != NULL) | 820 | if (a != NULL) |
806 | attrib_to_stat(a, &sb); | 821 | attrib_to_stat(a, &sb); |
807 | lname = ls_file(fname, &sb, 1); | 822 | lname = ls_file(fname, &sb, 1); |
@@ -1206,6 +1221,14 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1206 | return (0); | 1221 | return (0); |
1207 | } | 1222 | } |
1208 | 1223 | ||
1224 | #ifdef USE_LIBEDIT | ||
1225 | static char * | ||
1226 | prompt(EditLine *el) | ||
1227 | { | ||
1228 | return ("sftp> "); | ||
1229 | } | ||
1230 | #endif | ||
1231 | |||
1209 | int | 1232 | int |
1210 | interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | 1233 | interactive_loop(int fd_in, int fd_out, char *file1, char *file2) |
1211 | { | 1234 | { |
@@ -1214,6 +1237,27 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1214 | char cmd[2048]; | 1237 | char cmd[2048]; |
1215 | struct sftp_conn *conn; | 1238 | struct sftp_conn *conn; |
1216 | int err; | 1239 | int err; |
1240 | EditLine *el = NULL; | ||
1241 | #ifdef USE_LIBEDIT | ||
1242 | History *hl = NULL; | ||
1243 | HistEvent hev; | ||
1244 | extern char *__progname; | ||
1245 | |||
1246 | if (!batchmode && isatty(STDIN_FILENO)) { | ||
1247 | if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) | ||
1248 | fatal("Couldn't initialise editline"); | ||
1249 | if ((hl = history_init()) == NULL) | ||
1250 | fatal("Couldn't initialise editline history"); | ||
1251 | history(hl, &hev, H_SETSIZE, 100); | ||
1252 | el_set(el, EL_HIST, history, hl); | ||
1253 | |||
1254 | el_set(el, EL_PROMPT, prompt); | ||
1255 | el_set(el, EL_EDITOR, "emacs"); | ||
1256 | el_set(el, EL_TERMINAL, NULL); | ||
1257 | el_set(el, EL_SIGNAL, 1); | ||
1258 | el_source(el, NULL); | ||
1259 | } | ||
1260 | #endif /* USE_LIBEDIT */ | ||
1217 | 1261 | ||
1218 | conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); | 1262 | conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); |
1219 | if (conn == NULL) | 1263 | if (conn == NULL) |
@@ -1230,8 +1274,11 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1230 | if (remote_is_dir(conn, dir) && file2 == NULL) { | 1274 | if (remote_is_dir(conn, dir) && file2 == NULL) { |
1231 | printf("Changing to: %s\n", dir); | 1275 | printf("Changing to: %s\n", dir); |
1232 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); | 1276 | snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); |
1233 | if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) | 1277 | if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { |
1278 | xfree(dir); | ||
1279 | xfree(pwd); | ||
1234 | return (-1); | 1280 | return (-1); |
1281 | } | ||
1235 | } else { | 1282 | } else { |
1236 | if (file2 == NULL) | 1283 | if (file2 == NULL) |
1237 | snprintf(cmd, sizeof cmd, "get %s", dir); | 1284 | snprintf(cmd, sizeof cmd, "get %s", dir); |
@@ -1261,17 +1308,29 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) | |||
1261 | 1308 | ||
1262 | signal(SIGINT, SIG_IGN); | 1309 | signal(SIGINT, SIG_IGN); |
1263 | 1310 | ||
1264 | printf("sftp> "); | 1311 | if (el == NULL) { |
1312 | printf("sftp> "); | ||
1313 | if (fgets(cmd, sizeof(cmd), infile) == NULL) { | ||
1314 | printf("\n"); | ||
1315 | break; | ||
1316 | } | ||
1317 | if (batchmode) /* Echo command */ | ||
1318 | printf("%s", cmd); | ||
1319 | } else { | ||
1320 | #ifdef USE_LIBEDIT | ||
1321 | const char *line; | ||
1322 | int count = 0; | ||
1265 | 1323 | ||
1266 | /* XXX: use libedit */ | 1324 | if ((line = el_gets(el, &count)) == NULL || count <= 0) |
1267 | if (fgets(cmd, sizeof(cmd), infile) == NULL) { | 1325 | break; |
1268 | printf("\n"); | 1326 | history(hl, &hev, H_ENTER, line); |
1269 | break; | 1327 | if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { |
1328 | fprintf(stderr, "Error: input line too long\n"); | ||
1329 | continue; | ||
1330 | } | ||
1331 | #endif /* USE_LIBEDIT */ | ||
1270 | } | 1332 | } |
1271 | 1333 | ||
1272 | if (batchmode) /* Echo command */ | ||
1273 | printf("%s", cmd); | ||
1274 | |||
1275 | cp = strrchr(cmd, '\n'); | 1334 | cp = strrchr(cmd, '\n'); |
1276 | if (cp) | 1335 | if (cp) |
1277 | *cp = '\0'; | 1336 | *cp = '\0'; |
@@ -1420,6 +1479,7 @@ main(int argc, char **argv) | |||
1420 | fatal("%s (%s).", strerror(errno), optarg); | 1479 | fatal("%s (%s).", strerror(errno), optarg); |
1421 | showprogress = 0; | 1480 | showprogress = 0; |
1422 | batchmode = 1; | 1481 | batchmode = 1; |
1482 | addargs(&args, "-obatchmode yes"); | ||
1423 | break; | 1483 | break; |
1424 | case 'P': | 1484 | case 'P': |
1425 | sftp_direct = optarg; | 1485 | sftp_direct = optarg; |