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