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