Annotation of src/usr.bin/ftp/main.c, Revision 1.38
1.38 ! millert 1: /* $OpenBSD: main.c,v 1.37 1997/12/17 16:03:05 millert Exp $ */
1.36 millert 2: /* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
1.5 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1985, 1989, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: static char copyright[] =
39: "@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
40: The Regents of the University of California. All rights reserved.\n";
41: #endif /* not lint */
42:
43: #ifndef lint
44: #if 0
45: static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
46: #else
1.38 ! millert 47: static char rcsid[] = "$OpenBSD: main.c,v 1.37 1997/12/17 16:03:05 millert Exp $";
1.1 deraadt 48: #endif
49: #endif /* not lint */
50:
51: /*
52: * FTP User Program -- Command Interface.
53: */
54: #include <sys/types.h>
55: #include <sys/socket.h>
56:
1.18 millert 57: #include <ctype.h>
1.1 deraadt 58: #include <err.h>
59: #include <netdb.h>
60: #include <pwd.h>
61: #include <stdio.h>
1.18 millert 62: #include <stdlib.h>
1.1 deraadt 63: #include <string.h>
64: #include <unistd.h>
65:
66: #include "ftp_var.h"
67:
1.34 millert 68: int main __P((int, char **));
69:
1.1 deraadt 70: int
71: main(argc, argv)
72: int argc;
73: char *argv[];
74: {
1.17 millert 75: struct servent *sp;
1.34 millert 76: int ch, top, rval;
77: long port;
1.1 deraadt 78: struct passwd *pw = NULL;
1.36 millert 79: char *cp, *ep, homedir[MAXPATHLEN];
1.38 ! millert 80: char *outfile = NULL;
1.28 millert 81: int dumb_terminal = 0;
1.1 deraadt 82:
83: sp = getservbyname("ftp", "tcp");
84: if (sp == 0)
1.17 millert 85: ftpport = htons(FTP_PORT); /* good fallback */
86: else
87: ftpport = sp->s_port;
88: sp = getservbyname("http", "tcp");
89: if (sp == 0)
90: httpport = htons(HTTP_PORT); /* good fallback */
91: else
92: httpport = sp->s_port;
1.36 millert 93: gateport = 0;
94: cp = getenv("FTPSERVERPORT");
95: if (cp != NULL) {
96: port = strtol(cp, &ep, 10);
97: if (port < 1 || port > USHRT_MAX || *ep != '\0')
98: warnx("bad FTPSERVERPORT port number: %s (ignored)",
99: cp);
100: else
101: gateport = htons(port);
102: }
103: if (gateport == 0) {
104: sp = getservbyname("ftpgate", "tcp");
105: if (sp == 0)
106: gateport = htons(GATE_PORT);
107: else
108: gateport = sp->s_port;
109: }
1.1 deraadt 110: doglob = 1;
111: interactive = 1;
112: autologin = 1;
1.37 millert 113: passivemode = 1;
114: activefallback = 1;
1.17 millert 115: preserve = 1;
116: verbose = 0;
117: progress = 0;
1.36 millert 118: gatemode = 0;
1.25 millert 119: #ifndef SMALL
1.22 millert 120: editing = 0;
1.28 millert 121: el = NULL;
122: hist = NULL;
1.22 millert 123: #endif
1.8 kstailey 124: mark = HASHBYTES;
1.17 millert 125: marg_sl = sl_init();
1.1 deraadt 126:
1.37 millert 127: /* Set default operation mode based on FTPMODE environment variable */
128: if ((cp = getenv("FTPMODE")) != NULL) {
129: if (strcmp(cp, "passive") == 0) {
130: passivemode = 1;
131: activefallback = 0;
132: } else if (strcmp(cp, "active") == 0) {
133: passivemode = 0;
134: activefallback = 0;
135: } else if (strcmp(cp, "gate") == 0) {
136: gatemode = 1;
137: } else if (strcmp(cp, "auto") == 0) {
138: passivemode = 1;
139: activefallback = 1;
140: } else
141: warnx("unknown FTPMODE: %s. Using defaults", cp);
142: }
143:
144: if (strcmp(__progname, "gate-ftp") == 0)
1.36 millert 145: gatemode = 1;
146: gateserver = getenv("FTPSERVER");
147: if (gateserver == NULL || *gateserver == '\0')
148: gateserver = GATE_SERVER;
149: if (gatemode) {
150: if (*gateserver == '\0') {
151: warnx(
1.37 millert 152: "Neither $FTPSERVER nor $GATE_SERVER is defined; disabling gate-ftp");
1.36 millert 153: gatemode = 0;
154: }
155: }
1.17 millert 156:
1.31 millert 157: cp = getenv("TERM");
158: dumb_terminal = (cp == NULL || !strcmp(cp, "dumb") ||
159: !strcmp(cp, "emacs") || !strcmp(cp, "su"));
1.17 millert 160: fromatty = isatty(fileno(stdin));
1.22 millert 161: if (fromatty) {
1.17 millert 162: verbose = 1; /* verbose if from a tty */
1.25 millert 163: #ifndef SMALL
1.28 millert 164: if (!dumb_terminal)
1.34 millert 165: editing = 1; /* editing mode on if tty is usable */
1.22 millert 166: #endif
167: }
1.30 deraadt 168:
169: ttyout = stdout;
1.33 millert 170: if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc())
1.34 millert 171: progress = 1; /* progress bar on if tty is usable */
1.32 deraadt 172:
1.38 ! millert 173: while ((ch = getopt(argc, argv, "Aadegino:pPr:tvV")) != -1) {
1.1 deraadt 174: switch (ch) {
1.37 millert 175: case 'A':
176: activefallback = 0;
177: passivemode = 0;
178: break;
179:
1.17 millert 180: case 'a':
181: anonftp = 1;
182: break;
183:
1.1 deraadt 184: case 'd':
185: options |= SO_DEBUG;
186: debug++;
187: break;
1.17 millert 188:
1.28 millert 189: case 'e':
190: #ifndef SMALL
1.22 millert 191: editing = 0;
192: #endif
1.21 kstailey 193: break;
194:
1.1 deraadt 195: case 'g':
196: doglob = 0;
197: break;
198:
199: case 'i':
200: interactive = 0;
201: break;
202:
203: case 'n':
204: autologin = 0;
205: break;
206:
1.38 ! millert 207: case 'o':
! 208: outfile = optarg;
! 209: if (strcmp(outfile, "-") == 0)
! 210: ttyout = stderr;
! 211: break;
! 212:
1.3 deraadt 213: case 'p':
1.17 millert 214: passivemode = 1;
1.37 millert 215: activefallback = 0;
1.3 deraadt 216: break;
217:
1.17 millert 218: case 'P':
1.36 millert 219: port = strtol(optarg, &ep, 10);
220: if (port < 1 || port > USHRT_MAX || *ep != '\0')
1.18 millert 221: warnx("bad port number: %s (ignored)", optarg);
1.17 millert 222: else
1.34 millert 223: ftpport = htons((in_port_t)port);
1.7 mickey 224: break;
225:
1.18 millert 226: case 'r':
227: if (isdigit(*optarg))
228: retry_connect = atoi(optarg);
229: else
230: errx(1, "-r requires numeric argument");
231: break;
232:
1.1 deraadt 233: case 't':
1.17 millert 234: trace = 1;
1.1 deraadt 235: break;
236:
237: case 'v':
1.17 millert 238: verbose = 1;
239: break;
240:
241: case 'V':
242: verbose = 0;
1.1 deraadt 243: break;
244:
245: default:
1.17 millert 246: usage();
1.1 deraadt 247: }
248: }
249: argc -= optind;
250: argv += optind;
251:
252: cpend = 0; /* no pending replies */
253: proxy = 0; /* proxy not active */
254: crflag = 1; /* strip c.r. on ascii gets */
255: sendport = -1; /* not using ports */
256: /*
257: * Set up the home directory in case we're globbing.
258: */
259: cp = getlogin();
260: if (cp != NULL) {
261: pw = getpwnam(cp);
262: }
263: if (pw == NULL)
264: pw = getpwuid(getuid());
265: if (pw != NULL) {
266: home = homedir;
1.18 millert 267: (void)strcpy(home, pw->pw_dir);
1.3 deraadt 268: }
1.9 michaels 269:
1.17 millert 270: setttywidth(0);
1.18 millert 271: (void)signal(SIGWINCH, setttywidth);
1.17 millert 272:
1.34 millert 273: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
274: (void)&argc;
275: (void)&argv;
276: #endif
277:
1.17 millert 278: if (argc > 0) {
279: if (strchr(argv[0], ':') != NULL) {
280: anonftp = 1; /* Handle "automatic" transfers. */
1.38 ! millert 281: rval = auto_fetch(argc, argv, outfile);
1.17 millert 282: if (rval >= 0) /* -1 == connected and cd-ed */
283: exit(rval);
284: } else {
1.3 deraadt 285: char *xargv[5];
286:
287: if (setjmp(toplevel))
288: exit(0);
1.20 millert 289: (void)signal(SIGINT, (sig_t)intr);
290: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.3 deraadt 291: xargv[0] = __progname;
1.17 millert 292: xargv[1] = argv[0];
293: xargv[2] = argv[1];
294: xargv[3] = argv[2];
295: xargv[4] = NULL;
1.18 millert 296: do {
297: setpeer(argc+1, xargv);
298: if (!retry_connect)
299: break;
300: if (!connected) {
301: macnum = 0;
1.30 deraadt 302: fputs("Retrying...\n", ttyout);
1.18 millert 303: sleep(retry_connect);
304: }
305: } while (!connected);
1.35 mickey 306: retry_connect = 0; /* connected, stop hiding msgs */
1.3 deraadt 307: }
1.1 deraadt 308: }
1.28 millert 309: #ifndef SMALL
310: controlediting();
311: #endif /* !SMALL */
1.1 deraadt 312: top = setjmp(toplevel) == 0;
313: if (top) {
1.20 millert 314: (void)signal(SIGINT, (sig_t)intr);
315: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1 deraadt 316: }
317: for (;;) {
318: cmdscanner(top);
319: top = 1;
320: }
321: }
322:
323: void
324: intr()
325: {
326:
1.17 millert 327: alarmtimer(0);
1.1 deraadt 328: longjmp(toplevel, 1);
329: }
330:
331: void
332: lostpeer()
333: {
334:
1.17 millert 335: alarmtimer(0);
1.1 deraadt 336: if (connected) {
337: if (cout != NULL) {
1.18 millert 338: (void)shutdown(fileno(cout), 1+1);
339: (void)fclose(cout);
1.1 deraadt 340: cout = NULL;
341: }
342: if (data >= 0) {
1.18 millert 343: (void)shutdown(data, 1+1);
344: (void)close(data);
1.1 deraadt 345: data = -1;
346: }
347: connected = 0;
348: }
349: pswitch(1);
350: if (connected) {
351: if (cout != NULL) {
1.18 millert 352: (void)shutdown(fileno(cout), 1+1);
353: (void)fclose(cout);
1.1 deraadt 354: cout = NULL;
355: }
356: connected = 0;
357: }
358: proxflag = 0;
359: pswitch(0);
360: }
361:
362: /*
1.17 millert 363: * Generate a prompt
364: */
1.1 deraadt 365: char *
1.17 millert 366: prompt()
1.1 deraadt 367: {
1.17 millert 368: return ("ftp> ");
1.1 deraadt 369: }
370:
371: /*
372: * Command parser.
373: */
374: void
375: cmdscanner(top)
376: int top;
377: {
378: struct cmd *c;
1.17 millert 379: int num;
1.1 deraadt 380:
1.17 millert 381: if (!top
1.25 millert 382: #ifndef SMALL
1.17 millert 383: && !editing
1.25 millert 384: #endif /* !SMALL */
1.17 millert 385: )
1.30 deraadt 386: (void)putc('\n', ttyout);
1.1 deraadt 387: for (;;) {
1.25 millert 388: #ifndef SMALL
1.17 millert 389: if (!editing) {
1.25 millert 390: #endif /* !SMALL */
1.17 millert 391: if (fromatty) {
1.30 deraadt 392: fputs(prompt(), ttyout);
393: (void)fflush(ttyout);
1.17 millert 394: }
395: if (fgets(line, sizeof(line), stdin) == NULL)
396: quit(0, 0);
397: num = strlen(line);
398: if (num == 0)
399: break;
400: if (line[--num] == '\n') {
401: if (num == 0)
402: break;
403: line[num] = '\0';
404: } else if (num == sizeof(line) - 2) {
1.30 deraadt 405: fputs("sorry, input line too long.\n", ttyout);
1.17 millert 406: while ((num = getchar()) != '\n' && num != EOF)
407: /* void */;
408: break;
409: } /* else it was a line without a newline */
1.25 millert 410: #ifndef SMALL
1.17 millert 411: } else {
412: const char *buf;
413: cursor_pos = NULL;
414:
415: if ((buf = el_gets(el, &num)) == NULL || num == 0)
416: quit(0, 0);
417: if (line[--num] == '\n') {
418: if (num == 0)
419: break;
420: } else if (num >= sizeof(line)) {
1.30 deraadt 421: fputs("sorry, input line too long.\n", ttyout);
1.1 deraadt 422: break;
1.17 millert 423: }
1.34 millert 424: memcpy(line, buf, (size_t)num);
1.17 millert 425: line[num] = '\0';
426: history(hist, H_ENTER, buf);
427: }
1.25 millert 428: #endif /* !SMALL */
1.17 millert 429:
1.1 deraadt 430: makeargv();
1.17 millert 431: if (margc == 0)
1.1 deraadt 432: continue;
433: c = getcmd(margv[0]);
434: if (c == (struct cmd *)-1) {
1.30 deraadt 435: fputs("?Ambiguous command.\n", ttyout);
1.1 deraadt 436: continue;
437: }
438: if (c == 0) {
1.25 millert 439: #ifndef SMALL
1.24 millert 440: /*
441: * Give editline(3) a shot at unknown commands.
442: * XXX - bogus commands with a colon in
443: * them will not elicit an error.
444: */
445: if (el_parse(el, margc, margv) != 0)
1.25 millert 446: #endif /* !SMALL */
1.30 deraadt 447: fputs("?Invalid command.\n", ttyout);
1.1 deraadt 448: continue;
449: }
450: if (c->c_conn && !connected) {
1.30 deraadt 451: fputs("Not connected.\n", ttyout);
1.1 deraadt 452: continue;
453: }
1.17 millert 454: confirmrest = 0;
1.1 deraadt 455: (*c->c_handler)(margc, margv);
456: if (bell && c->c_bell)
1.30 deraadt 457: (void)putc('\007', ttyout);
1.1 deraadt 458: if (c->c_handler != help)
459: break;
460: }
1.20 millert 461: (void)signal(SIGINT, (sig_t)intr);
462: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1 deraadt 463: }
464:
465: struct cmd *
466: getcmd(name)
1.17 millert 467: const char *name;
1.1 deraadt 468: {
1.17 millert 469: const char *p, *q;
1.1 deraadt 470: struct cmd *c, *found;
471: int nmatches, longest;
1.2 deraadt 472:
473: if (name == NULL)
474: return (0);
1.1 deraadt 475:
476: longest = 0;
477: nmatches = 0;
478: found = 0;
1.17 millert 479: for (c = cmdtab; (p = c->c_name) != NULL; c++) {
1.1 deraadt 480: for (q = name; *q == *p++; q++)
481: if (*q == 0) /* exact match? */
482: return (c);
483: if (!*q) { /* the name was a prefix */
484: if (q - name > longest) {
485: longest = q - name;
486: nmatches = 1;
487: found = c;
488: } else if (q - name == longest)
489: nmatches++;
490: }
491: }
492: if (nmatches > 1)
493: return ((struct cmd *)-1);
494: return (found);
495: }
496:
497: /*
498: * Slice a string up into argc/argv.
499: */
500:
501: int slrflag;
502:
503: void
504: makeargv()
505: {
1.17 millert 506: char *argp;
1.1 deraadt 507:
508: stringbase = line; /* scan from first of buffer */
509: argbase = argbuf; /* store from first of buffer */
510: slrflag = 0;
1.17 millert 511: marg_sl->sl_cur = 0; /* reset to start of marg_sl */
1.1 deraadt 512: for (margc = 0; ; margc++) {
1.17 millert 513: argp = slurpstring();
514: sl_add(marg_sl, argp);
515: if (argp == NULL)
1.1 deraadt 516: break;
517: }
1.25 millert 518: #ifndef SMALL
1.17 millert 519: if (cursor_pos == line) {
520: cursor_argc = 0;
521: cursor_argo = 0;
522: } else if (cursor_pos != NULL) {
523: cursor_argc = margc;
524: cursor_argo = strlen(margv[margc-1]);
525: }
1.25 millert 526: #endif /* !SMALL */
1.17 millert 527: }
1.1 deraadt 528:
1.25 millert 529: #ifdef SMALL
1.17 millert 530: #define INC_CHKCURSOR(x) (x)++
1.25 millert 531: #else /* !SMALL */
1.17 millert 532: #define INC_CHKCURSOR(x) { (x)++ ; \
533: if (x == cursor_pos) { \
534: cursor_argc = margc; \
535: cursor_argo = ap-argbase; \
536: cursor_pos = NULL; \
537: } }
538:
1.25 millert 539: #endif /* !SMALL */
1.1 deraadt 540:
541: /*
542: * Parse string into argbuf;
543: * implemented with FSM to
544: * handle quoting and strings
545: */
546: char *
547: slurpstring()
548: {
549: int got_one = 0;
550: char *sb = stringbase;
551: char *ap = argbase;
552: char *tmp = argbase; /* will return this if token found */
553:
554: if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
555: switch (slrflag) { /* and $ as token for macro invoke */
556: case 0:
557: slrflag++;
1.17 millert 558: INC_CHKCURSOR(stringbase);
1.1 deraadt 559: return ((*sb == '!') ? "!" : "$");
560: /* NOTREACHED */
561: case 1:
562: slrflag++;
563: altarg = stringbase;
564: break;
565: default:
566: break;
567: }
568: }
569:
570: S0:
571: switch (*sb) {
572:
573: case '\0':
574: goto OUT;
575:
576: case ' ':
577: case '\t':
1.17 millert 578: INC_CHKCURSOR(sb);
579: goto S0;
1.1 deraadt 580:
581: default:
582: switch (slrflag) {
583: case 0:
584: slrflag++;
585: break;
586: case 1:
587: slrflag++;
588: altarg = sb;
589: break;
590: default:
591: break;
592: }
593: goto S1;
594: }
595:
596: S1:
597: switch (*sb) {
598:
599: case ' ':
600: case '\t':
601: case '\0':
602: goto OUT; /* end of token */
603:
604: case '\\':
1.17 millert 605: INC_CHKCURSOR(sb);
606: goto S2; /* slurp next character */
1.1 deraadt 607:
608: case '"':
1.17 millert 609: INC_CHKCURSOR(sb);
610: goto S3; /* slurp quoted string */
1.1 deraadt 611:
612: default:
1.17 millert 613: *ap = *sb; /* add character to token */
614: ap++;
615: INC_CHKCURSOR(sb);
1.1 deraadt 616: got_one = 1;
617: goto S1;
618: }
619:
620: S2:
621: switch (*sb) {
622:
623: case '\0':
624: goto OUT;
625:
626: default:
1.17 millert 627: *ap = *sb;
628: ap++;
629: INC_CHKCURSOR(sb);
1.1 deraadt 630: got_one = 1;
631: goto S1;
632: }
633:
634: S3:
635: switch (*sb) {
636:
637: case '\0':
638: goto OUT;
639:
640: case '"':
1.17 millert 641: INC_CHKCURSOR(sb);
642: goto S1;
1.1 deraadt 643:
644: default:
1.17 millert 645: *ap = *sb;
646: ap++;
647: INC_CHKCURSOR(sb);
1.1 deraadt 648: got_one = 1;
649: goto S3;
650: }
651:
652: OUT:
653: if (got_one)
654: *ap++ = '\0';
655: argbase = ap; /* update storage pointer */
656: stringbase = sb; /* update scan pointer */
657: if (got_one) {
658: return (tmp);
659: }
660: switch (slrflag) {
661: case 0:
662: slrflag++;
663: break;
664: case 1:
665: slrflag++;
666: altarg = (char *) 0;
667: break;
668: default:
669: break;
670: }
671: return ((char *)0);
672: }
673:
674: /*
675: * Help command.
676: * Call each command handler with argc == 0 and argv[0] == name.
677: */
678: void
679: help(argc, argv)
680: int argc;
681: char *argv[];
682: {
683: struct cmd *c;
684:
685: if (argc == 1) {
1.17 millert 686: StringList *buf;
1.1 deraadt 687:
1.17 millert 688: buf = sl_init();
1.30 deraadt 689: fprintf(ttyout, "%sommands may be abbreviated. Commands are:\n\n",
1.17 millert 690: proxy ? "Proxy c" : "C");
691: for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
692: if (c->c_name && (!proxy || c->c_proxy))
693: sl_add(buf, c->c_name);
694: list_vertical(buf);
695: sl_free(buf, 0);
1.1 deraadt 696: return;
697: }
1.17 millert 698:
1.18 millert 699: #define HELPINDENT ((int) sizeof("disconnect"))
1.17 millert 700:
1.1 deraadt 701: while (--argc > 0) {
702: char *arg;
1.17 millert 703:
1.1 deraadt 704: arg = *++argv;
705: c = getcmd(arg);
706: if (c == (struct cmd *)-1)
1.30 deraadt 707: fprintf(ttyout, "?Ambiguous help command %s\n", arg);
1.1 deraadt 708: else if (c == (struct cmd *)0)
1.30 deraadt 709: fprintf(ttyout, "?Invalid help command %s\n", arg);
1.1 deraadt 710: else
1.30 deraadt 711: fprintf(ttyout, "%-*s\t%s\n", HELPINDENT,
1.1 deraadt 712: c->c_name, c->c_help);
713: }
1.17 millert 714: }
715:
716: void
717: usage()
718: {
719: (void)fprintf(stderr,
1.35 mickey 720: "usage: %s [-adeginptvV] [-r <seconds>] [host [port]]\n"
1.17 millert 721: " %s host:path[/]\n"
722: " %s ftp://host[:port]/path[/]\n"
723: " %s http://host[:port]/file\n",
724: __progname, __progname, __progname, __progname);
725: exit(1);
1.1 deraadt 726: }