]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/sftp.c
Import tzdata 2017b
[FreeBSD/FreeBSD.git] / crypto / openssh / sftp.c
1 /* $OpenBSD: sftp.c,v 1.177 2016/10/18 12:41:22 millert Exp $ */
2 /*
3  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "includes.h"
19
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #ifdef HAVE_SYS_STAT_H
23 # include <sys/stat.h>
24 #endif
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/wait.h>
28 #ifdef HAVE_SYS_STATVFS_H
29 #include <sys/statvfs.h>
30 #endif
31
32 #include <ctype.h>
33 #include <errno.h>
34
35 #ifdef HAVE_PATHS_H
36 # include <paths.h>
37 #endif
38 #ifdef HAVE_LIBGEN_H
39 #include <libgen.h>
40 #endif
41 #ifdef HAVE_LOCALE_H
42 # include <locale.h>
43 #endif
44 #ifdef USE_LIBEDIT
45 #include <histedit.h>
46 #else
47 typedef void EditLine;
48 #endif
49 #include <limits.h>
50 #include <signal.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <stdarg.h>
57
58 #ifdef HAVE_UTIL_H
59 # include <util.h>
60 #endif
61
62 #include "xmalloc.h"
63 #include "log.h"
64 #include "pathnames.h"
65 #include "misc.h"
66 #include "utf8.h"
67
68 #include "sftp.h"
69 #include "ssherr.h"
70 #include "sshbuf.h"
71 #include "sftp-common.h"
72 #include "sftp-client.h"
73
74 #define DEFAULT_COPY_BUFLEN     32768   /* Size of buffer for up/download */
75 #define DEFAULT_NUM_REQUESTS    64      /* # concurrent outstanding requests */
76
77 /* File to read commands from */
78 FILE* infile;
79
80 /* Are we in batchfile mode? */
81 int batchmode = 0;
82
83 /* PID of ssh transport process */
84 static pid_t sshpid = -1;
85
86 /* Suppress diagnositic messages */
87 int quiet = 0;
88
89 /* This is set to 0 if the progressmeter is not desired. */
90 int showprogress = 1;
91
92 /* When this option is set, we always recursively download/upload directories */
93 int global_rflag = 0;
94
95 /* When this option is set, we resume download or upload if possible */
96 int global_aflag = 0;
97
98 /* When this option is set, the file transfers will always preserve times */
99 int global_pflag = 0;
100
101 /* When this option is set, transfers will have fsync() called on each file */
102 int global_fflag = 0;
103
104 /* SIGINT received during command processing */
105 volatile sig_atomic_t interrupted = 0;
106
107 /* I wish qsort() took a separate ctx for the comparison function...*/
108 int sort_flag;
109
110 /* Context used for commandline completion */
111 struct complete_ctx {
112         struct sftp_conn *conn;
113         char **remote_pathp;
114 };
115
116 int remote_glob(struct sftp_conn *, const char *, int,
117     int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
118
119 extern char *__progname;
120
121 /* Separators for interactive commands */
122 #define WHITESPACE " \t\r\n"
123
124 /* ls flags */
125 #define LS_LONG_VIEW    0x0001  /* Full view ala ls -l */
126 #define LS_SHORT_VIEW   0x0002  /* Single row view ala ls -1 */
127 #define LS_NUMERIC_VIEW 0x0004  /* Long view with numeric uid/gid */
128 #define LS_NAME_SORT    0x0008  /* Sort by name (default) */
129 #define LS_TIME_SORT    0x0010  /* Sort by mtime */
130 #define LS_SIZE_SORT    0x0020  /* Sort by file size */
131 #define LS_REVERSE_SORT 0x0040  /* Reverse sort order */
132 #define LS_SHOW_ALL     0x0080  /* Don't skip filenames starting with '.' */
133 #define LS_SI_UNITS     0x0100  /* Display sizes as K, M, G, etc. */
134
135 #define VIEW_FLAGS      (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
136 #define SORT_FLAGS      (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
137
138 /* Commands for interactive mode */
139 enum sftp_command {
140         I_CHDIR = 1,
141         I_CHGRP,
142         I_CHMOD,
143         I_CHOWN,
144         I_DF,
145         I_GET,
146         I_HELP,
147         I_LCHDIR,
148         I_LINK,
149         I_LLS,
150         I_LMKDIR,
151         I_LPWD,
152         I_LS,
153         I_LUMASK,
154         I_MKDIR,
155         I_PUT,
156         I_PWD,
157         I_QUIT,
158         I_REGET,
159         I_RENAME,
160         I_REPUT,
161         I_RM,
162         I_RMDIR,
163         I_SHELL,
164         I_SYMLINK,
165         I_VERSION,
166         I_PROGRESS,
167 };
168
169 struct CMD {
170         const char *c;
171         const int n;
172         const int t;
173 };
174
175 /* Type of completion */
176 #define NOARGS  0
177 #define REMOTE  1
178 #define LOCAL   2
179
180 static const struct CMD cmds[] = {
181         { "bye",        I_QUIT,         NOARGS  },
182         { "cd",         I_CHDIR,        REMOTE  },
183         { "chdir",      I_CHDIR,        REMOTE  },
184         { "chgrp",      I_CHGRP,        REMOTE  },
185         { "chmod",      I_CHMOD,        REMOTE  },
186         { "chown",      I_CHOWN,        REMOTE  },
187         { "df",         I_DF,           REMOTE  },
188         { "dir",        I_LS,           REMOTE  },
189         { "exit",       I_QUIT,         NOARGS  },
190         { "get",        I_GET,          REMOTE  },
191         { "help",       I_HELP,         NOARGS  },
192         { "lcd",        I_LCHDIR,       LOCAL   },
193         { "lchdir",     I_LCHDIR,       LOCAL   },
194         { "lls",        I_LLS,          LOCAL   },
195         { "lmkdir",     I_LMKDIR,       LOCAL   },
196         { "ln",         I_LINK,         REMOTE  },
197         { "lpwd",       I_LPWD,         LOCAL   },
198         { "ls",         I_LS,           REMOTE  },
199         { "lumask",     I_LUMASK,       NOARGS  },
200         { "mkdir",      I_MKDIR,        REMOTE  },
201         { "mget",       I_GET,          REMOTE  },
202         { "mput",       I_PUT,          LOCAL   },
203         { "progress",   I_PROGRESS,     NOARGS  },
204         { "put",        I_PUT,          LOCAL   },
205         { "pwd",        I_PWD,          REMOTE  },
206         { "quit",       I_QUIT,         NOARGS  },
207         { "reget",      I_REGET,        REMOTE  },
208         { "rename",     I_RENAME,       REMOTE  },
209         { "reput",      I_REPUT,        LOCAL   },
210         { "rm",         I_RM,           REMOTE  },
211         { "rmdir",      I_RMDIR,        REMOTE  },
212         { "symlink",    I_SYMLINK,      REMOTE  },
213         { "version",    I_VERSION,      NOARGS  },
214         { "!",          I_SHELL,        NOARGS  },
215         { "?",          I_HELP,         NOARGS  },
216         { NULL,         -1,             -1      }
217 };
218
219 int interactive_loop(struct sftp_conn *, char *file1, char *file2);
220
221 /* ARGSUSED */
222 static void
223 killchild(int signo)
224 {
225         if (sshpid > 1) {
226                 kill(sshpid, SIGTERM);
227                 waitpid(sshpid, NULL, 0);
228         }
229
230         _exit(1);
231 }
232
233 /* ARGSUSED */
234 static void
235 suspchild(int signo)
236 {
237         if (sshpid > 1) {
238                 kill(sshpid, signo);
239                 while (waitpid(sshpid, NULL, WUNTRACED) == -1 && errno == EINTR)
240                         continue;
241         }
242         kill(getpid(), SIGSTOP);
243 }
244
245 /* ARGSUSED */
246 static void
247 cmd_interrupt(int signo)
248 {
249         const char msg[] = "\rInterrupt  \n";
250         int olderrno = errno;
251
252         (void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
253         interrupted = 1;
254         errno = olderrno;
255 }
256
257 static void
258 help(void)
259 {
260         printf("Available commands:\n"
261             "bye                                Quit sftp\n"
262             "cd path                            Change remote directory to 'path'\n"
263             "chgrp grp path                     Change group of file 'path' to 'grp'\n"
264             "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
265             "chown own path                     Change owner of file 'path' to 'own'\n"
266             "df [-hi] [path]                    Display statistics for current directory or\n"
267             "                                   filesystem containing 'path'\n"
268             "exit                               Quit sftp\n"
269             "get [-afPpRr] remote [local]       Download file\n"
270             "reget [-fPpRr] remote [local]      Resume download file\n"
271             "reput [-fPpRr] [local] remote      Resume upload file\n"
272             "help                               Display this help text\n"
273             "lcd path                           Change local directory to 'path'\n"
274             "lls [ls-options [path]]            Display local directory listing\n"
275             "lmkdir path                        Create local directory\n"
276             "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
277             "lpwd                               Print local working directory\n"
278             "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
279             "lumask umask                       Set local umask to 'umask'\n"
280             "mkdir path                         Create remote directory\n"
281             "progress                           Toggle display of progress meter\n"
282             "put [-afPpRr] local [remote]       Upload file\n"
283             "pwd                                Display remote working directory\n"
284             "quit                               Quit sftp\n"
285             "rename oldpath newpath             Rename remote file\n"
286             "rm path                            Delete remote file\n"
287             "rmdir path                         Remove remote directory\n"
288             "symlink oldpath newpath            Symlink remote file\n"
289             "version                            Show SFTP version\n"
290             "!command                           Execute 'command' in local shell\n"
291             "!                                  Escape to local shell\n"
292             "?                                  Synonym for help\n");
293 }
294
295 static void
296 local_do_shell(const char *args)
297 {
298         int status;
299         char *shell;
300         pid_t pid;
301
302         if (!*args)
303                 args = NULL;
304
305         if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
306                 shell = _PATH_BSHELL;
307
308         if ((pid = fork()) == -1)
309                 fatal("Couldn't fork: %s", strerror(errno));
310
311         if (pid == 0) {
312                 /* XXX: child has pipe fds to ssh subproc open - issue? */
313                 if (args) {
314                         debug3("Executing %s -c \"%s\"", shell, args);
315                         execl(shell, shell, "-c", args, (char *)NULL);
316                 } else {
317                         debug3("Executing %s", shell);
318                         execl(shell, shell, (char *)NULL);
319                 }
320                 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
321                     strerror(errno));
322                 _exit(1);
323         }
324         while (waitpid(pid, &status, 0) == -1)
325                 if (errno != EINTR)
326                         fatal("Couldn't wait for child: %s", strerror(errno));
327         if (!WIFEXITED(status))
328                 error("Shell exited abnormally");
329         else if (WEXITSTATUS(status))
330                 error("Shell exited with status %d", WEXITSTATUS(status));
331 }
332
333 static void
334 local_do_ls(const char *args)
335 {
336         if (!args || !*args)
337                 local_do_shell(_PATH_LS);
338         else {
339                 int len = strlen(_PATH_LS " ") + strlen(args) + 1;
340                 char *buf = xmalloc(len);
341
342                 /* XXX: quoting - rip quoting code from ftp? */
343                 snprintf(buf, len, _PATH_LS " %s", args);
344                 local_do_shell(buf);
345                 free(buf);
346         }
347 }
348
349 /* Strip one path (usually the pwd) from the start of another */
350 static char *
351 path_strip(const char *path, const char *strip)
352 {
353         size_t len;
354
355         if (strip == NULL)
356                 return (xstrdup(path));
357
358         len = strlen(strip);
359         if (strncmp(path, strip, len) == 0) {
360                 if (strip[len - 1] != '/' && path[len] == '/')
361                         len++;
362                 return (xstrdup(path + len));
363         }
364
365         return (xstrdup(path));
366 }
367
368 static char *
369 make_absolute(char *p, const char *pwd)
370 {
371         char *abs_str;
372
373         /* Derelativise */
374         if (p && p[0] != '/') {
375                 abs_str = path_append(pwd, p);
376                 free(p);
377                 return(abs_str);
378         } else
379                 return(p);
380 }
381
382 static int
383 parse_getput_flags(const char *cmd, char **argv, int argc,
384     int *aflag, int *fflag, int *pflag, int *rflag)
385 {
386         extern int opterr, optind, optopt, optreset;
387         int ch;
388
389         optind = optreset = 1;
390         opterr = 0;
391
392         *aflag = *fflag = *rflag = *pflag = 0;
393         while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
394                 switch (ch) {
395                 case 'a':
396                         *aflag = 1;
397                         break;
398                 case 'f':
399                         *fflag = 1;
400                         break;
401                 case 'p':
402                 case 'P':
403                         *pflag = 1;
404                         break;
405                 case 'r':
406                 case 'R':
407                         *rflag = 1;
408                         break;
409                 default:
410                         error("%s: Invalid flag -%c", cmd, optopt);
411                         return -1;
412                 }
413         }
414
415         return optind;
416 }
417
418 static int
419 parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
420 {
421         extern int opterr, optind, optopt, optreset;
422         int ch;
423
424         optind = optreset = 1;
425         opterr = 0;
426
427         *sflag = 0;
428         while ((ch = getopt(argc, argv, "s")) != -1) {
429                 switch (ch) {
430                 case 's':
431                         *sflag = 1;
432                         break;
433                 default:
434                         error("%s: Invalid flag -%c", cmd, optopt);
435                         return -1;
436                 }
437         }
438
439         return optind;
440 }
441
442 static int
443 parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag)
444 {
445         extern int opterr, optind, optopt, optreset;
446         int ch;
447
448         optind = optreset = 1;
449         opterr = 0;
450
451         *lflag = 0;
452         while ((ch = getopt(argc, argv, "l")) != -1) {
453                 switch (ch) {
454                 case 'l':
455                         *lflag = 1;
456                         break;
457                 default:
458                         error("%s: Invalid flag -%c", cmd, optopt);
459                         return -1;
460                 }
461         }
462
463         return optind;
464 }
465
466 static int
467 parse_ls_flags(char **argv, int argc, int *lflag)
468 {
469         extern int opterr, optind, optopt, optreset;
470         int ch;
471
472         optind = optreset = 1;
473         opterr = 0;
474
475         *lflag = LS_NAME_SORT;
476         while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
477                 switch (ch) {
478                 case '1':
479                         *lflag &= ~VIEW_FLAGS;
480                         *lflag |= LS_SHORT_VIEW;
481                         break;
482                 case 'S':
483                         *lflag &= ~SORT_FLAGS;
484                         *lflag |= LS_SIZE_SORT;
485                         break;
486                 case 'a':
487                         *lflag |= LS_SHOW_ALL;
488                         break;
489                 case 'f':
490                         *lflag &= ~SORT_FLAGS;
491                         break;
492                 case 'h':
493                         *lflag |= LS_SI_UNITS;
494                         break;
495                 case 'l':
496                         *lflag &= ~LS_SHORT_VIEW;
497                         *lflag |= LS_LONG_VIEW;
498                         break;
499                 case 'n':
500                         *lflag &= ~LS_SHORT_VIEW;
501                         *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
502                         break;
503                 case 'r':
504                         *lflag |= LS_REVERSE_SORT;
505                         break;
506                 case 't':
507                         *lflag &= ~SORT_FLAGS;
508                         *lflag |= LS_TIME_SORT;
509                         break;
510                 default:
511                         error("ls: Invalid flag -%c", optopt);
512                         return -1;
513                 }
514         }
515
516         return optind;
517 }
518
519 static int
520 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
521 {
522         extern int opterr, optind, optopt, optreset;
523         int ch;
524
525         optind = optreset = 1;
526         opterr = 0;
527
528         *hflag = *iflag = 0;
529         while ((ch = getopt(argc, argv, "hi")) != -1) {
530                 switch (ch) {
531                 case 'h':
532                         *hflag = 1;
533                         break;
534                 case 'i':
535                         *iflag = 1;
536                         break;
537                 default:
538                         error("%s: Invalid flag -%c", cmd, optopt);
539                         return -1;
540                 }
541         }
542
543         return optind;
544 }
545
546 static int
547 parse_no_flags(const char *cmd, char **argv, int argc)
548 {
549         extern int opterr, optind, optopt, optreset;
550         int ch;
551
552         optind = optreset = 1;
553         opterr = 0;
554
555         while ((ch = getopt(argc, argv, "")) != -1) {
556                 switch (ch) {
557                 default:
558                         error("%s: Invalid flag -%c", cmd, optopt);
559                         return -1;
560                 }
561         }
562
563         return optind;
564 }
565
566 static int
567 is_dir(const char *path)
568 {
569         struct stat sb;
570
571         /* XXX: report errors? */
572         if (stat(path, &sb) == -1)
573                 return(0);
574
575         return(S_ISDIR(sb.st_mode));
576 }
577
578 static int
579 remote_is_dir(struct sftp_conn *conn, const char *path)
580 {
581         Attrib *a;
582
583         /* XXX: report errors? */
584         if ((a = do_stat(conn, path, 1)) == NULL)
585                 return(0);
586         if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
587                 return(0);
588         return(S_ISDIR(a->perm));
589 }
590
591 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
592 static int
593 pathname_is_dir(const char *pathname)
594 {
595         size_t l = strlen(pathname);
596
597         return l > 0 && pathname[l - 1] == '/';
598 }
599
600 static int
601 process_get(struct sftp_conn *conn, const char *src, const char *dst,
602     const char *pwd, int pflag, int rflag, int resume, int fflag)
603 {
604         char *abs_src = NULL;
605         char *abs_dst = NULL;
606         glob_t g;
607         char *filename, *tmp=NULL;
608         int i, r, err = 0;
609
610         abs_src = xstrdup(src);
611         abs_src = make_absolute(abs_src, pwd);
612         memset(&g, 0, sizeof(g));
613
614         debug3("Looking up %s", abs_src);
615         if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
616                 if (r == GLOB_NOSPACE) {
617                         error("Too many matches for \"%s\".", abs_src);
618                 } else {
619                         error("File \"%s\" not found.", abs_src);
620                 }
621                 err = -1;
622                 goto out;
623         }
624
625         /*
626          * If multiple matches then dst must be a directory or
627          * unspecified.
628          */
629         if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
630                 error("Multiple source paths, but destination "
631                     "\"%s\" is not a directory", dst);
632                 err = -1;
633                 goto out;
634         }
635
636         for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
637                 tmp = xstrdup(g.gl_pathv[i]);
638                 if ((filename = basename(tmp)) == NULL) {
639                         error("basename %s: %s", tmp, strerror(errno));
640                         free(tmp);
641                         err = -1;
642                         goto out;
643                 }
644
645                 if (g.gl_matchc == 1 && dst) {
646                         if (is_dir(dst)) {
647                                 abs_dst = path_append(dst, filename);
648                         } else {
649                                 abs_dst = xstrdup(dst);
650                         }
651                 } else if (dst) {
652                         abs_dst = path_append(dst, filename);
653                 } else {
654                         abs_dst = xstrdup(filename);
655                 }
656                 free(tmp);
657
658                 resume |= global_aflag;
659                 if (!quiet && resume)
660                         mprintf("Resuming %s to %s\n",
661                             g.gl_pathv[i], abs_dst);
662                 else if (!quiet && !resume)
663                         mprintf("Fetching %s to %s\n",
664                             g.gl_pathv[i], abs_dst);
665                 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
666                         if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
667                             pflag || global_pflag, 1, resume,
668                             fflag || global_fflag) == -1)
669                                 err = -1;
670                 } else {
671                         if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
672                             pflag || global_pflag, resume,
673                             fflag || global_fflag) == -1)
674                                 err = -1;
675                 }
676                 free(abs_dst);
677                 abs_dst = NULL;
678         }
679
680 out:
681         free(abs_src);
682         globfree(&g);
683         return(err);
684 }
685
686 static int
687 process_put(struct sftp_conn *conn, const char *src, const char *dst,
688     const char *pwd, int pflag, int rflag, int resume, int fflag)
689 {
690         char *tmp_dst = NULL;
691         char *abs_dst = NULL;
692         char *tmp = NULL, *filename = NULL;
693         glob_t g;
694         int err = 0;
695         int i, dst_is_dir = 1;
696         struct stat sb;
697
698         if (dst) {
699                 tmp_dst = xstrdup(dst);
700                 tmp_dst = make_absolute(tmp_dst, pwd);
701         }
702
703         memset(&g, 0, sizeof(g));
704         debug3("Looking up %s", src);
705         if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
706                 error("File \"%s\" not found.", src);
707                 err = -1;
708                 goto out;
709         }
710
711         /* If we aren't fetching to pwd then stash this status for later */
712         if (tmp_dst != NULL)
713                 dst_is_dir = remote_is_dir(conn, tmp_dst);
714
715         /* If multiple matches, dst may be directory or unspecified */
716         if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
717                 error("Multiple paths match, but destination "
718                     "\"%s\" is not a directory", tmp_dst);
719                 err = -1;
720                 goto out;
721         }
722
723         for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
724                 if (stat(g.gl_pathv[i], &sb) == -1) {
725                         err = -1;
726                         error("stat %s: %s", g.gl_pathv[i], strerror(errno));
727                         continue;
728                 }
729
730                 tmp = xstrdup(g.gl_pathv[i]);
731                 if ((filename = basename(tmp)) == NULL) {
732                         error("basename %s: %s", tmp, strerror(errno));
733                         free(tmp);
734                         err = -1;
735                         goto out;
736                 }
737
738                 if (g.gl_matchc == 1 && tmp_dst) {
739                         /* If directory specified, append filename */
740                         if (dst_is_dir)
741                                 abs_dst = path_append(tmp_dst, filename);
742                         else
743                                 abs_dst = xstrdup(tmp_dst);
744                 } else if (tmp_dst) {
745                         abs_dst = path_append(tmp_dst, filename);
746                 } else {
747                         abs_dst = make_absolute(xstrdup(filename), pwd);
748                 }
749                 free(tmp);
750
751                 resume |= global_aflag;
752                 if (!quiet && resume)
753                         mprintf("Resuming upload of %s to %s\n",
754                             g.gl_pathv[i], abs_dst);
755                 else if (!quiet && !resume)
756                         mprintf("Uploading %s to %s\n",
757                             g.gl_pathv[i], abs_dst);
758                 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
759                         if (upload_dir(conn, g.gl_pathv[i], abs_dst,
760                             pflag || global_pflag, 1, resume,
761                             fflag || global_fflag) == -1)
762                                 err = -1;
763                 } else {
764                         if (do_upload(conn, g.gl_pathv[i], abs_dst,
765                             pflag || global_pflag, resume,
766                             fflag || global_fflag) == -1)
767                                 err = -1;
768                 }
769         }
770
771 out:
772         free(abs_dst);
773         free(tmp_dst);
774         globfree(&g);
775         return(err);
776 }
777
778 static int
779 sdirent_comp(const void *aa, const void *bb)
780 {
781         SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
782         SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
783         int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
784
785 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
786         if (sort_flag & LS_NAME_SORT)
787                 return (rmul * strcmp(a->filename, b->filename));
788         else if (sort_flag & LS_TIME_SORT)
789                 return (rmul * NCMP(a->a.mtime, b->a.mtime));
790         else if (sort_flag & LS_SIZE_SORT)
791                 return (rmul * NCMP(a->a.size, b->a.size));
792
793         fatal("Unknown ls sort type");
794 }
795
796 /* sftp ls.1 replacement for directories */
797 static int
798 do_ls_dir(struct sftp_conn *conn, const char *path,
799     const char *strip_path, int lflag)
800 {
801         int n;
802         u_int c = 1, colspace = 0, columns = 1;
803         SFTP_DIRENT **d;
804
805         if ((n = do_readdir(conn, path, &d)) != 0)
806                 return (n);
807
808         if (!(lflag & LS_SHORT_VIEW)) {
809                 u_int m = 0, width = 80;
810                 struct winsize ws;
811                 char *tmp;
812
813                 /* Count entries for sort and find longest filename */
814                 for (n = 0; d[n] != NULL; n++) {
815                         if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
816                                 m = MAXIMUM(m, strlen(d[n]->filename));
817                 }
818
819                 /* Add any subpath that also needs to be counted */
820                 tmp = path_strip(path, strip_path);
821                 m += strlen(tmp);
822                 free(tmp);
823
824                 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
825                         width = ws.ws_col;
826
827                 columns = width / (m + 2);
828                 columns = MAXIMUM(columns, 1);
829                 colspace = width / columns;
830                 colspace = MINIMUM(colspace, width);
831         }
832
833         if (lflag & SORT_FLAGS) {
834                 for (n = 0; d[n] != NULL; n++)
835                         ;       /* count entries */
836                 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
837                 qsort(d, n, sizeof(*d), sdirent_comp);
838         }
839
840         for (n = 0; d[n] != NULL && !interrupted; n++) {
841                 char *tmp, *fname;
842
843                 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
844                         continue;
845
846                 tmp = path_append(path, d[n]->filename);
847                 fname = path_strip(tmp, strip_path);
848                 free(tmp);
849
850                 if (lflag & LS_LONG_VIEW) {
851                         if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
852                                 char *lname;
853                                 struct stat sb;
854
855                                 memset(&sb, 0, sizeof(sb));
856                                 attrib_to_stat(&d[n]->a, &sb);
857                                 lname = ls_file(fname, &sb, 1,
858                                     (lflag & LS_SI_UNITS));
859                                 mprintf("%s\n", lname);
860                                 free(lname);
861                         } else
862                                 mprintf("%s\n", d[n]->longname);
863                 } else {
864                         mprintf("%-*s", colspace, fname);
865                         if (c >= columns) {
866                                 printf("\n");
867                                 c = 1;
868                         } else
869                                 c++;
870                 }
871
872                 free(fname);
873         }
874
875         if (!(lflag & LS_LONG_VIEW) && (c != 1))
876                 printf("\n");
877
878         free_sftp_dirents(d);
879         return (0);
880 }
881
882 /* sftp ls.1 replacement which handles path globs */
883 static int
884 do_globbed_ls(struct sftp_conn *conn, const char *path,
885     const char *strip_path, int lflag)
886 {
887         char *fname, *lname;
888         glob_t g;
889         int err, r;
890         struct winsize ws;
891         u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
892
893         memset(&g, 0, sizeof(g));
894
895         if ((r = remote_glob(conn, path,
896             GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
897             NULL, &g)) != 0 ||
898             (g.gl_pathc && !g.gl_matchc)) {
899                 if (g.gl_pathc)
900                         globfree(&g);
901                 if (r == GLOB_NOSPACE) {
902                         error("Can't ls: Too many matches for \"%s\"", path);
903                 } else {
904                         error("Can't ls: \"%s\" not found", path);
905                 }
906                 return -1;
907         }
908
909         if (interrupted)
910                 goto out;
911
912         /*
913          * If the glob returns a single match and it is a directory,
914          * then just list its contents.
915          */
916         if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
917             S_ISDIR(g.gl_statv[0]->st_mode)) {
918                 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
919                 globfree(&g);
920                 return err;
921         }
922
923         if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
924                 width = ws.ws_col;
925
926         if (!(lflag & LS_SHORT_VIEW)) {
927                 /* Count entries for sort and find longest filename */
928                 for (i = 0; g.gl_pathv[i]; i++)
929                         m = MAXIMUM(m, strlen(g.gl_pathv[i]));
930
931                 columns = width / (m + 2);
932                 columns = MAXIMUM(columns, 1);
933                 colspace = width / columns;
934         }
935
936         for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
937                 fname = path_strip(g.gl_pathv[i], strip_path);
938                 if (lflag & LS_LONG_VIEW) {
939                         if (g.gl_statv[i] == NULL) {
940                                 error("no stat information for %s", fname);
941                                 continue;
942                         }
943                         lname = ls_file(fname, g.gl_statv[i], 1,
944                             (lflag & LS_SI_UNITS));
945                         mprintf("%s\n", lname);
946                         free(lname);
947                 } else {
948                         mprintf("%-*s", colspace, fname);
949                         if (c >= columns) {
950                                 printf("\n");
951                                 c = 1;
952                         } else
953                                 c++;
954                 }
955                 free(fname);
956         }
957
958         if (!(lflag & LS_LONG_VIEW) && (c != 1))
959                 printf("\n");
960
961  out:
962         if (g.gl_pathc)
963                 globfree(&g);
964
965         return 0;
966 }
967
968 static int
969 do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
970 {
971         struct sftp_statvfs st;
972         char s_used[FMT_SCALED_STRSIZE];
973         char s_avail[FMT_SCALED_STRSIZE];
974         char s_root[FMT_SCALED_STRSIZE];
975         char s_total[FMT_SCALED_STRSIZE];
976         unsigned long long ffree;
977
978         if (do_statvfs(conn, path, &st, 1) == -1)
979                 return -1;
980         if (iflag) {
981                 ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0;
982                 printf("     Inodes        Used       Avail      "
983                     "(root)    %%Capacity\n");
984                 printf("%11llu %11llu %11llu %11llu         %3llu%%\n",
985                     (unsigned long long)st.f_files,
986                     (unsigned long long)(st.f_files - st.f_ffree),
987                     (unsigned long long)st.f_favail,
988                     (unsigned long long)st.f_ffree, ffree);
989         } else if (hflag) {
990                 strlcpy(s_used, "error", sizeof(s_used));
991                 strlcpy(s_avail, "error", sizeof(s_avail));
992                 strlcpy(s_root, "error", sizeof(s_root));
993                 strlcpy(s_total, "error", sizeof(s_total));
994                 fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
995                 fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
996                 fmt_scaled(st.f_bfree * st.f_frsize, s_root);
997                 fmt_scaled(st.f_blocks * st.f_frsize, s_total);
998                 printf("    Size     Used    Avail   (root)    %%Capacity\n");
999                 printf("%7sB %7sB %7sB %7sB         %3llu%%\n",
1000                     s_total, s_used, s_avail, s_root,
1001                     (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
1002                     st.f_blocks));
1003         } else {
1004                 printf("        Size         Used        Avail       "
1005                     "(root)    %%Capacity\n");
1006                 printf("%12llu %12llu %12llu %12llu         %3llu%%\n",
1007                     (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
1008                     (unsigned long long)(st.f_frsize *
1009                     (st.f_blocks - st.f_bfree) / 1024),
1010                     (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
1011                     (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
1012                     (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
1013                     st.f_blocks));
1014         }
1015         return 0;
1016 }
1017
1018 /*
1019  * Undo escaping of glob sequences in place. Used to undo extra escaping
1020  * applied in makeargv() when the string is destined for a function that
1021  * does not glob it.
1022  */
1023 static void
1024 undo_glob_escape(char *s)
1025 {
1026         size_t i, j;
1027
1028         for (i = j = 0;;) {
1029                 if (s[i] == '\0') {
1030                         s[j] = '\0';
1031                         return;
1032                 }
1033                 if (s[i] != '\\') {
1034                         s[j++] = s[i++];
1035                         continue;
1036                 }
1037                 /* s[i] == '\\' */
1038                 ++i;
1039                 switch (s[i]) {
1040                 case '?':
1041                 case '[':
1042                 case '*':
1043                 case '\\':
1044                         s[j++] = s[i++];
1045                         break;
1046                 case '\0':
1047                         s[j++] = '\\';
1048                         s[j] = '\0';
1049                         return;
1050                 default:
1051                         s[j++] = '\\';
1052                         s[j++] = s[i++];
1053                         break;
1054                 }
1055         }
1056 }
1057
1058 /*
1059  * Split a string into an argument vector using sh(1)-style quoting,
1060  * comment and escaping rules, but with some tweaks to handle glob(3)
1061  * wildcards.
1062  * The "sloppy" flag allows for recovery from missing terminating quote, for
1063  * use in parsing incomplete commandlines during tab autocompletion.
1064  *
1065  * Returns NULL on error or a NULL-terminated array of arguments.
1066  *
1067  * If "lastquote" is not NULL, the quoting character used for the last
1068  * argument is placed in *lastquote ("\0", "'" or "\"").
1069  *
1070  * If "terminated" is not NULL, *terminated will be set to 1 when the
1071  * last argument's quote has been properly terminated or 0 otherwise.
1072  * This parameter is only of use if "sloppy" is set.
1073  */
1074 #define MAXARGS         128
1075 #define MAXARGLEN       8192
1076 static char **
1077 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1078     u_int *terminated)
1079 {
1080         int argc, quot;
1081         size_t i, j;
1082         static char argvs[MAXARGLEN];
1083         static char *argv[MAXARGS + 1];
1084         enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
1085
1086         *argcp = argc = 0;
1087         if (strlen(arg) > sizeof(argvs) - 1) {
1088  args_too_longs:
1089                 error("string too long");
1090                 return NULL;
1091         }
1092         if (terminated != NULL)
1093                 *terminated = 1;
1094         if (lastquote != NULL)
1095                 *lastquote = '\0';
1096         state = MA_START;
1097         i = j = 0;
1098         for (;;) {
1099                 if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
1100                         error("Too many arguments.");
1101                         return NULL;
1102                 }
1103                 if (isspace((unsigned char)arg[i])) {
1104                         if (state == MA_UNQUOTED) {
1105                                 /* Terminate current argument */
1106                                 argvs[j++] = '\0';
1107                                 argc++;
1108                                 state = MA_START;
1109                         } else if (state != MA_START)
1110                                 argvs[j++] = arg[i];
1111                 } else if (arg[i] == '"' || arg[i] == '\'') {
1112                         q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
1113                         if (state == MA_START) {
1114                                 argv[argc] = argvs + j;
1115                                 state = q;
1116                                 if (lastquote != NULL)
1117                                         *lastquote = arg[i];
1118                         } else if (state == MA_UNQUOTED)
1119                                 state = q;
1120                         else if (state == q)
1121                                 state = MA_UNQUOTED;
1122                         else
1123                                 argvs[j++] = arg[i];
1124                 } else if (arg[i] == '\\') {
1125                         if (state == MA_SQUOTE || state == MA_DQUOTE) {
1126                                 quot = state == MA_SQUOTE ? '\'' : '"';
1127                                 /* Unescape quote we are in */
1128                                 /* XXX support \n and friends? */
1129                                 if (arg[i + 1] == quot) {
1130                                         i++;
1131                                         argvs[j++] = arg[i];
1132                                 } else if (arg[i + 1] == '?' ||
1133                                     arg[i + 1] == '[' || arg[i + 1] == '*') {
1134                                         /*
1135                                          * Special case for sftp: append
1136                                          * double-escaped glob sequence -
1137                                          * glob will undo one level of
1138                                          * escaping. NB. string can grow here.
1139                                          */
1140                                         if (j >= sizeof(argvs) - 5)
1141                                                 goto args_too_longs;
1142                                         argvs[j++] = '\\';
1143                                         argvs[j++] = arg[i++];
1144                                         argvs[j++] = '\\';
1145                                         argvs[j++] = arg[i];
1146                                 } else {
1147                                         argvs[j++] = arg[i++];
1148                                         argvs[j++] = arg[i];
1149                                 }
1150                         } else {
1151                                 if (state == MA_START) {
1152                                         argv[argc] = argvs + j;
1153                                         state = MA_UNQUOTED;
1154                                         if (lastquote != NULL)
1155                                                 *lastquote = '\0';
1156                                 }
1157                                 if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1158                                     arg[i + 1] == '*' || arg[i + 1] == '\\') {
1159                                         /*
1160                                          * Special case for sftp: append
1161                                          * escaped glob sequence -
1162                                          * glob will undo one level of
1163                                          * escaping.
1164                                          */
1165                                         argvs[j++] = arg[i++];
1166                                         argvs[j++] = arg[i];
1167                                 } else {
1168                                         /* Unescape everything */
1169                                         /* XXX support \n and friends? */
1170                                         i++;
1171                                         argvs[j++] = arg[i];
1172                                 }
1173                         }
1174                 } else if (arg[i] == '#') {
1175                         if (state == MA_SQUOTE || state == MA_DQUOTE)
1176                                 argvs[j++] = arg[i];
1177                         else
1178                                 goto string_done;
1179                 } else if (arg[i] == '\0') {
1180                         if (state == MA_SQUOTE || state == MA_DQUOTE) {
1181                                 if (sloppy) {
1182                                         state = MA_UNQUOTED;
1183                                         if (terminated != NULL)
1184                                                 *terminated = 0;
1185                                         goto string_done;
1186                                 }
1187                                 error("Unterminated quoted argument");
1188                                 return NULL;
1189                         }
1190  string_done:
1191                         if (state == MA_UNQUOTED) {
1192                                 argvs[j++] = '\0';
1193                                 argc++;
1194                         }
1195                         break;
1196                 } else {
1197                         if (state == MA_START) {
1198                                 argv[argc] = argvs + j;
1199                                 state = MA_UNQUOTED;
1200                                 if (lastquote != NULL)
1201                                         *lastquote = '\0';
1202                         }
1203                         if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1204                             (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1205                                 /*
1206                                  * Special case for sftp: escape quoted
1207                                  * glob(3) wildcards. NB. string can grow
1208                                  * here.
1209                                  */
1210                                 if (j >= sizeof(argvs) - 3)
1211                                         goto args_too_longs;
1212                                 argvs[j++] = '\\';
1213                                 argvs[j++] = arg[i];
1214                         } else
1215                                 argvs[j++] = arg[i];
1216                 }
1217                 i++;
1218         }
1219         *argcp = argc;
1220         return argv;
1221 }
1222
1223 static int
1224 parse_args(const char **cpp, int *ignore_errors, int *aflag,
1225           int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1226           int *rflag, int *sflag,
1227     unsigned long *n_arg, char **path1, char **path2)
1228 {
1229         const char *cmd, *cp = *cpp;
1230         char *cp2, **argv;
1231         int base = 0;
1232         long l;
1233         int i, cmdnum, optidx, argc;
1234
1235         /* Skip leading whitespace */
1236         cp = cp + strspn(cp, WHITESPACE);
1237
1238         /* Check for leading '-' (disable error processing) */
1239         *ignore_errors = 0;
1240         if (*cp == '-') {
1241                 *ignore_errors = 1;
1242                 cp++;
1243                 cp = cp + strspn(cp, WHITESPACE);
1244         }
1245
1246         /* Ignore blank lines and lines which begin with comment '#' char */
1247         if (*cp == '\0' || *cp == '#')
1248                 return (0);
1249
1250         if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1251                 return -1;
1252
1253         /* Figure out which command we have */
1254         for (i = 0; cmds[i].c != NULL; i++) {
1255                 if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
1256                         break;
1257         }
1258         cmdnum = cmds[i].n;
1259         cmd = cmds[i].c;
1260
1261         /* Special case */
1262         if (*cp == '!') {
1263                 cp++;
1264                 cmdnum = I_SHELL;
1265         } else if (cmdnum == -1) {
1266                 error("Invalid command.");
1267                 return -1;
1268         }
1269
1270         /* Get arguments and parse flags */
1271         *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
1272         *rflag = *sflag = 0;
1273         *path1 = *path2 = NULL;
1274         optidx = 1;
1275         switch (cmdnum) {
1276         case I_GET:
1277         case I_REGET:
1278         case I_REPUT:
1279         case I_PUT:
1280                 if ((optidx = parse_getput_flags(cmd, argv, argc,
1281                     aflag, fflag, pflag, rflag)) == -1)
1282                         return -1;
1283                 /* Get first pathname (mandatory) */
1284                 if (argc - optidx < 1) {
1285                         error("You must specify at least one path after a "
1286                             "%s command.", cmd);
1287                         return -1;
1288                 }
1289                 *path1 = xstrdup(argv[optidx]);
1290                 /* Get second pathname (optional) */
1291                 if (argc - optidx > 1) {
1292                         *path2 = xstrdup(argv[optidx + 1]);
1293                         /* Destination is not globbed */
1294                         undo_glob_escape(*path2);
1295                 }
1296                 break;
1297         case I_LINK:
1298                 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1299                         return -1;
1300                 goto parse_two_paths;
1301         case I_RENAME:
1302                 if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1303                         return -1;
1304                 goto parse_two_paths;
1305         case I_SYMLINK:
1306                 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1307                         return -1;
1308  parse_two_paths:
1309                 if (argc - optidx < 2) {
1310                         error("You must specify two paths after a %s "
1311                             "command.", cmd);
1312                         return -1;
1313                 }
1314                 *path1 = xstrdup(argv[optidx]);
1315                 *path2 = xstrdup(argv[optidx + 1]);
1316                 /* Paths are not globbed */
1317                 undo_glob_escape(*path1);
1318                 undo_glob_escape(*path2);
1319                 break;
1320         case I_RM:
1321         case I_MKDIR:
1322         case I_RMDIR:
1323         case I_CHDIR:
1324         case I_LCHDIR:
1325         case I_LMKDIR:
1326                 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1327                         return -1;
1328                 /* Get pathname (mandatory) */
1329                 if (argc - optidx < 1) {
1330                         error("You must specify a path after a %s command.",
1331                             cmd);
1332                         return -1;
1333                 }
1334                 *path1 = xstrdup(argv[optidx]);
1335                 /* Only "rm" globs */
1336                 if (cmdnum != I_RM)
1337                         undo_glob_escape(*path1);
1338                 break;
1339         case I_DF:
1340                 if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1341                     iflag)) == -1)
1342                         return -1;
1343                 /* Default to current directory if no path specified */
1344                 if (argc - optidx < 1)
1345                         *path1 = NULL;
1346                 else {
1347                         *path1 = xstrdup(argv[optidx]);
1348                         undo_glob_escape(*path1);
1349                 }
1350                 break;
1351         case I_LS:
1352                 if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1353                         return(-1);
1354                 /* Path is optional */
1355                 if (argc - optidx > 0)
1356                         *path1 = xstrdup(argv[optidx]);
1357                 break;
1358         case I_LLS:
1359                 /* Skip ls command and following whitespace */
1360                 cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1361         case I_SHELL:
1362                 /* Uses the rest of the line */
1363                 break;
1364         case I_LUMASK:
1365         case I_CHMOD:
1366                 base = 8;
1367         case I_CHOWN:
1368         case I_CHGRP:
1369                 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1370                         return -1;
1371                 /* Get numeric arg (mandatory) */
1372                 if (argc - optidx < 1)
1373                         goto need_num_arg;
1374                 errno = 0;
1375                 l = strtol(argv[optidx], &cp2, base);
1376                 if (cp2 == argv[optidx] || *cp2 != '\0' ||
1377                     ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1378                     l < 0) {
1379  need_num_arg:
1380                         error("You must supply a numeric argument "
1381                             "to the %s command.", cmd);
1382                         return -1;
1383                 }
1384                 *n_arg = l;
1385                 if (cmdnum == I_LUMASK)
1386                         break;
1387                 /* Get pathname (mandatory) */
1388                 if (argc - optidx < 2) {
1389                         error("You must specify a path after a %s command.",
1390                             cmd);
1391                         return -1;
1392                 }
1393                 *path1 = xstrdup(argv[optidx + 1]);
1394                 break;
1395         case I_QUIT:
1396         case I_PWD:
1397         case I_LPWD:
1398         case I_HELP:
1399         case I_VERSION:
1400         case I_PROGRESS:
1401                 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1402                         return -1;
1403                 break;
1404         default:
1405                 fatal("Command not implemented");
1406         }
1407
1408         *cpp = cp;
1409         return(cmdnum);
1410 }
1411
1412 static int
1413 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1414     int err_abort)
1415 {
1416         char *path1, *path2, *tmp;
1417         int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
1418         iflag = 0;
1419         int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1420         int cmdnum, i;
1421         unsigned long n_arg = 0;
1422         Attrib a, *aa;
1423         char path_buf[PATH_MAX];
1424         int err = 0;
1425         glob_t g;
1426
1427         path1 = path2 = NULL;
1428         cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
1429             &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
1430         if (ignore_errors != 0)
1431                 err_abort = 0;
1432
1433         memset(&g, 0, sizeof(g));
1434
1435         /* Perform command */
1436         switch (cmdnum) {
1437         case 0:
1438                 /* Blank line */
1439                 break;
1440         case -1:
1441                 /* Unrecognized command */
1442                 err = -1;
1443                 break;
1444         case I_REGET:
1445                 aflag = 1;
1446                 /* FALLTHROUGH */
1447         case I_GET:
1448                 err = process_get(conn, path1, path2, *pwd, pflag,
1449                     rflag, aflag, fflag);
1450                 break;
1451         case I_REPUT:
1452                 aflag = 1;
1453                 /* FALLTHROUGH */
1454         case I_PUT:
1455                 err = process_put(conn, path1, path2, *pwd, pflag,
1456                     rflag, aflag, fflag);
1457                 break;
1458         case I_RENAME:
1459                 path1 = make_absolute(path1, *pwd);
1460                 path2 = make_absolute(path2, *pwd);
1461                 err = do_rename(conn, path1, path2, lflag);
1462                 break;
1463         case I_SYMLINK:
1464                 sflag = 1;
1465         case I_LINK:
1466                 if (!sflag)
1467                         path1 = make_absolute(path1, *pwd);
1468                 path2 = make_absolute(path2, *pwd);
1469                 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1470                 break;
1471         case I_RM:
1472                 path1 = make_absolute(path1, *pwd);
1473                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1474                 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1475                         if (!quiet)
1476                                 mprintf("Removing %s\n", g.gl_pathv[i]);
1477                         err = do_rm(conn, g.gl_pathv[i]);
1478                         if (err != 0 && err_abort)
1479                                 break;
1480                 }
1481                 break;
1482         case I_MKDIR:
1483                 path1 = make_absolute(path1, *pwd);
1484                 attrib_clear(&a);
1485                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1486                 a.perm = 0777;
1487                 err = do_mkdir(conn, path1, &a, 1);
1488                 break;
1489         case I_RMDIR:
1490                 path1 = make_absolute(path1, *pwd);
1491                 err = do_rmdir(conn, path1);
1492                 break;
1493         case I_CHDIR:
1494                 path1 = make_absolute(path1, *pwd);
1495                 if ((tmp = do_realpath(conn, path1)) == NULL) {
1496                         err = 1;
1497                         break;
1498                 }
1499                 if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1500                         free(tmp);
1501                         err = 1;
1502                         break;
1503                 }
1504                 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1505                         error("Can't change directory: Can't check target");
1506                         free(tmp);
1507                         err = 1;
1508                         break;
1509                 }
1510                 if (!S_ISDIR(aa->perm)) {
1511                         error("Can't change directory: \"%s\" is not "
1512                             "a directory", tmp);
1513                         free(tmp);
1514                         err = 1;
1515                         break;
1516                 }
1517                 free(*pwd);
1518                 *pwd = tmp;
1519                 break;
1520         case I_LS:
1521                 if (!path1) {
1522                         do_ls_dir(conn, *pwd, *pwd, lflag);
1523                         break;
1524                 }
1525
1526                 /* Strip pwd off beginning of non-absolute paths */
1527                 tmp = NULL;
1528                 if (*path1 != '/')
1529                         tmp = *pwd;
1530
1531                 path1 = make_absolute(path1, *pwd);
1532                 err = do_globbed_ls(conn, path1, tmp, lflag);
1533                 break;
1534         case I_DF:
1535                 /* Default to current directory if no path specified */
1536                 if (path1 == NULL)
1537                         path1 = xstrdup(*pwd);
1538                 path1 = make_absolute(path1, *pwd);
1539                 err = do_df(conn, path1, hflag, iflag);
1540                 break;
1541         case I_LCHDIR:
1542                 tmp = tilde_expand_filename(path1, getuid());
1543                 free(path1);
1544                 path1 = tmp;
1545                 if (chdir(path1) == -1) {
1546                         error("Couldn't change local directory to "
1547                             "\"%s\": %s", path1, strerror(errno));
1548                         err = 1;
1549                 }
1550                 break;
1551         case I_LMKDIR:
1552                 if (mkdir(path1, 0777) == -1) {
1553                         error("Couldn't create local directory "
1554                             "\"%s\": %s", path1, strerror(errno));
1555                         err = 1;
1556                 }
1557                 break;
1558         case I_LLS:
1559                 local_do_ls(cmd);
1560                 break;
1561         case I_SHELL:
1562                 local_do_shell(cmd);
1563                 break;
1564         case I_LUMASK:
1565                 umask(n_arg);
1566                 printf("Local umask: %03lo\n", n_arg);
1567                 break;
1568         case I_CHMOD:
1569                 path1 = make_absolute(path1, *pwd);
1570                 attrib_clear(&a);
1571                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1572                 a.perm = n_arg;
1573                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1574                 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1575                         if (!quiet)
1576                                 mprintf("Changing mode on %s\n",
1577                                     g.gl_pathv[i]);
1578                         err = do_setstat(conn, g.gl_pathv[i], &a);
1579                         if (err != 0 && err_abort)
1580                                 break;
1581                 }
1582                 break;
1583         case I_CHOWN:
1584         case I_CHGRP:
1585                 path1 = make_absolute(path1, *pwd);
1586                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1587                 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1588                         if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1589                                 if (err_abort) {
1590                                         err = -1;
1591                                         break;
1592                                 } else
1593                                         continue;
1594                         }
1595                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1596                                 error("Can't get current ownership of "
1597                                     "remote file \"%s\"", g.gl_pathv[i]);
1598                                 if (err_abort) {
1599                                         err = -1;
1600                                         break;
1601                                 } else
1602                                         continue;
1603                         }
1604                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1605                         if (cmdnum == I_CHOWN) {
1606                                 if (!quiet)
1607                                         mprintf("Changing owner on %s\n",
1608                                             g.gl_pathv[i]);
1609                                 aa->uid = n_arg;
1610                         } else {
1611                                 if (!quiet)
1612                                         mprintf("Changing group on %s\n",
1613                                             g.gl_pathv[i]);
1614                                 aa->gid = n_arg;
1615                         }
1616                         err = do_setstat(conn, g.gl_pathv[i], aa);
1617                         if (err != 0 && err_abort)
1618                                 break;
1619                 }
1620                 break;
1621         case I_PWD:
1622                 mprintf("Remote working directory: %s\n", *pwd);
1623                 break;
1624         case I_LPWD:
1625                 if (!getcwd(path_buf, sizeof(path_buf))) {
1626                         error("Couldn't get local cwd: %s", strerror(errno));
1627                         err = -1;
1628                         break;
1629                 }
1630                 mprintf("Local working directory: %s\n", path_buf);
1631                 break;
1632         case I_QUIT:
1633                 /* Processed below */
1634                 break;
1635         case I_HELP:
1636                 help();
1637                 break;
1638         case I_VERSION:
1639                 printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1640                 break;
1641         case I_PROGRESS:
1642                 showprogress = !showprogress;
1643                 if (showprogress)
1644                         printf("Progress meter enabled\n");
1645                 else
1646                         printf("Progress meter disabled\n");
1647                 break;
1648         default:
1649                 fatal("%d is not implemented", cmdnum);
1650         }
1651
1652         if (g.gl_pathc)
1653                 globfree(&g);
1654         free(path1);
1655         free(path2);
1656
1657         /* If an unignored error occurs in batch mode we should abort. */
1658         if (err_abort && err != 0)
1659                 return (-1);
1660         else if (cmdnum == I_QUIT)
1661                 return (1);
1662
1663         return (0);
1664 }
1665
1666 #ifdef USE_LIBEDIT
1667 static char *
1668 prompt(EditLine *el)
1669 {
1670         return ("sftp> ");
1671 }
1672
1673 /* Display entries in 'list' after skipping the first 'len' chars */
1674 static void
1675 complete_display(char **list, u_int len)
1676 {
1677         u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1678         struct winsize ws;
1679         char *tmp;
1680
1681         /* Count entries for sort and find longest */
1682         for (y = 0; list[y]; y++)
1683                 m = MAXIMUM(m, strlen(list[y]));
1684
1685         if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1686                 width = ws.ws_col;
1687
1688         m = m > len ? m - len : 0;
1689         columns = width / (m + 2);
1690         columns = MAXIMUM(columns, 1);
1691         colspace = width / columns;
1692         colspace = MINIMUM(colspace, width);
1693
1694         printf("\n");
1695         m = 1;
1696         for (y = 0; list[y]; y++) {
1697                 llen = strlen(list[y]);
1698                 tmp = llen > len ? list[y] + len : "";
1699                 mprintf("%-*s", colspace, tmp);
1700                 if (m >= columns) {
1701                         printf("\n");
1702                         m = 1;
1703                 } else
1704                         m++;
1705         }
1706         printf("\n");
1707 }
1708
1709 /*
1710  * Given a "list" of words that begin with a common prefix of "word",
1711  * attempt to find an autocompletion to extends "word" by the next
1712  * characters common to all entries in "list".
1713  */
1714 static char *
1715 complete_ambiguous(const char *word, char **list, size_t count)
1716 {
1717         if (word == NULL)
1718                 return NULL;
1719
1720         if (count > 0) {
1721                 u_int y, matchlen = strlen(list[0]);
1722
1723                 /* Find length of common stem */
1724                 for (y = 1; list[y]; y++) {
1725                         u_int x;
1726
1727                         for (x = 0; x < matchlen; x++)
1728                                 if (list[0][x] != list[y][x])
1729                                         break;
1730
1731                         matchlen = x;
1732                 }
1733
1734                 if (matchlen > strlen(word)) {
1735                         char *tmp = xstrdup(list[0]);
1736
1737                         tmp[matchlen] = '\0';
1738                         return tmp;
1739                 }
1740         }
1741
1742         return xstrdup(word);
1743 }
1744
1745 /* Autocomplete a sftp command */
1746 static int
1747 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1748     int terminated)
1749 {
1750         u_int y, count = 0, cmdlen, tmplen;
1751         char *tmp, **list, argterm[3];
1752         const LineInfo *lf;
1753
1754         list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1755
1756         /* No command specified: display all available commands */
1757         if (cmd == NULL) {
1758                 for (y = 0; cmds[y].c; y++)
1759                         list[count++] = xstrdup(cmds[y].c);
1760
1761                 list[count] = NULL;
1762                 complete_display(list, 0);
1763
1764                 for (y = 0; list[y] != NULL; y++)
1765                         free(list[y]);
1766                 free(list);
1767                 return count;
1768         }
1769
1770         /* Prepare subset of commands that start with "cmd" */
1771         cmdlen = strlen(cmd);
1772         for (y = 0; cmds[y].c; y++)  {
1773                 if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1774                         list[count++] = xstrdup(cmds[y].c);
1775         }
1776         list[count] = NULL;
1777
1778         if (count == 0) {
1779                 free(list);
1780                 return 0;
1781         }
1782
1783         /* Complete ambigious command */
1784         tmp = complete_ambiguous(cmd, list, count);
1785         if (count > 1)
1786                 complete_display(list, 0);
1787
1788         for (y = 0; list[y]; y++)
1789                 free(list[y]);
1790         free(list);
1791
1792         if (tmp != NULL) {
1793                 tmplen = strlen(tmp);
1794                 cmdlen = strlen(cmd);
1795                 /* If cmd may be extended then do so */
1796                 if (tmplen > cmdlen)
1797                         if (el_insertstr(el, tmp + cmdlen) == -1)
1798                                 fatal("el_insertstr failed.");
1799                 lf = el_line(el);
1800                 /* Terminate argument cleanly */
1801                 if (count == 1) {
1802                         y = 0;
1803                         if (!terminated)
1804                                 argterm[y++] = quote;
1805                         if (lastarg || *(lf->cursor) != ' ')
1806                                 argterm[y++] = ' ';
1807                         argterm[y] = '\0';
1808                         if (y > 0 && el_insertstr(el, argterm) == -1)
1809                                 fatal("el_insertstr failed.");
1810                 }
1811                 free(tmp);
1812         }
1813
1814         return count;
1815 }
1816
1817 /*
1818  * Determine whether a particular sftp command's arguments (if any)
1819  * represent local or remote files.
1820  */
1821 static int
1822 complete_is_remote(char *cmd) {
1823         int i;
1824
1825         if (cmd == NULL)
1826                 return -1;
1827
1828         for (i = 0; cmds[i].c; i++) {
1829                 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1830                         return cmds[i].t;
1831         }
1832
1833         return -1;
1834 }
1835
1836 /* Autocomplete a filename "file" */
1837 static int
1838 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1839     char *file, int remote, int lastarg, char quote, int terminated)
1840 {
1841         glob_t g;
1842         char *tmp, *tmp2, ins[8];
1843         u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
1844         int clen;
1845         const LineInfo *lf;
1846
1847         /* Glob from "file" location */
1848         if (file == NULL)
1849                 tmp = xstrdup("*");
1850         else
1851                 xasprintf(&tmp, "%s*", file);
1852
1853         /* Check if the path is absolute. */
1854         isabs = tmp[0] == '/';
1855
1856         memset(&g, 0, sizeof(g));
1857         if (remote != LOCAL) {
1858                 tmp = make_absolute(tmp, remote_path);
1859                 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1860         } else
1861                 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1862
1863         /* Determine length of pwd so we can trim completion display */
1864         for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1865                 /* Terminate counting on first unescaped glob metacharacter */
1866                 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1867                         if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1868                                 hadglob = 1;
1869                         break;
1870                 }
1871                 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1872                         tmplen++;
1873                 if (tmp[tmplen] == '/')
1874                         pwdlen = tmplen + 1;    /* track last seen '/' */
1875         }
1876         free(tmp);
1877         tmp = NULL;
1878
1879         if (g.gl_matchc == 0)
1880                 goto out;
1881
1882         if (g.gl_matchc > 1)
1883                 complete_display(g.gl_pathv, pwdlen);
1884
1885         /* Don't try to extend globs */
1886         if (file == NULL || hadglob)
1887                 goto out;
1888
1889         tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1890         tmp = path_strip(tmp2, isabs ? NULL : remote_path);
1891         free(tmp2);
1892
1893         if (tmp == NULL)
1894                 goto out;
1895
1896         tmplen = strlen(tmp);
1897         filelen = strlen(file);
1898
1899         /* Count the number of escaped characters in the input string. */
1900         cesc = isesc = 0;
1901         for (i = 0; i < filelen; i++) {
1902                 if (!isesc && file[i] == '\\' && i + 1 < filelen){
1903                         isesc = 1;
1904                         cesc++;
1905                 } else
1906                         isesc = 0;
1907         }
1908
1909         if (tmplen > (filelen - cesc)) {
1910                 tmp2 = tmp + filelen - cesc;
1911                 len = strlen(tmp2);
1912                 /* quote argument on way out */
1913                 for (i = 0; i < len; i += clen) {
1914                         if ((clen = mblen(tmp2 + i, len - i)) < 0 ||
1915                             (size_t)clen > sizeof(ins) - 2)
1916                                 fatal("invalid multibyte character");
1917                         ins[0] = '\\';
1918                         memcpy(ins + 1, tmp2 + i, clen);
1919                         ins[clen + 1] = '\0';
1920                         switch (tmp2[i]) {
1921                         case '\'':
1922                         case '"':
1923                         case '\\':
1924                         case '\t':
1925                         case '[':
1926                         case ' ':
1927                         case '#':
1928                         case '*':
1929                                 if (quote == '\0' || tmp2[i] == quote) {
1930                                         if (el_insertstr(el, ins) == -1)
1931                                                 fatal("el_insertstr "
1932                                                     "failed.");
1933                                         break;
1934                                 }
1935                                 /* FALLTHROUGH */
1936                         default:
1937                                 if (el_insertstr(el, ins + 1) == -1)
1938                                         fatal("el_insertstr failed.");
1939                                 break;
1940                         }
1941                 }
1942         }
1943
1944         lf = el_line(el);
1945         if (g.gl_matchc == 1) {
1946                 i = 0;
1947                 if (!terminated && quote != '\0')
1948                         ins[i++] = quote;
1949                 if (*(lf->cursor - 1) != '/' &&
1950                     (lastarg || *(lf->cursor) != ' '))
1951                         ins[i++] = ' ';
1952                 ins[i] = '\0';
1953                 if (i > 0 && el_insertstr(el, ins) == -1)
1954                         fatal("el_insertstr failed.");
1955         }
1956         free(tmp);
1957
1958  out:
1959         globfree(&g);
1960         return g.gl_matchc;
1961 }
1962
1963 /* tab-completion hook function, called via libedit */
1964 static unsigned char
1965 complete(EditLine *el, int ch)
1966 {
1967         char **argv, *line, quote;
1968         int argc, carg;
1969         u_int cursor, len, terminated, ret = CC_ERROR;
1970         const LineInfo *lf;
1971         struct complete_ctx *complete_ctx;
1972
1973         lf = el_line(el);
1974         if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
1975                 fatal("%s: el_get failed", __func__);
1976
1977         /* Figure out which argument the cursor points to */
1978         cursor = lf->cursor - lf->buffer;
1979         line = xmalloc(cursor + 1);
1980         memcpy(line, lf->buffer, cursor);
1981         line[cursor] = '\0';
1982         argv = makeargv(line, &carg, 1, &quote, &terminated);
1983         free(line);
1984
1985         /* Get all the arguments on the line */
1986         len = lf->lastchar - lf->buffer;
1987         line = xmalloc(len + 1);
1988         memcpy(line, lf->buffer, len);
1989         line[len] = '\0';
1990         argv = makeargv(line, &argc, 1, NULL, NULL);
1991
1992         /* Ensure cursor is at EOL or a argument boundary */
1993         if (line[cursor] != ' ' && line[cursor] != '\0' &&
1994             line[cursor] != '\n') {
1995                 free(line);
1996                 return ret;
1997         }
1998
1999         if (carg == 0) {
2000                 /* Show all available commands */
2001                 complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
2002                 ret = CC_REDISPLAY;
2003         } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
2004                 /* Handle the command parsing */
2005                 if (complete_cmd_parse(el, argv[0], argc == carg,
2006                     quote, terminated) != 0)
2007                         ret = CC_REDISPLAY;
2008         } else if (carg >= 1) {
2009                 /* Handle file parsing */
2010                 int remote = complete_is_remote(argv[0]);
2011                 char *filematch = NULL;
2012
2013                 if (carg > 1 && line[cursor-1] != ' ')
2014                         filematch = argv[carg - 1];
2015
2016                 if (remote != 0 &&
2017                     complete_match(el, complete_ctx->conn,
2018                     *complete_ctx->remote_pathp, filematch,
2019                     remote, carg == argc, quote, terminated) != 0)
2020                         ret = CC_REDISPLAY;
2021         }
2022
2023         free(line);
2024         return ret;
2025 }
2026 #endif /* USE_LIBEDIT */
2027
2028 int
2029 interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2030 {
2031         char *remote_path;
2032         char *dir = NULL;
2033         char cmd[2048];
2034         int err, interactive;
2035         EditLine *el = NULL;
2036 #ifdef USE_LIBEDIT
2037         History *hl = NULL;
2038         HistEvent hev;
2039         extern char *__progname;
2040         struct complete_ctx complete_ctx;
2041
2042         if (!batchmode && isatty(STDIN_FILENO)) {
2043                 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
2044                         fatal("Couldn't initialise editline");
2045                 if ((hl = history_init()) == NULL)
2046                         fatal("Couldn't initialise editline history");
2047                 history(hl, &hev, H_SETSIZE, 100);
2048                 el_set(el, EL_HIST, history, hl);
2049
2050                 el_set(el, EL_PROMPT, prompt);
2051                 el_set(el, EL_EDITOR, "emacs");
2052                 el_set(el, EL_TERMINAL, NULL);
2053                 el_set(el, EL_SIGNAL, 1);
2054                 el_source(el, NULL);
2055
2056                 /* Tab Completion */
2057                 el_set(el, EL_ADDFN, "ftp-complete",
2058                     "Context sensitive argument completion", complete);
2059                 complete_ctx.conn = conn;
2060                 complete_ctx.remote_pathp = &remote_path;
2061                 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
2062                 el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
2063                 /* enable ctrl-left-arrow and ctrl-right-arrow */
2064                 el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
2065                 el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL);
2066                 el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
2067                 el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
2068                 /* make ^w match ksh behaviour */
2069                 el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL);
2070         }
2071 #endif /* USE_LIBEDIT */
2072
2073         remote_path = do_realpath(conn, ".");
2074         if (remote_path == NULL)
2075                 fatal("Need cwd");
2076
2077         if (file1 != NULL) {
2078                 dir = xstrdup(file1);
2079                 dir = make_absolute(dir, remote_path);
2080
2081                 if (remote_is_dir(conn, dir) && file2 == NULL) {
2082                         if (!quiet)
2083                                 mprintf("Changing to: %s\n", dir);
2084                         snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
2085                         if (parse_dispatch_command(conn, cmd,
2086                             &remote_path, 1) != 0) {
2087                                 free(dir);
2088                                 free(remote_path);
2089                                 free(conn);
2090                                 return (-1);
2091                         }
2092                 } else {
2093                         /* XXX this is wrong wrt quoting */
2094                         snprintf(cmd, sizeof cmd, "get%s %s%s%s",
2095                             global_aflag ? " -a" : "", dir,
2096                             file2 == NULL ? "" : " ",
2097                             file2 == NULL ? "" : file2);
2098                         err = parse_dispatch_command(conn, cmd,
2099                             &remote_path, 1);
2100                         free(dir);
2101                         free(remote_path);
2102                         free(conn);
2103                         return (err);
2104                 }
2105                 free(dir);
2106         }
2107
2108         setvbuf(stdout, NULL, _IOLBF, 0);
2109         setvbuf(infile, NULL, _IOLBF, 0);
2110
2111         interactive = !batchmode && isatty(STDIN_FILENO);
2112         err = 0;
2113         for (;;) {
2114                 char *cp;
2115
2116                 signal(SIGINT, SIG_IGN);
2117
2118                 if (el == NULL) {
2119                         if (interactive)
2120                                 printf("sftp> ");
2121                         if (fgets(cmd, sizeof(cmd), infile) == NULL) {
2122                                 if (interactive)
2123                                         printf("\n");
2124                                 break;
2125                         }
2126                         if (!interactive) { /* Echo command */
2127                                 mprintf("sftp> %s", cmd);
2128                                 if (strlen(cmd) > 0 &&
2129                                     cmd[strlen(cmd) - 1] != '\n')
2130                                         printf("\n");
2131                         }
2132                 } else {
2133 #ifdef USE_LIBEDIT
2134                         const char *line;
2135                         int count = 0;
2136
2137                         if ((line = el_gets(el, &count)) == NULL ||
2138                             count <= 0) {
2139                                 printf("\n");
2140                                 break;
2141                         }
2142                         history(hl, &hev, H_ENTER, line);
2143                         if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
2144                                 fprintf(stderr, "Error: input line too long\n");
2145                                 continue;
2146                         }
2147 #endif /* USE_LIBEDIT */
2148                 }
2149
2150                 cp = strrchr(cmd, '\n');
2151                 if (cp)
2152                         *cp = '\0';
2153
2154                 /* Handle user interrupts gracefully during commands */
2155                 interrupted = 0;
2156                 signal(SIGINT, cmd_interrupt);
2157
2158                 err = parse_dispatch_command(conn, cmd, &remote_path,
2159                     batchmode);
2160                 if (err != 0)
2161                         break;
2162         }
2163         free(remote_path);
2164         free(conn);
2165
2166 #ifdef USE_LIBEDIT
2167         if (el != NULL)
2168                 el_end(el);
2169 #endif /* USE_LIBEDIT */
2170
2171         /* err == 1 signifies normal "quit" exit */
2172         return (err >= 0 ? 0 : -1);
2173 }
2174
2175 static void
2176 connect_to_server(char *path, char **args, int *in, int *out)
2177 {
2178         int c_in, c_out;
2179
2180 #ifdef USE_PIPES
2181         int pin[2], pout[2];
2182
2183         if ((pipe(pin) == -1) || (pipe(pout) == -1))
2184                 fatal("pipe: %s", strerror(errno));
2185         *in = pin[0];
2186         *out = pout[1];
2187         c_in = pout[0];
2188         c_out = pin[1];
2189 #else /* USE_PIPES */
2190         int inout[2];
2191
2192         if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2193                 fatal("socketpair: %s", strerror(errno));
2194         *in = *out = inout[0];
2195         c_in = c_out = inout[1];
2196 #endif /* USE_PIPES */
2197
2198         if ((sshpid = fork()) == -1)
2199                 fatal("fork: %s", strerror(errno));
2200         else if (sshpid == 0) {
2201                 if ((dup2(c_in, STDIN_FILENO) == -1) ||
2202                     (dup2(c_out, STDOUT_FILENO) == -1)) {
2203                         fprintf(stderr, "dup2: %s\n", strerror(errno));
2204                         _exit(1);
2205                 }
2206                 close(*in);
2207                 close(*out);
2208                 close(c_in);
2209                 close(c_out);
2210
2211                 /*
2212                  * The underlying ssh is in the same process group, so we must
2213                  * ignore SIGINT if we want to gracefully abort commands,
2214                  * otherwise the signal will make it to the ssh process and
2215                  * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2216                  * underlying ssh, it must *not* ignore that signal.
2217                  */
2218                 signal(SIGINT, SIG_IGN);
2219                 signal(SIGTERM, SIG_DFL);
2220                 execvp(path, args);
2221                 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2222                 _exit(1);
2223         }
2224
2225         signal(SIGTERM, killchild);
2226         signal(SIGINT, killchild);
2227         signal(SIGHUP, killchild);
2228         signal(SIGTSTP, suspchild);
2229         signal(SIGTTIN, suspchild);
2230         signal(SIGTTOU, suspchild);
2231         close(c_in);
2232         close(c_out);
2233 }
2234
2235 static void
2236 usage(void)
2237 {
2238         extern char *__progname;
2239
2240         fprintf(stderr,
2241             "usage: %s [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2242             "          [-D sftp_server_path] [-F ssh_config] "
2243             "[-i identity_file] [-l limit]\n"
2244             "          [-o ssh_option] [-P port] [-R num_requests] "
2245             "[-S program]\n"
2246             "          [-s subsystem | sftp_server] host\n"
2247             "       %s [user@]host[:file ...]\n"
2248             "       %s [user@]host[:dir[/]]\n"
2249             "       %s -b batchfile [user@]host\n",
2250             __progname, __progname, __progname, __progname);
2251         exit(1);
2252 }
2253
2254 int
2255 main(int argc, char **argv)
2256 {
2257         int in, out, ch, err;
2258         char *host = NULL, *userhost, *cp, *file2 = NULL;
2259         int debug_level = 0, sshver = 2;
2260         char *file1 = NULL, *sftp_server = NULL;
2261         char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2262         const char *errstr;
2263         LogLevel ll = SYSLOG_LEVEL_INFO;
2264         arglist args;
2265         extern int optind;
2266         extern char *optarg;
2267         struct sftp_conn *conn;
2268         size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2269         size_t num_requests = DEFAULT_NUM_REQUESTS;
2270         long long limit_kbps = 0;
2271
2272         ssh_malloc_init();      /* must be called before any mallocs */
2273         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2274         sanitise_stdfd();
2275         msetlocale();
2276
2277         __progname = ssh_get_progname(argv[0]);
2278         memset(&args, '\0', sizeof(args));
2279         args.list = NULL;
2280         addargs(&args, "%s", ssh_program);
2281         addargs(&args, "-oForwardX11 no");
2282         addargs(&args, "-oForwardAgent no");
2283         addargs(&args, "-oPermitLocalCommand no");
2284         addargs(&args, "-oClearAllForwardings yes");
2285
2286         ll = SYSLOG_LEVEL_INFO;
2287         infile = stdin;
2288
2289         while ((ch = getopt(argc, argv,
2290             "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2291                 switch (ch) {
2292                 /* Passed through to ssh(1) */
2293                 case '4':
2294                 case '6':
2295                 case 'C':
2296                         addargs(&args, "-%c", ch);
2297                         break;
2298                 /* Passed through to ssh(1) with argument */
2299                 case 'F':
2300                 case 'c':
2301                 case 'i':
2302                 case 'o':
2303                         addargs(&args, "-%c", ch);
2304                         addargs(&args, "%s", optarg);
2305                         break;
2306                 case 'q':
2307                         ll = SYSLOG_LEVEL_ERROR;
2308                         quiet = 1;
2309                         showprogress = 0;
2310                         addargs(&args, "-%c", ch);
2311                         break;
2312                 case 'P':
2313                         addargs(&args, "-oPort %s", optarg);
2314                         break;
2315                 case 'v':
2316                         if (debug_level < 3) {
2317                                 addargs(&args, "-v");
2318                                 ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2319                         }
2320                         debug_level++;
2321                         break;
2322                 case '1':
2323                         sshver = 1;
2324                         if (sftp_server == NULL)
2325                                 sftp_server = _PATH_SFTP_SERVER;
2326                         break;
2327                 case '2':
2328                         sshver = 2;
2329                         break;
2330                 case 'a':
2331                         global_aflag = 1;
2332                         break;
2333                 case 'B':
2334                         copy_buffer_len = strtol(optarg, &cp, 10);
2335                         if (copy_buffer_len == 0 || *cp != '\0')
2336                                 fatal("Invalid buffer size \"%s\"", optarg);
2337                         break;
2338                 case 'b':
2339                         if (batchmode)
2340                                 fatal("Batch file already specified.");
2341
2342                         /* Allow "-" as stdin */
2343                         if (strcmp(optarg, "-") != 0 &&
2344                             (infile = fopen(optarg, "r")) == NULL)
2345                                 fatal("%s (%s).", strerror(errno), optarg);
2346                         showprogress = 0;
2347                         quiet = batchmode = 1;
2348                         addargs(&args, "-obatchmode yes");
2349                         break;
2350                 case 'f':
2351                         global_fflag = 1;
2352                         break;
2353                 case 'p':
2354                         global_pflag = 1;
2355                         break;
2356                 case 'D':
2357                         sftp_direct = optarg;
2358                         break;
2359                 case 'l':
2360                         limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2361                             &errstr);
2362                         if (errstr != NULL)
2363                                 usage();
2364                         limit_kbps *= 1024; /* kbps */
2365                         break;
2366                 case 'r':
2367                         global_rflag = 1;
2368                         break;
2369                 case 'R':
2370                         num_requests = strtol(optarg, &cp, 10);
2371                         if (num_requests == 0 || *cp != '\0')
2372                                 fatal("Invalid number of requests \"%s\"",
2373                                     optarg);
2374                         break;
2375                 case 's':
2376                         sftp_server = optarg;
2377                         break;
2378                 case 'S':
2379                         ssh_program = optarg;
2380                         replacearg(&args, 0, "%s", ssh_program);
2381                         break;
2382                 case 'h':
2383                 default:
2384                         usage();
2385                 }
2386         }
2387
2388         if (!isatty(STDERR_FILENO))
2389                 showprogress = 0;
2390
2391         log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2392
2393         if (sftp_direct == NULL) {
2394                 if (optind == argc || argc > (optind + 2))
2395                         usage();
2396
2397                 userhost = xstrdup(argv[optind]);
2398                 file2 = argv[optind+1];
2399
2400                 if ((host = strrchr(userhost, '@')) == NULL)
2401                         host = userhost;
2402                 else {
2403                         *host++ = '\0';
2404                         if (!userhost[0]) {
2405                                 fprintf(stderr, "Missing username\n");
2406                                 usage();
2407                         }
2408                         addargs(&args, "-l");
2409                         addargs(&args, "%s", userhost);
2410                 }
2411
2412                 if ((cp = colon(host)) != NULL) {
2413                         *cp++ = '\0';
2414                         file1 = cp;
2415                 }
2416
2417                 host = cleanhostname(host);
2418                 if (!*host) {
2419                         fprintf(stderr, "Missing hostname\n");
2420                         usage();
2421                 }
2422
2423                 addargs(&args, "-oProtocol %d", sshver);
2424
2425                 /* no subsystem if the server-spec contains a '/' */
2426                 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2427                         addargs(&args, "-s");
2428
2429                 addargs(&args, "--");
2430                 addargs(&args, "%s", host);
2431                 addargs(&args, "%s", (sftp_server != NULL ?
2432                     sftp_server : "sftp"));
2433
2434                 connect_to_server(ssh_program, args.list, &in, &out);
2435         } else {
2436                 args.list = NULL;
2437                 addargs(&args, "sftp-server");
2438
2439                 connect_to_server(sftp_direct, args.list, &in, &out);
2440         }
2441         freeargs(&args);
2442
2443         conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2444         if (conn == NULL)
2445                 fatal("Couldn't initialise connection to server");
2446
2447         if (!quiet) {
2448                 if (sftp_direct == NULL)
2449                         fprintf(stderr, "Connected to %s.\n", host);
2450                 else
2451                         fprintf(stderr, "Attached to %s.\n", sftp_direct);
2452         }
2453
2454         err = interactive_loop(conn, file1, file2);
2455
2456 #if !defined(USE_PIPES)
2457         shutdown(in, SHUT_RDWR);
2458         shutdown(out, SHUT_RDWR);
2459 #endif
2460
2461         close(in);
2462         close(out);
2463         if (batchmode)
2464                 fclose(infile);
2465
2466         while (waitpid(sshpid, NULL, 0) == -1)
2467                 if (errno != EINTR)
2468                         fatal("Couldn't wait for ssh process: %s",
2469                             strerror(errno));
2470
2471         exit(err == 0 ? 0 : 1);
2472 }