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