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