Sync with NetBSD. In addition to some bug fixes, this brings in -s srcaddr
authorPeter Avalos <pavalos@dragonflybsd.org>
Sat, 21 Apr 2007 20:18:21 +0000 (20:18 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sat, 21 Apr 2007 20:18:21 +0000 (20:18 +0000)
functionality -- using srcaddr as the local IP address for the connection.

13 files changed:
contrib/tnftp/cmds.c
contrib/tnftp/cmdtab.c
contrib/tnftp/complete.c
contrib/tnftp/extern.h
contrib/tnftp/fetch.c
contrib/tnftp/ftp.1
contrib/tnftp/ftp.c
contrib/tnftp/ftp_var.h
contrib/tnftp/main.c
contrib/tnftp/progressbar.c
contrib/tnftp/ruserpass.c
contrib/tnftp/util.c
contrib/tnftp/version.h

index 10bebee..554b17a 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: cmds.c,v 1.118 2006/01/31 20:05:35 christos Exp $      */
+/*     $NetBSD: cmds.c,v 1.121 2007/04/18 01:39:04 lukem Exp $ */
 
 /*-
- * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
 #if 0
 static char sccsid[] = "@(#)cmds.c     8.6 (Berkeley) 10/9/94";
 #else
-__RCSID("$NetBSD: cmds.c,v 1.118 2006/01/31 20:05:35 christos Exp $");
+__RCSID("$NetBSD: cmds.c,v 1.121 2007/04/18 01:39:04 lukem Exp $");
 #endif
 #endif /* not lint */
 
@@ -131,7 +131,7 @@ __RCSID("$NetBSD: cmds.c,v 1.118 2006/01/31 20:05:35 christos Exp $");
 #include "ftp_var.h"
 #include "version.h"
 
-struct types {
+static struct types {
        char    *t_name;
        char    *t_mode;
        int     t_type;
@@ -145,30 +145,43 @@ struct    types {
        { NULL }
 };
 
-sigjmp_buf      jabort;
-const char     *mname;
+static sigjmp_buf       jabort;
 
 static int     confirm(const char *, const char *);
+static void    mintr(int);
+static void    mabort(const char *);
 
 static const char *doprocess(char *, size_t, const char *, int, int, int);
 static const char *domap(char *, size_t, const char *);
 static const char *docase(char *, size_t, const char *);
 static const char *dotrans(char *, size_t, const char *);
 
+/*
+ * Confirm if "cmd" is to be performed upon "file".
+ * If "file" is NULL, generate a "Continue with" prompt instead.
+ */
 static int
 confirm(const char *cmd, const char *file)
 {
        const char *errormsg;
        char line[BUFSIZ];
+       const char *promptleft, *promptright;
 
        if (!interactive || confirmrest)
                return (1);
+       if (file == NULL) {
+               promptleft = "Continue with";
+               promptright = cmd;
+       } else {
+               promptleft = cmd;
+               promptright = file;
+       }
        while (1) {
-               fprintf(ttyout, "%s %s [anpqy?]? ", cmd, file);
+               fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright);
                (void)fflush(ttyout);
                if (getline(stdin, line, sizeof(line), &errormsg) < 0) {
                        mflag = 0;
-                       fprintf(ttyout, "%s; %s aborted\n", errormsg, mname);
+                       fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd);
                        return (0);
                }
                switch (tolower((unsigned char)*line)) {
@@ -183,7 +196,7 @@ confirm(const char *cmd, const char *file)
                                break;
                        case 'q':
                                mflag = 0;
-                               fprintf(ttyout, "%s aborted.\n", mname);
+                               fprintf(ttyout, "%s aborted.\n", cmd);
                                /* FALLTHROUGH */
                        case 'n':
                                return (0);
@@ -270,8 +283,7 @@ changetype(int newtype, int show)
                if (newtype == p->t_type)
                        break;
        if (p->t_name == 0) {
-               warnx("internal error: unknown type %d.", newtype);
-               return;
+               errx(1, "changetype: unknown type %d", newtype);
        }
        if (newtype == TYPE_L && bytename[0] != '\0')
                comret = command("TYPE %s %s", p->t_mode, bytename);
@@ -459,11 +471,10 @@ mput(int argc, char *argv[])
                code = -1;
                return;
        }
-       mname = argv[0];
        mflag = 1;
        oldintr = xsignal(SIGINT, mintr);
        if (sigsetjmp(jabort, 1))
-               mabort();
+               mabort(argv[0]);
        if (proxy) {
                char *cp;
 
@@ -481,7 +492,7 @@ mput(int argc, char *argv[])
                                if (!mflag && fromatty) {
                                        ointer = interactive;
                                        interactive = 1;
-                                       if (confirm("Continue with", "mput")) {
+                                       if (confirm(argv[0], NULL)) {
                                                mflag++;
                                        }
                                        interactive = ointer;
@@ -505,7 +516,7 @@ mput(int argc, char *argv[])
                                if (!mflag && fromatty) {
                                        ointer = interactive;
                                        interactive = 1;
-                                       if (confirm("Continue with", "mput")) {
+                                       if (confirm(argv[0], NULL)) {
                                                mflag++;
                                        }
                                        interactive = ointer;
@@ -517,7 +528,7 @@ mput(int argc, char *argv[])
                memset(&gl, 0, sizeof(gl));
                flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
                if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
-                       warnx("%s: not found", argv[i]);
+                       warnx("Glob pattern `%s' not found", argv[i]);
                        globfree(&gl);
                        continue;
                }
@@ -533,7 +544,7 @@ mput(int argc, char *argv[])
                                if (!mflag && fromatty) {
                                        ointer = interactive;
                                        interactive = 1;
-                                       if (confirm("Continue with", "mput")) {
+                                       if (confirm(argv[0], NULL)) {
                                                mflag++;
                                        }
                                        interactive = ointer;
@@ -607,7 +618,7 @@ getit(int argc, char *argv[], int restartit, const char *mode)
                ret = stat(locfile, &stbuf);
                if (restartit == 1) {
                        if (ret < 0) {
-                               warn("local: %s", locfile);
+                               warn("Can't stat `%s'", locfile);
                                goto freegetit;
                        }
                        restart_point = stbuf.st_size;
@@ -635,7 +646,7 @@ getit(int argc, char *argv[], int restartit, const char *mode)
 }
 
 /* ARGSUSED */
-void
+static void
 mintr(int signo)
 {
 
@@ -645,8 +656,8 @@ mintr(int signo)
        siglongjmp(jabort, 1);
 }
 
-void
-mabort(void)
+static void
+mabort(const char *cmd)
 {
        int ointer, oconf;
 
@@ -655,7 +666,7 @@ mabort(void)
                oconf = confirmrest;
                interactive = 1;
                confirmrest = 0;
-               if (confirm("Continue with", mname)) {
+               if (confirm(cmd, NULL)) {
                        interactive = ointer;
                        confirmrest = oconf;
                        return;
@@ -684,7 +695,6 @@ mget(int argc, char *argv[])
                code = -1;
                return;
        }
-       mname = argv[0];
        mflag = 1;
        restart_point = 0;
        restartit = 0;
@@ -698,7 +708,7 @@ mget(int argc, char *argv[])
        }
        oldintr = xsignal(SIGINT, mintr);
        if (sigsetjmp(jabort, 1))
-               mabort();
+               mabort(argv[0]);
        while ((cp = remglob(argv, proxy, NULL)) != NULL) {
                char buf[MAXPATHLEN];
                if (*cp == '\0' || !connected) {
@@ -721,7 +731,7 @@ mget(int argc, char *argv[])
                        if (stat(tp, &stbuf) == 0)
                                restart_point = stbuf.st_size;
                        else
-                               warn("stat %s", tp);
+                               warn("Can't stat `%s'", tp);
                }
                recvrequest("RETR", tp, cp, restart_point ? "r+" : "w",
                    tp != cp || !interactive, 1);
@@ -729,7 +739,7 @@ mget(int argc, char *argv[])
                if (!mflag && fromatty) {
                        ointer = interactive;
                        interactive = 1;
-                       if (confirm("Continue with", "mget"))
+                       if (confirm(argv[0], NULL))
                                mflag++;
                        interactive = ointer;
                }
@@ -755,7 +765,7 @@ fget(int argc, char *argv[])
 
        fp = fopen(argv[1], "r");
        if (fp == NULL) {
-               fprintf(ttyout, "Cannot open source file %s\n", argv[1]);
+               fprintf(ttyout, "Can't open source file %s\n", argv[1]);
                code = -1;
                return;
        }
@@ -1171,7 +1181,7 @@ lcd(int argc, char *argv[])
        if ((locdir = globulize(argv[1])) == NULL)
                return;
        if (chdir(locdir) == -1)
-               warn("lcd %s", locdir);
+               warn("Can't chdir `%s'", locdir);
        else {
                updatelocalcwd();
                if (localcwd[0]) {
@@ -1217,11 +1227,10 @@ mdelete(int argc, char *argv[])
                code = -1;
                return;
        }
-       mname = argv[0];
        mflag = 1;
        oldintr = xsignal(SIGINT, mintr);
        if (sigsetjmp(jabort, 1))
-               mabort();
+               mabort(argv[0]);
        while ((cp = remglob(argv, 0, NULL)) != NULL) {
                if (*cp == '\0') {
                        mflag = 0;
@@ -1233,7 +1242,7 @@ mdelete(int argc, char *argv[])
                        if (!mflag && fromatty) {
                                ointer = interactive;
                                interactive = 1;
-                               if (confirm("Continue with", "mdelete")) {
+                               if (confirm(argv[0], NULL)) {
                                        mflag++;
                                }
                                interactive = ointer;
@@ -1337,7 +1346,6 @@ ls(int argc, char *argv[])
                (void)strlcpy(locfile + 1, p, len - 1);
                freelocfile = 1;
        } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
-               mname = argv[0];
                if ((locfile = globulize(locfile)) == NULL ||
                    !confirm("output to local-file:", locfile)) {
                        code = -1;
@@ -1374,7 +1382,6 @@ mls(int argc, char *argv[])
        }
        odest = dest = argv[argc - 1];
        argv[argc - 1] = NULL;
-       mname = argv[0];
        if (strcmp(dest, "-") && *dest != '|')
                if (((dest = globulize(dest)) == NULL) ||
                    !confirm("output to local-file:", dest)) {
@@ -1385,7 +1392,7 @@ mls(int argc, char *argv[])
        mflag = 1;
        oldintr = xsignal(SIGINT, mintr);
        if (sigsetjmp(jabort, 1))
-               mabort();
+               mabort(argv[0]);
        for (i = 1; mflag && i < argc-1 && connected; i++) {
                mode = (i == 1) ? "w" : "a";
                recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
@@ -1393,7 +1400,7 @@ mls(int argc, char *argv[])
                if (!mflag && fromatty) {
                        ointer = interactive;
                        interactive = 1;
-                       if (confirm("Continue with", argv[0])) {
+                       if (confirm(argv[0], NULL)) {
                                mflag++;
                        }
                        interactive = ointer;
@@ -1446,7 +1453,7 @@ shell(int argc, char *argv[])
                else {
                        execl(shell, shellnam, (char *)0);
                }
-               warn("%s", shell);
+               warn("Can't execute `%s'", shell);
                code = -1;
                exit(1);
        }
@@ -1455,7 +1462,7 @@ shell(int argc, char *argv[])
                        ;
        (void)xsignal(SIGINT, oldintr);
        if (pid == -1) {
-               warn("Try again later");
+               warn("Can't fork a subshell; try again later");
                code = -1;
        } else
                code = 0;
@@ -1468,6 +1475,7 @@ void
 user(int argc, char *argv[])
 {
        char *password;
+       char emptypass[] = "";
        int n, aflag = 0;
 
        if (argc == 0)
@@ -1485,6 +1493,8 @@ user(int argc, char *argv[])
        if (n == CONTINUE) {
                if (argc < 3) {
                        password = getpass("Password: ");
+                       if (password == NULL)
+                               password = emptypass;
                } else {
                        password = argv[2];
                }
@@ -1495,6 +1505,8 @@ user(int argc, char *argv[])
                aflag++;
                if (argc < 4) {
                        password = getpass("Account: ");
+                       if (password == NULL)
+                               password = emptypass;
                } else {
                        password = argv[3];
                }
@@ -1782,6 +1794,7 @@ void
 account(int argc, char *argv[])
 {
        char *ap;
+       char emptypass[] = "";
 
        if (argc == 0 || argc > 2) {
                UPRINTF("usage: %s [password]\n", argv[0]);
@@ -1790,9 +1803,13 @@ account(int argc, char *argv[])
        }
        else if (argc == 2)
                ap = argv[1];
-       else
+       else {
                ap = getpass("Account:");
+               if (ap == NULL)
+                       ap = emptypass;
+       }
        (void)command("ACCT %s", ap);
+       memset(ap, 0, strlen(ap));
 }
 
 sigjmp_buf abortprox;
index 6ebe22e..8f80e1c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: cmdtab.c,v 1.46 2006/01/31 20:05:36 christos Exp $     */
+/*     $NetBSD: cmdtab.c,v 1.47 2007/04/11 04:40:19 lukem Exp $        */
 
 /*-
  * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
 #if 0
 static char sccsid[] = "@(#)cmdtab.c   8.4 (Berkeley) 10/9/94";
 #else
-__RCSID("$NetBSD: cmdtab.c,v 1.46 2006/01/31 20:05:36 christos Exp $");
+__RCSID("$NetBSD: cmdtab.c,v 1.47 2007/04/11 04:40:19 lukem Exp $");
 #endif
 #endif /* not lint */
 
@@ -206,7 +206,7 @@ struct cmd cmdtab[] = {
        { "chmod",      H(chmodhelp),   0, 1, 1, CMPL(nr)       do_chmod },
        { "close",      H(disconhelp),  0, 1, 1, CMPL0          disconnect },
        { "cr",         H(crhelp),      0, 0, 0, CMPL0          setcr },
-       { "ftp_debug",  H(debughelp),   0, 0, 0, CMPL0          setdebug },
+       { "debug",      H(debughelp),   0, 0, 0, CMPL0          setdebug },
        { "delete",     H(deletehelp),  0, 1, 1, CMPL(r)        delete },
        { "dir",        H(lshelp),      1, 1, 1, CMPL(rl)       ls },
        { "disconnect", H(disconhelp),  0, 1, 1, CMPL0          disconnect },
index 0f593b3..dae7919 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: complete.c,v 1.41 2006/01/31 20:01:23 christos Exp $   */
+/*     $NetBSD: complete.c,v 1.42 2007/04/17 05:52:03 lukem Exp $      */
 
 /*-
  * Copyright (c) 1997-2000,2005 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: complete.c,v 1.41 2006/01/31 20:01:23 christos Exp $");
+__RCSID("$NetBSD: complete.c,v 1.42 2007/04/17 05:52:03 lukem Exp $");
 #endif /* not lint */
 
 /*
@@ -426,7 +426,8 @@ complete(EditLine *el, int ch)
                        }
                        return (complete_remote(word, dolist));
                default:
-                       errx(1, "unknown complete type `%c'", cmpltype);
+                       errx(1, "complete: unknown complete type `%c'",
+                           cmpltype);
                        return (CC_ERROR);
        }
        /* NOTREACHED */
index 206fc29..628384c 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: extern.h,v 1.70 2006/01/31 20:01:23 christos Exp $     */
+/*     $NetBSD: extern.h,v 1.71 2007/04/18 01:39:04 lukem Exp $        */
 
 /*-
- * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -160,13 +160,11 @@ void      lostpeer(int);
 void   lpage(int, char **);
 void   lpwd(int, char **);
 void   ls(int, char **);
-void   mabort(void);
 void   macdef(int, char **);
 void   makeargv(void);
 void   makedir(int, char **);
 void   mdelete(int, char **);
 void   mget(int, char **);
-void   mintr(int);
 void   mls(int, char **);
 void   mlst(int, char **);
 void   modtime(int, char **);
index 922752f..0b66024 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: fetch.c,v 1.171 2006/09/22 22:29:25 elad Exp $ */
+/*     $NetBSD: fetch.c,v 1.175 2007/04/17 05:52:03 lukem Exp $        */
 
 /*-
- * Copyright (c) 1997-2006 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -41,7 +41,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: fetch.c,v 1.171 2006/09/22 22:29:25 elad Exp $");
+__RCSID("$NetBSD: fetch.c,v 1.175 2007/04/17 05:52:03 lukem Exp $");
 #endif /* not lint */
 
 /*
@@ -112,7 +112,7 @@ static int  redirect_loop;
  * Determine if token is the next word in buf (case insensitive).
  * If so, advance buf past the token and any trailing LWS, and
  * return a pointer to the token (in buf).  Otherwise, return NULL.
- * token may be preceeded by LWS.
+ * token may be preceded by LWS.
  * token must be followed by LWS or NUL.  (I.e, don't partial match).
  */
 static const char *
@@ -161,7 +161,7 @@ auth_url(const char *challenge, char **response, const char *guser,
        DPRINTF("auth_url: challenge `%s'\n", challenge);
 
        if (! match_token(&cp, scheme)) {
-               warnx("Unsupported authentication challenge `%s'",
+               warnx("Unsupported authentication challenge `%s'",
                    challenge);
                goto cleanup_auth_url;
        }
@@ -170,7 +170,7 @@ auth_url(const char *challenge, char **response, const char *guser,
        if (STRNEQUAL(cp, REALM))
                cp += sizeof(REALM) - 1;
        else {
-               warnx("Unsupported authentication challenge `%s'",
+               warnx("Unsupported authentication challenge `%s'",
                    challenge);
                goto cleanup_auth_url;
        }
@@ -181,7 +181,7 @@ auth_url(const char *challenge, char **response, const char *guser,
                realm = (char *)ftp_malloc(len + 1);
                (void)strlcpy(realm, cp, len + 1);
        } else {
-               warnx("Unsupported authentication challenge `%s'",
+               warnx("Unsupported authentication challenge `%s'",
                    challenge);
                goto cleanup_auth_url;
        }
@@ -199,8 +199,13 @@ auth_url(const char *challenge, char **response, const char *guser,
        }
        if (gpass != NULL)
                pass = (char *)gpass;
-       else
+       else {
                pass = getpass("Password: ");
+               if (pass == NULL) {
+                       warnx("Can't read password");
+                       goto cleanup_auth_url;
+               }
+       }
 
        clen = strlen(user) + strlen(pass) + 2; /* user + ":" + pass + "\0" */
        clear = (char *)ftp_malloc(clen);
@@ -467,21 +472,31 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
        struct addrinfo         hints, *res, *res0 = NULL;
        int                     error;
        char                    hbuf[NI_MAXHOST];
-       volatile sigfunc        oldintr, oldintp;
-       volatile int            s;
+       sigfunc volatile        oldintr;
+       sigfunc volatile        oldintp;
+       int volatile            s;
        struct stat             sb;
-       int                     ischunked, isproxy, rval, hcode;
+       int volatile            ischunked;
+       int volatile            isproxy;
+       int volatile            rval;
+       int volatile            hcode;
        size_t                  len;
        static size_t           bufsize;
        static char             *xferbuf;
        const char              *cp, *token;
-       char                    *ep, *buf, *savefile;
-       char                    *auth, *location, *message;
-       char                    *user, *pass, *host, *port, *path, *decodedpath;
+       char                    *ep;
+       char                    *volatile buf;
+       char                    *volatile savefile;
+       char                    *volatile auth;
+       char                    *volatile location;
+       char                    *volatile message;
+       char                    *user, *pass, *host, *port, *path;
+       char                    *volatile decodedpath;
        char                    *puser, *ppass, *useragent;
        off_t                   hashbytes, rangestart, rangeend, entitylen;
-       int                      (*closefunc)(FILE *);
-       FILE                    *fin, *fout;
+       int                     (*volatile closefunc)(FILE *);
+       FILE                    *volatile fin;
+       FILE                    *volatile fout;
        time_t                  mtime;
        url_t                   urltype;
        in_port_t               portnum;
@@ -496,22 +511,6 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
        rval = 1;
        user = pass = host = path = decodedpath = puser = ppass = NULL;
 
-#ifdef __GNUC__                        /* shut up gcc warnings */
-       (void)&closefunc;
-       (void)&fin;
-       (void)&fout;
-       (void)&buf;
-       (void)&savefile;
-       (void)&rval;
-       (void)&isproxy;
-       (void)&hcode;
-       (void)&ischunked;
-       (void)&message;
-       (void)&location;
-       (void)&auth;
-       (void)&decodedpath;
-#endif
-
        if (parse_url(url, "URL", &urltype, &user, &pass, &host, &port,
            &portnum, &path) == -1)
                goto cleanup_fetch_url;
@@ -550,7 +549,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                        rval = fetch_ftp(url);
                        goto cleanup_fetch_url;
                }
-               warnx("no file after directory (you must specify an "
+               warnx("No file after directory (you must specify an "
                    "output file) `%s'", url);
                goto cleanup_fetch_url;
        } else {
@@ -570,7 +569,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                direction = "copied";
                fin = fopen(decodedpath, "r");
                if (fin == NULL) {
-                       warn("Cannot open file `%s'", decodedpath);
+                       warn("Can't open `%s'", decodedpath);
                        goto cleanup_fetch_url;
                }
                if (fstat(fileno(fin), &sb) == 0) {
@@ -579,7 +578,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                }
                if (restart_point) {
                        if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
-                               warn("Can't lseek to restart `%s'",
+                               warn("Can't seek to restart `%s'",
                                    decodedpath);
                                goto cleanup_fetch_url;
                        }
@@ -692,7 +691,9 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                hints.ai_protocol = 0;
                error = getaddrinfo(host, NULL, &hints, &res0);
                if (error) {
-                       warnx("%s: %s", host, gai_strerror(error));
+                       warnx("Can't lookup `%s': %s", host,
+                           (error == EAI_SYSTEM) ? strerror(errno)
+                                                 : gai_strerror(error));
                        goto cleanup_fetch_url;
                }
                if (res0->ai_canonname)
@@ -700,13 +701,10 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
 
                s = -1;
                for (res = res0; res; res = res->ai_next) {
-                       /*
-                        * see comment in hookup()
-                        */
                        ai_unmapped(res);
                        if (getnameinfo(res->ai_addr, res->ai_addrlen,
                            hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
-                               strlcpy(hbuf, "invalid", sizeof(hbuf));
+                               strlcpy(hbuf, "?", sizeof(hbuf));
 
                        if (verbose && res0->ai_next) {
                                fprintf(ttyout, "Trying %s...\n", hbuf);
@@ -717,12 +715,13 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                        s = socket(res->ai_family, SOCK_STREAM,
                            res->ai_protocol);
                        if (s < 0) {
-                               warn("Can't create socket");
+                               warn(
+                                 "Can't create socket for connection to `%s'",
+                                   hbuf);
                                continue;
                        }
 
                        if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
-                               warn("Connect to address `%s'", hbuf);
                                close(s);
                                s = -1;
                                continue;
@@ -733,7 +732,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                }
 
                if (s < 0) {
-                       warn("Can't connect to %s", host);
+                       warnx("Can't connect to `%s'", host);
                        goto cleanup_fetch_url;
                }
 
@@ -952,12 +951,12 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                        } else if (match_token(&cp, "Transfer-Encoding:")) {
                                if (match_token(&cp, "binary")) {
                                        warnx(
-                       "Bogus transfer encoding `binary' (fetching anyway)");
+                       "Bogus transfer encoding `binary' (fetching anyway)");
                                        continue;
                                }
                                if (! (token = match_token(&cp, "chunked"))) {
                                        warnx(
-                                   "Unsupported transfer encoding `%s'",
+                                   "Unsupported transfer encoding `%s'",
                                            token);
                                        goto cleanup_fetch_url;
                                }
@@ -1067,7 +1066,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
 #endif
                default:
                        if (message)
-                               warnx("Error retrieving file `%s'", message);
+                               warnx("Error retrieving file `%s'", message);
                        else
                                warnx("Unknown error retrieving file");
                        goto cleanup_fetch_url;
@@ -1081,7 +1080,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
                oldintp = xsignal(SIGPIPE, SIG_IGN);
                fout = popen(savefile + 1, "w");
                if (fout == NULL) {
-                       warn("Can't run `%s'", savefile + 1);
+                       warn("Can't execute `%s'", savefile + 1);
                        goto cleanup_fetch_url;
                }
                closefunc = pclose;
index f1cffbe..ea2a50d 100644 (file)
@@ -1,6 +1,6 @@
-.\"    $NetBSD: ftp.1,v 1.114 2006/10/27 01:29:17 lukem Exp $
+.\"    $NetBSD: ftp.1,v 1.115 2007/04/17 05:52:03 lukem Exp $
 .\"
-.\" Copyright (c) 1996-2006 The NetBSD Foundation, Inc.
+.\" Copyright (c) 1996-2007 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\"
 .\" This code is derived from software contributed to The NetBSD Foundation
@@ -64,7 +64,7 @@
 .\"
 .\"    @(#)ftp.1       8.3 (Berkeley) 10/9/94
 .\"
-.Dd October 27, 2006
+.Dd April 16, 2007
 .Dt FTP 1
 .Os
 .Sh NAME
@@ -86,6 +86,7 @@ Internet file transfer program
 .Bk -words
 .Op Fl q Ar quittime
 .Ek
+.Op Fl s Ar srcaddr
 .Bk -words
 .Op Fl r Ar retry
 .Ek
@@ -179,7 +180,7 @@ below for more information.
 .Pp
 Options may be specified at the command line, or to the
 command interpreter.
-.Bl -tag -width "port   "
+.Bl -tag -width Fl
 .It Fl 4
 Forces
 .Nm
@@ -272,16 +273,20 @@ if the server does not support passive connections.
 .It Fl P Ar port
 Sets the port number to
 .Ar port .
-.It Fl r Ar wait
-Retry the connection attempt if it failed, pausing for
-.Ar wait
-seconds.
 .It Fl q Ar quittime
 Quit if the connection has stalled for
 .Ar quittime
 seconds.
+.It Fl r Ar wait
+Retry the connection attempt if it failed, pausing for
+.Ar wait
+seconds.
 .It Fl R
 Restart all non-proxied auto-fetches.
+.It Fl s Ar srcaddr
+Uses
+.Ar srcaddr
+as the local IP address for all connections.
 .It Fl t
 Enables packet tracing.
 .It Xo
@@ -352,7 +357,7 @@ is provided to the user.
 The following commands are recognized
 by
 .Nm ftp  :
-.Bl -tag -width Fl
+.Bl -tag -width Ic
 .It Ic \&! Op Ar command Op Ar args
 Invoke an interactive shell on the local machine.
 If there are arguments, the first is taken to be a command to execute
index 5a77d3b..b6cc64f 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: ftp.c,v 1.142 2006/10/23 19:53:24 christos Exp $       */
+/*     $NetBSD: ftp.c,v 1.148 2007/04/18 01:50:45 lukem Exp $  */
 
 /*-
- * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -99,7 +99,7 @@
 #if 0
 static char sccsid[] = "@(#)ftp.c      8.6 (Berkeley) 10/27/94";
 #else
-__RCSID("$NetBSD: ftp.c,v 1.142 2006/10/23 19:53:24 christos Exp $");
+__RCSID("$NetBSD: ftp.c,v 1.148 2007/04/18 01:50:45 lukem Exp $");
 #endif
 #endif /* not lint */
 
@@ -168,7 +168,6 @@ hookup(char *host, char *port)
        struct addrinfo hints, *res, *res0;
        char hbuf[MAXHOSTNAMELEN];
        static char hostnamebuf[MAXHOSTNAMELEN];
-       char *cause = "unknown";
        socklen_t len;
        int on = 1;
 
@@ -182,7 +181,9 @@ hookup(char *host, char *port)
        hints.ai_protocol = 0;
        error = getaddrinfo(host, NULL, &hints, &res0);
        if (error) {
-               warnx("%s: %s", host, gai_strerror(error));
+               warnx("Can't lookup `%s': %s", host,
+                   (error == EAI_SYSTEM) ? strerror(errno)
+                                         : gai_strerror(error));
                code = -1;
                return (0);
        }
@@ -195,49 +196,22 @@ hookup(char *host, char *port)
        hostname = hostnamebuf;
 
        for (res = res0; res; res = res->ai_next) {
-               /*
-                * make sure that ai_addr is NOT an IPv4 mapped address.
-                * IPv4 mapped address complicates too many things in FTP
-                * protocol handling, as FTP protocol is defined differently
-                * between IPv4 and IPv6.
-                *
-                * This may not be the best way to handle this situation,
-                * since the semantics of IPv4 mapped address is defined in
-                * the kernel.  There are configurations where we should use
-                * IPv4 mapped address as native IPv6 address, not as
-                * "an IPv6 address that embeds IPv4 address" (namely, SIIT).
-                *
-                * More complete solution would be to have an additional
-                * getsockopt to grab "real" peername/sockname.  "real"
-                * peername/sockname will be AF_INET if IPv4 mapped address
-                * is used to embed IPv4 address, and will be AF_INET6 if
-                * we use it as native.  What a mess!
-                */
                ai_unmapped(res);
+               if (getnameinfo(res->ai_addr, res->ai_addrlen,
+                   hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
+                       strlcpy(hbuf, "?", sizeof(hbuf));
                if (verbose && res0->ai_next) {
                                /* if we have multiple possibilities */
-                       if (getnameinfo(res->ai_addr, res->ai_addrlen,
-                           hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
-                               strlcpy(hbuf, "?", sizeof(hbuf));
                        fprintf(ttyout, "Trying %s...\n", hbuf);
                }
                ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(portnum);
                s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
                if (s < 0) {
-                       cause = "socket";
+                       warn("Can't create socket for connection to `%s'",
+                           hbuf);
                        continue;
                }
-               error = ftp_connect(s, res->ai_addr, res->ai_addrlen);
-               if (error) {
-                       /* this "if" clause is to prevent print warning twice */
-                       if (res->ai_next) {
-                               if (getnameinfo(res->ai_addr, res->ai_addrlen,
-                                   hbuf, sizeof(hbuf), NULL, 0,
-                                   NI_NUMERICHOST))
-                                       strlcpy(hbuf, "?", sizeof(hbuf));
-                               warn("connect to address %s", hbuf);
-                       }
-                       cause = "connect";
+               if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
                        close(s);
                        s = -1;
                        continue;
@@ -247,7 +221,7 @@ hookup(char *host, char *port)
                break;
        }
        if (s < 0) {
-               warn("%s", cause);
+               warnx("Can't connect to `%s'", host);
                code = -1;
                freeaddrinfo(res0);
                return 0;
@@ -259,7 +233,7 @@ hookup(char *host, char *port)
 
        len = hisctladdr.su_len;
        if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) {
-               warn("getsockname");
+               warn("Can't determine my address of connection to `%s'", host);
                code = -1;
                goto bad;
        }
@@ -278,7 +252,7 @@ hookup(char *host, char *port)
        cin = fdopen(s, "r");
        cout = fdopen(s, "w");
        if (cin == NULL || cout == NULL) {
-               warnx("fdopen failed.");
+               warnx("Can't fdopen socket");
                if (cin)
                        (void)fclose(cin);
                if (cout)
@@ -360,7 +334,7 @@ command(const char *fmt, ...)
        }
 #endif
        if (cout == NULL) {
-               warnx("No control connection for command.");
+               warnx("No control connection for command");
                code = -1;
                return (0);
        }
@@ -455,7 +429,7 @@ getreply(int expecteof)
                                                midx = 1;
                                        else
                                                midx = 2;
-                                       (void)fprintf(ttyout,
+                                       (void)fprintf(ttyout,
                            "421 Service not available, %s.\n", m421[midx]);
                                        (void)fflush(ttyout);
                                }
@@ -505,7 +479,7 @@ getreply(int expecteof)
                if (verbose > 0 || ((verbose > -1 && n == '5') &&
                    (n < '5' || !retry_connect))) {
                        (void)putc(c, ttyout);
-                       (void)fflush (ttyout);
+                       (void)fflush(ttyout);
                }
                if (cp[-1] == '\r')
                        cp[-1] = '\0';
@@ -585,8 +559,7 @@ abortxfer(int notused)
                strlcpy(msgbuf, "\nsend", sizeof(msgbuf));
                break;
        default:
-               errx(1, "abortxfer called with unknown direction `%s'",
-                   direction);
+               errx(1, "abortxfer: unknown direction `%s'", direction);
        }
        len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n",
            sizeof(msgbuf));
@@ -600,25 +573,18 @@ sendrequest(const char *cmd, const char *local, const char *remote,
 {
        struct stat st;
        int c, d;
-       FILE *fin, *dout;
-       int (*closefunc)(FILE *);
-       sigfunc oldintr, oldintp;
-       volatile off_t hashbytes;
-       char *lmode, *bufp;
+       FILE *volatile fin;
+       FILE *volatile dout;
+       int (*volatile closefunc)(FILE *);
+       sigfunc volatile oldintr;
+       sigfunc volatile oldintp;
+       off_t volatile hashbytes;
+       char *volatile lmode;
+       char *bufp;
        static size_t bufsize;
        static char *buf;
        int oprogress;
 
-#ifdef __GNUC__                        /* to shut up gcc warnings */
-       (void)&fin;
-       (void)&dout;
-       (void)&closefunc;
-       (void)&oldintr;
-       (void)&oldintp;
-       (void)&lmode;
-       fin = NULL;     /* XXX gcc4 */
-#endif
-
        hashbytes = mark;
        direction = "sent";
        dout = NULL;
@@ -656,7 +622,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
                oldintp = xsignal(SIGPIPE, SIG_IGN);
                fin = popen(local + 1, "r");
                if (fin == NULL) {
-                       warn("%s", local + 1);
+                       warn("Can't execute `%s'", local + 1);
                        code = -1;
                        goto cleanupsend;
                }
@@ -665,7 +631,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
        } else {
                fin = fopen(local, "r");
                if (fin == NULL) {
-                       warn("local: %s", local);
+                       warn("Can't open `%s'", local);
                        code = -1;
                        goto cleanupsend;
                }
@@ -699,7 +665,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
                        break;
                }
                if (rc < 0) {
-                       warn("local: %s", local);
+                       warn("Can't seek to restart `%s'", local);
                        goto cleanupsend;
                }
                if (command("REST " LLF, (LLT)restart_point) != CONTINUE)
@@ -798,10 +764,10 @@ sendrequest(const char *cmd, const char *local, const char *remote,
                        (void)putc('\n', ttyout);
                }
                if (c < 0)
-                       warn("local: %s", local);
+                       warn("Reading `%s'", local);
                if (d < 0) {
                        if (errno != EPIPE)
-                               warn("netout");
+                               warn("Writing to network");
                        bytes = -1;
                }
                break;
@@ -835,10 +801,10 @@ sendrequest(const char *cmd, const char *local, const char *remote,
                        (void)putc('\n', ttyout);
                }
                if (ferror(fin))
-                       warn("local: %s", local);
+                       warn("Reading `%s'", local);
                if (ferror(dout)) {
                        if (errno != EPIPE)
-                               warn("netout");
+                               warn("Writing to network");
                        bytes = -1;
                }
                break;
@@ -895,32 +861,27 @@ sendrequest(const char *cmd, const char *local, const char *remote,
 }
 
 void
-recvrequest(const char *cmd, const char *local, const char *remote,
+recvrequest(const char *cmd, const char *volatile local, const char *remote,
            const char *lmode, int printnames, int ignorespecial)
 {
-       FILE *fout, *din;
-       int (*closefunc)(FILE *);
-       sigfunc oldintr, oldintp;
+       FILE *volatile fout;
+       FILE *volatile din;
+       int (*volatile closefunc)(FILE *);
+       sigfunc volatile oldintr;
+       sigfunc volatile oldintp;
        int c, d;
-       volatile int is_retr, tcrflag, bare_lfs;
+       int volatile is_retr;
+       int volatile tcrflag;
+       int volatile bare_lfs;
        static size_t bufsize;
        static char *buf;
-       volatile off_t hashbytes;
+       off_t volatile hashbytes;
        struct stat st;
        time_t mtime;
        struct timeval tval[2];
        int oprogress;
        int opreserve;
 
-#ifdef __GNUC__                        /* to shut up gcc warnings */
-       (void)&local;
-       (void)&fout;
-       (void)&din;
-       (void)&closefunc;
-       (void)&oldintr;
-       (void)&oldintp;
-#endif
-
        fout = NULL;
        din = NULL;
        hashbytes = mark;
@@ -958,7 +919,7 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                        char *dir = strrchr(local, '/');
 
                        if (errno != ENOENT && errno != EACCES) {
-                               warn("local: %s", local);
+                               warn("Can't access `%s'", local);
                                code = -1;
                                goto cleanuprecv;
                        }
@@ -969,13 +930,13 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                        if (dir != NULL)
                                *dir = '/';
                        if (d < 0) {
-                               warn("local: %s", local);
+                               warn("Can't access `%s'", local);
                                code = -1;
                                goto cleanuprecv;
                        }
                        if (!runique && errno == EACCES &&
                            chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
-                               warn("local: %s", local);
+                               warn("Can't chmod `%s'", local);
                                code = -1;
                                goto cleanuprecv;
                        }
@@ -1027,7 +988,7 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                oldintp = xsignal(SIGPIPE, SIG_IGN);
                fout = popen(local + 1, "w");
                if (fout == NULL) {
-                       warn("%s", local+1);
+                       warn("Can't execute `%s'", local+1);
                        goto abort;
                }
                progress = 0;
@@ -1036,7 +997,7 @@ recvrequest(const char *cmd, const char *local, const char *remote,
        } else {
                fout = fopen(local, lmode);
                if (fout == NULL) {
-                       warn("local: %s", local);
+                       warn("Can't open `%s'", local);
                        goto abort;
                }
                closefunc = fclose;
@@ -1061,7 +1022,7 @@ recvrequest(const char *cmd, const char *local, const char *remote,
        case TYPE_L:
                if (is_retr && restart_point &&
                    lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
-                       warn("local: %s", local);
+                       warn("Can't seek to restart `%s'", local);
                        goto cleanuprecv;
                }
                if (rate_get) {         /* rate limiting */
@@ -1123,14 +1084,14 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                }
                if (c < 0) {
                        if (errno != EPIPE)
-                               warn("netin");
+                               warn("Reading from network");
                        bytes = -1;
                }
                if (d < c) {
                        if (d < 0)
-                               warn("local: %s", local);
+                               warn("Writing `%s'", local);
                        else
-                               warnx("%s: short write", local);
+                               warnx("Writing `%s': short write", local);
                }
                break;
 
@@ -1149,7 +1110,7 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                        }
                        if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) {
  done:
-                               warn("local: %s", local);
+                               warn("Can't seek to restart `%s'", local);
                                goto cleanuprecv;
                        }
                }
@@ -1188,11 +1149,11 @@ recvrequest(const char *cmd, const char *local, const char *remote,
                }
                if (ferror(din)) {
                        if (errno != EPIPE)
-                               warn("netin");
+                               warn("Reading from network");
                        bytes = -1;
                }
                if (ferror(fout))
-                       warn("local: %s", local);
+                       warn("Writing `%s'", local);
                break;
        }
 
@@ -1279,22 +1240,24 @@ initconn(void)
        unsigned int af, hal, pal;
        socklen_t len;
        char *pasvcmd = NULL;
+       int overbose;
 
 #ifdef INET6
 #ifndef NO_DEBUG
        if (myctladdr.su_family == AF_INET6 && ftp_debug &&
            (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) ||
             IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) {
-               warnx("use of scoped address can be troublesome");
+               warnx("Use of scoped addresses can be troublesome");
        }
 #endif
 #endif
+
  reinit:
        if (passivemode) {
                data_addr = myctladdr;
                data = socket(data_addr.su_family, SOCK_STREAM, 0);
                if (data < 0) {
-                       warn("socket");
+                       warn("Can't create socket for data connection");
                        return (1);
                }
                if ((options & SO_DEBUG) &&
@@ -1307,7 +1270,14 @@ initconn(void)
                case AF_INET:
                        if (epsv4 && !epsv4bad) {
                                pasvcmd = "EPSV";
+                               overbose = verbose;
+                               if (ftp_debug == 0)
+                                       verbose = -1;
                                result = command("EPSV");
+                               verbose = overbose;
+                               if (verbose > 0 &&
+                                   (result == COMPLETE || !connected))
+                                       fprintf(ttyout, "%s\n", reply_string);
                                if (!connected)
                                        return (1);
                                /*
@@ -1336,7 +1306,14 @@ initconn(void)
 #ifdef INET6
                case AF_INET6:
                        pasvcmd = "EPSV";
+                       overbose = verbose;
+                       if (ftp_debug == 0)
+                               verbose = -1;
                        result = command("EPSV");
+                       verbose = overbose;
+                       if (verbose > 0 &&
+                           (result == COMPLETE || !connected))
+                               fprintf(ttyout, "%s\n", reply_string);
                        if (!connected)
                                return (1);
                        /* this code is to be friendly with broken BSDI ftpd */
@@ -1516,8 +1493,8 @@ initconn(void)
                } else
                        goto bad;
 
-               while (ftp_connect(data, (struct sockaddr *)&data_addr.si_su,
-                           data_addr.su_len) < 0) {
+               if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su,
+                   data_addr.su_len) < 0) {
                        if (activefallback) {
                                (void)close(data);
                                data = -1;
@@ -1527,7 +1504,6 @@ initconn(void)
 #endif
                                goto reinit;
                        }
-                       warn("connect for data channel");
                        goto bad;
                }
 #ifdef IPTOS_THROUGHPUT
@@ -1551,7 +1527,7 @@ initconn(void)
                (void)close(data);
        data = socket(data_addr.su_family, SOCK_STREAM, 0);
        if (data < 0) {
-               warn("socket");
+               warn("Can't create socket for data connection");
                if (tmpno)
                        sendport = 1;
                return (1);
@@ -1559,12 +1535,12 @@ initconn(void)
        if (!sendport)
                if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
                                (void *)&on, sizeof(on)) == -1) {
-                       warn("setsockopt %s", "SO_REUSEADDR");
+                       warn("Can't set SO_REUSEADDR on data connection");
                        goto bad;
                }
        if (bind(data, (struct sockaddr *)&data_addr.si_su,
            data_addr.su_len) < 0) {
-               warn("bind");
+               warn("Can't bind for data connection");
                goto bad;
        }
        if ((options & SO_DEBUG) &&
@@ -1575,12 +1551,12 @@ initconn(void)
        len = sizeof(data_addr.si_su);
        memset((char *)&data_addr, 0, sizeof (data_addr));
        if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) {
-               warn("getsockname");
+               warn("Can't determine my address of data connection");
                goto bad;
        }
        data_addr.su_len = len;
        if (ftp_listen(data, 1) < 0)
-               warn("listen");
+               warn("Can't listen to data connection");
 
        if (sendport) {
                char hname[NI_MAXHOST], sname[NI_MAXSERV];
@@ -1608,8 +1584,15 @@ initconn(void)
                            sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) {
                                result = ERROR;
                        } else {
+                               overbose = verbose;
+                               if (ftp_debug == 0)
+                                       verbose = -1;
                                result = command("EPRT |%d|%s|%s|", af, hname,
                                    sname);
+                               verbose = overbose;
+                               if (verbose > 0 &&
+                                   (result == COMPLETE || !connected))
+                                       fprintf(ttyout, "%s\n", reply_string);
                                if (!connected)
                                        return (1);
                                if (result != COMPLETE) {
@@ -1717,11 +1700,11 @@ dataconn(const char *lmode)
                rv = ftp_poll(pfd, 1, timeout);
        } while (rv == -1 && errno == EINTR);   /* loop until poll ! EINTR */
        if (rv == -1) {
-               warn("poll waiting before accept");
+               warn("Can't poll waiting before accept");
                goto dataconn_failed;
        }
        if (rv == 0) {
-               warn("poll timeout waiting before accept");
+               warnx("Poll timeout waiting before accept");
                goto dataconn_failed;
        }
 
@@ -1731,7 +1714,7 @@ dataconn(const char *lmode)
                s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
        } while (s == -1 && errno == EINTR);    /* loop until accept ! EINTR */
        if (s == -1) {
-               warn("accept");
+               warn("Can't accept data connection");
                goto dataconn_failed;
        }
 
@@ -1872,15 +1855,10 @@ abortpt(int notused)
 void
 proxtrans(const char *cmd, const char *local, const char *remote)
 {
-       sigfunc oldintr;
+       sigfunc volatile oldintr;
        int prox_type, nfnd;
-       volatile int secndflag;
-       char *cmd2;
-
-#ifdef __GNUC__                        /* to shut up gcc warnings */
-       (void)&oldintr;
-       (void)&cmd2;
-#endif
+       int volatile secndflag;
+       char *volatile cmd2;
 
        oldintr = NULL;
        secndflag = 0;
@@ -1984,7 +1962,7 @@ proxtrans(const char *cmd, const char *local, const char *remote)
        if (cpend) {
                if ((nfnd = empty(cin, NULL, 10)) <= 0) {
                        if (nfnd < 0)
-                               warn("abort");
+                               warn("Error aborting proxy command");
                        if (ptabflg)
                                code = -1;
                        lostpeer(0);
@@ -2012,7 +1990,7 @@ reset(int argc, char *argv[])
        }
        while (nfnd > 0) {
                if ((nfnd = empty(cin, NULL, 0)) < 0) {
-                       warn("reset");
+                       warn("Error resetting connection");
                        code = -1;
                        lostpeer(0);
                } else if (nfnd)
@@ -2034,7 +2012,7 @@ gunique(const char *local)
        if (cp)
                *cp = '/';
        if (d < 0) {
-               warn("local: %s", local);
+               warn("Can't access `%s'", local);
                return (NULL);
        }
        len = strlcpy(new, local, sizeof(new));
@@ -2094,7 +2072,7 @@ abort_remote(FILE *din)
        int nfnd;
 
        if (cout == NULL) {
-               warnx("Lost control connection for abort.");
+               warnx("Lost control connection for abort");
                if (ptabflg)
                        code = -1;
                lostpeer(0);
@@ -2108,12 +2086,12 @@ abort_remote(FILE *din)
        buf[1] = IP;
        buf[2] = IAC;
        if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
-               warn("abort");
+               warn("Can't send abort message");
        fprintf(cout, "%cABOR\r\n", DM);
        (void)fflush(cout);
        if ((nfnd = empty(cin, din, 10)) <= 0) {
                if (nfnd < 0)
-                       warn("abort");
+                       warn("Can't send abort message");
                if (ptabflg)
                        code = -1;
                lostpeer(0);
@@ -2129,6 +2107,24 @@ abort_remote(FILE *din)
        (void)getreply(0);
 }
 
+/*
+ * Ensure that ai->ai_addr is NOT an IPv4 mapped address.
+ * IPv4 mapped address complicates too many things in FTP
+ * protocol handling, as FTP protocol is defined differently
+ * between IPv4 and IPv6.
+ *
+ * This may not be the best way to handle this situation,
+ * since the semantics of IPv4 mapped address is defined in
+ * the kernel.  There are configurations where we should use
+ * IPv4 mapped address as native IPv6 address, not as
+ * "an IPv6 address that embeds IPv4 address" (namely, SIIT).
+ *
+ * More complete solution would be to have an additional
+ * getsockopt to grab "real" peername/sockname.  "real"
+ * peername/sockname will be AF_INET if IPv4 mapped address
+ * is used to embed IPv4 address, and will be AF_INET6 if
+ * we use it as native.  What a mess!
+ */
 void
 ai_unmapped(struct addrinfo *ai)
 {
index 3c8a31b..0997376 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: ftp_var.h,v 1.73 2006/01/31 20:05:36 christos Exp $    */
+/*     $NetBSD: ftp_var.h,v 1.74 2007/04/17 05:52:03 lukem Exp $       */
 
 /*-
- * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -210,7 +210,7 @@ GLOBAL      int     sendport;       /* use PORT/LPRT cmd for each data connection */
 GLOBAL int     connected;      /* 1 = connected to server, -1 = logged in */
 GLOBAL int     interactive;    /* interactively prompt on m* cmds */
 GLOBAL int     confirmrest;    /* confirm rest of current m* cmd */
-GLOBAL int     ftp_debug;              /* debugging level */
+GLOBAL int     ftp_debug;      /* debugging level */
 GLOBAL int     bell;           /* ring bell on cmd completion */
 GLOBAL int     doglob;         /* glob local file names */
 GLOBAL int     autologin;      /* establish user account on connection */
@@ -279,6 +279,7 @@ GLOBAL      sa_family_t family;     /* address family to use for connections */
 GLOBAL char    *ftpport;       /* port number to use for FTP connections */
 GLOBAL char    *httpport;      /* port number to use for HTTP connections */
 GLOBAL char    *gateport;      /* port number to use for gateftp connections */
+GLOBAL struct addrinfo *bindai; /* local address to bind as */
 
 GLOBAL char   *outfile;        /* filename to output URLs to */
 GLOBAL int     restartautofetch; /* restart auto-fetch */
index 443654c..c7740de 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: main.c,v 1.101 2006/01/31 20:05:36 christos Exp $      */
+/*     $NetBSD: main.c,v 1.104 2007/04/17 05:52:03 lukem Exp $ */
 
 /*-
  * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
@@ -104,7 +104,7 @@ __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
 #if 0
 static char sccsid[] = "@(#)main.c     8.6 (Berkeley) 10/9/94";
 #else
-__RCSID("$NetBSD: main.c,v 1.101 2006/01/31 20:05:36 christos Exp $");
+__RCSID("$NetBSD: main.c,v 1.104 2007/04/17 05:52:03 lukem Exp $");
 #endif
 #endif /* not lint */
 
@@ -138,11 +138,11 @@ static void       setupoption(char *, char *, char *);
 int            main(int, char *[]);
 
 int
-main(int argc, char *argv[])
+main(int volatile argc, char **volatile argv)
 {
        int ch, rval;
        struct passwd *pw;
-       char *cp, *ep, *anonuser, *anonpass, *upload_path;
+       char *cp, *ep, *anonuser, *anonpass, *upload_path, *src_addr;
        int dumbterm, s, isupload;
        size_t len;
        socklen_t slen;
@@ -189,6 +189,7 @@ main(int argc, char *argv[])
        epsv4 = 0;
 #endif
        epsv4bad = 0;
+       src_addr = NULL;
        upload_path = NULL;
        isupload = 0;
        reply_callback = NULL;
@@ -207,15 +208,15 @@ main(int argc, char *argv[])
         */
        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s == -1)
-               err(1, "can't create socket");
+               err(1, "Can't create socket to determine default socket sizes");
        slen = sizeof(rcvbuf_size);
        if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
            (void *)&rcvbuf_size, &slen) == -1)
-               err(1, "unable to get default rcvbuf size");
+               err(1, "Unable to get default rcvbuf size");
        slen = sizeof(sndbuf_size);
        if (getsockopt(s, SOL_SOCKET, SO_SNDBUF,
            (void *)&sndbuf_size, &slen) == -1)
-               err(1, "unable to get default sndbuf size");
+               err(1, "Unable to get default sndbuf size");
        (void)close(s);
                                        /* sanity check returned buffer sizes */
        if (rcvbuf_size <= 0)
@@ -246,7 +247,7 @@ main(int argc, char *argv[])
                        passivemode = 1;
                        activefallback = 1;
                } else
-                       warnx("unknown $FTPMODE '%s'; using defaults", cp);
+                       warnx("Unknown $FTPMODE `%s'; using defaults", cp);
        }
 
        if (strcmp(getprogname(), "pftp") == 0) {
@@ -287,7 +288,7 @@ main(int argc, char *argv[])
                }
        }
 
-       while ((ch = getopt(argc, argv, "46AadefginN:o:pP:q:r:RtT:u:vV")) != -1) {
+       while ((ch = getopt(argc, argv, "46AadefginN:o:pP:q:r:Rs:tT:u:vV")) != -1) {
                switch (ch) {
                case '4':
                        family = AF_INET;
@@ -362,19 +363,23 @@ main(int argc, char *argv[])
                case 'q':
                        quit_time = strtol(optarg, &ep, 10);
                        if (quit_time < 1 || *ep != '\0')
-                               errx(1, "bad quit value: %s", optarg);
+                               errx(1, "Bad quit value: %s", optarg);
                        break;
 
                case 'r':
                        retry_connect = strtol(optarg, &ep, 10);
                        if (retry_connect < 1 || *ep != '\0')
-                               errx(1, "bad retry value: %s", optarg);
+                               errx(1, "Bad retry value: %s", optarg);
                        break;
 
                case 'R':
                        restartautofetch = 1;
                        break;
 
+               case 's':
+                       src_addr = optarg;
+                       break;
+
                case 't':
                        trace = 1;
                        break;
@@ -391,7 +396,8 @@ main(int argc, char *argv[])
 
                        while ((cp = strsep(&oac, ",")) != NULL) {
                                if (*cp == '\0') {
-                                       warnx("bad throttle value: %s", optarg);
+                                       warnx("Bad throttle value `%s'",
+                                           optarg);
                                        usage();
                                        /* NOTREACHED */
                                }
@@ -436,6 +442,22 @@ main(int argc, char *argv[])
        crflag = 1;     /* strip c.r. on ascii gets */
        sendport = -1;  /* not using ports */
 
+       if (src_addr != NULL) {
+               struct addrinfo hints;
+               int error;
+
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = family;
+               hints.ai_socktype = SOCK_STREAM;
+               hints.ai_flags = AI_PASSIVE;
+               error = getaddrinfo(src_addr, NULL, &hints, &bindai);
+               if (error) {
+                       errx(1, "Can't lookup `%s': %s", src_addr,
+                           (error == EAI_SYSTEM) ? strerror(errno)
+                                                 : gai_strerror(error));
+               }
+       }
+
        /*
         * Cache the user name and home directory.
         */
@@ -503,11 +525,6 @@ main(int argc, char *argv[])
        (void)xsignal(SIGUSR2, crankrate);
        (void)xsignal(SIGWINCH, setttywidth);
 
-#ifdef __GNUC__                        /* to shut up gcc warnings */
-       (void)&argc;
-       (void)&argv;
-#endif
-
        if (argc > 0) {
                if (isupload) {
                        rval = auto_put(argc, argv, upload_path);
@@ -595,7 +612,7 @@ prompt(void)
 
                o = getoption("prompt");
                if (o == NULL)
-                       errx(1, "no such option `prompt'");
+                       errx(1, "prompt: no such option `prompt'");
                prompt = &(o->value);
        }
        formatbuf(buf, sizeof(buf), *prompt ? *prompt : DEFAULTPROMPT);
@@ -616,7 +633,7 @@ rprompt(void)
 
                o = getoption("rprompt");
                if (o == NULL)
-                       errx(1, "no such option `rprompt'");
+                       errx(1, "rprompt: no such option `rprompt'");
                rprompt = &(o->value);
        }
        formatbuf(buf, sizeof(buf), *rprompt ? *rprompt : DEFAULTRPROMPT);
@@ -645,8 +662,8 @@ cmdscanner(void)
                                p = rprompt();
                                if (*p)
                                        fprintf(ttyout, "%s ", p);
-                               (void)fflush(ttyout);
                        }
+                       (void)fflush(ttyout);
                        num = getline(stdin, line, sizeof(line), NULL);
                        switch (num) {
                        case -1:        /* EOF */
@@ -1016,11 +1033,11 @@ getoptionvalue(const char *name)
        struct option *c;
 
        if (name == NULL)
-               errx(1, "getoptionvalue() invoked with NULL name");
+               errx(1, "getoptionvalue: invoked with NULL name");
        c = getoption(name);
        if (c != NULL)
                return (c->value);
-       errx(1, "getoptionvalue() invoked with unknown option `%s'", name);
+       errx(1, "getoptionvalue: invoked with unknown option `%s'", name);
        /* NOTREACHED */
 }
 
@@ -1046,8 +1063,9 @@ usage(void)
 
        (void)fprintf(stderr,
 "usage: %s [-46AadefginpRtvV] [-N netrc] [-o outfile] [-P port] [-q quittime]\n"
-"           [-r retry] [-T dir,max[,inc][[user@]host [port]]] [host:path[/]]\n"
-"           [file:///file] [ftp://[user[:pass]@]host[:port]/path[/]]\n"
+"           [-r retry] [-s srcaddr] [-T dir,max[,inc]]\n"
+"           [[user@]host [port]] [host:path[/]] [file:///file]\n"
+"           [ftp://[user[:pass]@]host[:port]/path[/]]\n"
 "           [http://[user[:pass]@]host[:port]/path] [...]\n"
 "       %s -u URL file [...]\n", progname, progname);
        exit(1);
index 0e779d0..34d3cc6 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: progressbar.c,v 1.13 2006/05/01 23:02:03 christos Exp $        */
+/*     $NetBSD: progressbar.c,v 1.15 2007/04/17 05:52:03 lukem Exp $   */
 
 /*-
- * Copyright (c) 1997-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: progressbar.c,v 1.13 2006/05/01 23:02:03 christos Exp $");
+__RCSID("$NetBSD: progressbar.c,v 1.15 2007/04/17 05:52:03 lukem Exp $");
 #endif /* not lint */
 
 /*
@@ -91,10 +91,23 @@ updateprogressmeter(int dummy)
 }
 
 /*
- * List of order of magnitude prefixes.
- * The last is `P', as 2^64 = 16384 Petabytes
+ * List of order of magnitude suffixes, per IEC 60027-2.
  */
-static const char prefixes[] = " KMGTP";
+static const char const *suffixes[] = {
+       "",     /* 2^0  (byte) */
+       "KiB",  /* 2^10 Kibibyte */
+       "MiB",  /* 2^20 Mebibyte */
+       "GiB",  /* 2^30 Gibibyte */
+       "TiB",  /* 2^40 Tebibyte */
+       "PiB",  /* 2^50 Pebibyte */
+       "EiB",  /* 2^60 Exbibyte */
+#if 0
+               /* The following are not necessary for signed 64-bit off_t */
+       "ZiB",  /* 2^70 Zebibyte */
+       "YiB",  /* 2^80 Yobibyte */
+#endif
+};
+#define NSUFFIXES      (sizeof(suffixes) / sizeof(suffixes[0]))
 
 /*
  * Display a transfer progress bar if progress is non-zero.
@@ -135,7 +148,7 @@ progressmeter(int flag)
        size_t          len;
        char            buf[256];       /* workspace for progress bar */
 #ifndef NO_PROGRESS
-#define        BAROVERHEAD     43              /* non `*' portion of progress bar */
+#define        BAROVERHEAD     45              /* non `*' portion of progress bar */
                                        /*
                                         * stars should contain at least
                                         * sizeof(buf) - BAROVERHEAD entries
@@ -224,14 +237,13 @@ progressmeter(int flag)
        }
 
        abbrevsize = cursize;
-       for (i = 0; abbrevsize >= 100000 && i < sizeof(prefixes); i++)
+       for (i = 0; abbrevsize >= 100000 && i < NSUFFIXES; i++)
                abbrevsize >>= 10;
-       if (i == sizeof(prefixes))
+       if (i == NSUFFIXES)
                i--;
-       len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %c%c ",
+       len += snprintf(buf + len, BUFLEFT, " " LLFP("5") " %-3s ",
            (LLT)abbrevsize,
-           prefixes[i],
-           i == 0 ? ' ' : 'B');
+           suffixes[i]);
 
        timersub(&now, &start, &td);
        elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
@@ -242,13 +254,13 @@ progressmeter(int flag)
                if (elapsed > 0.0)
                        bytespersec /= elapsed;
        }
-       for (i = 1; bytespersec >= 1024000 && i < sizeof(prefixes); i++)
+       for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
                bytespersec >>= 10;
        len += snprintf(buf + len, BUFLEFT,
-           " " LLFP("3") ".%02d %cB/s ",
+           " " LLFP("3") ".%02d %.2sB/s ",
            (LLT)(bytespersec / 1024),
            (int)((bytespersec % 1024) * 100 / 1024),
-           prefixes[i]);
+           suffixes[i]);
 
        if (filesize > 0) {
                if (bytes <= 0 || elapsed <= 0.0 || cursize > filesize) {
@@ -334,14 +346,14 @@ ptransfer(int siginfo)
        len += snprintf(buf + len, BUFLEFT,
            "%02d:%02d ", remaining / 60, remaining % 60);
 
-       for (i = 1; bytespersec >= 1024000 && i < sizeof(prefixes); i++)
+       for (i = 1; bytespersec >= 1024000 && i < NSUFFIXES; i++)
                bytespersec >>= 10;
-       if (i == sizeof(prefixes))
+       if (i == NSUFFIXES)
                i--;
-       len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %cB/s)",
+       len += snprintf(buf + len, BUFLEFT, "(" LLF ".%02d %.2sB/s)",
            (LLT)(bytespersec / 1024),
            (int)((bytespersec % 1024) * 100 / 1024),
-           prefixes[i]);
+           suffixes[i]);
 
        if (siginfo && bytes > 0 && elapsed > 0.0 && filesize >= 0
            && bytes + restart_point <= filesize) {
@@ -459,7 +471,7 @@ xsignal(int sig, sigfunc func)
                 * This is unpleasant, but I don't know what would be better.
                 * Right now, this "can't happen"
                 */
-               errx(1, "xsignal_restart called with signal %d", sig);
+               errx(1, "xsignal_restart: called with signal %d", sig);
        }
 
        return(xsignal_restart(sig, func, restartable));
index 5b4683f..e434052 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: ruserpass.c,v 1.31 2006/01/31 20:01:23 christos Exp $  */
+/*     $NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp $     */
 
 /*
  * Copyright (c) 1985, 1993, 1994
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)ruserpass.c        8.4 (Berkeley) 4/27/95";
 #else
-__RCSID("$NetBSD: ruserpass.c,v 1.31 2006/01/31 20:01:23 christos Exp $");
+__RCSID("$NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp $");
 #endif
 #endif /* not lint */
 
@@ -93,7 +93,7 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
        cfile = fopen(netrc, "r");
        if (cfile == NULL) {
                if (errno != ENOENT)
-                       warn("%s", netrc);
+                       warn("Can't read `%s'", netrc);
                return (0);
        }
        if (gethostname(myname, sizeof(myname)) < 0)
@@ -102,7 +102,7 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
        if ((mydomain = strchr(myname, '.')) == NULL)
                mydomain = "";
  next:
-       while ((t = token())) switch(t) {
+       while ((t = token()) > 0) switch(t) {
 
        case DEFAULT:
                usedefault = 1;
@@ -110,7 +110,9 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
 
        case MACH:
                if (!usedefault) {
-                       if (token() != ID)
+                       if ((t = token()) == -1)
+                               goto bad;
+                       if (t != ID)
                                continue;
                        /*
                         * Allow match either for user's input host name
@@ -134,10 +136,13 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
                        continue;
                }
        match:
-               while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
+               while ((t = token()) > 0 &&
+                   t != MACH && t != DEFAULT) switch(t) {
 
                case LOGIN:
-                       if (token()) {
+                       if ((t = token()) == -1)
+                               goto bad;
+                       if (t) {
                                if (*aname == NULL)
                                        *aname = ftp_strdup(tokval);
                                else {
@@ -150,21 +155,25 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
                        if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
                            fstat(fileno(cfile), &stb) >= 0 &&
                            (stb.st_mode & 077) != 0) {
-       warnx("Error: .netrc file is readable by others.");
-       warnx("Remove password or make file unreadable by others.");
+       warnx("Error: .netrc file is readable by others");
+       warnx("Remove password or make file unreadable by others");
                                goto bad;
                        }
-                       if (token() && *apass == NULL)
+                       if ((t = token()) == -1)
+                               goto bad;
+                       if (t && *apass == NULL)
                                *apass = ftp_strdup(tokval);
                        break;
                case ACCOUNT:
                        if (fstat(fileno(cfile), &stb) >= 0
                            && (stb.st_mode & 077) != 0) {
-       warnx("Error: .netrc file is readable by others.");
-       warnx("Remove account or make file unreadable by others.");
+       warnx("Error: .netrc file is readable by others");
+       warnx("Remove account or make file unreadable by others");
                                goto bad;
                        }
-                       if (token() && *aacct == NULL)
+                       if ((t = token()) == -1)
+                               goto bad;
+                       if (t && *aacct == NULL)
                                *aacct = ftp_strdup(tokval);
                        break;
                case MACDEF:
@@ -225,9 +234,13 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
                                }
                                *tmp = c;
                                if (*tmp == '\n') {
-                                       if (*(tmp-1) == '\0') {
-                                          macros[macnum++].mac_end = tmp - 1;
-                                          break;
+                                       if (tmp == macros[macnum].mac_start) {
+                                               macros[macnum++].mac_end = tmp;
+                                               break;
+                                       } else if (*(tmp - 1) == '\0') {
+                                               macros[macnum++].mac_end =
+                                                   tmp - 1;
+                                               break;
                                        }
                                        *tmp = '\0';
                                }
@@ -240,12 +253,14 @@ ruserpass(const char *host, char **aname, char **apass, char **aacct)
                        }
                        break;
                default:
-                       warnx("Unknown .netrc keyword %s", tokval);
+                       warnx("Unknown .netrc keyword `%s'", tokval);
                        break;
                }
                goto done;
        }
  done:
+       if (t == -1)
+               goto bad;
        (void)fclose(cfile);
        return (0);
  bad:
@@ -271,16 +286,26 @@ token(void)
        if (c == '"') {
                while ((c = getc(cfile)) != EOF && c != '"') {
                        if (c == '\\')
-                               c = getc(cfile);
+                               if ((c = getc(cfile)) == EOF)
+                                       break;
                        *cp++ = c;
+                       if (cp == tokval + sizeof(tokval)) {
+                               warnx("Token in .netrc too long");
+                               return (-1);
+                       }
                }
        } else {
                *cp++ = c;
                while ((c = getc(cfile)) != EOF
                    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
                        if (c == '\\')
-                               c = getc(cfile);
+                               if ((c = getc(cfile)) == EOF)
+                                       break;
                        *cp++ = c;
+                       if (cp == tokval + sizeof(tokval)) {
+                               warnx("Token in .netrc too long");
+                               return (-1);
+                       }
                }
        }
        *cp = 0;
index 0e17f1f..6162fbc 100644 (file)
@@ -1,7 +1,7 @@
-/*     $NetBSD: util.c,v 1.135 2006/05/23 23:59:48 jnemeth Exp $       */
+/*     $NetBSD: util.c,v 1.138 2007/04/17 05:52:04 lukem Exp $ */
 
 /*-
- * Copyright (c) 1997-2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -71,7 +71,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: util.c,v 1.135 2006/05/23 23:59:48 jnemeth Exp $");
+__RCSID("$NetBSD: util.c,v 1.138 2007/04/17 05:52:04 lukem Exp $");
 #endif /* not lint */
 
 /*
@@ -137,7 +137,7 @@ setpeer(int argc, char *argv[])
 
        if (gatemode) {
                if (gateserver == NULL || *gateserver == '\0')
-                       errx(1, "gateserver not defined (shouldn't happen)");
+                       errx(1, "main: gateserver not defined");
                host = hookup(gateserver, port);
        } else
                host = hookup(argv[1], port);
@@ -379,6 +379,7 @@ ftp_login(const char *host, const char *luser, const char *lpass)
 {
        char tmp[80];
        char *user, *pass, *acct, *p;
+       char emptypass[] = "";
        const char *errormsg;
        int n, aflag, rval, nlen;
 
@@ -443,6 +444,8 @@ ftp_login(const char *host, const char *luser, const char *lpass)
        if (n == CONTINUE) {
                if (pass == NULL) {
                        p = getpass("Password: ");
+                       if (p == NULL)
+                               p = emptypass;
                        pass = ftp_strdup(p);
                        memset(p, 0, strlen(p));
                }
@@ -453,11 +456,13 @@ ftp_login(const char *host, const char *luser, const char *lpass)
                aflag++;
                if (acct == NULL) {
                        p = getpass("Account: ");
+                       if (p == NULL)
+                               p = emptypass;
                        acct = ftp_strdup(p);
                        memset(p, 0, strlen(p));
                }
                if (acct[0] == '\0') {
-                       warnx("Login failed.");
+                       warnx("Login failed");
                        goto cleanup_ftp_login;
                }
                n = command("ACCT %s", acct);
@@ -465,7 +470,7 @@ ftp_login(const char *host, const char *luser, const char *lpass)
        }
        if ((n != COMPLETE) ||
            (!aflag && acct != NULL && command("ACCT %s", acct) != COMPLETE)) {
-               warnx("Login failed.");
+               warnx("Login failed");
                goto cleanup_ftp_login;
        }
        rval = 1;
@@ -572,7 +577,7 @@ remglob(char *argv[], int doswitch, const char **errbuf)
                        (void)strlcat(temp, "/", sizeof(temp));
                (void)strlcat(temp, TMPFILE, sizeof(temp));
                if ((fd = mkstemp(temp)) < 0) {
-                       warn("unable to create temporary file %s", temp);
+                       warn("Unable to create temporary file `%s'", temp);
                        return (NULL);
                }
                close(fd);
@@ -599,12 +604,10 @@ remglob(char *argv[], int doswitch, const char **errbuf)
                (void)unlink(temp);
                if (ftemp == NULL) {
                        if (errbuf == NULL)
-                               fputs(
-                                   "can't find list of remote files, oops.\n",
-                                   ttyout);
+                               warnx("Can't find list of remote files");
                        else
                                *errbuf =
-                                   "can't find list of remote files, oops.";
+                                   "Can't find list of remote files";
                        return (NULL);
                }
        }
@@ -638,7 +641,7 @@ globulize(const char *pattern)
        flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
        memset(&gl, 0, sizeof(gl));
        if (glob(pattern, flags, NULL, &gl) || gl.gl_pathc == 0) {
-               warnx("%s: not found", pattern);
+               warnx("Glob pattern `%s' not found", pattern);
                globfree(&gl);
                return (NULL);
        }
@@ -767,7 +770,7 @@ remotemodtime(const char *file, int noisy)
                                goto bad_parse_time;
                        else
                                goto cleanup_parse_time;
-               } else 
+               } else
                        DPRINTF("parsed date as: %s", ctime(&rtime));
        } else {
                if (r == ERROR && code == 500 && features[FEAT_MDTM] == -1)
@@ -845,7 +848,7 @@ fileindir(const char *file, const char *dir)
        char    realdir[PATH_MAX+1];
        size_t  dirlen;
 
-                                       /* determine parent directory of file */
+                                       /* determine parent directory of file */
        (void)strlcpy(parentdirbuf, file, sizeof(parentdirbuf));
        parentdir = dirname(parentdirbuf);
        if (strcmp(parentdir, ".") == 0)
@@ -1052,11 +1055,11 @@ setupsockbufsize(int sock)
 
        if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
            (void *)&sndbuf_size, sizeof(sndbuf_size)) == -1)
-               warn("unable to set sndbuf size %d", sndbuf_size);
+               warn("Unable to set sndbuf size %d", sndbuf_size);
 
        if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
            (void *)&rcvbuf_size, sizeof(rcvbuf_size)) == -1)
-               warn("unable to set rcvbuf size %d", rcvbuf_size);
+               warn("Unable to set rcvbuf size %d", rcvbuf_size);
 }
 
 /*
@@ -1310,14 +1313,15 @@ getline(FILE *stream, char *buf, size_t buflen, const char **errormsg)
        return len;
 }
 
-
 /*
- * Internal version of connect(2); sets socket buffer sizes first and
+ * Internal version of connect(2); sets socket buffer sizes,
+ * binds to a specific local address (if set), and
  * supports a connection timeout using a non-blocking connect(2) with
  * a poll(2).
  * Socket fcntl flags are temporarily updated to include O_NONBLOCK;
  * these will not be reverted on connection failure.
- * Returns -1 upon failure (with errno set to the problem), or 0 on success.
+ * Returns 0 on success, or -1 upon failure (with an appropriate
+ * error message displayed.)
  */
 int
 ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen)
@@ -1326,13 +1330,48 @@ ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen)
        socklen_t       slen;
        struct timeval  endtime, now, td;
        struct pollfd   pfd[1];
+       char            hname[NI_MAXHOST];
 
        setupsockbufsize(sock);
+       if (getnameinfo(name, namelen,
+           hname, sizeof(hname), NULL, 0, NI_NUMERICHOST) != 0)
+               strlcpy(hname, "?", sizeof(hname));
+
+       if (bindai != NULL) {                   /* bind to specific addr */
+               struct addrinfo *ai;
+
+               for (ai = bindai; ai != NULL; ai = ai->ai_next) {
+                       if (ai->ai_family == name->sa_family)
+                               break;
+               }
+               if (ai == NULL)
+                       ai = bindai;
+               if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
+                       char    bname[NI_MAXHOST];
+                       int     saveerr;
+
+                       saveerr = errno;
+                       if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                           bname, sizeof(bname), NULL, 0, NI_NUMERICHOST) != 0)
+                               strlcpy(bname, "?", sizeof(bname));
+                       errno = saveerr;
+                       warn("Can't bind to `%s'", bname);
+                       return -1;
+               }
+       }
 
-       if ((flags = fcntl(sock, F_GETFL, 0)) == -1)
-               return -1;                      /* get current socket flags  */
-       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
-               return -1;                      /* set non-blocking connect */
+                                               /* save current socket flags */
+       if ((flags = fcntl(sock, F_GETFL, 0)) == -1) {
+               warn("Can't %s socket flags for connect to `%s'",
+                   "save", hname);
+               return -1;
+       }
+                                               /* set non-blocking connect */
+       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+               warn("Can't set socket non-blocking for connect to `%s'",
+                   hname);
+               return -1;
+       }
 
        /* NOTE: we now must restore socket flags on successful exit */
 
@@ -1346,8 +1385,11 @@ ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen)
 
        rv = connect(sock, name, namelen);      /* inititate the connection */
        if (rv == -1) {                         /* connection error */
-               if (errno != EINPROGRESS)       /* error isn't "please wait" */
+               if (errno != EINPROGRESS) {     /* error isn't "please wait" */
+ connecterror:
+                       warn("Can't connect to `%s'", hname);
                        return -1;
+               }
 
                                                /* connect EINPROGRESS; wait */
                do {
@@ -1367,28 +1409,33 @@ ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen)
 
                if (rv == 0) {                  /* poll (connect) timed out */
                        errno = ETIMEDOUT;
-                       return -1;
+                       goto connecterror;
                }
 
                if (rv == -1) {                 /* poll error */
-                       return -1;
+                       goto connecterror;
                } else if (pfd[0].revents & (POLLIN|POLLOUT)) {
                        slen = sizeof(error);   /* OK, or pending error */
                        if (getsockopt(sock, SOL_SOCKET, SO_ERROR,
-                           &error, &slen) == -1)
-                               return -1;      /* Solaris pending error */
-                       if (error != 0) {
+                           &error, &slen) == -1) {
+                                               /* Solaris pending error */
+                               goto connecterror;
+                       } else if (error != 0) {
                                errno = error;  /* BSD pending error */
-                               return -1;
+                               goto connecterror;
                        }
                } else {
                        errno = EBADF;          /* this shouldn't happen ... */
-                       return -1;
+                       goto connecterror;
                }
        }
 
-       if (fcntl(sock, F_SETFL, flags) == -1)  /* restore socket flags */
+       if (fcntl(sock, F_SETFL, flags) == -1) {
+                                               /* restore socket flags */
+               warn("Can't %s socket flags for connect to `%s'",
+                   "restore", hname);
                return -1;
+       }
        return 0;
 }
 
@@ -1461,7 +1508,7 @@ ftp_strdup(const char *str)
        char *s;
 
        if (str == NULL)
-               errx(1, "ftp_strdup() called with NULL argument");
+               errx(1, "ftp_strdup: called with NULL argument");
        s = strdup(str);
        if (s == NULL)
                err(1, "Unable to allocate memory for string copy");
index d952407..b9937b3 100644 (file)
@@ -1,6 +1,6 @@
-/*     $NetBSD: version.h,v 1.58 2006/07/26 14:28:11 lukem Exp $       */
+/*     $NetBSD: version.h,v 1.63 2007/04/18 01:39:04 lukem Exp $       */
 /*-
- * Copyright (c) 1999-2006 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999-2007 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -40,5 +40,5 @@
 #endif
 
 #ifndef FTP_VERSION
-#define        FTP_VERSION     "20060726"
+#define        FTP_VERSION     "20070418"
 #endif