1 /* $NetBSD: main.c,v 1.22 2021/04/25 07:50:37 lukem Exp $ */
2 /* from NetBSD: main.c,v 1.127 2020/07/18 03:00:37 lukem Exp */
5 * Copyright (c) 1996-2015 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1985, 1989, 1993, 1994
35 * The Regents of the University of California. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * Copyright (C) 1997 and 1998 WIDE Project.
64 * All rights reserved.
66 * Redistribution and use in source and binary forms, with or without
67 * modification, are permitted provided that the following conditions
69 * 1. Redistributions of source code must retain the above copyright
70 * notice, this list of conditions and the following disclaimer.
71 * 2. Redistributions in binary form must reproduce the above copyright
72 * notice, this list of conditions and the following disclaimer in the
73 * documentation and/or other materials provided with the distribution.
74 * 3. Neither the name of the project nor the names of its contributors
75 * may be used to endorse or promote products derived from this software
76 * without specific prior written permission.
78 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95 #include <sys/cdefs.h>
97 __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\
98 The Regents of the University of California. All rights reserved.\
99 Copyright 1996-2015 The NetBSD Foundation, Inc. All rights reserved");
100 #endif /* not lint */
104 static char sccsid
[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
106 __RCSID(" NetBSD: main.c,v 1.127 2020/07/18 03:00:37 lukem Exp ");
108 #endif /* not lint */
111 * FTP User Program -- Command Interface.
113 #include <sys/types.h>
114 #include <sys/socket.h>
131 #define GLOBAL /* force GLOBAL decls in ftp_var.h to be declared */
134 #define FTP_PROXY "ftp_proxy" /* env var with FTP proxy location */
135 #define HTTP_PROXY "http_proxy" /* env var with HTTP proxy location */
136 #define HTTPS_PROXY "https_proxy" /* env var with HTTPS proxy location */
137 #define NO_PROXY "no_proxy" /* env var with list of non-proxied
138 * hosts, comma or space separated */
140 static int usage(void);
141 static int usage_help(void);
142 static void setupoption(const char *, const char *, const char *);
145 main(int volatile argc
, char **volatile argv
)
149 char *cp
, *ep
, *anonpass
, *upload_path
, *src_addr
;
150 const char *anonuser
;
151 int dumbterm
, isupload
;
155 #if defined(HAVE_SETLOCALE)
156 setlocale(LC_ALL
, "");
158 setprogname(argv
[0]);
168 cp
= getenv("FTPSERVERPORT");
172 gateport
= "ftpgate";
184 restartautofetch
= 0;
185 #ifndef NO_EDITCOMPLETE
193 rate_get_incr
= DEFAULTINCR
;
195 rate_put_incr
= DEFAULTINCR
;
208 reply_callback
= NULL
;
212 family
= AF_INET
; /* force AF_INET if no INET6 support */
216 cp
= getenv("NETRC");
217 if (cp
!= NULL
&& strlcpy(netrc
, cp
, sizeof(netrc
)) >= sizeof(netrc
))
218 errx(1, "$NETRC `%s': %s", cp
, strerror(ENAMETOOLONG
));
220 marg_sl
= ftp_sl_init();
221 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
224 /* Set default operation mode based on FTPMODE environment variable */
225 if ((cp
= getenv("FTPMODE")) != NULL
) {
226 if (strcasecmp(cp
, "passive") == 0) {
229 } else if (strcasecmp(cp
, "active") == 0) {
232 } else if (strcasecmp(cp
, "gate") == 0) {
234 } else if (strcasecmp(cp
, "auto") == 0) {
238 warnx("Unknown $FTPMODE `%s'; using defaults", cp
);
241 if (strcmp(getprogname(), "pftp") == 0) {
244 } else if (strcmp(getprogname(), "gate-ftp") == 0)
247 gateserver
= getenv("FTPSERVER");
248 if (gateserver
== NULL
|| *gateserver
== '\0')
249 gateserver
= GATE_SERVER
;
251 if (*gateserver
== '\0') {
253 "Neither $FTPSERVER nor GATE_SERVER is defined; disabling gate-ftp");
259 if (cp
== NULL
|| strcmp(cp
, "dumb") == 0)
263 fromatty
= isatty(fileno(stdin
));
265 if (isatty(fileno(ttyout
))) {
266 verbose
= 1; /* verbose if to a tty */
268 #ifndef NO_EDITCOMPLETE
269 if (fromatty
) /* editing mode on if tty is usable */
273 if (foregroundproc())
274 progress
= 1; /* progress bar on if fg */
279 while ((ch
= getopt(argc
, argv
, "?46AadefginN:o:pP:q:r:Rs:tT:u:vVx:")) != -1) {
289 warnx("INET6 support is not available; ignoring -6");
308 #ifndef NO_EDITCOMPLETE
330 if (strlcpy(netrc
, optarg
, sizeof(netrc
))
332 errx(1, "%s: %s", optarg
,
333 strerror(ENAMETOOLONG
));
337 outfile
= ftp_strdup(optarg
);
338 if (strcmp(outfile
, "-") == 0)
352 quit_time
= strtol(optarg
, &ep
, 10);
353 if (quit_time
< 1 || *ep
!= '\0')
354 errx(1, "Bad quit value: %s", optarg
);
358 retry_connect
= strtol(optarg
, &ep
, 10);
359 if (retry_connect
< 1 || *ep
!= '\0')
360 errx(1, "Bad retry value: %s", optarg
);
364 restartautofetch
= 1;
378 char *targv
[6], *oac
;
379 char cmdbuf
[MAX_C_NAME
];
381 /* look for `dir,max[,incr]' */
383 (void)strlcpy(cmdbuf
, "-T", sizeof(cmdbuf
));
384 targv
[targc
++] = cmdbuf
;
385 oac
= ftp_strdup(optarg
);
387 while ((cp
= strsep(&oac
, ",")) != NULL
) {
389 warnx("Bad throttle value `%s'",
397 if (parserate(targc
, targv
, 1) == -1) {
408 upload_path
= ftp_strdup(optarg
);
414 progress
= verbose
= 1;
418 progress
= verbose
= 0;
422 sndbuf_size
= strsuftoi(optarg
);
424 errx(1, "Bad xferbuf value: %s", optarg
);
425 rcvbuf_size
= sndbuf_size
;
435 errx(1, "unimplemented option -%c", ch
);
438 /* set line buffering on ttyout */
439 setvbuf(ttyout
, NULL
, _IOLBF
, 0);
443 cpend
= 0; /* no pending replies */
444 proxy
= 0; /* proxy not active */
445 crflag
= 1; /* strip c.r. on ascii gets */
446 sendport
= -1; /* not using ports */
448 if (src_addr
!= NULL
) {
449 struct addrinfo hints
;
452 memset(&hints
, 0, sizeof(hints
));
453 hints
.ai_family
= family
;
454 hints
.ai_socktype
= SOCK_STREAM
;
455 hints
.ai_flags
= AI_PASSIVE
;
456 error
= getaddrinfo(src_addr
, NULL
, &hints
, &bindai
);
458 errx(1, "Can't lookup `%s': %s", src_addr
,
459 (error
== EAI_SYSTEM
) ? strerror(errno
)
460 : gai_strerror(error
));
465 * Cache the user name and home directory.
469 anonuser
= "anonymous";
471 if (! EMPTYSTRING(cp
))
472 localhome
= ftp_strdup(cp
);
478 pw
= getpwuid(getuid());
480 if (localhome
== NULL
&& !EMPTYSTRING(pw
->pw_dir
))
481 localhome
= ftp_strdup(pw
->pw_dir
);
482 localname
= ftp_strdup(pw
->pw_name
);
484 if (netrc
[0] == '\0' && localhome
!= NULL
) {
485 if (strlcpy(netrc
, localhome
, sizeof(netrc
)) >= sizeof(netrc
) ||
486 strlcat(netrc
, "/.netrc", sizeof(netrc
)) >= sizeof(netrc
)) {
487 warnx("%s/.netrc: %s", localhome
,
488 strerror(ENAMETOOLONG
));
492 if (localhome
== NULL
)
493 localhome
= ftp_strdup("/");
496 * Every anonymous FTP server I've encountered will accept the
497 * string "username@", and will append the hostname itself. We
498 * do this by default since many servers are picky about not
499 * having a FQDN in the anonymous password.
500 * - thorpej@NetBSD.org
502 len
= strlen(anonuser
) + 2;
503 anonpass
= ftp_malloc(len
);
504 (void)strlcpy(anonpass
, anonuser
, len
);
505 (void)strlcat(anonpass
, "@", len
);
508 * set all the defaults for options defined in
509 * struct option optiontab[] declared in cmdtab.c
511 setupoption("anonpass", getenv("FTPANONPASS"), anonpass
);
512 setupoption("ftp_proxy", getenv(FTP_PROXY
), "");
513 setupoption("http_proxy", getenv(HTTP_PROXY
), "");
514 setupoption("https_proxy", getenv(HTTPS_PROXY
), "");
515 setupoption("no_proxy", getenv(NO_PROXY
), "");
516 setupoption("pager", getenv("PAGER"), DEFAULTPAGER
);
517 setupoption("prompt", getenv("FTPPROMPT"), DEFAULTPROMPT
);
518 setupoption("rprompt", getenv("FTPRPROMPT"), DEFAULTRPROMPT
);
524 (void)xsignal(SIGINFO
, psummary
);
526 (void)xsignal(SIGQUIT
, psummary
);
527 (void)xsignal(SIGUSR1
, crankrate
);
528 (void)xsignal(SIGUSR2
, crankrate
);
529 (void)xsignal(SIGWINCH
, setttywidth
);
533 rval
= auto_put(argc
, argv
, upload_path
);
536 (void)xsignal(SIGINT
, SIG_DFL
);
540 } else if (strchr(argv
[0], ':') != NULL
541 && ! isipv6addr(argv
[0])) {
542 rval
= auto_fetch(argc
, argv
);
543 if (rval
>= 0) /* -1 == connected and cd-ed */
544 goto sigint_or_rval_exit
;
546 char *xargv
[4], *uuser
, *host
;
547 char cmdbuf
[MAXPATHLEN
];
549 if ((rval
= sigsetjmp(toplevel
, 1)))
550 goto sigint_or_rval_exit
;
551 (void)xsignal(SIGINT
, intr
);
552 (void)xsignal(SIGPIPE
, lostpeer
);
555 cp
= strchr(host
, '@');
561 (void)strlcpy(cmdbuf
, getprogname(), sizeof(cmdbuf
));
569 oautologin
= autologin
;
574 setpeer(argc
+1, xargv
);
575 autologin
= oautologin
;
576 if (connected
== 1 && uuser
!= NULL
)
577 (void)ftp_login(host
, uuser
, NULL
);
583 "Retrying in %d seconds...\n",
585 sleep(retry_connect
);
587 } while (!connected
);
588 retry_connect
= 0; /* connected, stop hiding msgs */
595 #ifndef NO_EDITCOMPLETE
597 #endif /* !NO_EDITCOMPLETE */
599 (void)sigsetjmp(toplevel
, 1);
600 (void)xsignal(SIGINT
, intr
);
601 (void)xsignal(SIGPIPE
, lostpeer
);
612 static char **promptopt
;
613 static char buf
[MAXPATHLEN
];
615 if (promptopt
== NULL
) {
618 o
= getoption("prompt");
620 errx(1, "prompt: no such option `prompt'");
621 promptopt
= &(o
->value
);
623 formatbuf(buf
, sizeof(buf
), *promptopt
? *promptopt
: DEFAULTPROMPT
);
628 * Generate an rprompt
633 static char **rpromptopt
;
634 static char buf
[MAXPATHLEN
];
636 if (rpromptopt
== NULL
) {
639 o
= getoption("rprompt");
641 errx(1, "rprompt: no such option `rprompt'");
642 rpromptopt
= &(o
->value
);
644 formatbuf(buf
, sizeof(buf
), *rpromptopt
? *rpromptopt
: DEFAULTRPROMPT
);
656 #ifndef NO_EDITCOMPLETE
661 char cmdbuf
[MAX_C_NAME
];
664 #ifndef NO_EDITCOMPLETE
666 #endif /* !NO_EDITCOMPLETE */
668 fputs(prompt(), ttyout
);
671 fprintf(ttyout
, "%s ", p
);
673 (void)fflush(ttyout
);
674 len
= get_line(stdin
, line
, sizeof(line
), NULL
);
682 case -3: /* too long; try again */
683 fputs("Sorry, input line is too long.\n",
686 case 0: /* empty; try again */
688 default: /* all ok */
691 #ifndef NO_EDITCOMPLETE
697 buf
= el_gets(el
, &ch
);
699 if (buf
== NULL
|| num
== 0) {
704 if (num
>= sizeof(line
)) {
705 fputs("Sorry, input line is too long.\n",
709 memcpy(line
, buf
, num
);
710 if (line
[--num
] == '\n') {
715 history(hist
, &ev
, H_ENTER
, buf
);
717 #endif /* !NO_EDITCOMPLETE */
722 c
= getcmd(margv
[0]);
723 if (c
== (struct cmd
*)-1) {
724 fputs("?Ambiguous command.\n", ttyout
);
728 #if !defined(NO_EDITCOMPLETE)
730 * attempt to el_parse() unknown commands.
731 * any command containing a ':' would be parsed
732 * as "[prog:]cmd ...", and will result in a
733 * false positive if prog != "ftp", so treat
734 * such commands as invalid.
736 if (strchr(margv
[0], ':') != NULL
||
738 el_parse(el
, margc
, (void *)margv
) != 0)
739 #endif /* !NO_EDITCOMPLETE */
740 fputs("?Invalid command.\n", ttyout
);
743 if (c
->c_conn
&& !connected
) {
744 fputs("Not connected.\n", ttyout
);
748 (void)strlcpy(cmdbuf
, c
->c_name
, sizeof(cmdbuf
));
750 (*c
->c_handler
)(margc
, margv
);
751 if (bell
&& c
->c_bell
)
752 (void)putc('\007', ttyout
);
753 if (c
->c_handler
!= help
)
756 (void)xsignal(SIGINT
, intr
);
757 (void)xsignal(SIGPIPE
, lostpeer
);
761 getcmd(const char *name
)
764 struct cmd
*c
, *found
;
765 int nmatches
, longest
;
773 for (c
= cmdtab
; (p
= c
->c_name
) != NULL
; c
++) {
774 for (q
= name
; *q
== *p
++; q
++)
775 if (*q
== 0) /* exact match? */
777 if (!*q
) { /* the name was a prefix */
778 if (q
- name
> longest
) {
782 } else if (q
- name
== longest
)
787 return ((struct cmd
*)-1);
792 * Slice a string up into argc/argv.
802 stringbase
= line
; /* scan from first of buffer */
803 argbase
= argbuf
; /* store from first of buffer */
805 marg_sl
->sl_cur
= 0; /* reset to start of marg_sl */
806 for (margc
= 0; ; margc
++) {
807 argp
= slurpstring();
808 ftp_sl_add(marg_sl
, argp
);
812 #ifndef NO_EDITCOMPLETE
813 if (cursor_pos
== line
) {
816 } else if (cursor_pos
!= NULL
) {
818 cursor_argo
= strlen(margv
[margc
-1]);
820 #endif /* !NO_EDITCOMPLETE */
823 #ifdef NO_EDITCOMPLETE
824 #define INC_CHKCURSOR(x) (x)++
825 #else /* !NO_EDITCOMPLETE */
826 #define INC_CHKCURSOR(x) { (x)++ ; \
827 if (x == cursor_pos) { \
828 cursor_argc = margc; \
829 cursor_argo = ap-argbase; \
833 #endif /* !NO_EDITCOMPLETE */
836 * Parse string into argbuf;
837 * implemented with FSM to
838 * handle quoting and strings
843 static char bangstr
[2] = { '!', '\0' };
844 static char dollarstr
[2] = { '$', '\0' };
846 char *sb
= stringbase
;
848 char *tmp
= argbase
; /* will return this if token found */
850 if (*sb
== '!' || *sb
== '$') { /* recognize ! as a token for shell */
851 switch (slrflag
) { /* and $ as token for macro invoke */
854 INC_CHKCURSOR(stringbase
);
855 return ((*sb
== '!') ? bangstr
: dollarstr
);
897 goto OUT
; /* end of token */
901 goto S2
; /* slurp next character */
905 goto S3
; /* slurp quoted string */
908 *ap
= *sb
; /* add character to token */
950 argbase
= ap
; /* update storage pointer */
951 stringbase
= sb
; /* update scan pointer */
970 * Help/usage command.
971 * Call each command handler with argc == 0 and argv[0] == name.
974 help(int argc
, char *argv
[])
977 char *nargv
[1], *cmd
;
982 isusage
= (strcmp(cmd
, "usage") == 0);
983 if (argc
== 0 || (isusage
&& argc
== 1)) {
984 UPRINTF("usage: %s [command ...]\n", cmd
);
992 "%sommands may be abbreviated. Commands are:\n\n",
993 proxy
? "Proxy c" : "C");
994 for (c
= cmdtab
; (p
= c
->c_name
) != NULL
; c
++)
995 if (!proxy
|| c
->c_proxy
)
996 ftp_sl_add(buf
, ftp_strdup(p
));
1002 #define HELPINDENT ((int) sizeof("disconnect"))
1004 while (--argc
> 0) {
1006 char cmdbuf
[MAX_C_NAME
];
1010 if (c
== (struct cmd
*)-1)
1011 fprintf(ttyout
, "?Ambiguous %s command `%s'\n",
1014 fprintf(ttyout
, "?Invalid %s command `%s'\n",
1018 (void)strlcpy(cmdbuf
, c
->c_name
, sizeof(cmdbuf
));
1020 (*c
->c_handler
)(0, nargv
);
1022 fprintf(ttyout
, "%-*s\t%s\n", HELPINDENT
,
1023 c
->c_name
, c
->c_help
);
1029 getoption(const char *name
)
1036 for (c
= optiontab
; (p
= c
->name
) != NULL
; c
++) {
1037 if (strcasecmp(p
, name
) == 0)
1044 getoptionvalue(const char *name
)
1049 errx(1, "getoptionvalue: invoked with NULL name");
1050 c
= getoption(name
);
1053 errx(1, "getoptionvalue: invoked with unknown option `%s'", name
);
1058 setupoption(const char *name
, const char *value
, const char *defaultvalue
)
1060 set_option(name
, value
? value
: defaultvalue
, 0);
1064 synopsis(FILE * stream
)
1066 const char * progname
= getprogname();
1069 "usage: %s [-46AadefginpRtVv] [-N NETRC] [-o OUTPUT] [-P PORT] [-q QUITTIME]\n"
1070 " [-r RETRY] [-s SRCADDR] [-T DIR,MAX[,INC]] [-x XFERSIZE]\n"
1071 " [[USER@]HOST [PORT]]\n"
1072 " [[USER@]HOST:[PATH][/]]\n"
1074 " [ftp://[USER[:PASSWORD]@]HOST[:PORT]/PATH[/][;type=TYPE]]\n"
1075 " [http://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n"
1077 " [https://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n"
1080 " %s -u URL FILE ...\n"
1082 progname
, progname
, progname
);
1091 " -4 Only use IPv4 addresses\n"
1092 " -6 Only use IPv6 addresses\n"
1093 " -A Force active mode\n"
1094 " -a Use anonymous login\n"
1095 " -d Enable debugging\n"
1096 " -e Disable command-line editing\n"
1097 " -f Force cache reload for FTP or HTTP proxy transfers\n"
1098 " -g Disable file name globbing\n"
1099 " -i Disable interactive prompt during multiple file transfers\n"
1100 " -N NETRC Use NETRC instead of ~/.netrc\n"
1101 " -n Disable auto-login\n"
1102 " -o OUTPUT Save auto-fetched files to OUTPUT\n"
1103 " -P PORT Use port PORT\n"
1104 " -p Force passive mode\n"
1105 " -q QUITTIME Quit if connection stalls for QUITTIME seconds\n"
1106 " -R Restart non-proxy auto-fetch\n"
1107 " -r RETRY Retry failed connection attempts after RETRY seconds\n"
1108 " -s SRCADDR Use source address SRCADDR\n"
1109 " -t Enable packet tracing\n"
1110 " -T DIR,MAX[,INC]\n"
1111 " Set maximum transfer rate for direction DIR to MAX bytes/s,\n"
1112 " with optional increment INC bytes/s\n"
1113 " -u URL URL to upload file arguments to\n"
1114 " -V Disable verbose and progress\n"
1115 " -v Enable verbose and progress\n"
1116 " -x XFERSIZE Set socket send and receive size to XFERSIZE\n"
1117 " -? Display this help and exit\n"
1120 return EXIT_SUCCESS
;
1127 return EXIT_FAILURE
;