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