|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: * ! 17: * @(#)ftpcmd.y 5.11 (Berkeley) 6/18/88 ! 18: */ ! 19: ! 20: /* ! 21: * Grammar for FTP commands. ! 22: * See RFC 765. ! 23: */ ! 24: ! 25: %{ ! 26: ! 27: #ifndef lint ! 28: static char sccsid[] = "@(#)ftpcmd.y 5.11 (Berkeley) 6/18/88"; ! 29: #endif /* not lint */ ! 30: ! 31: #include <sys/types.h> ! 32: #include <sys/socket.h> ! 33: ! 34: #include <netinet/in.h> ! 35: ! 36: #include <arpa/ftp.h> ! 37: ! 38: #include <stdio.h> ! 39: #include <signal.h> ! 40: #include <ctype.h> ! 41: #include <pwd.h> ! 42: #include <setjmp.h> ! 43: #include <syslog.h> ! 44: ! 45: extern struct sockaddr_in data_dest; ! 46: extern int logged_in; ! 47: extern struct passwd *pw; ! 48: extern int guest; ! 49: extern int logging; ! 50: extern int type; ! 51: extern int form; ! 52: extern int debug; ! 53: extern int timeout; ! 54: extern int pdata; ! 55: extern char hostname[]; ! 56: extern char *globerr; ! 57: extern int usedefault; ! 58: extern int unique; ! 59: extern int transflag; ! 60: extern char tmpline[]; ! 61: char **glob(); ! 62: ! 63: static int cmd_type; ! 64: static int cmd_form; ! 65: static int cmd_bytesz; ! 66: char cbuf[512]; ! 67: char *fromname; ! 68: ! 69: char *index(); ! 70: %} ! 71: ! 72: %token ! 73: A B C E F I ! 74: L N P R S T ! 75: ! 76: SP CRLF COMMA STRING NUMBER ! 77: ! 78: USER PASS ACCT REIN QUIT PORT ! 79: PASV TYPE STRU MODE RETR STOR ! 80: APPE MLFL MAIL MSND MSOM MSAM ! 81: MRSQ MRCP ALLO REST RNFR RNTO ! 82: ABOR DELE CWD LIST NLST SITE ! 83: STAT HELP NOOP XMKD XRMD XPWD ! 84: XCUP STOU ! 85: ! 86: LEXERR ! 87: ! 88: %start cmd_list ! 89: ! 90: %% ! 91: ! 92: cmd_list: /* empty */ ! 93: | cmd_list cmd ! 94: = { ! 95: fromname = (char *) 0; ! 96: } ! 97: | cmd_list rcmd ! 98: ; ! 99: ! 100: cmd: USER SP username CRLF ! 101: = { ! 102: extern struct passwd *getpwnam(); ! 103: ! 104: logged_in = 0; ! 105: if (strcmp((char *) $3, "ftp") == 0 || ! 106: strcmp((char *) $3, "anonymous") == 0) { ! 107: if ((pw = getpwnam("ftp")) != NULL) { ! 108: guest = 1; ! 109: reply(331, ! 110: "Guest login ok, send ident as password."); ! 111: } ! 112: else { ! 113: reply(530, "User %s unknown.", $3); ! 114: } ! 115: } else if (checkuser((char *) $3)) { ! 116: guest = 0; ! 117: pw = getpwnam((char *) $3); ! 118: if (pw == NULL) { ! 119: reply(530, "User %s unknown.", $3); ! 120: } ! 121: else { ! 122: reply(331, "Password required for %s.", $3); ! 123: } ! 124: } else { ! 125: reply(530, "User %s access denied.", $3); ! 126: } ! 127: free((char *) $3); ! 128: } ! 129: | PASS SP password CRLF ! 130: = { ! 131: pass((char *) $3); ! 132: free((char *) $3); ! 133: } ! 134: | PORT SP host_port CRLF ! 135: = { ! 136: usedefault = 0; ! 137: if (pdata > 0) { ! 138: (void) close(pdata); ! 139: } ! 140: pdata = -1; ! 141: reply(200, "PORT command successful."); ! 142: } ! 143: | PASV CRLF ! 144: = { ! 145: passive(); ! 146: } ! 147: | TYPE SP type_code CRLF ! 148: = { ! 149: switch (cmd_type) { ! 150: ! 151: case TYPE_A: ! 152: if (cmd_form == FORM_N) { ! 153: reply(200, "Type set to A."); ! 154: type = cmd_type; ! 155: form = cmd_form; ! 156: } else ! 157: reply(504, "Form must be N."); ! 158: break; ! 159: ! 160: case TYPE_E: ! 161: reply(504, "Type E not implemented."); ! 162: break; ! 163: ! 164: case TYPE_I: ! 165: reply(200, "Type set to I."); ! 166: type = cmd_type; ! 167: break; ! 168: ! 169: case TYPE_L: ! 170: if (cmd_bytesz == 8) { ! 171: reply(200, ! 172: "Type set to L (byte size 8)."); ! 173: type = cmd_type; ! 174: } else ! 175: reply(504, "Byte size must be 8."); ! 176: } ! 177: } ! 178: | STRU SP struct_code CRLF ! 179: = { ! 180: switch ($3) { ! 181: ! 182: case STRU_F: ! 183: reply(200, "STRU F ok."); ! 184: break; ! 185: ! 186: default: ! 187: reply(504, "Unimplemented STRU type."); ! 188: } ! 189: } ! 190: | MODE SP mode_code CRLF ! 191: = { ! 192: switch ($3) { ! 193: ! 194: case MODE_S: ! 195: reply(200, "MODE S ok."); ! 196: break; ! 197: ! 198: default: ! 199: reply(502, "Unimplemented MODE type."); ! 200: } ! 201: } ! 202: | ALLO SP NUMBER CRLF ! 203: = { ! 204: reply(202, "ALLO command ignored."); ! 205: } ! 206: | RETR check_login SP pathname CRLF ! 207: = { ! 208: if ($2 && $4 != NULL) ! 209: retrieve((char *) 0, (char *) $4); ! 210: if ($4 != NULL) ! 211: free((char *) $4); ! 212: } ! 213: | STOR check_login SP pathname CRLF ! 214: = { ! 215: if ($2 && $4 != NULL) ! 216: store((char *) $4, "w"); ! 217: if ($4 != NULL) ! 218: free((char *) $4); ! 219: } ! 220: | APPE check_login SP pathname CRLF ! 221: = { ! 222: if ($2 && $4 != NULL) ! 223: store((char *) $4, "a"); ! 224: if ($4 != NULL) ! 225: free((char *) $4); ! 226: } ! 227: | NLST check_login CRLF ! 228: = { ! 229: if ($2) ! 230: retrieve("/bin/ls", ""); ! 231: } ! 232: | NLST check_login SP pathname CRLF ! 233: = { ! 234: if ($2 && $4 != NULL) ! 235: retrieve("/bin/ls %s", (char *) $4); ! 236: if ($4 != NULL) ! 237: free((char *) $4); ! 238: } ! 239: | LIST check_login CRLF ! 240: = { ! 241: if ($2) ! 242: retrieve("/bin/ls -lg", ""); ! 243: } ! 244: | LIST check_login SP pathname CRLF ! 245: = { ! 246: if ($2 && $4 != NULL) ! 247: retrieve("/bin/ls -lg %s", (char *) $4); ! 248: if ($4 != NULL) ! 249: free((char *) $4); ! 250: } ! 251: | DELE check_login SP pathname CRLF ! 252: = { ! 253: if ($2 && $4 != NULL) ! 254: delete((char *) $4); ! 255: if ($4 != NULL) ! 256: free((char *) $4); ! 257: } ! 258: | RNTO SP pathname CRLF ! 259: = { ! 260: if (fromname) { ! 261: renamecmd(fromname, (char *) $3); ! 262: free(fromname); ! 263: fromname = (char *) 0; ! 264: } else { ! 265: reply(503, "Bad sequence of commands."); ! 266: } ! 267: free((char *) $3); ! 268: } ! 269: | ABOR CRLF ! 270: = { ! 271: reply(225, "ABOR command successful."); ! 272: } ! 273: | CWD check_login CRLF ! 274: = { ! 275: if ($2) ! 276: cwd(pw->pw_dir); ! 277: } ! 278: | CWD check_login SP pathname CRLF ! 279: = { ! 280: if ($2 && $4 != NULL) ! 281: cwd((char *) $4); ! 282: if ($4 != NULL) ! 283: free((char *) $4); ! 284: } ! 285: | HELP CRLF ! 286: = { ! 287: help((char *) 0); ! 288: } ! 289: | HELP SP STRING CRLF ! 290: = { ! 291: help((char *) $3); ! 292: } ! 293: | NOOP CRLF ! 294: = { ! 295: reply(200, "NOOP command successful."); ! 296: } ! 297: | XMKD check_login SP pathname CRLF ! 298: = { ! 299: if ($2 && $4 != NULL) ! 300: makedir((char *) $4); ! 301: if ($4 != NULL) ! 302: free((char *) $4); ! 303: } ! 304: | XRMD check_login SP pathname CRLF ! 305: = { ! 306: if ($2 && $4 != NULL) ! 307: removedir((char *) $4); ! 308: if ($4 != NULL) ! 309: free((char *) $4); ! 310: } ! 311: | XPWD check_login CRLF ! 312: = { ! 313: if ($2) ! 314: pwd(); ! 315: } ! 316: | XCUP check_login CRLF ! 317: = { ! 318: if ($2) ! 319: cwd(".."); ! 320: } ! 321: | STOU check_login SP pathname CRLF ! 322: = { ! 323: if ($2 && $4 != NULL) { ! 324: unique++; ! 325: store((char *) $4, "w"); ! 326: unique = 0; ! 327: } ! 328: if ($4 != NULL) ! 329: free((char *) $4); ! 330: } ! 331: | QUIT CRLF ! 332: = { ! 333: reply(221, "Goodbye."); ! 334: dologout(0); ! 335: } ! 336: | error CRLF ! 337: = { ! 338: yyerrok; ! 339: } ! 340: ; ! 341: ! 342: rcmd: RNFR check_login SP pathname CRLF ! 343: = { ! 344: char *renamefrom(); ! 345: ! 346: if ($2 && $4) { ! 347: fromname = renamefrom((char *) $4); ! 348: if (fromname == (char *) 0 && $4) { ! 349: free((char *) $4); ! 350: } ! 351: } ! 352: } ! 353: ; ! 354: ! 355: username: STRING ! 356: ; ! 357: ! 358: password: STRING ! 359: ; ! 360: ! 361: byte_size: NUMBER ! 362: ; ! 363: ! 364: host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA ! 365: NUMBER COMMA NUMBER ! 366: = { ! 367: register char *a, *p; ! 368: ! 369: a = (char *)&data_dest.sin_addr; ! 370: a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; ! 371: p = (char *)&data_dest.sin_port; ! 372: p[0] = $9; p[1] = $11; ! 373: data_dest.sin_family = AF_INET; ! 374: } ! 375: ; ! 376: ! 377: form_code: N ! 378: = { ! 379: $$ = FORM_N; ! 380: } ! 381: | T ! 382: = { ! 383: $$ = FORM_T; ! 384: } ! 385: | C ! 386: = { ! 387: $$ = FORM_C; ! 388: } ! 389: ; ! 390: ! 391: type_code: A ! 392: = { ! 393: cmd_type = TYPE_A; ! 394: cmd_form = FORM_N; ! 395: } ! 396: | A SP form_code ! 397: = { ! 398: cmd_type = TYPE_A; ! 399: cmd_form = $3; ! 400: } ! 401: | E ! 402: = { ! 403: cmd_type = TYPE_E; ! 404: cmd_form = FORM_N; ! 405: } ! 406: | E SP form_code ! 407: = { ! 408: cmd_type = TYPE_E; ! 409: cmd_form = $3; ! 410: } ! 411: | I ! 412: = { ! 413: cmd_type = TYPE_I; ! 414: } ! 415: | L ! 416: = { ! 417: cmd_type = TYPE_L; ! 418: cmd_bytesz = 8; ! 419: } ! 420: | L SP byte_size ! 421: = { ! 422: cmd_type = TYPE_L; ! 423: cmd_bytesz = $3; ! 424: } ! 425: /* this is for a bug in the BBN ftp */ ! 426: | L byte_size ! 427: = { ! 428: cmd_type = TYPE_L; ! 429: cmd_bytesz = $2; ! 430: } ! 431: ; ! 432: ! 433: struct_code: F ! 434: = { ! 435: $$ = STRU_F; ! 436: } ! 437: | R ! 438: = { ! 439: $$ = STRU_R; ! 440: } ! 441: | P ! 442: = { ! 443: $$ = STRU_P; ! 444: } ! 445: ; ! 446: ! 447: mode_code: S ! 448: = { ! 449: $$ = MODE_S; ! 450: } ! 451: | B ! 452: = { ! 453: $$ = MODE_B; ! 454: } ! 455: | C ! 456: = { ! 457: $$ = MODE_C; ! 458: } ! 459: ; ! 460: ! 461: pathname: pathstring ! 462: = { ! 463: /* ! 464: * Problem: this production is used for all pathname ! 465: * processing, but only gives a 550 error reply. ! 466: * This is a valid reply in some cases but not in others. ! 467: */ ! 468: if ($1 && strncmp((char *) $1, "~", 1) == 0) { ! 469: $$ = (int)*glob((char *) $1); ! 470: if (globerr != NULL) { ! 471: reply(550, globerr); ! 472: $$ = NULL; ! 473: } ! 474: free((char *) $1); ! 475: } else ! 476: $$ = $1; ! 477: } ! 478: ; ! 479: ! 480: pathstring: STRING ! 481: ; ! 482: ! 483: check_login: /* empty */ ! 484: = { ! 485: if (logged_in) ! 486: $$ = 1; ! 487: else { ! 488: reply(530, "Please login with USER and PASS."); ! 489: $$ = 0; ! 490: } ! 491: } ! 492: ; ! 493: ! 494: %% ! 495: ! 496: extern jmp_buf errcatch; ! 497: ! 498: #define CMD 0 /* beginning of command */ ! 499: #define ARGS 1 /* expect miscellaneous arguments */ ! 500: #define STR1 2 /* expect SP followed by STRING */ ! 501: #define STR2 3 /* expect STRING */ ! 502: #define OSTR 4 /* optional STRING */ ! 503: ! 504: struct tab { ! 505: char *name; ! 506: short token; ! 507: short state; ! 508: short implemented; /* 1 if command is implemented */ ! 509: char *help; ! 510: }; ! 511: ! 512: struct tab cmdtab[] = { /* In order defined in RFC 765 */ ! 513: { "USER", USER, STR1, 1, "<sp> username" }, ! 514: { "PASS", PASS, STR1, 1, "<sp> password" }, ! 515: { "ACCT", ACCT, STR1, 0, "(specify account)" }, ! 516: { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, ! 517: { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, ! 518: { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, ! 519: { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, ! 520: { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, ! 521: { "STRU", STRU, ARGS, 1, "(specify file structure)" }, ! 522: { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, ! 523: { "RETR", RETR, STR1, 1, "<sp> file-name" }, ! 524: { "STOR", STOR, STR1, 1, "<sp> file-name" }, ! 525: { "APPE", APPE, STR1, 1, "<sp> file-name" }, ! 526: { "MLFL", MLFL, OSTR, 0, "(mail file)" }, ! 527: { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, ! 528: { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, ! 529: { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, ! 530: { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, ! 531: { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, ! 532: { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, ! 533: { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, ! 534: { "REST", REST, STR1, 0, "(restart command)" }, ! 535: { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, ! 536: { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, ! 537: { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, ! 538: { "DELE", DELE, STR1, 1, "<sp> file-name" }, ! 539: { "CWD", CWD, OSTR, 1, "[ <sp> directory-name]" }, ! 540: { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, ! 541: { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, ! 542: { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, ! 543: { "SITE", SITE, STR1, 0, "(get site parameters)" }, ! 544: { "STAT", STAT, OSTR, 0, "(get server status)" }, ! 545: { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, ! 546: { "NOOP", NOOP, ARGS, 1, "" }, ! 547: { "MKD", XMKD, STR1, 1, "<sp> path-name" }, ! 548: { "XMKD", XMKD, STR1, 1, "<sp> path-name" }, ! 549: { "RMD", XRMD, STR1, 1, "<sp> path-name" }, ! 550: { "XRMD", XRMD, STR1, 1, "<sp> path-name" }, ! 551: { "PWD", XPWD, ARGS, 1, "(return current directory)" }, ! 552: { "XPWD", XPWD, ARGS, 1, "(return current directory)" }, ! 553: { "CDUP", XCUP, ARGS, 1, "(change to parent directory)" }, ! 554: { "XCUP", XCUP, ARGS, 1, "(change to parent directory)" }, ! 555: { "STOU", STOU, STR1, 1, "<sp> file-name" }, ! 556: { NULL, 0, 0, 0, 0 } ! 557: }; ! 558: ! 559: struct tab * ! 560: lookup(cmd) ! 561: char *cmd; ! 562: { ! 563: register struct tab *p; ! 564: ! 565: for (p = cmdtab; p->name != NULL; p++) ! 566: if (strcmp(cmd, p->name) == 0) ! 567: return (p); ! 568: return (0); ! 569: } ! 570: ! 571: #include <arpa/telnet.h> ! 572: ! 573: /* ! 574: * getline - a hacked up version of fgets to ignore TELNET escape codes. ! 575: */ ! 576: char * ! 577: getline(s, n, iop) ! 578: char *s; ! 579: register FILE *iop; ! 580: { ! 581: register c; ! 582: register char *cs; ! 583: ! 584: cs = s; ! 585: /* tmpline may contain saved command from urgent mode interruption */ ! 586: for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { ! 587: *cs++ = tmpline[c]; ! 588: if (tmpline[c] == '\n') { ! 589: *cs++ = '\0'; ! 590: if (debug) { ! 591: syslog(LOG_DEBUG, "FTPD: command: %s", s); ! 592: } ! 593: tmpline[0] = '\0'; ! 594: return(s); ! 595: } ! 596: if (c == 0) { ! 597: tmpline[0] = '\0'; ! 598: } ! 599: } ! 600: while (--n > 0 && (c = getc(iop)) != EOF) { ! 601: c = 0377 & c; ! 602: while (c == IAC) { ! 603: switch (c = 0377 & getc(iop)) { ! 604: case WILL: ! 605: case WONT: ! 606: c = 0377 & getc(iop); ! 607: printf("%c%c%c", IAC, WONT, c); ! 608: (void) fflush(stdout); ! 609: break; ! 610: case DO: ! 611: case DONT: ! 612: c = 0377 & getc(iop); ! 613: printf("%c%c%c", IAC, DONT, c); ! 614: (void) fflush(stdout); ! 615: break; ! 616: default: ! 617: break; ! 618: } ! 619: c = 0377 & getc(iop); /* try next character */ ! 620: } ! 621: *cs++ = c; ! 622: if (c=='\n') ! 623: break; ! 624: } ! 625: if (c == EOF && cs == s) ! 626: return (NULL); ! 627: *cs++ = '\0'; ! 628: if (debug) { ! 629: syslog(LOG_DEBUG, "FTPD: command: %s", s); ! 630: } ! 631: return (s); ! 632: } ! 633: ! 634: static int ! 635: toolong() ! 636: { ! 637: time_t now; ! 638: extern char *ctime(); ! 639: extern time_t time(); ! 640: ! 641: reply(421, ! 642: "Timeout (%d seconds): closing control connection.", timeout); ! 643: (void) time(&now); ! 644: if (logging) { ! 645: syslog(LOG_INFO, ! 646: "FTPD: User %s timed out after %d seconds at %s", ! 647: (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); ! 648: } ! 649: dologout(1); ! 650: } ! 651: ! 652: yylex() ! 653: { ! 654: static int cpos, state; ! 655: register char *cp; ! 656: register struct tab *p; ! 657: int n; ! 658: char c; ! 659: ! 660: for (;;) { ! 661: switch (state) { ! 662: ! 663: case CMD: ! 664: (void) signal(SIGALRM, toolong); ! 665: (void) alarm((unsigned) timeout); ! 666: if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { ! 667: reply(221, "You could at least say goodbye."); ! 668: dologout(0); ! 669: } ! 670: (void) alarm(0); ! 671: if (index(cbuf, '\r')) { ! 672: cp = index(cbuf, '\r'); ! 673: cp[0] = '\n'; cp[1] = 0; ! 674: } ! 675: if (index(cbuf, ' ')) ! 676: cpos = index(cbuf, ' ') - cbuf; ! 677: else ! 678: cpos = index(cbuf, '\n') - cbuf; ! 679: if (cpos == 0) { ! 680: cpos = 4; ! 681: } ! 682: c = cbuf[cpos]; ! 683: cbuf[cpos] = '\0'; ! 684: upper(cbuf); ! 685: p = lookup(cbuf); ! 686: cbuf[cpos] = c; ! 687: if (p != 0) { ! 688: if (p->implemented == 0) { ! 689: nack(p->name); ! 690: longjmp(errcatch,0); ! 691: /* NOTREACHED */ ! 692: } ! 693: state = p->state; ! 694: yylval = (int) p->name; ! 695: return (p->token); ! 696: } ! 697: break; ! 698: ! 699: case OSTR: ! 700: if (cbuf[cpos] == '\n') { ! 701: state = CMD; ! 702: return (CRLF); ! 703: } ! 704: /* FALL THRU */ ! 705: ! 706: case STR1: ! 707: if (cbuf[cpos] == ' ') { ! 708: cpos++; ! 709: state = STR2; ! 710: return (SP); ! 711: } ! 712: break; ! 713: ! 714: case STR2: ! 715: cp = &cbuf[cpos]; ! 716: n = strlen(cp); ! 717: cpos += n - 1; ! 718: /* ! 719: * Make sure the string is nonempty and \n terminated. ! 720: */ ! 721: if (n > 1 && cbuf[cpos] == '\n') { ! 722: cbuf[cpos] = '\0'; ! 723: yylval = copy(cp); ! 724: cbuf[cpos] = '\n'; ! 725: state = ARGS; ! 726: return (STRING); ! 727: } ! 728: break; ! 729: ! 730: case ARGS: ! 731: if (isdigit(cbuf[cpos])) { ! 732: cp = &cbuf[cpos]; ! 733: while (isdigit(cbuf[++cpos])) ! 734: ; ! 735: c = cbuf[cpos]; ! 736: cbuf[cpos] = '\0'; ! 737: yylval = atoi(cp); ! 738: cbuf[cpos] = c; ! 739: return (NUMBER); ! 740: } ! 741: switch (cbuf[cpos++]) { ! 742: ! 743: case '\n': ! 744: state = CMD; ! 745: return (CRLF); ! 746: ! 747: case ' ': ! 748: return (SP); ! 749: ! 750: case ',': ! 751: return (COMMA); ! 752: ! 753: case 'A': ! 754: case 'a': ! 755: return (A); ! 756: ! 757: case 'B': ! 758: case 'b': ! 759: return (B); ! 760: ! 761: case 'C': ! 762: case 'c': ! 763: return (C); ! 764: ! 765: case 'E': ! 766: case 'e': ! 767: return (E); ! 768: ! 769: case 'F': ! 770: case 'f': ! 771: return (F); ! 772: ! 773: case 'I': ! 774: case 'i': ! 775: return (I); ! 776: ! 777: case 'L': ! 778: case 'l': ! 779: return (L); ! 780: ! 781: case 'N': ! 782: case 'n': ! 783: return (N); ! 784: ! 785: case 'P': ! 786: case 'p': ! 787: return (P); ! 788: ! 789: case 'R': ! 790: case 'r': ! 791: return (R); ! 792: ! 793: case 'S': ! 794: case 's': ! 795: return (S); ! 796: ! 797: case 'T': ! 798: case 't': ! 799: return (T); ! 800: ! 801: } ! 802: break; ! 803: ! 804: default: ! 805: fatal("Unknown state in scanner."); ! 806: } ! 807: yyerror((char *) 0); ! 808: state = CMD; ! 809: longjmp(errcatch,0); ! 810: } ! 811: } ! 812: ! 813: upper(s) ! 814: char *s; ! 815: { ! 816: while (*s != '\0') { ! 817: if (islower(*s)) ! 818: *s = toupper(*s); ! 819: s++; ! 820: } ! 821: } ! 822: ! 823: copy(s) ! 824: char *s; ! 825: { ! 826: char *p; ! 827: extern char *malloc(), *strcpy(); ! 828: ! 829: p = malloc((unsigned) strlen(s) + 1); ! 830: if (p == NULL) ! 831: fatal("Ran out of memory."); ! 832: (void) strcpy(p, s); ! 833: return ((int)p); ! 834: } ! 835: ! 836: help(s) ! 837: char *s; ! 838: { ! 839: register struct tab *c; ! 840: register int width, NCMDS; ! 841: ! 842: width = 0, NCMDS = 0; ! 843: for (c = cmdtab; c->name != NULL; c++) { ! 844: int len = strlen(c->name) + 1; ! 845: ! 846: if (len > width) ! 847: width = len; ! 848: NCMDS++; ! 849: } ! 850: width = (width + 8) &~ 7; ! 851: if (s == 0) { ! 852: register int i, j, w; ! 853: int columns, lines; ! 854: ! 855: lreply(214, ! 856: "The following commands are recognized (* =>'s unimplemented)."); ! 857: columns = 76 / width; ! 858: if (columns == 0) ! 859: columns = 1; ! 860: lines = (NCMDS + columns - 1) / columns; ! 861: for (i = 0; i < lines; i++) { ! 862: printf(" "); ! 863: for (j = 0; j < columns; j++) { ! 864: c = cmdtab + j * lines + i; ! 865: printf("%s%c", c->name, ! 866: c->implemented ? ' ' : '*'); ! 867: if (c + lines >= &cmdtab[NCMDS]) ! 868: break; ! 869: w = strlen(c->name) + 1; ! 870: while (w < width) { ! 871: putchar(' '); ! 872: w++; ! 873: } ! 874: } ! 875: printf("\r\n"); ! 876: } ! 877: (void) fflush(stdout); ! 878: reply(214, "Direct comments to ftp-bugs@%s.", hostname); ! 879: return; ! 880: } ! 881: upper(s); ! 882: c = lookup(s); ! 883: if (c == (struct tab *)0) { ! 884: reply(502, "Unknown command %s.", s); ! 885: return; ! 886: } ! 887: if (c->implemented) ! 888: reply(214, "Syntax: %s %s", c->name, c->help); ! 889: else ! 890: reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help); ! 891: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.