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