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