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