Annotation of src/usr.bin/ftp/main.c, Revision 1.59
1.59 ! fgsch 1: /* $OpenBSD: main.c,v 1.58 2004/07/20 03:50:26 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.59 ! fgsch 69: static char rcsid[] = "$OpenBSD: main.c,v 1.58 2004/07/20 03:50:26 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.59 ! fgsch 175: while ((ch = getopt(argc, argv, "46AadEegimno: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.59 ! fgsch 197: case 'E':
! 198: epsv4 = 0;
! 199: break;
! 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
1.58 deraadt 331: intr(void)
1.1 deraadt 332: {
333:
1.17 millert 334: alarmtimer(0);
1.1 deraadt 335: longjmp(toplevel, 1);
336: }
337:
338: void
1.58 deraadt 339: lostpeer(void)
1.1 deraadt 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.58 deraadt 375: prompt(void)
1.1 deraadt 376: {
1.17 millert 377: return ("ftp> ");
1.1 deraadt 378: }
379:
380: /*
381: * Command parser.
382: */
383: void
1.58 deraadt 384: cmdscanner(int top)
1.1 deraadt 385: {
386: struct cmd *c;
1.17 millert 387: int num;
1.55 otto 388: #ifndef SMALL
389: HistEvent hev;
390: #endif
1.1 deraadt 391:
1.17 millert 392: if (!top
1.25 millert 393: #ifndef SMALL
1.17 millert 394: && !editing
1.25 millert 395: #endif /* !SMALL */
1.17 millert 396: )
1.30 deraadt 397: (void)putc('\n', ttyout);
1.1 deraadt 398: for (;;) {
1.25 millert 399: #ifndef SMALL
1.17 millert 400: if (!editing) {
1.25 millert 401: #endif /* !SMALL */
1.17 millert 402: if (fromatty) {
1.30 deraadt 403: fputs(prompt(), ttyout);
404: (void)fflush(ttyout);
1.17 millert 405: }
406: if (fgets(line, sizeof(line), stdin) == NULL)
407: quit(0, 0);
408: num = strlen(line);
409: if (num == 0)
410: break;
411: if (line[--num] == '\n') {
412: if (num == 0)
413: break;
414: line[num] = '\0';
415: } else if (num == sizeof(line) - 2) {
1.30 deraadt 416: fputs("sorry, input line too long.\n", ttyout);
1.17 millert 417: while ((num = getchar()) != '\n' && num != EOF)
418: /* void */;
419: break;
420: } /* else it was a line without a newline */
1.25 millert 421: #ifndef SMALL
1.17 millert 422: } else {
423: const char *buf;
424: cursor_pos = NULL;
425:
426: if ((buf = el_gets(el, &num)) == NULL || num == 0)
427: quit(0, 0);
1.46 fgsch 428: if (buf[--num] == '\n') {
1.17 millert 429: if (num == 0)
430: break;
1.46 fgsch 431: }
432: if (num >= sizeof(line)) {
1.30 deraadt 433: fputs("sorry, input line too long.\n", ttyout);
1.1 deraadt 434: break;
1.17 millert 435: }
1.34 millert 436: memcpy(line, buf, (size_t)num);
1.17 millert 437: line[num] = '\0';
1.55 otto 438: history(hist, &hev, H_ENTER, buf);
1.17 millert 439: }
1.25 millert 440: #endif /* !SMALL */
1.17 millert 441:
1.1 deraadt 442: makeargv();
1.17 millert 443: if (margc == 0)
1.1 deraadt 444: continue;
445: c = getcmd(margv[0]);
446: if (c == (struct cmd *)-1) {
1.30 deraadt 447: fputs("?Ambiguous command.\n", ttyout);
1.1 deraadt 448: continue;
449: }
450: if (c == 0) {
1.25 millert 451: #ifndef SMALL
1.24 millert 452: /*
453: * Give editline(3) a shot at unknown commands.
454: * XXX - bogus commands with a colon in
455: * them will not elicit an error.
456: */
1.45 markus 457: if (editing &&
1.55 otto 458: el_parse(el, margc, (const char **)margv) != 0)
1.25 millert 459: #endif /* !SMALL */
1.30 deraadt 460: fputs("?Invalid command.\n", ttyout);
1.1 deraadt 461: continue;
462: }
463: if (c->c_conn && !connected) {
1.30 deraadt 464: fputs("Not connected.\n", ttyout);
1.1 deraadt 465: continue;
466: }
1.17 millert 467: confirmrest = 0;
1.1 deraadt 468: (*c->c_handler)(margc, margv);
469: if (bell && c->c_bell)
1.30 deraadt 470: (void)putc('\007', ttyout);
1.1 deraadt 471: if (c->c_handler != help)
472: break;
473: }
1.20 millert 474: (void)signal(SIGINT, (sig_t)intr);
475: (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1 deraadt 476: }
477:
478: struct cmd *
1.58 deraadt 479: getcmd(const char *name)
1.1 deraadt 480: {
1.17 millert 481: const char *p, *q;
1.1 deraadt 482: struct cmd *c, *found;
483: int nmatches, longest;
1.2 deraadt 484:
485: if (name == NULL)
486: return (0);
1.1 deraadt 487:
488: longest = 0;
489: nmatches = 0;
490: found = 0;
1.17 millert 491: for (c = cmdtab; (p = c->c_name) != NULL; c++) {
1.1 deraadt 492: for (q = name; *q == *p++; q++)
493: if (*q == 0) /* exact match? */
494: return (c);
495: if (!*q) { /* the name was a prefix */
496: if (q - name > longest) {
497: longest = q - name;
498: nmatches = 1;
499: found = c;
500: } else if (q - name == longest)
501: nmatches++;
502: }
503: }
504: if (nmatches > 1)
505: return ((struct cmd *)-1);
506: return (found);
507: }
508:
509: /*
510: * Slice a string up into argc/argv.
511: */
512:
513: int slrflag;
514:
515: void
1.58 deraadt 516: makeargv(void)
1.1 deraadt 517: {
1.17 millert 518: char *argp;
1.1 deraadt 519:
520: stringbase = line; /* scan from first of buffer */
521: argbase = argbuf; /* store from first of buffer */
522: slrflag = 0;
1.17 millert 523: marg_sl->sl_cur = 0; /* reset to start of marg_sl */
1.1 deraadt 524: for (margc = 0; ; margc++) {
1.17 millert 525: argp = slurpstring();
526: sl_add(marg_sl, argp);
527: if (argp == NULL)
1.1 deraadt 528: break;
529: }
1.25 millert 530: #ifndef SMALL
1.17 millert 531: if (cursor_pos == line) {
532: cursor_argc = 0;
533: cursor_argo = 0;
534: } else if (cursor_pos != NULL) {
535: cursor_argc = margc;
536: cursor_argo = strlen(margv[margc-1]);
537: }
1.25 millert 538: #endif /* !SMALL */
1.17 millert 539: }
1.1 deraadt 540:
1.25 millert 541: #ifdef SMALL
1.17 millert 542: #define INC_CHKCURSOR(x) (x)++
1.25 millert 543: #else /* !SMALL */
1.17 millert 544: #define INC_CHKCURSOR(x) { (x)++ ; \
545: if (x == cursor_pos) { \
546: cursor_argc = margc; \
547: cursor_argo = ap-argbase; \
548: cursor_pos = NULL; \
549: } }
550:
1.25 millert 551: #endif /* !SMALL */
1.1 deraadt 552:
553: /*
554: * Parse string into argbuf;
555: * implemented with FSM to
556: * handle quoting and strings
557: */
558: char *
1.58 deraadt 559: slurpstring(void)
1.1 deraadt 560: {
561: int got_one = 0;
562: char *sb = stringbase;
563: char *ap = argbase;
564: char *tmp = argbase; /* will return this if token found */
565:
566: if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
567: switch (slrflag) { /* and $ as token for macro invoke */
568: case 0:
569: slrflag++;
1.17 millert 570: INC_CHKCURSOR(stringbase);
1.1 deraadt 571: return ((*sb == '!') ? "!" : "$");
572: /* NOTREACHED */
573: case 1:
574: slrflag++;
575: altarg = stringbase;
576: break;
577: default:
578: break;
579: }
580: }
581:
582: S0:
583: switch (*sb) {
584:
585: case '\0':
586: goto OUT;
587:
588: case ' ':
589: case '\t':
1.17 millert 590: INC_CHKCURSOR(sb);
591: goto S0;
1.1 deraadt 592:
593: default:
594: switch (slrflag) {
595: case 0:
596: slrflag++;
597: break;
598: case 1:
599: slrflag++;
600: altarg = sb;
601: break;
602: default:
603: break;
604: }
605: goto S1;
606: }
607:
608: S1:
609: switch (*sb) {
610:
611: case ' ':
612: case '\t':
613: case '\0':
614: goto OUT; /* end of token */
615:
616: case '\\':
1.17 millert 617: INC_CHKCURSOR(sb);
618: goto S2; /* slurp next character */
1.1 deraadt 619:
620: case '"':
1.17 millert 621: INC_CHKCURSOR(sb);
622: goto S3; /* slurp quoted string */
1.1 deraadt 623:
624: default:
1.17 millert 625: *ap = *sb; /* add character to token */
626: ap++;
627: INC_CHKCURSOR(sb);
1.1 deraadt 628: got_one = 1;
629: goto S1;
630: }
631:
632: S2:
633: switch (*sb) {
634:
635: case '\0':
636: goto OUT;
637:
638: default:
1.17 millert 639: *ap = *sb;
640: ap++;
641: INC_CHKCURSOR(sb);
1.1 deraadt 642: got_one = 1;
643: goto S1;
644: }
645:
646: S3:
647: switch (*sb) {
648:
649: case '\0':
650: goto OUT;
651:
652: case '"':
1.17 millert 653: INC_CHKCURSOR(sb);
654: goto S1;
1.1 deraadt 655:
656: default:
1.17 millert 657: *ap = *sb;
658: ap++;
659: INC_CHKCURSOR(sb);
1.1 deraadt 660: got_one = 1;
661: goto S3;
662: }
663:
664: OUT:
665: if (got_one)
666: *ap++ = '\0';
667: argbase = ap; /* update storage pointer */
668: stringbase = sb; /* update scan pointer */
669: if (got_one) {
670: return (tmp);
671: }
672: switch (slrflag) {
673: case 0:
674: slrflag++;
675: break;
676: case 1:
677: slrflag++;
678: altarg = (char *) 0;
679: break;
680: default:
681: break;
682: }
683: return ((char *)0);
684: }
685:
686: /*
687: * Help command.
688: * Call each command handler with argc == 0 and argv[0] == name.
689: */
690: void
1.58 deraadt 691: help(int argc, char *argv[])
1.1 deraadt 692: {
693: struct cmd *c;
694:
695: if (argc == 1) {
1.17 millert 696: StringList *buf;
1.1 deraadt 697:
1.17 millert 698: buf = sl_init();
1.30 deraadt 699: fprintf(ttyout, "%sommands may be abbreviated. Commands are:\n\n",
1.17 millert 700: proxy ? "Proxy c" : "C");
701: for (c = cmdtab; c < &cmdtab[NCMDS]; c++)
702: if (c->c_name && (!proxy || c->c_proxy))
703: sl_add(buf, c->c_name);
704: list_vertical(buf);
705: sl_free(buf, 0);
1.1 deraadt 706: return;
707: }
1.17 millert 708:
1.18 millert 709: #define HELPINDENT ((int) sizeof("disconnect"))
1.17 millert 710:
1.1 deraadt 711: while (--argc > 0) {
712: char *arg;
1.17 millert 713:
1.1 deraadt 714: arg = *++argv;
715: c = getcmd(arg);
716: if (c == (struct cmd *)-1)
1.30 deraadt 717: fprintf(ttyout, "?Ambiguous help command %s\n", arg);
1.1 deraadt 718: else if (c == (struct cmd *)0)
1.30 deraadt 719: fprintf(ttyout, "?Invalid help command %s\n", arg);
1.1 deraadt 720: else
1.30 deraadt 721: fprintf(ttyout, "%-*s\t%s\n", HELPINDENT,
1.1 deraadt 722: c->c_name, c->c_help);
723: }
1.17 millert 724: }
725:
726: void
1.58 deraadt 727: usage(void)
1.17 millert 728: {
729: (void)fprintf(stderr,
1.59 ! fgsch 730: "usage: %s [-46AadEegimnptVv] [-P port] [-r seconds] [host [port]]\n"
1.56 jmc 731: " %s [-o output] ftp://[user:password@]host[:port]/file[/]\n"
732: " %s [-o output] http://host[:port]/file\n"
733: " %s [-o output] host:[/path/]file[/]\n",
1.17 millert 734: __progname, __progname, __progname, __progname);
735: exit(1);
1.1 deraadt 736: }