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