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