]> andersk Git - openssh.git/blob - sftp-int.c
0851e63a22e09544d30ccf7775b2ddf1486bc4cd
[openssh.git] / sftp-int.c
1 /*
2  * Copyright (c) 2001 Damien Miller.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 /* XXX: globbed ls */
26 /* XXX: recursive operations */
27
28 #include "includes.h"
29 RCSID("$OpenBSD: sftp-int.c,v 1.39 2001/07/31 12:42:50 jakob Exp $");
30
31 #include "buffer.h"
32 #include "xmalloc.h"
33 #include "log.h"
34 #include "pathnames.h"
35
36 #include "sftp.h"
37 #include "sftp-common.h"
38 #include "sftp-glob.h"
39 #include "sftp-client.h"
40 #include "sftp-int.h"
41
42 /* File to read commands from */
43 extern FILE *infile;
44
45 /* Version of server we are speaking to */
46 int version;
47
48 /* Seperators for interactive commands */
49 #define WHITESPACE " \t\r\n"
50
51 /* Commands for interactive mode */
52 #define I_CHDIR         1
53 #define I_CHGRP         2
54 #define I_CHMOD         3
55 #define I_CHOWN         4
56 #define I_GET           5
57 #define I_HELP          6
58 #define I_LCHDIR        7
59 #define I_LLS           8
60 #define I_LMKDIR        9
61 #define I_LPWD          10
62 #define I_LS            11
63 #define I_LUMASK        12
64 #define I_MKDIR         13
65 #define I_PUT           14
66 #define I_PWD           15
67 #define I_QUIT          16
68 #define I_RENAME        17
69 #define I_RM            18
70 #define I_RMDIR         19
71 #define I_SHELL         20
72 #define I_SYMLINK       21
73 #define I_VERSION       22
74
75 struct CMD {
76         const char *c;
77         const int n;
78 };
79
80 const struct CMD cmds[] = {
81         { "cd",         I_CHDIR },
82         { "chdir",      I_CHDIR },
83         { "chgrp",      I_CHGRP },
84         { "chmod",      I_CHMOD },
85         { "chown",      I_CHOWN },
86         { "dir",        I_LS },
87         { "exit",       I_QUIT },
88         { "get",        I_GET },
89         { "mget",       I_GET },
90         { "help",       I_HELP },
91         { "lcd",        I_LCHDIR },
92         { "lchdir",     I_LCHDIR },
93         { "lls",        I_LLS },
94         { "lmkdir",     I_LMKDIR },
95         { "ln",         I_SYMLINK },
96         { "lpwd",       I_LPWD },
97         { "ls",         I_LS },
98         { "lumask",     I_LUMASK },
99         { "mkdir",      I_MKDIR },
100         { "put",        I_PUT },
101         { "mput",       I_PUT },
102         { "pwd",        I_PWD },
103         { "quit",       I_QUIT },
104         { "rename",     I_RENAME },
105         { "rm",         I_RM },
106         { "rmdir",      I_RMDIR },
107         { "symlink",    I_SYMLINK },
108         { "version",    I_VERSION },
109         { "!",          I_SHELL },
110         { "?",          I_HELP },
111         { NULL,                 -1}
112 };
113
114 static void
115 help(void)
116 {
117         printf("Available commands:\n");
118         printf("cd path                       Change remote directory to 'path'\n");
119         printf("lcd path                      Change local directory to 'path'\n");
120         printf("chgrp grp path                Change group of file 'path' to 'grp'\n");
121         printf("chmod mode path               Change permissions of file 'path' to 'mode'\n");
122         printf("chown own path                Change owner of file 'path' to 'own'\n");
123         printf("help                          Display this help text\n");
124         printf("get remote-path [local-path]  Download file\n");
125         printf("lls [ls-options [path]]       Display local directory listing\n");
126         printf("ln oldpath newpath            Symlink remote file\n");
127         printf("lmkdir path                   Create local directory\n");
128         printf("lpwd                          Print local working directory\n");
129         printf("ls [path]                     Display remote directory listing\n");
130         printf("lumask umask                  Set local umask to 'umask'\n");
131         printf("mkdir path                    Create remote directory\n");
132         printf("put local-path [remote-path]  Upload file\n");
133         printf("pwd                           Display remote working directory\n");
134         printf("exit                          Quit sftp\n");
135         printf("quit                          Quit sftp\n");
136         printf("rename oldpath newpath        Rename remote file\n");
137         printf("rmdir path                    Remove remote directory\n");
138         printf("rm path                       Delete remote file\n");
139         printf("symlink oldpath newpath       Symlink remote file\n");
140         printf("version                       Show SFTP version\n");
141         printf("!command                      Execute 'command' in local shell\n");
142         printf("!                             Escape to local shell\n");
143         printf("?                             Synonym for help\n");
144 }
145
146 static void
147 local_do_shell(const char *args)
148 {
149         int status;
150         char *shell;
151         pid_t pid;
152
153         if (!*args)
154                 args = NULL;
155
156         if ((shell = getenv("SHELL")) == NULL)
157                 shell = _PATH_BSHELL;
158
159         if ((pid = fork()) == -1)
160                 fatal("Couldn't fork: %s", strerror(errno));
161
162         if (pid == 0) {
163                 /* XXX: child has pipe fds to ssh subproc open - issue? */
164                 if (args) {
165                         debug3("Executing %s -c \"%s\"", shell, args);
166                         execl(shell, shell, "-c", args, (char *)NULL);
167                 } else {
168                         debug3("Executing %s", shell);
169                         execl(shell, shell, (char *)NULL);
170                 }
171                 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
172                     strerror(errno));
173                 _exit(1);
174         }
175         if (waitpid(pid, &status, 0) == -1)
176                 fatal("Couldn't wait for child: %s", strerror(errno));
177         if (!WIFEXITED(status))
178                 error("Shell exited abormally");
179         else if (WEXITSTATUS(status))
180                 error("Shell exited with status %d", WEXITSTATUS(status));
181 }
182
183 static void
184 local_do_ls(const char *args)
185 {
186         if (!args || !*args)
187                 local_do_shell(_PATH_LS);
188         else {
189                 int len = strlen(_PATH_LS " ") + strlen(args) + 1;
190                 char *buf = xmalloc(len);
191
192                 /* XXX: quoting - rip quoting code from ftp? */
193                 snprintf(buf, len, _PATH_LS " %s", args);
194                 local_do_shell(buf);
195                 xfree(buf);
196         }
197 }
198
199 static char *
200 path_append(char *p1, char *p2)
201 {
202         char *ret;
203         int len = strlen(p1) + strlen(p2) + 2;
204
205         ret = xmalloc(len);
206         strlcpy(ret, p1, len);
207         if (strcmp(p1, "/") != 0) 
208                 strlcat(ret, "/", len);
209         strlcat(ret, p2, len);
210
211         return(ret);
212 }
213
214 static char *
215 make_absolute(char *p, char *pwd)
216 {
217         char *abs;
218
219         /* Derelativise */
220         if (p && p[0] != '/') {
221                 abs = path_append(pwd, p);
222                 xfree(p);
223                 return(abs);
224         } else
225                 return(p);
226 }
227
228 static int
229 infer_path(const char *p, char **ifp)
230 {
231         char *cp;
232
233         cp = strrchr(p, '/');
234         if (cp == NULL) {
235                 *ifp = xstrdup(p);
236                 return(0);
237         }
238
239         if (!cp[1]) {
240                 error("Invalid path");
241                 return(-1);
242         }
243
244         *ifp = xstrdup(cp + 1);
245         return(0);
246 }
247
248 static int
249 parse_getput_flags(const char **cpp, int *pflag)
250 {
251         const char *cp = *cpp;
252
253         /* Check for flags */
254         if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) {
255                 switch (cp[1]) {
256                 case 'p':
257                 case 'P':
258                         *pflag = 1;
259                         break;
260                 default:
261                         error("Invalid flag -%c", cp[1]);
262                         return(-1);
263                 }
264                 cp += 2;
265                 *cpp = cp + strspn(cp, WHITESPACE);
266         }
267
268         return(0);
269 }
270
271 static int
272 get_pathname(const char **cpp, char **path)
273 {
274         const char *cp = *cpp, *end;
275         char quot;
276         int i;
277
278         cp += strspn(cp, WHITESPACE);
279         if (!*cp) {
280                 *cpp = cp;
281                 *path = NULL;
282                 return (0);
283         }
284
285         /* Check for quoted filenames */
286         if (*cp == '\"' || *cp == '\'') {
287                 quot = *cp++;
288
289                 end = strchr(cp, quot);
290                 if (end == NULL) {
291                         error("Unterminated quote");
292                         goto fail;
293                 }
294                 if (cp == end) {
295                         error("Empty quotes");
296                         goto fail;
297                 }
298                 *cpp = end + 1 + strspn(end + 1, WHITESPACE);
299         } else {
300                 /* Read to end of filename */
301                 end = strpbrk(cp, WHITESPACE);
302                 if (end == NULL)
303                         end = strchr(cp, '\0');
304                 *cpp = end + strspn(end, WHITESPACE);
305         }
306
307         i = end - cp;
308
309         *path = xmalloc(i + 1);
310         memcpy(*path, cp, i);
311         (*path)[i] = '\0';
312         return(0);
313
314  fail:
315         *path = NULL;
316         return (-1);
317 }
318
319 static int
320 is_dir(char *path)
321 {
322         struct stat sb;
323
324         /* XXX: report errors? */
325         if (stat(path, &sb) == -1)
326                 return(0);
327
328         return(sb.st_mode & S_IFDIR);
329 }
330
331 static int
332 remote_is_dir(int in, int out, char *path)
333 {
334         Attrib *a;
335
336         /* XXX: report errors? */
337         if ((a = do_stat(in, out, path, 1)) == NULL)
338                 return(0);
339         if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
340                 return(0);
341         return(a->perm & S_IFDIR);
342 }
343
344 static int
345 process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
346 {
347         char *abs_src = NULL;
348         char *abs_dst = NULL;
349         char *tmp;
350         glob_t g;
351         int err = 0;
352         int i;
353
354         abs_src = xstrdup(src);
355         abs_src = make_absolute(abs_src, pwd);
356
357         memset(&g, 0, sizeof(g));
358         debug3("Looking up %s", abs_src);
359         if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
360                 error("File \"%s\" not found.", abs_src);
361                 err = -1;
362                 goto out;
363         }
364
365         /* Only one match, dst may be file, directory or unspecified */
366         if (g.gl_pathv[0] && g.gl_matchc == 1) {
367                 if (dst) {
368                         /* If directory specified, append filename */
369                         if (is_dir(dst)) {
370                                 if (infer_path(g.gl_pathv[0], &tmp)) {
371                                         err = 1;
372                                         goto out;
373                                 }
374                                 abs_dst = path_append(dst, tmp);
375                                 xfree(tmp);
376                         } else
377                                 abs_dst = xstrdup(dst);
378                 } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
379                         err = -1;
380                         goto out;
381                 }
382                 printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
383                 err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
384                 goto out;
385         }
386
387         /* Multiple matches, dst may be directory or unspecified */
388         if (dst && !is_dir(dst)) {
389                 error("Multiple files match, but \"%s\" is not a directory",
390                     dst);
391                 err = -1;
392                 goto out;
393         }
394
395         for(i = 0; g.gl_pathv[i]; i++) {
396                 if (infer_path(g.gl_pathv[i], &tmp)) {
397                         err = -1;
398                         goto out;
399                 }
400                 if (dst) {
401                         abs_dst = path_append(dst, tmp);
402                         xfree(tmp);
403                 } else
404                         abs_dst = tmp;
405
406                 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
407                 if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
408                         err = -1;
409                 xfree(abs_dst);
410                 abs_dst = NULL;
411         }
412
413 out:
414         xfree(abs_src);
415         if (abs_dst)
416                 xfree(abs_dst);
417         globfree(&g);
418         return(err);
419 }
420
421 static int
422 process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
423 {
424         char *tmp_dst = NULL;
425         char *abs_dst = NULL;
426         char *tmp;
427         glob_t g;
428         int err = 0;
429         int i;
430
431         if (dst) {
432                 tmp_dst = xstrdup(dst);
433                 tmp_dst = make_absolute(tmp_dst, pwd);
434         }
435
436         memset(&g, 0, sizeof(g));
437         debug3("Looking up %s", src);
438         if (glob(src, 0, NULL, &g)) {
439                 error("File \"%s\" not found.", src);
440                 err = -1;
441                 goto out;
442         }
443
444         /* Only one match, dst may be file, directory or unspecified */
445         if (g.gl_pathv[0] && g.gl_matchc == 1) {
446                 if (tmp_dst) {
447                         /* If directory specified, append filename */
448                         if (remote_is_dir(in, out, tmp_dst)) {
449                                 if (infer_path(g.gl_pathv[0], &tmp)) {
450                                         err = 1;
451                                         goto out;
452                                 }
453                                 abs_dst = path_append(tmp_dst, tmp);
454                                 xfree(tmp);
455                         } else
456                                 abs_dst = xstrdup(tmp_dst);
457                 } else {
458                         if (infer_path(g.gl_pathv[0], &abs_dst)) {
459                                 err = -1;
460                                 goto out;
461                         }
462                         abs_dst = make_absolute(abs_dst, pwd);
463                 }
464                 printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
465                 err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
466                 goto out;
467         }
468
469         /* Multiple matches, dst may be directory or unspecified */
470         if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
471                 error("Multiple files match, but \"%s\" is not a directory",
472                     tmp_dst);
473                 err = -1;
474                 goto out;
475         }
476
477         for(i = 0; g.gl_pathv[i]; i++) {
478                 if (infer_path(g.gl_pathv[i], &tmp)) {
479                         err = -1;
480                         goto out;
481                 }
482                 if (tmp_dst) {
483                         abs_dst = path_append(tmp_dst, tmp);
484                         xfree(tmp);
485                 } else
486                         abs_dst = make_absolute(tmp, pwd);
487
488                 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
489                 if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
490                         err = -1;
491         }
492
493 out:
494         if (abs_dst)
495                 xfree(abs_dst);
496         if (tmp_dst)
497                 xfree(tmp_dst);
498         return(err);
499 }
500
501 static int
502 parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
503     char **path1, char **path2)
504 {
505         const char *cmd, *cp = *cpp;
506         char *cp2;
507         int base = 0;
508         long l;
509         int i, cmdnum;
510
511         /* Skip leading whitespace */
512         cp = cp + strspn(cp, WHITESPACE);
513
514         /* Ignore blank lines */
515         if (!*cp)
516                 return(-1);
517
518         /* Figure out which command we have */
519         for(i = 0; cmds[i].c; i++) {
520                 int cmdlen = strlen(cmds[i].c);
521
522                 /* Check for command followed by whitespace */
523                 if (!strncasecmp(cp, cmds[i].c, cmdlen) &&
524                     strchr(WHITESPACE, cp[cmdlen])) {
525                         cp += cmdlen;
526                         cp = cp + strspn(cp, WHITESPACE);
527                         break;
528                 }
529         }
530         cmdnum = cmds[i].n;
531         cmd = cmds[i].c;
532
533         /* Special case */
534         if (*cp == '!') {
535                 cp++;
536                 cmdnum = I_SHELL;
537         } else if (cmdnum == -1) {
538                 error("Invalid command.");
539                 return(-1);
540         }
541
542         /* Get arguments and parse flags */
543         *pflag = *n_arg = 0;
544         *path1 = *path2 = NULL;
545         switch (cmdnum) {
546         case I_GET:
547         case I_PUT:
548                 if (parse_getput_flags(&cp, pflag))
549                         return(-1);
550                 /* Get first pathname (mandatory) */
551                 if (get_pathname(&cp, path1))
552                         return(-1);
553                 if (*path1 == NULL) {
554                         error("You must specify at least one path after a "
555                             "%s command.", cmd);
556                         return(-1);
557                 }
558                 /* Try to get second pathname (optional) */
559                 if (get_pathname(&cp, path2))
560                         return(-1);
561                 break;
562         case I_RENAME:
563         case I_SYMLINK:
564                 if (get_pathname(&cp, path1))
565                         return(-1);
566                 if (get_pathname(&cp, path2))
567                         return(-1);
568                 if (!*path1 || !*path2) {
569                         error("You must specify two paths after a %s "
570                             "command.", cmd);
571                         return(-1);
572                 }
573                 break;
574         case I_RM:
575         case I_MKDIR:
576         case I_RMDIR:
577         case I_CHDIR:
578         case I_LCHDIR:
579         case I_LMKDIR:
580                 /* Get pathname (mandatory) */
581                 if (get_pathname(&cp, path1))
582                         return(-1);
583                 if (*path1 == NULL) {
584                         error("You must specify a path after a %s command.",
585                             cmd);
586                         return(-1);
587                 }
588                 break;
589         case I_LS:
590                 /* Path is optional */
591                 if (get_pathname(&cp, path1))
592                         return(-1);
593                 break;
594         case I_LLS:
595         case I_SHELL:
596                 /* Uses the rest of the line */
597                 break;
598         case I_LUMASK:
599                 base = 8;
600         case I_CHMOD:
601                 base = 8;
602         case I_CHOWN:
603         case I_CHGRP:
604                 /* Get numeric arg (mandatory) */
605                 l = strtol(cp, &cp2, base);
606                 if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) &&
607                     errno == ERANGE) || l < 0) {
608                         error("You must supply a numeric argument "
609                             "to the %s command.", cmd);
610                         return(-1);
611                 }
612                 cp = cp2;
613                 *n_arg = l;
614                 if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp))
615                         break;
616                 if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) {
617                         error("You must supply a numeric argument "
618                             "to the %s command.", cmd);
619                         return(-1);
620                 }
621                 cp += strspn(cp, WHITESPACE);
622
623                 /* Get pathname (mandatory) */
624                 if (get_pathname(&cp, path1))
625                         return(-1);
626                 if (*path1 == NULL) {
627                         error("You must specify a path after a %s command.",
628                             cmd);
629                         return(-1);
630                 }
631                 break;
632         case I_QUIT:
633         case I_PWD:
634         case I_LPWD:
635         case I_HELP:
636         case I_VERSION:
637                 break;
638         default:
639                 fatal("Command not implemented");
640         }
641
642         *cpp = cp;
643         return(cmdnum);
644 }
645
646 static int
647 parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
648 {
649         char *path1, *path2, *tmp;
650         int pflag, cmdnum, i;
651         unsigned long n_arg;
652         Attrib a, *aa;
653         char path_buf[MAXPATHLEN];
654         int err = 0;
655         glob_t g;
656
657         path1 = path2 = NULL;
658         cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
659
660         memset(&g, 0, sizeof(g));
661
662         /* Perform command */
663         switch (cmdnum) {
664         case -1:
665                 break;
666         case I_GET:
667                 err = process_get(in, out, path1, path2, *pwd, pflag);
668                 break;
669         case I_PUT:
670                 err = process_put(in, out, path1, path2, *pwd, pflag);
671                 break;
672         case I_RENAME:
673                 path1 = make_absolute(path1, *pwd);
674                 path2 = make_absolute(path2, *pwd);
675                 err = do_rename(in, out, path1, path2);
676                 break;
677         case I_SYMLINK:
678                 if (version < 3) {
679                         error("The server (version %d) does not support "
680                             "this operation", version);
681                         err = -1;
682                 } else {
683                         path2 = make_absolute(path2, *pwd);
684                         err = do_symlink(in, out, path1, path2);
685                 }
686                 break;
687         case I_RM:
688                 path1 = make_absolute(path1, *pwd);
689                 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
690                 for(i = 0; g.gl_pathv[i]; i++) {
691                         printf("Removing %s\n", g.gl_pathv[i]);
692                         if (do_rm(in, out, g.gl_pathv[i]) == -1)
693                                 err = -1;
694                 }
695                 break;
696         case I_MKDIR:
697                 path1 = make_absolute(path1, *pwd);
698                 attrib_clear(&a);
699                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
700                 a.perm = 0777;
701                 err = do_mkdir(in, out, path1, &a);
702                 break;
703         case I_RMDIR:
704                 path1 = make_absolute(path1, *pwd);
705                 err = do_rmdir(in, out, path1);
706                 break;
707         case I_CHDIR:
708                 path1 = make_absolute(path1, *pwd);
709                 if ((tmp = do_realpath(in, out, path1)) == NULL) {
710                         err = 1;
711                         break;
712                 }
713                 if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
714                         xfree(tmp);
715                         err = 1;
716                         break;
717                 }
718                 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
719                         error("Can't change directory: Can't check target");
720                         xfree(tmp);
721                         err = 1;
722                         break;
723                 }
724                 if (!S_ISDIR(aa->perm)) {
725                         error("Can't change directory: \"%s\" is not "
726                             "a directory", tmp);
727                         xfree(tmp);
728                         err = 1;
729                         break;
730                 }
731                 xfree(*pwd);
732                 *pwd = tmp;
733                 break;
734         case I_LS:
735                 if (!path1) {
736                         do_ls(in, out, *pwd);
737                         break;
738                 }
739                 path1 = make_absolute(path1, *pwd);
740                 if ((tmp = do_realpath(in, out, path1)) == NULL)
741                         break;
742                 xfree(path1);
743                 path1 = tmp;
744                 if ((aa = do_stat(in, out, path1, 0)) == NULL)
745                         break;
746                 if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
747                     !S_ISDIR(aa->perm)) {
748                         error("Can't ls: \"%s\" is not a directory", path1);
749                         break;
750                 }
751                 do_ls(in, out, path1);
752                 break;
753         case I_LCHDIR:
754                 if (chdir(path1) == -1) {
755                         error("Couldn't change local directory to "
756                             "\"%s\": %s", path1, strerror(errno));
757                         err = 1;
758                 }
759                 break;
760         case I_LMKDIR:
761                 if (mkdir(path1, 0777) == -1) {
762                         error("Couldn't create local directory "
763                             "\"%s\": %s", path1, strerror(errno));
764                         err = 1;
765                 }
766                 break;
767         case I_LLS:
768                 local_do_ls(cmd);
769                 break;
770         case I_SHELL:
771                 local_do_shell(cmd);
772                 break;
773         case I_LUMASK:
774                 umask(n_arg);
775                 printf("Local umask: %03lo\n", n_arg);
776                 break;
777         case I_CHMOD:
778                 path1 = make_absolute(path1, *pwd);
779                 attrib_clear(&a);
780                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
781                 a.perm = n_arg;
782                 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
783                 for(i = 0; g.gl_pathv[i]; i++) {
784                         printf("Changing mode on %s\n", g.gl_pathv[i]);
785                         do_setstat(in, out, g.gl_pathv[i], &a);
786                 }
787                 break;
788         case I_CHOWN:
789                 path1 = make_absolute(path1, *pwd);
790                 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
791                 for(i = 0; g.gl_pathv[i]; i++) {
792                         if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
793                                 continue;
794                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
795                                 error("Can't get current ownership of "
796                                     "remote file \"%s\"", g.gl_pathv[i]);
797                                 continue;
798                         }
799                         printf("Changing owner on %s\n", g.gl_pathv[i]);
800                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
801                         aa->uid = n_arg;
802                         do_setstat(in, out, g.gl_pathv[i], aa);
803                 }
804                 break;
805         case I_CHGRP:
806                 path1 = make_absolute(path1, *pwd);
807                 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
808                 for(i = 0; g.gl_pathv[i]; i++) {
809                         if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
810                                 continue;
811                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
812                                 error("Can't get current ownership of "
813                                     "remote file \"%s\"", g.gl_pathv[i]);
814                                 continue;
815                         }
816                         printf("Changing group on %s\n", g.gl_pathv[i]);
817                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
818                         aa->gid = n_arg;
819                         do_setstat(in, out, g.gl_pathv[i], aa);
820                 }
821                 break;
822         case I_PWD:
823                 printf("Remote working directory: %s\n", *pwd);
824                 break;
825         case I_LPWD:
826                 if (!getcwd(path_buf, sizeof(path_buf)))
827                         error("Couldn't get local cwd: %s",
828                             strerror(errno));
829                 else
830                         printf("Local working directory: %s\n",
831                             path_buf);
832                 break;
833         case I_QUIT:
834                 return(-1);
835         case I_HELP:
836                 help();
837                 break;
838         case I_VERSION:
839                 printf("SFTP protocol version %d\n", version);
840                 break;
841         default:
842                 fatal("%d is not implemented", cmdnum);
843         }
844
845         if (g.gl_pathc)
846                 globfree(&g);
847         if (path1)
848                 xfree(path1);
849         if (path2)
850                 xfree(path2);
851
852         /* If an error occurs in batch mode we should abort. */
853         if (infile != stdin && err > 0)
854                 return -1;
855
856         return(0);
857 }
858
859 void
860 interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
861 {
862         char *pwd;
863         char *dir = NULL;
864         char cmd[2048];
865
866         version = do_init(fd_in, fd_out);
867         if (version == -1)
868                 fatal("Couldn't initialise connection to server");
869
870         pwd = do_realpath(fd_in, fd_out, ".");
871         if (pwd == NULL)
872                 fatal("Need cwd");
873
874         if (file1 != NULL) {
875                 dir = xstrdup(file1);
876                 dir = make_absolute(dir, pwd);
877
878                 if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) {
879                         printf("Changing to: %s\n", dir);
880                         snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
881                         parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
882                 } else {
883                         if (file2 == NULL)
884                                 snprintf(cmd, sizeof cmd, "get %s", dir);
885                         else
886                                 snprintf(cmd, sizeof cmd, "get %s %s", dir,
887                                     file2);
888
889                         parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
890                         return;
891                 }
892         }
893 #if HAVE_SETVBUF
894         setvbuf(stdout, NULL, _IOLBF, 0);
895         setvbuf(infile, NULL, _IOLBF, 0);
896 #else
897         setlinebuf(stdout);
898         setlinebuf(infile);
899 #endif
900
901         for(;;) {
902                 char *cp;
903
904                 printf("sftp> ");
905
906                 /* XXX: use libedit */
907                 if (fgets(cmd, sizeof(cmd), infile) == NULL) {
908                         printf("\n");
909                         break;
910                 } else if (infile != stdin) /* Bluff typing */
911                         printf("%s", cmd);
912
913                 cp = strrchr(cmd, '\n');
914                 if (cp)
915                         *cp = '\0';
916
917                 if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
918                         break;
919         }
920         xfree(pwd);
921 }
This page took 0.371623 seconds and 3 git commands to generate.