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