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