merge of changes from jsq@utexas-11
authorSam Leffler <sam@ucbvax.Berkeley.EDU>
Thu, 24 Mar 1983 02:27:47 +0000 (18:27 -0800)
committerSam Leffler <sam@ucbvax.Berkeley.EDU>
Thu, 24 Mar 1983 02:27:47 +0000 (18:27 -0800)
SCCS-vsn: usr.bin/ftp/cmds.c 4.4
SCCS-vsn: usr.bin/ftp/cmdtab.c 4.4
SCCS-vsn: usr.bin/ftp/ftp.c 4.7
SCCS-vsn: usr.bin/ftp/ftp_var.h 4.4
SCCS-vsn: libexec/ftpd/ftpcmd.y 4.9
SCCS-vsn: libexec/ftpd/ftpd.c 4.18
SCCS-vsn: usr.bin/ftp/main.c 4.6

usr/src/libexec/ftpd/ftpcmd.y
usr/src/libexec/ftpd/ftpd.c
usr/src/usr.bin/ftp/cmds.c
usr/src/usr.bin/ftp/cmdtab.c
usr/src/usr.bin/ftp/ftp.c
usr/src/usr.bin/ftp/ftp_var.h
usr/src/usr.bin/ftp/main.c

index 7db456c..3391fa5 100644 (file)
@@ -6,7 +6,7 @@
 %{
 
 #ifndef lint
 %{
 
 #ifndef lint
-static char sccsid[] = "@(#)ftpcmd.y   4.8 83/02/21";
+static char sccsid[] = "@(#)ftpcmd.y   4.9 83/03/23";
 #endif
 
 #include <sys/types.h>
 #endif
 
 #include <sys/types.h>
@@ -15,6 +15,7 @@ static char sccsid[] = "@(#)ftpcmd.y  4.8 83/02/21";
 #include <netinet/in.h>
 
 #include <stdio.h>
 #include <netinet/in.h>
 
 #include <stdio.h>
+#include <signal.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <setjmp.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <setjmp.h>
@@ -28,6 +29,7 @@ extern        int logging;
 extern int type;
 extern int form;
 extern int debug;
 extern int type;
 extern int form;
 extern int debug;
+extern int timeout;
 extern char hostname[];
 extern char *globerr;
 extern int usedefault;
 extern char hostname[];
 extern char *globerr;
 extern int usedefault;
@@ -528,13 +530,33 @@ getline(s, n, iop)
        if (c < 0 && cs == s)
                return (NULL);
        *cs++ = '\0';
        if (c < 0 && cs == s)
                return (NULL);
        *cs++ = '\0';
-       fprintf(stderr, "FTPD: command: %s", s);
-       if (c != '\n')
-               putc('\n', stderr);
-       fflush(stderr);
+       if (debug) {
+               fprintf(stderr, "FTPD: command: %s", s);
+               if (c != '\n')
+                       putc('\n', stderr);
+               fflush(stderr);
+       }
        return (s);
 }
 
        return (s);
 }
 
+static int
+toolong()
+{
+       long now;
+       extern char *ctime();
+
+       reply(421,
+         "Timeout (%d seconds): closing control connection.", timeout);
+       time(&now);
+       if (logging) {
+               fprintf(stderr,
+                       "FTPD: User %s timed out after %d seconds at %s",
+                       (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now));
+               fflush(stderr);
+       }
+       exit(1);
+}
+
 yylex()
 {
        static char cbuf[512];
 yylex()
 {
        static char cbuf[512];
@@ -548,10 +570,13 @@ yylex()
                switch (state) {
 
                case CMD:
                switch (state) {
 
                case CMD:
+                       signal(SIGALRM, toolong);
+                       alarm(timeout);
                        if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
                                reply(221, "You could at least say goodbye.");
                                exit(0);
                        }
                        if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) {
                                reply(221, "You could at least say goodbye.");
                                exit(0);
                        }
+                       alarm(0);
                        if (index(cbuf, '\r')) {
                                cp = index(cbuf, '\r');
                                cp[0] = '\n'; cp[1] = 0;
                        if (index(cbuf, '\r')) {
                                cp = index(cbuf, '\r');
                                cp[0] = '\n'; cp[1] = 0;
index c643c3c..e0eaa8c 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)ftpd.c     4.17 (Berkeley) %G%";
+static char sccsid[] = "@(#)ftpd.c     4.18 (Berkeley) %G%";
 #endif
 
 /*
 #endif
 
 /*
@@ -49,6 +49,7 @@ jmp_buf       errcatch;
 int    logged_in;
 struct passwd *pw;
 int    debug;
 int    logged_in;
 struct passwd *pw;
 int    debug;
+int    timeout;
 int    logging = 1;
 int    guest;
 int    type;
 int    logging = 1;
 int    guest;
 int    type;
@@ -60,6 +61,17 @@ char hostname[32];
 char   *remotehost;
 struct servent *sp;
 
 char   *remotehost;
 struct servent *sp;
 
+/*
+ * Timeout intervals for retrying connections
+ * to hosts that don't accept PORT cmds.  This
+ * is a kludge, but given the problems with TCP...
+ */
+#define        SWAITMAX        90      /* wait at most 90 seconds */
+#define        SWAITINT        5       /* interval between retries */
+
+int    swaitmax = SWAITMAX;
+int    swaitint = SWAITINT;
+
 int    lostconn();
 int    reapchild();
 FILE   *getdatasock(), *dataconn();
 int    lostconn();
 int    reapchild();
 FILE   *getdatasock(), *dataconn();
@@ -85,25 +97,38 @@ main(argc, argv)
        while (argc > 0 && *argv[0] == '-') {
                for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
 
        while (argc > 0 && *argv[0] == '-') {
                for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
 
+               case 'v':
+                       debug = 1;
+                       break;
+
                case 'd':
                        debug = 1;
                        options |= SO_DEBUG;
                        break;
 
                case 'd':
                        debug = 1;
                        options |= SO_DEBUG;
                        break;
 
+               case 't':
+                       timeout = atoi(++cp);
+                       goto nextopt;
+                       break;
+
                default:
                default:
-                       fprintf(stderr, "Unknown flag -%c ignored.\n", cp);
+                       fprintf(stderr, "Unknown flag -%c ignored.\n", *cp);
                        break;
                }
                        break;
                }
+nextopt:
                argc--, argv++;
        }
 #ifndef DEBUG
        if (fork())
                exit(0);
        for (s = 0; s < 10; s++)
                argc--, argv++;
        }
 #ifndef DEBUG
        if (fork())
                exit(0);
        for (s = 0; s < 10; s++)
+               if (!logging || (s != 2))
+                       (void) close(s);
                (void) close(s);
        (void) open("/", 0);
        (void) dup2(0, 1);
                (void) close(s);
        (void) open("/", 0);
        (void) dup2(0, 1);
-       (void) dup2(0, 2);
+       if (!logging)
+               (void) dup2(0, 2);
        { int tt = open("/dev/tty", 2);
          if (tt > 0) {
                ioctl(tt, TIOCNOTTY, 0);
        { int tt = open("/dev/tty", 2);
          if (tt > 0) {
                ioctl(tt, TIOCNOTTY, 0);
@@ -256,7 +281,7 @@ retrieve(cmd, name)
        if (cmd == 0) {
 #ifdef notdef
                /* no remote command execution -- it's a security hole */
        if (cmd == 0) {
 #ifdef notdef
                /* no remote command execution -- it's a security hole */
-               if (*name == '!')
+               if (*name == '|')
                        fin = popen(name + 1, "r"), closefunc = pclose;
                else
 #endif
                        fin = popen(name + 1, "r"), closefunc = pclose;
                else
 #endif
@@ -297,7 +322,7 @@ store(name, mode)
 
 #ifdef notdef
        /* no remote command execution -- it's a security hole */
 
 #ifdef notdef
        /* no remote command execution -- it's a security hole */
-       if (name[0] == '!')
+       if (name[0] == '|')
                fout = popen(&name[1], "w"), closefunc = pclose;
        else
 #endif
                fout = popen(&name[1], "w"), closefunc = pclose;
        else
 #endif
@@ -312,7 +337,7 @@ store(name, mode)
                reply(550, "%s: %s.", name, sys_errlist[errno]);
                return;
        }
                reply(550, "%s: %s.", name, sys_errlist[errno]);
                return;
        }
-       din = dataconn(name, -1, "r");
+       din = dataconn(name, (off_t)-1, "r");
        if (din == NULL)
                goto done;
        if (receive_data(din, fout) || ferror(fout))
        if (din == NULL)
                goto done;
        if (receive_data(din, fout) || ferror(fout))
@@ -353,14 +378,15 @@ bad:
 FILE *
 dataconn(name, size, mode)
        char *name;
 FILE *
 dataconn(name, size, mode)
        char *name;
-       int size;
+       off_t size;
        char *mode;
 {
        char sizebuf[32];
        FILE *file;
        char *mode;
 {
        char sizebuf[32];
        FILE *file;
+       int retry = 0;
 
        if (size >= 0)
 
        if (size >= 0)
-               sprintf(sizebuf, " (%d bytes)", size);
+               sprintf (sizebuf, " (%ld bytes)", size);
        else
                (void) strcpy(sizebuf, "");
        if (data >= 0) {
        else
                (void) strcpy(sizebuf, "");
        if (data >= 0) {
@@ -384,7 +410,12 @@ dataconn(name, size, mode)
            name, ntoa(data_dest.sin_addr.s_addr),
            ntohs(data_dest.sin_port), sizebuf);
        data = fileno(file);
            name, ntoa(data_dest.sin_addr.s_addr),
            ntohs(data_dest.sin_port), sizebuf);
        data = fileno(file);
-       if (connect(data, &data_dest, sizeof (data_dest), 0) < 0) {
+       while (connect(data, &data_dest, sizeof (data_dest), 0) < 0) {
+               if (errno == EADDRINUSE && retry < swaitmax) {
+                       sleep(swaitint);
+                       retry += swaitint;
+                       continue;
+               }
                reply(425, "Can't build data connection: %s.",
                    sys_errlist[errno]);
                (void) fclose(file);
                reply(425, "Can't build data connection: %s.",
                    sys_errlist[errno]);
                (void) fclose(file);
@@ -619,7 +650,6 @@ removedir(name)
 pwd()
 {
        char path[MAXPATHLEN + 1];
 pwd()
 {
        char path[MAXPATHLEN + 1];
-       char *p;
 
        if (getwd(path) == NULL) {
                reply(451, "%s.", path);
 
        if (getwd(path) == NULL) {
                reply(451, "%s.", path);
@@ -653,41 +683,6 @@ renamecmd(from, to)
        ack("RNTO");
 }
 
        ack("RNTO");
 }
 
-int guest;
-/*
- * Test pathname for guest-user safety.
- */
-inappropriate_request(name)
-       char *name;
-{
-       int bogus = 0, depth = 0, length = strlen(name);
-       char *p, *s;
-
-       if (!guest)
-               return (0);
-       if (name[0] == '/' || name[0] == '|')
-               bogus = 1;
-       for (p = name; p < name+length;) {
-               s = p;                          /* start of token */
-               while ( *p && *p!= '/')
-                       p++;
-               *p = 0;
-               if (strcmp(s, "..") == 0)
-                       depth -= 1;             /* backing up */
-               else if (strcmp(s, ".") == 0)
-                       depth += 0;             /* no change */
-               else
-                       depth += 1;             /* descending */
-               if (depth < 0) {
-                       bogus = 1;
-                       break;
-               }
-       }
-       if (bogus)
-               reply(553, "%s: pathname disallowed guest users", name);
-       return (bogus);
-}
-
 /*
  * Convert network-format internet address
  * to base 256 d.d.d.d representation.
 /*
  * Convert network-format internet address
  * to base 256 d.d.d.d representation.
index 2236ae9..770be33 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)cmds.c     4.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)cmds.c     4.4 (Berkeley) %G%";
 #endif
 
 /*
 #endif
 
 /*
@@ -197,14 +197,26 @@ setstruct(argc, argv)
 /*
  * Send a single file.
  */
 /*
  * Send a single file.
  */
+append(argc, argv)
+       char *argv[];
+{
+
+       return (put1("APPE", argc, argv));
+}
+
 put(argc, argv)
        char *argv[];
 {
 
 put(argc, argv)
        char *argv[];
 {
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
+       return (put1("STOR", argc, argv));
+}
+
+put1(cmd, argc, argv)
+       char *cmd;
+       int argc;
+       char *argv[];
+{
+
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
@@ -232,7 +244,7 @@ usage:
                goto usage;
        if (!globulize(&argv[1]))
                return;
                goto usage;
        if (!globulize(&argv[1]))
                return;
-       sendrequest("STOR", argv[1], argv[2]);
+       sendrequest(cmd, argv[1], argv[2]);
 }
 
 /*
 }
 
 /*
@@ -241,51 +253,38 @@ usage:
 mput(argc, argv)
        char *argv[];
 {
 mput(argc, argv)
        char *argv[];
 {
-       char **cpp, *dst;
+       char **cpp, **gargs = NULL;
        int i;
 
        int i;
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(local-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
        }
        if (argc < 2) {
        }
        if (argc < 2) {
-               printf("%s local-file remote-file, or\n", argv[0]);
                printf("%s local-files\n", argv[0]);
                return;
        }
                printf("%s local-files\n", argv[0]);
                return;
        }
-       if (argc == 3)  {
-               if (!globulize(&argv[1]))
-                       return;
-               sendrequest("STOR", argv[1], argv[2]);
-               return;
-       }
-       /*
-        * Check for shell metacharacters which we might
-        * want to expand into a list of file names.
-        */
-       for (i = 1; i < argc; i++) {
-               if (!doglob) {
-                       if (!skip(argv[0], argv[i]))
-                               sendrequest("STOR", argv[i], argv[i]);
-                       continue;
-               }
-               cpp = glob(argv[i]);
+       cpp = argv + 1;
+       if (doglob) {
+               gargs = glob(cpp);
                if (globerr != NULL) {
                if (globerr != NULL) {
-                       printf("%s: %s\n", argv[i], globerr);
-                       if (cpp)
-                               blkfree(cpp);
-                       continue;
-               }
-               if (cpp == NULL) {
-                       printf("%s: no match\n", argv[i]);
-                       continue;
-               }
-               while (*cpp != NULL) {
-                       if (!skip(argv[0], *cpp))
-                               sendrequest("STOR", *cpp, *cpp);
-                       free(*cpp), cpp++;
+                       printf("%s\n", globerr);
+                       if (gargs)
+                               blkfree(gargs);
+                       return;
                }
        }
                }
        }
+       if (gargs != NULL)
+               cpp = gargs;
+       for (; *cpp != NULL; cpp++)
+               if (confirm(argv[0], *cpp))
+                       sendrequest("STOR", *cpp, *cpp);
+       if (gargs != NULL)
+               blkfree(gargs);
 }
 
 /*
 }
 
 /*
@@ -295,10 +294,6 @@ get(argc, argv)
        char *argv[];
 {
 
        char *argv[];
 {
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
        if (argc == 2)
                argc++, argv[2] = argv[1];
        if (argc < 2) {
@@ -326,7 +321,7 @@ usage:
                goto usage;
        if (!globulize(&argv[2]))
                return;
                goto usage;
        if (!globulize(&argv[2]))
                return;
-       recvrequest("RETR", argv[2], argv[1]);
+       recvrequest("RETR", argv[2], argv[1], "w");
 }
 
 /*
 }
 
 /*
@@ -335,17 +330,8 @@ usage:
 mget(argc, argv)
        char *argv[];
 {
 mget(argc, argv)
        char *argv[];
 {
-       char temp[16], *dst, dstpath[MAXPATHLEN], buf[MAXPATHLEN];
-       FILE *ftemp;
-       int madedir = 0, oldverbose;
-       struct stat stb;
+       register char *cp;
 
 
-       if (!connected) {
-               printf("Not connected.\n");
-               return;
-       }
-       if (argc == 2)
-               argc++, argv[2] = argv[1];
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-directory) ");
        if (argc < 2) {
                strcat(line, " ");
                printf("(remote-directory) ");
@@ -355,81 +341,51 @@ mget(argc, argv)
                argv = margv;
        }
        if (argc < 2) {
                argv = margv;
        }
        if (argc < 2) {
-usage:
-               printf("%s remote-directory [ local-directory ], or\n",
-                       argv[0]);
-               printf("%s remote-files local-directory\n", argv[0]);
+               printf("%s remote-files\n", argv[0]);
                return;
        }
                return;
        }
-       if (argc < 3) {
-               strcat(line, " ");
-               printf("(local-directory) ");
-               gets(&line[strlen(line)]);
-               makeargv();
-               argc = margc;
-               argv = margv;
-       }
-       if (argc < 3) 
-               goto usage;
-       dst = argv[argc - 1];
-       if (!globulize(&dst))
-               return;
-       /*
-        * If destination doesn't exist,
-        * try and create it.
-        */
-       if (stat(dst, &stb) < 0) {
-               if (mkdir(dst, 0777) < 0) {
-                       perror(dst);
-                       return;
-               }
-               madedir++;
-       } else {
-               if ((stb.st_mode & S_IFMT) != S_IFDIR) {
-                       printf("%s: not a directory\n", dst);
-                       return;
-               }
-       }
-       /*
-        * Multiple files, just get each one without an nlst.
-        */
-       if (argc > 3) {
-               int i;
+       while ((cp = remglob(argc, argv)) != NULL)
+               if (confirm(argv[0], cp))
+                       recvrequest("RETR", cp, cp, "w");
+}
 
 
-               for (i = 1; i < argc - 1; i++)
-                       recvrequest("RETR",
-                         sprintf(dstpath, "%s/%s", dst, argv[i]), argv[i]);
-               return;
+char *
+remglob(argc, argv)
+       char *argv[];
+{
+       char temp[16], *cp;
+       static char buf[MAXPATHLEN];
+       static FILE *ftemp = NULL;
+       static char **args;
+       int oldverbose;
+
+       if (!doglob) {
+               if (argc == NULL)
+                       args = argv;
+               if ((cp = *++args) == NULL)
+                       args = NULL;
+               return (cp);
        }
        }
-       /*
-        * Get a directory full of files.  Perform an
-        * nlst to find the file names, then retrieve
-        * each individually.  If prompting is on, ask
-        * before grabbing each file.
-        */
-       strcpy(temp, "/tmp/ftpXXXXXX");
-       mktemp(temp);
-       oldverbose = verbose, verbose = 0;
-       recvrequest("NLST", temp, argv[1]);
-       verbose = oldverbose;
-       ftemp = fopen(temp, "r");
-       unlink(temp);
        if (ftemp == NULL) {
        if (ftemp == NULL) {
-               printf("can't find list of remote files, oops\n");
-               if (madedir)
-                       (void) rmdir(dst);
-               return;
+               strcpy(temp, "/tmp/ftpXXXXXX");
+               mktemp(temp);
+               oldverbose = verbose, verbose = 0;
+               recvrequest("NLST", temp, argv[1], "w");
+               verbose = oldverbose;
+               ftemp = fopen(temp, "r");
+               unlink(temp);
+               if (ftemp == NULL) {
+                       printf("can't find list of remote files, oops\n");
+                       return;
+               }
        }
        }
-       while (fgets(buf, sizeof (buf), ftemp) != NULL) {
-               char *cp = index(buf, '\n');
-
-               if (cp)
-                       *cp = '\0';
-               if (skip(argv[0], buf))
-                       continue;
-               recvrequest("RETR", sprintf(dstpath, "%s/%s", dst, buf), buf);
+       if (fgets(buf, sizeof (buf), ftemp) == NULL) {
+               fclose(ftemp), ftemp = NULL;
+               return (NULL);
        }
        }
-       fclose(ftemp);
+       if ((cp = index(buf, '\n')) != NULL)
+               *cp = '\0';
+       return (buf);
 }
 
 char *
 }
 
 char *
@@ -456,6 +412,8 @@ status(argc, argv)
        printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
                onoff(verbose), onoff(bell), onoff(interactive),
                onoff(doglob));
        printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
                onoff(verbose), onoff(bell), onoff(interactive),
                onoff(doglob));
+       printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
+               onoff(hash), onoff(sendport));
 }
 
 /*
 }
 
 /*
@@ -480,6 +438,20 @@ settrace()
        printf("Packet tracing %s.\n", onoff(trace));
 }
 
        printf("Packet tracing %s.\n", onoff(trace));
 }
 
+/*
+ * Toggle hash mark printing during transfers.
+ */
+/*VARARGS*/
+sethash()
+{
+
+       hash = !hash;
+       printf("Hash mark printing %s", onoff(hash));
+       if (hash)
+               printf(" (%d bytes/hash mark)", BUFSIZ);
+       printf(".\n");
+}
+
 /*
  * Turn on printing of server echo's.
  */
 /*
  * Turn on printing of server echo's.
  */
@@ -491,6 +463,17 @@ setverbose()
        printf("Verbose mode %s.\n", onoff(verbose));
 }
 
        printf("Verbose mode %s.\n", onoff(verbose));
 }
 
+/*
+ * Toggle PORT cmd use before each data connection.
+ */
+/*VARARGS*/
+setport()
+{
+
+       sendport = !sendport;
+       printf("Use of PORT cmds %s.\n", onoff(sendport));
+}
+
 /*
  * Turn on interactive prompting
  * during mget, mput, and mdelete.
 /*
  * Turn on interactive prompting
  * during mget, mput, and mdelete.
@@ -614,6 +597,30 @@ delete(argc, argv)
        (void) command("DELE %s", argv[1]);
 }
 
        (void) command("DELE %s", argv[1]);
 }
 
+/*
+ * Delete multiple files.
+ */
+mdelete(argc, argv)
+       char *argv[];
+{
+       char *cp;
+
+       if (argc < 2) {
+               strcat(line, " ");
+               printf("(remote-files) ");
+               gets(&line[strlen(line)]);
+               makeargv();
+               argc = margc;
+               argv = margv;
+       }
+       if (argc < 2) {
+               printf("%s remote-files\n", argv[0]);
+               return;
+       }
+       while ((cp = remglob(argc, argv)) != NULL)
+               if (confirm(argv[0], cp))
+                       (void) command("DELE %s", cp);
+}
 /*
  * Rename a remote file.
  */
 /*
  * Rename a remote file.
  */
@@ -655,20 +662,19 @@ usage:
 ls(argc, argv)
        char *argv[];
 {
 ls(argc, argv)
        char *argv[];
 {
-       char *cmd;
+       char *cmd, *mode;
+       int i;
 
        if (argc < 2)
                argc++, argv[1] = NULL;
        if (argc < 3)
                argc++, argv[2] = "-";
 
        if (argc < 2)
                argc++, argv[1] = NULL;
        if (argc < 3)
                argc++, argv[2] = "-";
-       if (argc > 3) {
-               printf("usage: %s remote-directory local-file\n", argv[0]);
-               return;
-       }
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
        if (strcmp(argv[2], "-") && !globulize(&argv[2]))
                return;
        cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
        if (strcmp(argv[2], "-") && !globulize(&argv[2]))
                return;
-       recvrequest(cmd, argv[2], argv[1]);
+       mode = argc > 3 ? "a" : "w";
+       for (i = 1; i < argc - 1; i++)
+               recvrequest(cmd, argv[argc - 1], argv[i], mode);
 }
 
 /*
 }
 
 /*
@@ -852,17 +858,17 @@ disconnect()
        data = -1;
 }
 
        data = -1;
 }
 
-skip(cmd, file)
+confirm(cmd, file)
        char *cmd, *file;
 {
        char line[BUFSIZ];
 
        if (!interactive)
        char *cmd, *file;
 {
        char line[BUFSIZ];
 
        if (!interactive)
-               return (0);
+               return (1);
        printf("%s %s? ", cmd, file);
        fflush(stdout);
        gets(line);
        printf("%s %s? ", cmd, file);
        fflush(stdout);
        gets(line);
-       return (*line == 'y');
+       return (*line != 'n' && *line != 'N');
 }
 
 fatal(msg)
 }
 
 fatal(msg)
index 311d7e2..df7119a 100644 (file)
@@ -1,21 +1,24 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)cmdtab.c   4.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)cmdtab.c   4.4 (Berkeley) %G%";
 #endif
 #endif
+
 #include "ftp_var.h"
 
 /*
  * User FTP -- Command Tables.
  */
 int    setascii(), setbell(), setbinary(), setdebug(), setform();
 #include "ftp_var.h"
 
 /*
  * User FTP -- Command Tables.
  */
 int    setascii(), setbell(), setbinary(), setdebug(), setform();
-int    setglob(), setmode(), setpeer(), setprompt(), setstruct();
+int    setglob(), sethash(), setmode(), setpeer(), setport ();
+int    setprompt(), setstruct();
 int    settenex(), settrace(), settype(), setverbose();
 int    disconnect();
 int    settenex(), settrace(), settype(), setverbose();
 int    disconnect();
-int    cd(), lcd(), delete(), user();
-int    ls(), get(), mget(), help(), put(), mput();
+int    cd(), lcd(), delete(), mdelete(), user();
+int    ls(), get(), mget(), help(), append(), put(), mput();
 int    quit(), renamefile(), status();
 int    quote(), rmthelp(), shell();
 int    pwd(), makedir(), removedir();
 
 int    quit(), renamefile(), status();
 int    quote(), rmthelp(), shell();
 int    pwd(), makedir(), removedir();
 
+char   appendhelp[] =  "append to a file";
 char   asciihelp[] =   "set ascii transfer type";
 char   beephelp[] =    "beep when command completed";
 char   binaryhelp[] =  "set binary transfer type";
 char   asciihelp[] =   "set ascii transfer type";
 char   beephelp[] =    "beep when command completed";
 char   binaryhelp[] =  "set binary transfer type";
@@ -27,13 +30,16 @@ char        dirhelp[] =     "list contents of remote directory";
 char   disconhelp[] =  "terminate ftp session";
 char   formhelp[] =    "set file transfer format";
 char   globhelp[] =    "toggle metacharacter expansion of local file names";
 char   disconhelp[] =  "terminate ftp session";
 char   formhelp[] =    "set file transfer format";
 char   globhelp[] =    "toggle metacharacter expansion of local file names";
+char   hashhelp[] =    "toggle printing `#' for each buffer transferred";
 char   helphelp[] =    "print local help information";
 char   lcdhelp[] =     "change local working directory";
 char   lshelp[] =      "nlist contents of remote directory";
 char   helphelp[] =    "print local help information";
 char   lcdhelp[] =     "change local working directory";
 char   lshelp[] =      "nlist contents of remote directory";
+char   mdeletehelp[] = "delete multiple files";
 char   mgethelp[] =    "get multiple files";
 char   mkdirhelp[] =   "make directory on the remote machine";
 char   modehelp[] =    "set file transfer mode";
 char   mputhelp[] =    "send multiple files";
 char   mgethelp[] =    "get multiple files";
 char   mkdirhelp[] =   "make directory on the remote machine";
 char   modehelp[] =    "set file transfer mode";
 char   mputhelp[] =    "send multiple files";
+char   porthelp[] =    "toggle use of PORT cmd for each data connection";
 char   prompthelp[] =  "force interactive prompting on multiple commands";
 char   pwdhelp[] =     "print working directory on remote machine";
 char   quithelp[] =    "terminate ftp session and exit";
 char   prompthelp[] =  "force interactive prompting on multiple commands";
 char   pwdhelp[] =     "print working directory on remote machine";
 char   quithelp[] =    "terminate ftp session and exit";
@@ -53,46 +59,50 @@ char        userhelp[] =    "send new user information";
 char   verbosehelp[] = "toggle verbose mode";
 
 struct cmd cmdtab[] = {
 char   verbosehelp[] = "toggle verbose mode";
 
 struct cmd cmdtab[] = {
-       { "!",          shellhelp,      0,      shell },
-       { "ascii",      asciihelp,      0,      setascii },
-       { "bell",       beephelp,       0,      setbell },
-       { "binary",     binaryhelp,     0,      setbinary },
-       { "bye",        quithelp,       0,      quit },
-       { "cd",         cdhelp,         0,      cd },
-       { "close",      disconhelp,     0,      disconnect },
-       { "delete",     deletehelp,     0,      delete },
-       { "debug",      debughelp,      0,      setdebug },
-       { "dir",        dirhelp,        1,      ls },
-       { "form",       formhelp,       0,      setform },
-       { "get",        receivehelp,    1,      get },
-       { "glob",       globhelp,       0,      setglob },
-       { "help",       helphelp,       0,      help },
-       { "lcd",        lcdhelp,        0,      lcd },
-       { "ls",         lshelp,         1,      ls },
-       { "mget",       mgethelp,       1,      mget },
-       { "mkdir",      mkdirhelp,      0,      makedir },
-       { "mode",       modehelp,       0,      setmode },
-       { "mput",       mputhelp,       1,      mput },
-       { "open",       connecthelp,    0,      setpeer },
-       { "prompt",     prompthelp,     0,      setprompt },
-       { "put",        sendhelp,       1,      put },
-       { "pwd",        pwdhelp,        0,      pwd },
-       { "quit",       quithelp,       0,      quit },
-       { "quote",      quotehelp,      1,      quote },
-       { "recv",       receivehelp,    1,      get },
-       { "remotehelp", remotehelp,     0,      rmthelp },
-       { "rename",     renamehelp,     0,      renamefile },
-       { "rmdir",      rmdirhelp,      0,      removedir },
-       { "send",       sendhelp,       1,      put },
-       { "status",     statushelp,     0,      status },
-       { "struct",     structhelp,     0,      setstruct },
-       { "tenex",      tenexhelp,      0,      settenex },
-       { "trace",      tracehelp,      0,      settrace },
-       { "type",       typehelp,       0,      settype },
-       { "user",       userhelp,       0,      user },
-       { "verbose",    verbosehelp,    0,      setverbose },
-       { "?",          helphelp,       0,      help },
-       0
+       { "!",          shellhelp,      0,      0,      shell },
+       { "append",     appendhelp,     1,      1,      append },
+       { "ascii",      asciihelp,      0,      1,      setascii },
+       { "bell",       beephelp,       0,      0,      setbell },
+       { "binary",     binaryhelp,     0,      1,      setbinary },
+       { "bye",        quithelp,       0,      0,      quit },
+       { "cd",         cdhelp,         0,      1,      cd },
+       { "close",      disconhelp,     0,      1,      disconnect },
+       { "delete",     deletehelp,     0,      1,      delete },
+       { "debug",      debughelp,      0,      0,      setdebug },
+       { "dir",        dirhelp,        1,      1,      ls },
+       { "form",       formhelp,       0,      1,      setform },
+       { "get",        receivehelp,    1,      1,      get },
+       { "glob",       globhelp,       0,      0,      setglob },
+       { "hash",       hashhelp,       0,      0,      sethash },
+       { "help",       helphelp,       0,      0,      help },
+       { "lcd",        lcdhelp,        0,      0,      lcd },
+       { "ls",         lshelp,         1,      1,      ls },
+       { "mdelete",    mdeletehelp,    1,      1,      mdelete },
+       { "mget",       mgethelp,       1,      1,      mget },
+       { "mkdir",      mkdirhelp,      0,      1,      makedir },
+       { "mode",       modehelp,       0,      1,      setmode },
+       { "mput",       mputhelp,       1,      1,      mput },
+       { "open",       connecthelp,    0,      0,      setpeer },
+       { "prompt",     prompthelp,     0,      0,      setprompt },
+       { "sendport",   porthelp,       0,      0,      setport },
+       { "put",        sendhelp,       1,      1,      put },
+       { "pwd",        pwdhelp,        0,      1,      pwd },
+       { "quit",       quithelp,       0,      0,      quit },
+       { "quote",      quotehelp,      1,      1,      quote },
+       { "recv",       receivehelp,    1,      1,      get },
+       { "remotehelp", remotehelp,     0,      1,      rmthelp },
+       { "rename",     renamehelp,     0,      1,      renamefile },
+       { "rmdir",      rmdirhelp,      0,      1,      removedir },
+       { "send",       sendhelp,       1,      1,      put },
+       { "status",     statushelp,     0,      0,      status },
+       { "struct",     structhelp,     0,      1,      setstruct },
+       { "tenex",      tenexhelp,      0,      1,      settenex },
+       { "trace",      tracehelp,      0,      0,      settrace },
+       { "type",       typehelp,       0,      1,      settype },
+       { "user",       userhelp,       0,      1,      user },
+       { "verbose",    verbosehelp,    0,      0,      setverbose },
+       { "?",          helphelp,       0,      0,      help },
+       { 0 },
 };
 
 int    NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
 };
 
 int    NCMDS = sizeof (cmdtab) / sizeof (cmdtab[0]);
index 413c34d..85c9d4e 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)ftp.c      4.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)ftp.c      4.7 (Berkeley) %G%";
 #endif
 
 #include <sys/param.h>
 #endif
 
 #include <sys/param.h>
@@ -190,7 +190,7 @@ getreply(expecteof)
 empty(f)
        FILE *f;
 {
 empty(f)
        FILE *f;
 {
-       int mask;
+       long mask;
        struct timeval t;
 
        if (f->_cnt > 0)
        struct timeval t;
 
        if (f->_cnt > 0)
@@ -215,7 +215,7 @@ sendrequest(cmd, local, remote)
        FILE *fin, *dout, *popen();
        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
        char buf[BUFSIZ];
        FILE *fin, *dout, *popen();
        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
        char buf[BUFSIZ];
-       register int bytes = 0;
+       long bytes = 0, hashbytes = sizeof (buf);
        register int c, d;
        struct stat st;
        struct timeval start, stop;
        register int c, d;
        struct stat st;
        struct timeval start, stop;
@@ -267,6 +267,14 @@ sendrequest(cmd, local, remote)
                        if ((d = write(fileno (dout), buf, c)) < 0)
                                break;
                        bytes += c;
                        if ((d = write(fileno (dout), buf, c)) < 0)
                                break;
                        bytes += c;
+                       if (hash) {
+                               putchar('#');
+                               fflush(stdout);
+                       }
+               }
+               if (hash) {
+                       putchar('\n');
+                       fflush(stdout);
                }
                if (c < 0)
                        perror(local);
                }
                if (c < 0)
                        perror(local);
@@ -277,6 +285,11 @@ sendrequest(cmd, local, remote)
        case TYPE_A:
                while ((c = getc(fin)) != EOF) {
                        if (c == '\n') {
        case TYPE_A:
                while ((c = getc(fin)) != EOF) {
                        if (c == '\n') {
+                               while (hash && (bytes >= hashbytes)) {
+                                       putchar('#');
+                                       fflush(stdout);
+                                       hashbytes += sizeof (buf);
+                               }
                                if (ferror(dout))
                                        break;
                                putc('\r', dout);
                                if (ferror(dout))
                                        break;
                                putc('\r', dout);
@@ -289,6 +302,10 @@ sendrequest(cmd, local, remote)
                                bytes++;
                        }
                }
                                bytes++;
                        }
                }
+               if (hash) {
+                       putchar('\n');
+                       fflush(stdout);
+               }
                if (ferror(fin))
                        perror(local);
                if (ferror(dout))
                if (ferror(fin))
                        perror(local);
                if (ferror(dout))
@@ -321,13 +338,13 @@ abortrecv()
        longjmp(recvabort, 1);
 }
 
        longjmp(recvabort, 1);
 }
 
-recvrequest(cmd, local, remote)
-       char *cmd, *local, *remote;
+recvrequest(cmd, local, remote, mode)
+       char *cmd, *local, *remote, *mode;
 {
        FILE *fout, *din, *popen();
 {
        FILE *fout, *din, *popen();
-       char buf[BUFSIZ];
        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
-       register int bytes = 0;
+       char buf[BUFSIZ];
+       long bytes = 0, hashbytes = sizeof (buf);
        register int c, d;
        struct timeval start, stop;
 
        register int c, d;
        struct timeval start, stop;
 
@@ -362,7 +379,7 @@ recvrequest(cmd, local, remote)
                fout = popen(local + 1, "w");
                closefunc = pclose;
        } else {
                fout = popen(local + 1, "w");
                closefunc = pclose;
        } else {
-               fout = fopen(local, "w");
+               fout = fopen(local, mode);
                closefunc = fclose;
        }
        if (fout == NULL) {
                closefunc = fclose;
        }
        if (fout == NULL) {
@@ -382,6 +399,14 @@ recvrequest(cmd, local, remote)
                        if ((d = write(fileno(fout), buf, c)) < 0)
                                break;
                        bytes += c;
                        if ((d = write(fileno(fout), buf, c)) < 0)
                                break;
                        bytes += c;
+                       if (hash) {
+                               putchar('#');
+                               fflush(stdout);
+                       }
+               }
+               if (hash) {
+                       putchar('\n');
+                       fflush(stdout);
                }
                if (c < 0)
                        perror("netin");
                }
                if (c < 0)
                        perror("netin");
@@ -392,6 +417,11 @@ recvrequest(cmd, local, remote)
        case TYPE_A:
                while ((c = getc(din)) != EOF) {
                        if (c == '\r') {
        case TYPE_A:
                while ((c = getc(din)) != EOF) {
                        if (c == '\r') {
+                               while (hash && (bytes >= hashbytes)) {
+                                       putchar('#');
+                                       fflush(stdout);
+                                       hashbytes += sizeof (buf);
+                               }
                                bytes++;
                                if ((c = getc(din)) != '\n') {
                                        if (ferror (fout))
                                bytes++;
                                if ((c = getc(din)) != '\n') {
                                        if (ferror (fout))
@@ -406,6 +436,10 @@ recvrequest(cmd, local, remote)
                        putc (c, fout);
                        bytes++;
                }
                        putc (c, fout);
                        bytes++;
                }
+               if (hash) {
+                       putchar('\n');
+                       fflush(stdout);
+               }
                if (ferror (din))
                        perror ("netin");
                if (ferror (fout))
                if (ferror (din))
                        perror ("netin");
                if (ferror (fout))
@@ -435,13 +469,19 @@ bad:
  * before we send the command, otherwise the
  * server's connect may fail.
  */
  * before we send the command, otherwise the
  * server's connect may fail.
  */
+static int sendport = -1;
+
 initconn()
 {
        register char *p, *a;
        int result, len;
 
 initconn()
 {
        register char *p, *a;
        int result, len;
 
+noport:
        data_addr = myctladdr;
        data_addr = myctladdr;
-       data_addr.sin_port = 0;         /* let system pick one */
+       if (sendport)
+               data_addr.sin_port = 0; /* let system pick one */ 
+       if (data != -1)
+               (void) close (data);
        data = socket(AF_INET, SOCK_STREAM, 0, 0);
        if (data < 0) {
                perror("ftp: socket");
        data = socket(AF_INET, SOCK_STREAM, 0, 0);
        if (data < 0) {
                perror("ftp: socket");
@@ -463,14 +503,21 @@ initconn()
                perror("ftp: listen");
                goto bad;
        }
                perror("ftp: listen");
                goto bad;
        }
-       a = (char *)&data_addr.sin_addr;
-       p = (char *)&data_addr.sin_port;
+       if (sendport) {
+               a = (char *)&data_addr.sin_addr;
+               p = (char *)&data_addr.sin_port;
 #define        UC(b)   (((int)b)&0xff)
 #define        UC(b)   (((int)b)&0xff)
-       result =
-           command("PORT %d,%d,%d,%d,%d,%d",
-             UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
-             UC(p[0]), UC(p[1]));
-       return (result != COMPLETE);
+               result =
+                   command("PORT %d,%d,%d,%d,%d,%d",
+                     UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
+                     UC(p[0]), UC(p[1]));
+               if (result == ERROR && sendport == -1) {
+                       sendport = 0;
+                       goto noport;
+               }
+               return (result != COMPLETE);
+       }
+       return (0);
 bad:
        (void) close(data), data = -1;
        return (1);
 bad:
        (void) close(data), data = -1;
        return (1);
@@ -496,19 +543,19 @@ dataconn(mode)
 
 ptransfer(direction, bytes, t0, t1)
        char *direction;
 
 ptransfer(direction, bytes, t0, t1)
        char *direction;
-       int bytes;
+       long bytes;
        struct timeval *t0, *t1;
 {
        struct timeval td;
        struct timeval *t0, *t1;
 {
        struct timeval td;
-       int ms, bs;
+       long ms;
+       float bs;
 
        tvsub(&td, t1, t0);
        ms = (td.tv_sec * 1000) + (td.tv_usec / 1000);
 #define        nz(x)   ((x) == 0 ? 1 : (x))
 
        tvsub(&td, t1, t0);
        ms = (td.tv_sec * 1000) + (td.tv_usec / 1000);
 #define        nz(x)   ((x) == 0 ? 1 : (x))
-       bs = ((bytes * NBBY * 1000) / nz(ms)) / NBBY;
-       printf("%d bytes %s in %d.%02d seconds (%d.%01d Kbytes/s)\n",
-               bytes, direction, td.tv_sec, td.tv_usec / 10000,
-               bs / 1024, (((bs % 1024) * 10) + 1023) / 1024);
+       bs = ((bytes * NBBY * 1000) / (float) nz(ms)) / NBBY;
+       printf("%ld bytes %s in %d.%02d seconds (%.2g Kbytes/s)\n",
+               bytes, direction, td.tv_sec, td.tv_usec / 10000, bs / 1024.);
 }
 
 tvadd(tsum, t0)
 }
 
 tvadd(tsum, t0)
index b0e2142..0397e27 100644 (file)
@@ -1,4 +1,4 @@
-/*     ftp_var.h       4.3     83/03/01        */
+/*     ftp_var.h       4.4     83/03/23        */
 
 /*
  * FTP global variables.
 
 /*
  * FTP global variables.
@@ -8,6 +8,8 @@
  * Options and other state info.
  */
 int    trace;                  /* trace packets exchanged */
  * Options and other state info.
  */
 int    trace;                  /* trace packets exchanged */
+int    hash;                   /* print # for each buffer transferred */
+int    sendport;               /* use PORT cmd for each data connection */
 int    verbose;                /* print messages coming back from server */
 int    connected;              /* connected to server */
 int    fromatty;               /* input is from a terminal */
 int    verbose;                /* print messages coming back from server */
 int    connected;              /* connected to server */
 int    fromatty;               /* input is from a terminal */
@@ -51,10 +53,12 @@ struct cmd {
        char    *c_name;        /* name of command */
        char    *c_help;        /* help string */
        char    c_bell;         /* give bell when command completes */
        char    *c_name;        /* name of command */
        char    *c_help;        /* help string */
        char    c_bell;         /* give bell when command completes */
+       char    c_conn;         /* must be connected to use command */
        int     (*c_handler)(); /* function to call */
 };
 
 extern char *tail();
 extern char *index();
 extern char *rindex();
        int     (*c_handler)(); /* function to call */
 };
 
 extern char *tail();
 extern char *index();
 extern char *rindex();
+extern char *remglob();
 extern int errno;
 extern int errno;
index d9d981b..69aaf9d 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)main.c     4.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)main.c     4.6 (Berkeley) %G%";
 #endif
 
 /*
 #endif
 
 /*
@@ -37,6 +37,7 @@ main(argc, argv)
                exit(1);
        }
        doglob = 1;
                exit(1);
        }
        doglob = 1;
+       interactive = 1;
        autologin = 1;
        argc--, argv++;
        while (argc > 0 && **argv == '-') {
        autologin = 1;
        argc--, argv++;
        while (argc > 0 && **argv == '-') {
@@ -57,7 +58,7 @@ main(argc, argv)
                                break;
 
                        case 'i':
                                break;
 
                        case 'i':
-                               interactive++;
+                               interactive = 0;
                                break;
 
                        case 'n':
                                break;
 
                        case 'n':
@@ -190,6 +191,10 @@ cmdscanner(top)
                        printf("?Invalid command\n");
                        continue;
                }
                        printf("?Invalid command\n");
                        continue;
                }
+               if (c->c_conn && !connected) {
+                       printf ("Not connected.\n");
+                       continue;
+               }
                (*c->c_handler)(margc, margv);
                if (bell && c->c_bell)
                        putchar(CTRL(g));
                (*c->c_handler)(margc, margv);
                if (bell && c->c_bell)
                        putchar(CTRL(g));
@@ -257,6 +262,10 @@ slurpstring()
        register char *ap = argbase;
        char *tmp = argbase;            /* will return this if token found */
 
        register char *ap = argbase;
        char *tmp = argbase;            /* will return this if token found */
 
+       if (*sb == '!') {               /* recognize ! as a token for shell */
+               stringbase++;
+               return ("!");
+       }
 S0:
        switch (*sb) {
 
 S0:
        switch (*sb) {