int main(volatile int argc, char *argv[]) { int ch, top, rval; struct passwd *pw = NULL; char *cp, homedir[MAXPATHLEN]; char *outfile = NULL; const char *errstr; int dumb_terminal = 0; ftpport = "ftp"; httpport = "http"; #ifndef SMALL httpsport = "https"; #endif /* !SMALL */ gateport = getenv("FTPSERVERPORT"); if (gateport == NULL || *gateport == '\0') gateport = "ftpgate"; doglob = 1; interactive = 1; autologin = 1; passivemode = 1; activefallback = 1; preserve = 1; verbose = 0; progress = 0; gatemode = 0; #ifndef SMALL editing = 0; el = NULL; hist = NULL; cookiefile = NULL; resume = 0; srcaddr = NULL; marg_sl = sl_init(); #endif /* !SMALL */ mark = HASHBYTES; #ifdef INET6 epsv4 = 1; #else epsv4 = 0; #endif epsv4bad = 0; /* Set default operation mode based on FTPMODE environment variable */ if ((cp = getenv("FTPMODE")) != NULL && *cp != '\0') { if (strcmp(cp, "passive") == 0) { passivemode = 1; activefallback = 0; } else if (strcmp(cp, "active") == 0) { passivemode = 0; activefallback = 0; } else if (strcmp(cp, "gate") == 0) { gatemode = 1; } else if (strcmp(cp, "auto") == 0) { passivemode = 1; activefallback = 1; } else warnx("unknown FTPMODE: %s. Using defaults", cp); } if (strcmp(__progname, "gate-ftp") == 0) gatemode = 1; gateserver = getenv("FTPSERVER"); if (gateserver == NULL || *gateserver == '\0') gateserver = GATE_SERVER; if (gatemode) { if (*gateserver == '\0') { warnx( "Neither $FTPSERVER nor $GATE_SERVER is defined; disabling gate-ftp"); gatemode = 0; } } cp = getenv("TERM"); dumb_terminal = (cp == NULL || *cp == '\0' || !strcmp(cp, "dumb") || !strcmp(cp, "emacs") || !strcmp(cp, "su")); fromatty = isatty(fileno(stdin)); if (fromatty) { verbose = 1; /* verbose if from a tty */ #ifndef SMALL if (!dumb_terminal) editing = 1; /* editing mode on if tty is usable */ #endif /* !SMALL */ } ttyout = stdout; if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc()) progress = 1; /* progress bar on if tty is usable */ #ifndef SMALL cookiefile = getenv("http_cookies"); #endif /* !SMALL */ while ((ch = getopt(argc, argv, "46AaCc:dD:Eegik:mno:pP:r:S:s:tvV")) != -1) { switch (ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case 'A': activefallback = 0; passivemode = 0; break; case 'a': anonftp = 1; break; case 'C': #ifndef SMALL resume = 1; #endif /* !SMALL */ break; case 'c': #ifndef SMALL cookiefile = optarg; #endif /* !SMALL */ break; case 'D': action = optarg; break; case 'd': #ifndef SMALL options |= SO_DEBUG; debug++; #endif /* !SMALL */ break; case 'E': epsv4 = 0; break; case 'e': #ifndef SMALL editing = 0; #endif /* !SMALL */ break; case 'g': doglob = 0; break; case 'i': interactive = 0; break; case 'k': keep_alive_timeout = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) { warnx("keep alive amount is %s: %s", errstr, optarg); usage(); } break; case 'm': progress = -1; break; case 'n': autologin = 0; break; case 'o': outfile = optarg; if (*outfile == '\0') { pipeout = 0; outfile = NULL; ttyout = stdout; } else { pipeout = strcmp(outfile, "-") == 0; ttyout = pipeout ? stderr : stdout; } break; case 'p': passivemode = 1; activefallback = 0; break; case 'P': ftpport = optarg; break; case 'r': retry_connect = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) { warnx("retry amount is %s: %s", errstr, optarg); usage(); } break; case 'S': #ifndef SMALL cp = optarg; while (*cp) { char *str; switch (getsubopt(&cp, ssl_verify_opts, &str)) { case SSL_CAFILE: if (str == NULL) errx(1, "missing CA file"); ssl_ca_file = str; break; case SSL_CAPATH: if (str == NULL) errx(1, "missing CA directory" " path"); ssl_ca_path = str; break; case SSL_CIPHERS: if (str == NULL) errx(1, "missing cipher list"); ssl_ciphers = str; break; case SSL_DONTVERIFY: ssl_verify = 0; break; case SSL_DOVERIFY: ssl_verify = 1; break; case SSL_VERIFYDEPTH: if (str == NULL) errx(1, "missing depth"); ssl_verify_depth = strtonum(str, 0, INT_MAX, &errstr); if (errstr) errx(1, "certificate " "validation depth is %s", errstr); break; default: errx(1, "unknown -S suboption `%s'", suboptarg ? suboptarg : ""); /* NOTREACHED */ } } #endif break; case 's': #ifndef SMALL srcaddr = optarg; #endif /* !SMALL */ break; case 't': trace = 1; break; case 'v': verbose = 1; break; case 'V': verbose = 0; break; default: usage(); } } argc -= optind; argv += optind; #ifndef SMALL cookie_load(); #endif /* !SMALL */ cpend = 0; /* no pending replies */ proxy = 0; /* proxy not active */ crflag = 1; /* strip c.r. on ascii gets */ sendport = -1; /* not using ports */ /* * Set up the home directory in case we're globbing. */ cp = getlogin(); if (cp != NULL) { pw = getpwnam(cp); } if (pw == NULL) pw = getpwuid(getuid()); if (pw != NULL) { (void)strlcpy(homedir, pw->pw_dir, sizeof homedir); home = homedir; } setttywidth(0); (void)signal(SIGWINCH, setttywidth); if (argc > 0) { if (isurl(argv[0])) { rval = auto_fetch(argc, argv, outfile); if (rval >= 0) /* -1 == connected and cd-ed */ exit(rval); } else { #ifndef SMALL char *xargv[5]; if (setjmp(toplevel)) exit(0); (void)signal(SIGINT, (sig_t)intr); (void)signal(SIGPIPE, (sig_t)lostpeer); xargv[0] = __progname; xargv[1] = argv[0]; xargv[2] = argv[1]; xargv[3] = argv[2]; xargv[4] = NULL; do { setpeer(argc+1, xargv); if (!retry_connect) break; if (!connected) { macnum = 0; fputs("Retrying...\n", ttyout); sleep(retry_connect); } } while (!connected); retry_connect = 0; /* connected, stop hiding msgs */ #endif /* !SMALL */ } } #ifndef SMALL controlediting(); top = setjmp(toplevel) == 0; if (top) { (void)signal(SIGINT, (sig_t)intr); (void)signal(SIGPIPE, (sig_t)lostpeer); } for (;;) { cmdscanner(top); top = 1; } #else /* !SMALL */ usage(); #endif /* !SMALL */ }
int main(int volatile argc, char **volatile argv) { int ch, rval; struct passwd *pw; char *cp, *ep, *anonuser, *anonpass, *upload_path, *src_addr; int dumbterm, s, isupload; size_t len; socklen_t slen; tzset(); #if 0 /* tnftp */ /* XXX */ setlocale(LC_ALL, ""); #endif /* tnftp */ setprogname(argv[0]); sigint_raised = 0; ftpport = "ftp"; httpport = "http"; gateport = NULL; cp = getenv("FTPSERVERPORT"); if (cp != NULL) gateport = cp; else gateport = "ftpgate"; doglob = 1; interactive = 1; autologin = 1; passivemode = 1; activefallback = 1; preserve = 1; verbose = 0; progress = 0; gatemode = 0; data = -1; outfile = NULL; restartautofetch = 0; #ifndef NO_EDITCOMPLETE editing = 0; el = NULL; hist = NULL; #endif bytes = 0; mark = HASHBYTES; rate_get = 0; rate_get_incr = DEFAULTINCR; rate_put = 0; rate_put_incr = DEFAULTINCR; #ifdef INET6 epsv4 = 1; #else epsv4 = 0; #endif epsv4bad = 0; src_addr = NULL; upload_path = NULL; isupload = 0; reply_callback = NULL; family = AF_UNSPEC; netrc[0] = '\0'; cp = getenv("NETRC"); if (cp != NULL && strlcpy(netrc, cp, sizeof(netrc)) >= sizeof(netrc)) errx(1, "$NETRC `%s': %s", cp, strerror(ENAMETOOLONG)); /* * Get the default socket buffer sizes if we don't already have them. * It doesn't matter which socket we do this to, because on the first * call no socket buffer sizes will have been modified, so we are * guaranteed to get the system defaults. */ s = socket(AF_INET, SOCK_STREAM, 0); if (s == -1) 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"); slen = sizeof(sndbuf_size); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void *)&sndbuf_size, &slen) == -1) err(1, "Unable to get default sndbuf size"); (void)close(s); /* sanity check returned buffer sizes */ if (rcvbuf_size <= 0) rcvbuf_size = 8 * 1024; if (sndbuf_size <= 0) sndbuf_size = 8 * 1024; if (sndbuf_size > 8 * 1024 * 1024) sndbuf_size = 8 * 1024 * 1024; if (rcvbuf_size > 8 * 1024 * 1024) rcvbuf_size = 8 * 1024 * 1024; marg_sl = ftp_sl_init(); if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = _PATH_TMP; /* Set default operation mode based on FTPMODE environment variable */ if ((cp = getenv("FTPMODE")) != NULL) { if (strcasecmp(cp, "passive") == 0) { passivemode = 1; activefallback = 0; } else if (strcasecmp(cp, "active") == 0) { passivemode = 0; activefallback = 0; } else if (strcasecmp(cp, "gate") == 0) { gatemode = 1; } else if (strcasecmp(cp, "auto") == 0) { passivemode = 1; activefallback = 1; } else warnx("Unknown $FTPMODE `%s'; using defaults", cp); } if (strcmp(getprogname(), "pftp") == 0) { passivemode = 1; activefallback = 0; } else if (strcmp(getprogname(), "gate-ftp") == 0) gatemode = 1; gateserver = getenv("FTPSERVER"); if (gateserver == NULL || *gateserver == '\0') gateserver = GATE_SERVER; if (gatemode) { if (*gateserver == '\0') { warnx( "Neither $FTPSERVER nor GATE_SERVER is defined; disabling gate-ftp"); gatemode = 0; } } cp = getenv("TERM"); if (cp == NULL || strcmp(cp, "dumb") == 0) dumbterm = 1; else dumbterm = 0; fromatty = isatty(fileno(stdin)); ttyout = stdout; if (isatty(fileno(ttyout))) { verbose = 1; /* verbose if to a tty */ if (! dumbterm) { #ifndef NO_EDITCOMPLETE if (fromatty) /* editing mode on if tty is usable */ editing = 1; #endif #ifndef NO_PROGRESS if (foregroundproc()) progress = 1; /* progress bar on if fg */ #endif } } while ((ch = getopt(argc, argv, "46AadefginN:o:pP:q:r:Rs:tT:u:vV")) != -1) { switch (ch) { case '4': family = AF_INET; break; case '6': #ifdef INET6 family = AF_INET6; #else warnx("INET6 support is not available; ignoring -6"); #endif break; case 'A': activefallback = 0; passivemode = 0; break; case 'a': anonftp = 1; break; case 'd': options |= SO_DEBUG; ftp_debug++; break; case 'e': #ifndef NO_EDITCOMPLETE editing = 0; #endif break; case 'f': flushcache = 1; break; case 'g': doglob = 0; break; case 'i': interactive = 0; break; case 'n': autologin = 0; break; case 'N': if (strlcpy(netrc, optarg, sizeof(netrc)) >= sizeof(netrc)) errx(1, "%s: %s", optarg, strerror(ENAMETOOLONG)); break; case 'o': outfile = optarg; if (strcmp(outfile, "-") == 0) ttyout = stderr; break; case 'p': passivemode = 1; activefallback = 0; break; case 'P': ftpport = optarg; break; case 'q': quit_time = strtol(optarg, &ep, 10); if (quit_time < 1 || *ep != '\0') 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); break; case 'R': restartautofetch = 1; break; case 's': src_addr = optarg; break; case 't': trace = 1; break; case 'T': { int targc; char *targv[6], *oac; /* look for `dir,max[,incr]' */ targc = 0; targv[targc++] = "-T"; oac = ftp_strdup(optarg); while ((cp = strsep(&oac, ",")) != NULL) { if (*cp == '\0') { warnx("Bad throttle value `%s'", optarg); usage(); /* NOTREACHED */ } targv[targc++] = cp; if (targc >= 5) break; } if (parserate(targc, targv, 1) == -1) usage(); free(oac); break; } case 'u': { isupload = 1; interactive = 0; upload_path = ftp_strdup(optarg); break; } case 'v': progress = verbose = 1; break; case 'V': progress = verbose = 0; break; default: usage(); } } /* set line buffering on ttyout */ setvbuf(ttyout, NULL, _IOLBF, 0); argc -= optind; argv += optind; cpend = 0; /* no pending replies */ proxy = 0; /* proxy not active */ 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. */ localhome = NULL; localname = NULL; anonuser = "******"; cp = getenv("HOME"); if (! EMPTYSTRING(cp)) localhome = ftp_strdup(cp); pw = NULL; cp = getlogin(); if (cp != NULL) pw = getpwnam(cp); if (pw == NULL) pw = getpwuid(getuid()); if (pw != NULL) { if (localhome == NULL && !EMPTYSTRING(pw->pw_dir)) localhome = ftp_strdup(pw->pw_dir); localname = ftp_strdup(pw->pw_name); anonuser = localname; } if (netrc[0] == '\0' && localhome != NULL) { if (strlcpy(netrc, localhome, sizeof(netrc)) >= sizeof(netrc) || strlcat(netrc, "/.netrc", sizeof(netrc)) >= sizeof(netrc)) { warnx("%s/.netrc: %s", localhome, strerror(ENAMETOOLONG)); netrc[0] = '\0'; } } if (localhome == NULL) localhome = ftp_strdup("/"); /* * Every anonymous FTP server I've encountered will accept the * string "username@", and will append the hostname itself. We * do this by default since many servers are picky about not * having a FQDN in the anonymous password. * - [email protected] */ len = strlen(anonuser) + 2; anonpass = ftp_malloc(len); (void)strlcpy(anonpass, anonuser, len); (void)strlcat(anonpass, "@", len); /* * set all the defaults for options defined in * struct option optiontab[] declared in cmdtab.c */ setupoption("anonpass", getenv("FTPANONPASS"), anonpass); setupoption("ftp_proxy", getenv(FTP_PROXY), ""); setupoption("http_proxy", getenv(HTTP_PROXY), ""); setupoption("no_proxy", getenv(NO_PROXY), ""); setupoption("pager", getenv("PAGER"), DEFAULTPAGER); setupoption("prompt", getenv("FTPPROMPT"), DEFAULTPROMPT); setupoption("rprompt", getenv("FTPRPROMPT"), DEFAULTRPROMPT); free(anonpass); setttywidth(0); #ifdef SIGINFO (void)xsignal(SIGINFO, psummary); #endif (void)xsignal(SIGQUIT, psummary); (void)xsignal(SIGUSR1, crankrate); (void)xsignal(SIGUSR2, crankrate); (void)xsignal(SIGWINCH, setttywidth); if (argc > 0) { if (isupload) { rval = auto_put(argc, argv, upload_path); sigint_or_rval_exit: if (sigint_raised) { (void)xsignal(SIGINT, SIG_DFL); raise(SIGINT); } exit(rval); } else if (strchr(argv[0], ':') != NULL && ! isipv6addr(argv[0])) { rval = auto_fetch(argc, argv); if (rval >= 0) /* -1 == connected and cd-ed */ goto sigint_or_rval_exit; } else { char *xargv[4], *user, *host; if ((rval = sigsetjmp(toplevel, 1))) goto sigint_or_rval_exit; (void)xsignal(SIGINT, intr); (void)xsignal(SIGPIPE, lostpeer); user = NULL; host = argv[0]; cp = strchr(host, '@'); if (cp) { *cp = '\0'; user = host; host = cp + 1; } /* XXX discards const */ xargv[0] = (char *)getprogname(); xargv[1] = host; xargv[2] = argv[1]; xargv[3] = NULL; do { int oautologin; oautologin = autologin; if (user != NULL) { anonftp = 0; autologin = 0; } setpeer(argc+1, xargv); autologin = oautologin; if (connected == 1 && user != NULL) (void)ftp_login(host, user, NULL); if (!retry_connect) break; if (!connected) { macnum = 0; fprintf(ttyout, "Retrying in %d seconds...\n", retry_connect); sleep(retry_connect); } } while (!connected); retry_connect = 0; /* connected, stop hiding msgs */ } } if (isupload) usage(); #ifndef NO_EDITCOMPLETE controlediting(); #endif /* !NO_EDITCOMPLETE */ (void)sigsetjmp(toplevel, 1); (void)xsignal(SIGINT, intr); (void)xsignal(SIGPIPE, lostpeer); for (;;) cmdscanner(); }