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