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