Merge branch 'vendor/OPENSSH'
[dragonfly.git] / crypto / openssh / sftp.c
1 /* $OpenBSD: sftp.c,v 1.136 2012/06/22 14:36:33 dtucker Exp $ */
2 /*
3  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "includes.h"
19
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #ifdef HAVE_SYS_STAT_H
23 # include <sys/stat.h>
24 #endif
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/wait.h>
28 #ifdef HAVE_SYS_STATVFS_H
29 #include <sys/statvfs.h>
30 #endif
31
32 #include <ctype.h>
33 #include <errno.h>
34
35 #ifdef HAVE_PATHS_H
36 # include <paths.h>
37 #endif
38 #ifdef HAVE_LIBGEN_H
39 #include <libgen.h>
40 #endif
41 #ifdef 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    256     /* # 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         char *fname, *lname;
787         glob_t g;
788         int err;
789         struct winsize ws;
790         u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
791
792         memset(&g, 0, sizeof(g));
793
794         if (remote_glob(conn, path,
795             GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
796             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++) {
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                 xfree(list);
1635                 return 0;
1636         }
1637
1638         /* Complete ambigious command */
1639         tmp = complete_ambiguous(cmd, list, count);
1640         if (count > 1)
1641                 complete_display(list, 0);
1642
1643         for (y = 0; list[y]; y++)  
1644                 xfree(list[y]); 
1645         xfree(list);
1646
1647         if (tmp != NULL) {
1648                 tmplen = strlen(tmp);
1649                 cmdlen = strlen(cmd);
1650                 /* If cmd may be extended then do so */
1651                 if (tmplen > cmdlen)
1652                         if (el_insertstr(el, tmp + cmdlen) == -1)
1653                                 fatal("el_insertstr failed.");
1654                 lf = el_line(el);
1655                 /* Terminate argument cleanly */
1656                 if (count == 1) {
1657                         y = 0;
1658                         if (!terminated)
1659                                 argterm[y++] = quote;
1660                         if (lastarg || *(lf->cursor) != ' ')
1661                                 argterm[y++] = ' ';
1662                         argterm[y] = '\0';
1663                         if (y > 0 && el_insertstr(el, argterm) == -1)
1664                                 fatal("el_insertstr failed.");
1665                 }
1666                 xfree(tmp);
1667         }
1668
1669         return count;
1670 }
1671
1672 /*
1673  * Determine whether a particular sftp command's arguments (if any)
1674  * represent local or remote files.
1675  */
1676 static int
1677 complete_is_remote(char *cmd) {
1678         int i;
1679
1680         if (cmd == NULL)
1681                 return -1;
1682
1683         for (i = 0; cmds[i].c; i++) {
1684                 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 
1685                         return cmds[i].t;
1686         }
1687
1688         return -1;
1689 }
1690
1691 /* Autocomplete a filename "file" */
1692 static int
1693 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1694     char *file, int remote, int lastarg, char quote, int terminated)
1695 {
1696         glob_t g;
1697         char *tmp, *tmp2, ins[3];
1698         u_int i, hadglob, pwdlen, len, tmplen, filelen;
1699         const LineInfo *lf;
1700         
1701         /* Glob from "file" location */
1702         if (file == NULL)
1703                 tmp = xstrdup("*");
1704         else
1705                 xasprintf(&tmp, "%s*", file);
1706
1707         memset(&g, 0, sizeof(g));
1708         if (remote != LOCAL) {
1709                 tmp = make_absolute(tmp, remote_path);
1710                 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1711         } else 
1712                 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1713         
1714         /* Determine length of pwd so we can trim completion display */
1715         for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1716                 /* Terminate counting on first unescaped glob metacharacter */
1717                 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1718                         if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1719                                 hadglob = 1;
1720                         break;
1721                 }
1722                 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1723                         tmplen++;
1724                 if (tmp[tmplen] == '/')
1725                         pwdlen = tmplen + 1;    /* track last seen '/' */
1726         }
1727         xfree(tmp);
1728
1729         if (g.gl_matchc == 0) 
1730                 goto out;
1731
1732         if (g.gl_matchc > 1)
1733                 complete_display(g.gl_pathv, pwdlen);
1734
1735         tmp = NULL;
1736         /* Don't try to extend globs */
1737         if (file == NULL || hadglob)
1738                 goto out;
1739
1740         tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1741         tmp = path_strip(tmp2, remote_path);
1742         xfree(tmp2);
1743
1744         if (tmp == NULL)
1745                 goto out;
1746
1747         tmplen = strlen(tmp);
1748         filelen = strlen(file);
1749
1750         if (tmplen > filelen)  {
1751                 tmp2 = tmp + filelen;
1752                 len = strlen(tmp2); 
1753                 /* quote argument on way out */
1754                 for (i = 0; i < len; i++) {
1755                         ins[0] = '\\';
1756                         ins[1] = tmp2[i];
1757                         ins[2] = '\0';
1758                         switch (tmp2[i]) {
1759                         case '\'':
1760                         case '"':
1761                         case '\\':
1762                         case '\t':
1763                         case '[':
1764                         case ' ':
1765                                 if (quote == '\0' || tmp2[i] == quote) {
1766                                         if (el_insertstr(el, ins) == -1)
1767                                                 fatal("el_insertstr "
1768                                                     "failed.");
1769                                         break;
1770                                 }
1771                                 /* FALLTHROUGH */
1772                         default:
1773                                 if (el_insertstr(el, ins + 1) == -1)
1774                                         fatal("el_insertstr failed.");
1775                                 break;
1776                         }
1777                 }
1778         }
1779
1780         lf = el_line(el);
1781         if (g.gl_matchc == 1) {
1782                 i = 0;
1783                 if (!terminated)
1784                         ins[i++] = quote;
1785                 if (*(lf->cursor - 1) != '/' &&
1786                     (lastarg || *(lf->cursor) != ' '))
1787                         ins[i++] = ' ';
1788                 ins[i] = '\0';
1789                 if (i > 0 && el_insertstr(el, ins) == -1)
1790                         fatal("el_insertstr failed.");
1791         }
1792         xfree(tmp);
1793
1794  out:
1795         globfree(&g);
1796         return g.gl_matchc;
1797 }
1798
1799 /* tab-completion hook function, called via libedit */
1800 static unsigned char
1801 complete(EditLine *el, int ch)
1802 {
1803         char **argv, *line, quote; 
1804         u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
1805         const LineInfo *lf;
1806         struct complete_ctx *complete_ctx;
1807
1808         lf = el_line(el);
1809         if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
1810                 fatal("%s: el_get failed", __func__);
1811
1812         /* Figure out which argument the cursor points to */
1813         cursor = lf->cursor - lf->buffer;
1814         line = (char *)xmalloc(cursor + 1);
1815         memcpy(line, lf->buffer, cursor);
1816         line[cursor] = '\0';
1817         argv = makeargv(line, &carg, 1, &quote, &terminated);
1818         xfree(line);
1819
1820         /* Get all the arguments on the line */
1821         len = lf->lastchar - lf->buffer;
1822         line = (char *)xmalloc(len + 1);
1823         memcpy(line, lf->buffer, len);
1824         line[len] = '\0';
1825         argv = makeargv(line, &argc, 1, NULL, NULL);
1826
1827         /* Ensure cursor is at EOL or a argument boundary */
1828         if (line[cursor] != ' ' && line[cursor] != '\0' &&
1829             line[cursor] != '\n') {
1830                 xfree(line);
1831                 return ret;
1832         }
1833
1834         if (carg == 0) {
1835                 /* Show all available commands */
1836                 complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
1837                 ret = CC_REDISPLAY;
1838         } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
1839                 /* Handle the command parsing */
1840                 if (complete_cmd_parse(el, argv[0], argc == carg,
1841                     quote, terminated) != 0) 
1842                         ret = CC_REDISPLAY;
1843         } else if (carg >= 1) {
1844                 /* Handle file parsing */
1845                 int remote = complete_is_remote(argv[0]);
1846                 char *filematch = NULL;
1847
1848                 if (carg > 1 && line[cursor-1] != ' ')
1849                         filematch = argv[carg - 1];
1850
1851                 if (remote != 0 &&
1852                     complete_match(el, complete_ctx->conn,
1853                     *complete_ctx->remote_pathp, filematch,
1854                     remote, carg == argc, quote, terminated) != 0) 
1855                         ret = CC_REDISPLAY;
1856         }
1857
1858         xfree(line);    
1859         return ret;
1860 }
1861 #endif /* USE_LIBEDIT */
1862
1863 int
1864 interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1865 {
1866         char *remote_path;
1867         char *dir = NULL;
1868         char cmd[2048];
1869         int err, interactive;
1870         EditLine *el = NULL;
1871 #ifdef USE_LIBEDIT
1872         History *hl = NULL;
1873         HistEvent hev;
1874         extern char *__progname;
1875         struct complete_ctx complete_ctx;
1876
1877         if (!batchmode && isatty(STDIN_FILENO)) {
1878                 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
1879                         fatal("Couldn't initialise editline");
1880                 if ((hl = history_init()) == NULL)
1881                         fatal("Couldn't initialise editline history");
1882                 history(hl, &hev, H_SETSIZE, 100);
1883                 el_set(el, EL_HIST, history, hl);
1884
1885                 el_set(el, EL_PROMPT, prompt);
1886                 el_set(el, EL_EDITOR, "emacs");
1887                 el_set(el, EL_TERMINAL, NULL);
1888                 el_set(el, EL_SIGNAL, 1);
1889                 el_source(el, NULL);
1890
1891                 /* Tab Completion */
1892                 el_set(el, EL_ADDFN, "ftp-complete", 
1893                     "Context sensitive argument completion", complete);
1894                 complete_ctx.conn = conn;
1895                 complete_ctx.remote_pathp = &remote_path;
1896                 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
1897                 el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
1898         }
1899 #endif /* USE_LIBEDIT */
1900
1901         remote_path = do_realpath(conn, ".");
1902         if (remote_path == NULL)
1903                 fatal("Need cwd");
1904
1905         if (file1 != NULL) {
1906                 dir = xstrdup(file1);
1907                 dir = make_absolute(dir, remote_path);
1908
1909                 if (remote_is_dir(conn, dir) && file2 == NULL) {
1910                         printf("Changing to: %s\n", dir);
1911                         snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1912                         if (parse_dispatch_command(conn, cmd,
1913                             &remote_path, 1) != 0) {
1914                                 xfree(dir);
1915                                 xfree(remote_path);
1916                                 xfree(conn);
1917                                 return (-1);
1918                         }
1919                 } else {
1920                         if (file2 == NULL)
1921                                 snprintf(cmd, sizeof cmd, "get %s", dir);
1922                         else
1923                                 snprintf(cmd, sizeof cmd, "get %s %s", dir,
1924                                     file2);
1925
1926                         err = parse_dispatch_command(conn, cmd,
1927                             &remote_path, 1);
1928                         xfree(dir);
1929                         xfree(remote_path);
1930                         xfree(conn);
1931                         return (err);
1932                 }
1933                 xfree(dir);
1934         }
1935
1936         setlinebuf(stdout);
1937         setlinebuf(infile);
1938
1939         interactive = !batchmode && isatty(STDIN_FILENO);
1940         err = 0;
1941         for (;;) {
1942                 char *cp;
1943
1944                 signal(SIGINT, SIG_IGN);
1945
1946                 if (el == NULL) {
1947                         if (interactive)
1948                                 printf("sftp> ");
1949                         if (fgets(cmd, sizeof(cmd), infile) == NULL) {
1950                                 if (interactive)
1951                                         printf("\n");
1952                                 break;
1953                         }
1954                         if (!interactive) { /* Echo command */
1955                                 printf("sftp> %s", cmd);
1956                                 if (strlen(cmd) > 0 &&
1957                                     cmd[strlen(cmd) - 1] != '\n')
1958                                         printf("\n");
1959                         }
1960                 } else {
1961 #ifdef USE_LIBEDIT
1962                         const char *line;
1963                         int count = 0;
1964
1965                         if ((line = el_gets(el, &count)) == NULL ||
1966                             count <= 0) {
1967                                 printf("\n");
1968                                 break;
1969                         }
1970                         history(hl, &hev, H_ENTER, line);
1971                         if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
1972                                 fprintf(stderr, "Error: input line too long\n");
1973                                 continue;
1974                         }
1975 #endif /* USE_LIBEDIT */
1976                 }
1977
1978                 cp = strrchr(cmd, '\n');
1979                 if (cp)
1980                         *cp = '\0';
1981
1982                 /* Handle user interrupts gracefully during commands */
1983                 interrupted = 0;
1984                 signal(SIGINT, cmd_interrupt);
1985
1986                 err = parse_dispatch_command(conn, cmd, &remote_path,
1987                     batchmode);
1988                 if (err != 0)
1989                         break;
1990         }
1991         xfree(remote_path);
1992         xfree(conn);
1993
1994 #ifdef USE_LIBEDIT
1995         if (el != NULL)
1996                 el_end(el);
1997 #endif /* USE_LIBEDIT */
1998
1999         /* err == 1 signifies normal "quit" exit */
2000         return (err >= 0 ? 0 : -1);
2001 }
2002
2003 static void
2004 connect_to_server(char *path, char **args, int *in, int *out)
2005 {
2006         int c_in, c_out;
2007
2008 #ifdef USE_PIPES
2009         int pin[2], pout[2];
2010
2011         if ((pipe(pin) == -1) || (pipe(pout) == -1))
2012                 fatal("pipe: %s", strerror(errno));
2013         *in = pin[0];
2014         *out = pout[1];
2015         c_in = pout[0];
2016         c_out = pin[1];
2017 #else /* USE_PIPES */
2018         int inout[2];
2019
2020         if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2021                 fatal("socketpair: %s", strerror(errno));
2022         *in = *out = inout[0];
2023         c_in = c_out = inout[1];
2024 #endif /* USE_PIPES */
2025
2026         if ((sshpid = fork()) == -1)
2027                 fatal("fork: %s", strerror(errno));
2028         else if (sshpid == 0) {
2029                 if ((dup2(c_in, STDIN_FILENO) == -1) ||
2030                     (dup2(c_out, STDOUT_FILENO) == -1)) {
2031                         fprintf(stderr, "dup2: %s\n", strerror(errno));
2032                         _exit(1);
2033                 }
2034                 close(*in);
2035                 close(*out);
2036                 close(c_in);
2037                 close(c_out);
2038
2039                 /*
2040                  * The underlying ssh is in the same process group, so we must
2041                  * ignore SIGINT if we want to gracefully abort commands,
2042                  * otherwise the signal will make it to the ssh process and
2043                  * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2044                  * underlying ssh, it must *not* ignore that signal.
2045                  */
2046                 signal(SIGINT, SIG_IGN);
2047                 signal(SIGTERM, SIG_DFL);
2048                 execvp(path, args);
2049                 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2050                 _exit(1);
2051         }
2052
2053         signal(SIGTERM, killchild);
2054         signal(SIGINT, killchild);
2055         signal(SIGHUP, killchild);
2056         close(c_in);
2057         close(c_out);
2058 }
2059
2060 static void
2061 usage(void)
2062 {
2063         extern char *__progname;
2064
2065         fprintf(stderr,
2066             "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2067             "          [-D sftp_server_path] [-F ssh_config] "
2068             "[-i identity_file] [-l limit]\n"
2069             "          [-o ssh_option] [-P port] [-R num_requests] "
2070             "[-S program]\n"
2071             "          [-s subsystem | sftp_server] host\n"
2072             "       %s [user@]host[:file ...]\n"
2073             "       %s [user@]host[:dir[/]]\n"
2074             "       %s -b batchfile [user@]host\n",
2075             __progname, __progname, __progname, __progname);
2076         exit(1);
2077 }
2078
2079 int
2080 main(int argc, char **argv)
2081 {
2082         int in, out, ch, err;
2083         char *host = NULL, *userhost, *cp, *file2 = NULL;
2084         int debug_level = 0, sshver = 2;
2085         char *file1 = NULL, *sftp_server = NULL;
2086         char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2087         const char *errstr;
2088         LogLevel ll = SYSLOG_LEVEL_INFO;
2089         arglist args;
2090         extern int optind;
2091         extern char *optarg;
2092         struct sftp_conn *conn;
2093         size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2094         size_t num_requests = DEFAULT_NUM_REQUESTS;
2095         long long limit_kbps = 0;
2096
2097         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2098         sanitise_stdfd();
2099
2100         __progname = ssh_get_progname(argv[0]);
2101         memset(&args, '\0', sizeof(args));
2102         args.list = NULL;
2103         addargs(&args, "%s", ssh_program);
2104         addargs(&args, "-oForwardX11 no");
2105         addargs(&args, "-oForwardAgent no");
2106         addargs(&args, "-oPermitLocalCommand no");
2107         addargs(&args, "-oClearAllForwardings yes");
2108
2109         ll = SYSLOG_LEVEL_INFO;
2110         infile = stdin;
2111
2112         while ((ch = getopt(argc, argv,
2113             "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2114                 switch (ch) {
2115                 /* Passed through to ssh(1) */
2116                 case '4':
2117                 case '6':
2118                 case 'C':
2119                         addargs(&args, "-%c", ch);
2120                         break;
2121                 /* Passed through to ssh(1) with argument */
2122                 case 'F':
2123                 case 'c':
2124                 case 'i':
2125                 case 'o':
2126                         addargs(&args, "-%c", ch);
2127                         addargs(&args, "%s", optarg);
2128                         break;
2129                 case 'q':
2130                         showprogress = 0;
2131                         addargs(&args, "-%c", ch);
2132                         break;
2133                 case 'P':
2134                         addargs(&args, "-oPort %s", optarg);
2135                         break;
2136                 case 'v':
2137                         if (debug_level < 3) {
2138                                 addargs(&args, "-v");
2139                                 ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2140                         }
2141                         debug_level++;
2142                         break;
2143                 case '1':
2144                         sshver = 1;
2145                         if (sftp_server == NULL)
2146                                 sftp_server = _PATH_SFTP_SERVER;
2147                         break;
2148                 case '2':
2149                         sshver = 2;
2150                         break;
2151                 case 'B':
2152                         copy_buffer_len = strtol(optarg, &cp, 10);
2153                         if (copy_buffer_len == 0 || *cp != '\0')
2154                                 fatal("Invalid buffer size \"%s\"", optarg);
2155                         break;
2156                 case 'b':
2157                         if (batchmode)
2158                                 fatal("Batch file already specified.");
2159
2160                         /* Allow "-" as stdin */
2161                         if (strcmp(optarg, "-") != 0 &&
2162                             (infile = fopen(optarg, "r")) == NULL)
2163                                 fatal("%s (%s).", strerror(errno), optarg);
2164                         showprogress = 0;
2165                         batchmode = 1;
2166                         addargs(&args, "-obatchmode yes");
2167                         break;
2168                 case 'p':
2169                         global_pflag = 1;
2170                         break;
2171                 case 'D':
2172                         sftp_direct = optarg;
2173                         break;
2174                 case 'l':
2175                         limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2176                             &errstr);
2177                         if (errstr != NULL)
2178                                 usage();
2179                         limit_kbps *= 1024; /* kbps */
2180                         break;
2181                 case 'r':
2182                         global_rflag = 1;
2183                         break;
2184                 case 'R':
2185                         num_requests = strtol(optarg, &cp, 10);
2186                         if (num_requests == 0 || *cp != '\0')
2187                                 fatal("Invalid number of requests \"%s\"",
2188                                     optarg);
2189                         break;
2190                 case 's':
2191                         sftp_server = optarg;
2192                         break;
2193                 case 'S':
2194                         ssh_program = optarg;
2195                         replacearg(&args, 0, "%s", ssh_program);
2196                         break;
2197                 case 'h':
2198                 default:
2199                         usage();
2200                 }
2201         }
2202
2203         if (!isatty(STDERR_FILENO))
2204                 showprogress = 0;
2205
2206         log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2207
2208         if (sftp_direct == NULL) {
2209                 if (optind == argc || argc > (optind + 2))
2210                         usage();
2211
2212                 userhost = xstrdup(argv[optind]);
2213                 file2 = argv[optind+1];
2214
2215                 if ((host = strrchr(userhost, '@')) == NULL)
2216                         host = userhost;
2217                 else {
2218                         *host++ = '\0';
2219                         if (!userhost[0]) {
2220                                 fprintf(stderr, "Missing username\n");
2221                                 usage();
2222                         }
2223                         addargs(&args, "-l");
2224                         addargs(&args, "%s", userhost);
2225                 }
2226
2227                 if ((cp = colon(host)) != NULL) {
2228                         *cp++ = '\0';
2229                         file1 = cp;
2230                 }
2231
2232                 host = cleanhostname(host);
2233                 if (!*host) {
2234                         fprintf(stderr, "Missing hostname\n");
2235                         usage();
2236                 }
2237
2238                 addargs(&args, "-oProtocol %d", sshver);
2239
2240                 /* no subsystem if the server-spec contains a '/' */
2241                 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2242                         addargs(&args, "-s");
2243
2244                 addargs(&args, "--");
2245                 addargs(&args, "%s", host);
2246                 addargs(&args, "%s", (sftp_server != NULL ?
2247                     sftp_server : "sftp"));
2248
2249                 connect_to_server(ssh_program, args.list, &in, &out);
2250         } else {
2251                 args.list = NULL;
2252                 addargs(&args, "sftp-server");
2253
2254                 connect_to_server(sftp_direct, args.list, &in, &out);
2255         }
2256         freeargs(&args);
2257
2258         conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2259         if (conn == NULL)
2260                 fatal("Couldn't initialise connection to server");
2261
2262         if (!batchmode) {
2263                 if (sftp_direct == NULL)
2264                         fprintf(stderr, "Connected to %s.\n", host);
2265                 else
2266                         fprintf(stderr, "Attached to %s.\n", sftp_direct);
2267         }
2268
2269         err = interactive_loop(conn, file1, file2);
2270
2271 #if !defined(USE_PIPES)
2272         shutdown(in, SHUT_RDWR);
2273         shutdown(out, SHUT_RDWR);
2274 #endif
2275
2276         close(in);
2277         close(out);
2278         if (batchmode)
2279                 fclose(infile);
2280
2281         while (waitpid(sshpid, NULL, 0) == -1)
2282                 if (errno != EINTR)
2283                         fatal("Couldn't wait for ssh process: %s",
2284                             strerror(errno));
2285
2286         exit(err == 0 ? 0 : 1);
2287 }