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