Annotation of src/usr.bin/ftp/main.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2: * Copyright (c) 1985, 1989, 1993, 1994
! 3: * The Regents of the University of California. All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: #ifndef lint
! 35: static char copyright[] =
! 36: "@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
! 37: The Regents of the University of California. All rights reserved.\n";
! 38: #endif /* not lint */
! 39:
! 40: #ifndef lint
! 41: #if 0
! 42: static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
! 43: #else
! 44: static char rcsid[] = "$NetBSD: main.c,v 1.10 1995/09/15 00:32:33 pk Exp $";
! 45: #endif
! 46: #endif /* not lint */
! 47:
! 48: /*
! 49: * FTP User Program -- Command Interface.
! 50: */
! 51: /*#include <sys/ioctl.h>*/
! 52: #include <sys/types.h>
! 53: #include <sys/socket.h>
! 54:
! 55: #include <arpa/ftp.h>
! 56:
! 57: #include <ctype.h>
! 58: #include <err.h>
! 59: #include <netdb.h>
! 60: #include <pwd.h>
! 61: #include <signal.h>
! 62: #include <stdio.h>
! 63: #include <stdlib.h>
! 64: #include <string.h>
! 65: #include <unistd.h>
! 66:
! 67: #include "ftp_var.h"
! 68:
! 69: int
! 70: main(argc, argv)
! 71: int argc;
! 72: char *argv[];
! 73: {
! 74: int ch, top;
! 75: struct passwd *pw = NULL;
! 76: char *cp, homedir[MAXPATHLEN];
! 77:
! 78: sp = getservbyname("ftp", "tcp");
! 79: if (sp == 0)
! 80: errx(1, "ftp/tcp: unknown service");
! 81: doglob = 1;
! 82: interactive = 1;
! 83: autologin = 1;
! 84:
! 85: while ((ch = getopt(argc, argv, "dgintv")) != EOF) {
! 86: switch (ch) {
! 87: case 'd':
! 88: options |= SO_DEBUG;
! 89: debug++;
! 90: break;
! 91:
! 92: case 'g':
! 93: doglob = 0;
! 94: break;
! 95:
! 96: case 'i':
! 97: interactive = 0;
! 98: break;
! 99:
! 100: case 'n':
! 101: autologin = 0;
! 102: break;
! 103:
! 104: case 't':
! 105: trace++;
! 106: break;
! 107:
! 108: case 'v':
! 109: verbose++;
! 110: break;
! 111:
! 112: default:
! 113: (void)fprintf(stderr,
! 114: "usage: ftp [-dgintv] [host [port]]\n");
! 115: exit(1);
! 116: }
! 117: }
! 118: argc -= optind;
! 119: argv += optind;
! 120:
! 121: fromatty = isatty(fileno(stdin));
! 122: if (fromatty)
! 123: verbose++;
! 124: cpend = 0; /* no pending replies */
! 125: proxy = 0; /* proxy not active */
! 126: passivemode = 0; /* passive mode not active */
! 127: crflag = 1; /* strip c.r. on ascii gets */
! 128: sendport = -1; /* not using ports */
! 129: /*
! 130: * Set up the home directory in case we're globbing.
! 131: */
! 132: cp = getlogin();
! 133: if (cp != NULL) {
! 134: pw = getpwnam(cp);
! 135: }
! 136: if (pw == NULL)
! 137: pw = getpwuid(getuid());
! 138: if (pw != NULL) {
! 139: home = homedir;
! 140: (void) strcpy(home, pw->pw_dir);
! 141: }
! 142: if (argc > 0) {
! 143: char *xargv[5];
! 144: extern char *__progname;
! 145:
! 146: if (setjmp(toplevel))
! 147: exit(0);
! 148: (void) signal(SIGINT, intr);
! 149: (void) signal(SIGPIPE, lostpeer);
! 150: xargv[0] = __progname;
! 151: xargv[1] = argv[0];
! 152: xargv[2] = argv[1];
! 153: xargv[3] = argv[2];
! 154: xargv[4] = NULL;
! 155: setpeer(argc+1, xargv);
! 156: }
! 157: top = setjmp(toplevel) == 0;
! 158: if (top) {
! 159: (void) signal(SIGINT, intr);
! 160: (void) signal(SIGPIPE, lostpeer);
! 161: }
! 162: for (;;) {
! 163: cmdscanner(top);
! 164: top = 1;
! 165: }
! 166: }
! 167:
! 168: void
! 169: intr()
! 170: {
! 171:
! 172: longjmp(toplevel, 1);
! 173: }
! 174:
! 175: void
! 176: lostpeer()
! 177: {
! 178:
! 179: if (connected) {
! 180: if (cout != NULL) {
! 181: (void) shutdown(fileno(cout), 1+1);
! 182: (void) fclose(cout);
! 183: cout = NULL;
! 184: }
! 185: if (data >= 0) {
! 186: (void) shutdown(data, 1+1);
! 187: (void) close(data);
! 188: data = -1;
! 189: }
! 190: connected = 0;
! 191: }
! 192: pswitch(1);
! 193: if (connected) {
! 194: if (cout != NULL) {
! 195: (void) shutdown(fileno(cout), 1+1);
! 196: (void) fclose(cout);
! 197: cout = NULL;
! 198: }
! 199: connected = 0;
! 200: }
! 201: proxflag = 0;
! 202: pswitch(0);
! 203: }
! 204:
! 205: /*
! 206: char *
! 207: tail(filename)
! 208: char *filename;
! 209: {
! 210: char *s;
! 211:
! 212: while (*filename) {
! 213: s = strrchr(filename, '/');
! 214: if (s == NULL)
! 215: break;
! 216: if (s[1])
! 217: return (s + 1);
! 218: *s = '\0';
! 219: }
! 220: return (filename);
! 221: }
! 222: */
! 223:
! 224: /*
! 225: * Command parser.
! 226: */
! 227: void
! 228: cmdscanner(top)
! 229: int top;
! 230: {
! 231: struct cmd *c;
! 232: int l;
! 233:
! 234: if (!top)
! 235: (void) putchar('\n');
! 236: for (;;) {
! 237: if (fromatty) {
! 238: printf("ftp> ");
! 239: (void) fflush(stdout);
! 240: }
! 241: if (fgets(line, sizeof line, stdin) == NULL)
! 242: quit(0, 0);
! 243: l = strlen(line);
! 244: if (l == 0)
! 245: break;
! 246: if (line[--l] == '\n') {
! 247: if (l == 0)
! 248: break;
! 249: line[l] = '\0';
! 250: } else if (l == sizeof(line) - 2) {
! 251: printf("sorry, input line too long\n");
! 252: while ((l = getchar()) != '\n' && l != EOF)
! 253: /* void */;
! 254: break;
! 255: } /* else it was a line without a newline */
! 256: makeargv();
! 257: if (margc == 0) {
! 258: continue;
! 259: }
! 260: c = getcmd(margv[0]);
! 261: if (c == (struct cmd *)-1) {
! 262: printf("?Ambiguous command\n");
! 263: continue;
! 264: }
! 265: if (c == 0) {
! 266: printf("?Invalid command\n");
! 267: continue;
! 268: }
! 269: if (c->c_conn && !connected) {
! 270: printf("Not connected.\n");
! 271: continue;
! 272: }
! 273: (*c->c_handler)(margc, margv);
! 274: if (bell && c->c_bell)
! 275: (void) putchar('\007');
! 276: if (c->c_handler != help)
! 277: break;
! 278: }
! 279: (void) signal(SIGINT, intr);
! 280: (void) signal(SIGPIPE, lostpeer);
! 281: }
! 282:
! 283: struct cmd *
! 284: getcmd(name)
! 285: char *name;
! 286: {
! 287: char *p, *q;
! 288: struct cmd *c, *found;
! 289: int nmatches, longest;
! 290:
! 291: longest = 0;
! 292: nmatches = 0;
! 293: found = 0;
! 294: for (c = cmdtab; p = c->c_name; c++) {
! 295: for (q = name; *q == *p++; q++)
! 296: if (*q == 0) /* exact match? */
! 297: return (c);
! 298: if (!*q) { /* the name was a prefix */
! 299: if (q - name > longest) {
! 300: longest = q - name;
! 301: nmatches = 1;
! 302: found = c;
! 303: } else if (q - name == longest)
! 304: nmatches++;
! 305: }
! 306: }
! 307: if (nmatches > 1)
! 308: return ((struct cmd *)-1);
! 309: return (found);
! 310: }
! 311:
! 312: /*
! 313: * Slice a string up into argc/argv.
! 314: */
! 315:
! 316: int slrflag;
! 317:
! 318: void
! 319: makeargv()
! 320: {
! 321: char **argp;
! 322:
! 323: argp = margv;
! 324: stringbase = line; /* scan from first of buffer */
! 325: argbase = argbuf; /* store from first of buffer */
! 326: slrflag = 0;
! 327: for (margc = 0; ; margc++) {
! 328: /* Expand array if necessary */
! 329: if (margc == margvlen) {
! 330: margv = (margvlen == 0)
! 331: ? (char **)malloc(20 * sizeof(char *))
! 332: : (char **)realloc(margv,
! 333: (margvlen + 20)*sizeof(char *));
! 334: if (margv == NULL)
! 335: errx(1, "cannot realloc argv array");
! 336: margvlen += 20;
! 337: argp = margv + margc;
! 338: }
! 339:
! 340: if ((*argp++ = slurpstring()) == NULL)
! 341: break;
! 342: }
! 343:
! 344: }
! 345:
! 346: /*
! 347: * Parse string into argbuf;
! 348: * implemented with FSM to
! 349: * handle quoting and strings
! 350: */
! 351: char *
! 352: slurpstring()
! 353: {
! 354: int got_one = 0;
! 355: char *sb = stringbase;
! 356: char *ap = argbase;
! 357: char *tmp = argbase; /* will return this if token found */
! 358:
! 359: if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
! 360: switch (slrflag) { /* and $ as token for macro invoke */
! 361: case 0:
! 362: slrflag++;
! 363: stringbase++;
! 364: return ((*sb == '!') ? "!" : "$");
! 365: /* NOTREACHED */
! 366: case 1:
! 367: slrflag++;
! 368: altarg = stringbase;
! 369: break;
! 370: default:
! 371: break;
! 372: }
! 373: }
! 374:
! 375: S0:
! 376: switch (*sb) {
! 377:
! 378: case '\0':
! 379: goto OUT;
! 380:
! 381: case ' ':
! 382: case '\t':
! 383: sb++; goto S0;
! 384:
! 385: default:
! 386: switch (slrflag) {
! 387: case 0:
! 388: slrflag++;
! 389: break;
! 390: case 1:
! 391: slrflag++;
! 392: altarg = sb;
! 393: break;
! 394: default:
! 395: break;
! 396: }
! 397: goto S1;
! 398: }
! 399:
! 400: S1:
! 401: switch (*sb) {
! 402:
! 403: case ' ':
! 404: case '\t':
! 405: case '\0':
! 406: goto OUT; /* end of token */
! 407:
! 408: case '\\':
! 409: sb++; goto S2; /* slurp next character */
! 410:
! 411: case '"':
! 412: sb++; goto S3; /* slurp quoted string */
! 413:
! 414: default:
! 415: *ap++ = *sb++; /* add character to token */
! 416: got_one = 1;
! 417: goto S1;
! 418: }
! 419:
! 420: S2:
! 421: switch (*sb) {
! 422:
! 423: case '\0':
! 424: goto OUT;
! 425:
! 426: default:
! 427: *ap++ = *sb++;
! 428: got_one = 1;
! 429: goto S1;
! 430: }
! 431:
! 432: S3:
! 433: switch (*sb) {
! 434:
! 435: case '\0':
! 436: goto OUT;
! 437:
! 438: case '"':
! 439: sb++; goto S1;
! 440:
! 441: default:
! 442: *ap++ = *sb++;
! 443: got_one = 1;
! 444: goto S3;
! 445: }
! 446:
! 447: OUT:
! 448: if (got_one)
! 449: *ap++ = '\0';
! 450: argbase = ap; /* update storage pointer */
! 451: stringbase = sb; /* update scan pointer */
! 452: if (got_one) {
! 453: return (tmp);
! 454: }
! 455: switch (slrflag) {
! 456: case 0:
! 457: slrflag++;
! 458: break;
! 459: case 1:
! 460: slrflag++;
! 461: altarg = (char *) 0;
! 462: break;
! 463: default:
! 464: break;
! 465: }
! 466: return ((char *)0);
! 467: }
! 468:
! 469: #define HELPINDENT ((int) sizeof ("directory"))
! 470:
! 471: /*
! 472: * Help command.
! 473: * Call each command handler with argc == 0 and argv[0] == name.
! 474: */
! 475: void
! 476: help(argc, argv)
! 477: int argc;
! 478: char *argv[];
! 479: {
! 480: struct cmd *c;
! 481:
! 482: if (argc == 1) {
! 483: int i, j, w, k;
! 484: int columns, width = 0, lines;
! 485:
! 486: printf("Commands may be abbreviated. Commands are:\n\n");
! 487: for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
! 488: int len = strlen(c->c_name);
! 489:
! 490: if (len > width)
! 491: width = len;
! 492: }
! 493: width = (width + 8) &~ 7;
! 494: columns = 80 / width;
! 495: if (columns == 0)
! 496: columns = 1;
! 497: lines = (NCMDS + columns - 1) / columns;
! 498: for (i = 0; i < lines; i++) {
! 499: for (j = 0; j < columns; j++) {
! 500: c = cmdtab + j * lines + i;
! 501: if (c->c_name && (!proxy || c->c_proxy)) {
! 502: printf("%s", c->c_name);
! 503: }
! 504: else if (c->c_name) {
! 505: for (k=0; k < strlen(c->c_name); k++) {
! 506: (void) putchar(' ');
! 507: }
! 508: }
! 509: if (c + lines >= &cmdtab[NCMDS]) {
! 510: printf("\n");
! 511: break;
! 512: }
! 513: w = strlen(c->c_name);
! 514: while (w < width) {
! 515: w = (w + 8) &~ 7;
! 516: (void) putchar('\t');
! 517: }
! 518: }
! 519: }
! 520: return;
! 521: }
! 522: while (--argc > 0) {
! 523: char *arg;
! 524: arg = *++argv;
! 525: c = getcmd(arg);
! 526: if (c == (struct cmd *)-1)
! 527: printf("?Ambiguous help command %s\n", arg);
! 528: else if (c == (struct cmd *)0)
! 529: printf("?Invalid help command %s\n", arg);
! 530: else
! 531: printf("%-*s\t%s\n", HELPINDENT,
! 532: c->c_name, c->c_help);
! 533: }
! 534: }