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