|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)main.c 4.9 (Berkeley) 7/18/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * FTP User Program -- Command Interface. ! 7: */ ! 8: #include <sys/param.h> ! 9: #include <sys/socket.h> ! 10: #include <sys/ioctl.h> ! 11: ! 12: #include <arpa/ftp.h> ! 13: ! 14: #include <signal.h> ! 15: #include <stdio.h> ! 16: #include <errno.h> ! 17: #include <ctype.h> ! 18: #include <netdb.h> ! 19: #include <pwd.h> ! 20: ! 21: #include "ftp_var.h" ! 22: ! 23: int intr(); ! 24: int lostpeer(); ! 25: int firstime; ! 26: extern char *home; ! 27: ! 28: /* Changes made to this file : ! 29: (1) lostpeer() : Add printf to tell user remote host is disconneted. ! 30: ! 31: (2) when longjumping to the top level, always restore signal ! 32: handling so that future longjumping does not jump to bad frames. ! 33: ! 34: (3) makearg(): ! 35: Handle blanks & tabs in front of commands. Peter P. 07/02/85 ! 36: */ ! 37: ! 38: main(argc, argv) ! 39: char *argv[]; ! 40: { ! 41: register char *cp; ! 42: int top; ! 43: struct passwd *pw; ! 44: char homedir[MAXPATHLEN]; ! 45: ! 46: sp = getservbyname("ftp", "tcp"); ! 47: if (sp == 0) { ! 48: fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); ! 49: exit(1); ! 50: } ! 51: doglob = 1; ! 52: interactive = 1; ! 53: autologin = 1; ! 54: argc--, argv++; ! 55: while (argc > 0 && **argv == '-') { ! 56: for (cp = *argv + 1; *cp; cp++) ! 57: switch (*cp) { ! 58: ! 59: case 'd': ! 60: options |= SO_DEBUG; ! 61: debug++; ! 62: break; ! 63: ! 64: case 'v': ! 65: verbose++; ! 66: break; ! 67: ! 68: case 't': ! 69: trace++; ! 70: break; ! 71: ! 72: case 'i': ! 73: interactive = 0; ! 74: break; ! 75: ! 76: case 'n': ! 77: autologin = 0; ! 78: break; ! 79: ! 80: case 'g': ! 81: doglob = 0; ! 82: break; ! 83: ! 84: default: ! 85: fprintf(stderr, ! 86: "ftp: %c: unknown option\n", *cp); ! 87: exit(1); ! 88: } ! 89: argc--, argv++; ! 90: } ! 91: fromatty = isatty(fileno(stdin)); ! 92: /* ! 93: * Set up defaults for FTP. ! 94: */ ! 95: strcpy(typename, "ascii"), type = TYPE_A; ! 96: strcpy(formname, "non-print"), form = FORM_N; ! 97: strcpy(modename, "stream"), mode = MODE_S; ! 98: strcpy(structname, "file"), stru = STRU_F; ! 99: strcpy(bytename, "8"), bytesize = 8; ! 100: if (fromatty) ! 101: verbose++; ! 102: /* ! 103: * Set up the home directory in case we're globbing. ! 104: */ ! 105: pw = getpwnam(getlogin()); ! 106: if (pw == NULL) ! 107: pw = getpwuid(getuid()); ! 108: if (pw != NULL) { ! 109: home = homedir; ! 110: strcpy(home, pw->pw_dir); ! 111: } ! 112: if (argc > 0) { ! 113: if (setjmp(toplevel)) ! 114: exit(0); ! 115: signal(SIGINT, intr); ! 116: signal(SIGPIPE, lostpeer); ! 117: setpeer(argc + 1, argv - 1); ! 118: } ! 119: top = setjmp(toplevel) == 0; ! 120: signal(SIGINT, intr); ! 121: signal(SIGPIPE, lostpeer); ! 122: for (;;) { ! 123: firstime = YES; ! 124: cmdscanner(top); ! 125: top = 1; ! 126: } ! 127: } ! 128: ! 129: intr() ! 130: { ! 131: ! 132: longjmp(toplevel, 1); ! 133: } ! 134: ! 135: lostpeer() ! 136: { ! 137: extern FILE *cout; ! 138: extern int data; ! 139: ! 140: if (connected) { ! 141: if (cout != NULL) { ! 142: shutdown(fileno(cout), 1+1); ! 143: fclose(cout); ! 144: cout = NULL; ! 145: } ! 146: if (data >= 0) { ! 147: shutdown(data, 1+1); ! 148: (void) close(data); ! 149: data = -1; ! 150: } ! 151: connected = 0; ! 152: printf("Lost peer, %s is disconnected\n",hostname); ! 153: } ! 154: longjmp(toplevel, 1); ! 155: } ! 156: ! 157: char * ! 158: tail(filename) ! 159: char *filename; ! 160: { ! 161: register char *s; ! 162: ! 163: while (*filename) { ! 164: s = rindex(filename, '/'); ! 165: if (s == NULL) ! 166: break; ! 167: if (s[1]) ! 168: return (s + 1); ! 169: *s = '\0'; ! 170: } ! 171: return (filename); ! 172: } ! 173: ! 174: /* ! 175: * Command parser. ! 176: */ ! 177: cmdscanner(top) ! 178: int top; ! 179: { ! 180: register struct cmd *c; ! 181: struct cmd *getcmd(); ! 182: extern struct cmd cmdtab[]; ! 183: extern int help(); ! 184: ! 185: if (!top) ! 186: putchar('\n'); ! 187: for (;;) { ! 188: if (fromatty) { ! 189: printf("ftp> "); ! 190: fflush(stdout); ! 191: } ! 192: if (gets(line) == 0) { ! 193: if (feof(stdin)) { ! 194: clearerr(stdin); ! 195: putchar('\n'); ! 196: } ! 197: break; ! 198: } ! 199: if (line[0] == 0) ! 200: break; ! 201: makeargv(); ! 202: c = getcmd(margv[0]); ! 203: if (c == (struct cmd *)-1) { ! 204: printf("?Ambiguous command\n"); ! 205: continue; ! 206: } ! 207: if (c == 0) { ! 208: printf("?Invalid command\n"); ! 209: continue; ! 210: } ! 211: if (c->c_conn && !connected) { ! 212: printf ("Not connected.\n"); ! 213: continue; ! 214: } ! 215: (*c->c_handler)(margc, margv); ! 216: if (bell && c->c_bell) ! 217: putchar(CTRL(g)); ! 218: if (c->c_handler != help) ! 219: break; ! 220: } ! 221: longjmp(toplevel, 0); ! 222: } ! 223: ! 224: struct cmd * ! 225: getcmd(name) ! 226: register char *name; ! 227: { ! 228: register char *p, *q; ! 229: register struct cmd *c, *found; ! 230: register int nmatches, longest; ! 231: ! 232: longest = 0; ! 233: nmatches = 0; ! 234: found = 0; ! 235: for (c = cmdtab; p = c->c_name; c++) { ! 236: for (q = name; *q == *p++; q++) ! 237: if (*q == 0) /* exact match? */ ! 238: return (c); ! 239: if (!*q) { /* the name was a prefix */ ! 240: if (q - name > longest) { ! 241: longest = q - name; ! 242: nmatches = 1; ! 243: found = c; ! 244: } else if (q - name == longest) ! 245: nmatches++; ! 246: } ! 247: } ! 248: if (nmatches > 1) ! 249: return ((struct cmd *)-1); ! 250: return (found); ! 251: } ! 252: ! 253: /* ! 254: * Slice a string up into argc/argv. ! 255: */ ! 256: makeargv() ! 257: { ! 258: char **argp; ! 259: char *slurpstring(); ! 260: ! 261: margc = 0; ! 262: argp = margv; ! 263: stringbase = line; /* scan from first of buffer */ ! 264: argbase = argbuf; /* store from first of buffer */ ! 265: while (*stringbase == ' ' || *stringbase == '\t') ! 266: stringbase++; ! 267: if (*stringbase == '!') { ! 268: stringbase++; ! 269: *argp++ = "!"; ! 270: margc++; ! 271: while (*stringbase == ' ' || *stringbase == '\t') ! 272: stringbase++; ! 273: if (*stringbase != '\0') { ! 274: *argp++ = stringbase; ! 275: margc++; ! 276: } ! 277: *argp++ = NULL; ! 278: } else { ! 279: while (*argp++ = slurpstring()) ! 280: margc++; ! 281: } ! 282: } ! 283: ! 284: /* ! 285: * Parse string into argbuf; ! 286: * implemented with FSM to ! 287: * handle quoting and strings ! 288: */ ! 289: char * ! 290: slurpstring() ! 291: { ! 292: int got_one = 0; ! 293: register char *sb = stringbase; ! 294: register char *ap = argbase; ! 295: char *tmp = argbase; /* will return this if token found */ ! 296: ! 297: if (*sb == '!') { /* recognize ! as a token for shell */ ! 298: stringbase++; ! 299: return ("!"); ! 300: } ! 301: S0: ! 302: switch (*sb) { ! 303: ! 304: case '\0': ! 305: goto OUT; ! 306: ! 307: case ' ': ! 308: case '\t': ! 309: sb++; goto S0; ! 310: ! 311: default: ! 312: goto S1; ! 313: } ! 314: ! 315: S1: ! 316: switch (*sb) { ! 317: ! 318: case ' ': ! 319: case '\t': ! 320: case '\0': ! 321: goto OUT; /* end of token */ ! 322: ! 323: case '\\': ! 324: sb++; goto S2; /* slurp next character */ ! 325: ! 326: case '"': ! 327: sb++; goto S3; /* slurp quoted string */ ! 328: ! 329: default: ! 330: *ap++ = *sb++; /* add character to token */ ! 331: got_one = 1; ! 332: goto S1; ! 333: } ! 334: ! 335: S2: ! 336: switch (*sb) { ! 337: ! 338: case '\0': ! 339: goto OUT; ! 340: ! 341: default: ! 342: *ap++ = *sb++; ! 343: got_one = 1; ! 344: goto S1; ! 345: } ! 346: ! 347: S3: ! 348: switch (*sb) { ! 349: ! 350: case '\0': ! 351: goto OUT; ! 352: ! 353: case '"': ! 354: sb++; goto S1; ! 355: ! 356: default: ! 357: *ap++ = *sb++; ! 358: got_one = 1; ! 359: goto S3; ! 360: } ! 361: ! 362: OUT: ! 363: if (got_one) ! 364: *ap++ = '\0'; ! 365: argbase = ap; /* update storage pointer */ ! 366: stringbase = sb; /* update scan pointer */ ! 367: if (got_one) ! 368: return(tmp); ! 369: return((char *)0); ! 370: } ! 371: ! 372: #define HELPINDENT (sizeof ("directory")) ! 373: ! 374: /* ! 375: * Help command. ! 376: * Call each command handler with argc == 0 and argv[0] == name. ! 377: */ ! 378: help(argc, argv) ! 379: int argc; ! 380: char *argv[]; ! 381: { ! 382: register struct cmd *c; ! 383: ! 384: if (argc == 1) { ! 385: register int i, j, w; ! 386: int columns, width = 0, lines; ! 387: extern int NCMDS; ! 388: ! 389: printf("Commands may be abbreviated. Commands are:\n\n"); ! 390: for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { ! 391: int len = strlen(c->c_name); ! 392: ! 393: if (len > width) ! 394: width = len; ! 395: } ! 396: width = (width + 8) &~ 7; ! 397: columns = 80 / width; ! 398: if (columns == 0) ! 399: columns = 1; ! 400: lines = (NCMDS + columns - 1) / columns; ! 401: for (i = 0; i < lines; i++) { ! 402: for (j = 0; j < columns; j++) { ! 403: c = cmdtab + j * lines + i; ! 404: printf("%s", c->c_name); ! 405: if (c + lines >= &cmdtab[NCMDS]) { ! 406: printf("\n"); ! 407: break; ! 408: } ! 409: w = strlen(c->c_name); ! 410: while (w < width) { ! 411: w = (w + 8) &~ 7; ! 412: putchar('\t'); ! 413: } ! 414: } ! 415: } ! 416: return; ! 417: } ! 418: while (--argc > 0) { ! 419: register char *arg; ! 420: arg = *++argv; ! 421: c = getcmd(arg); ! 422: if (c == (struct cmd *)-1) ! 423: printf("?Ambiguous help command %s\n", arg); ! 424: else if (c == (struct cmd *)0) ! 425: printf("?Invalid help command %s\n", arg); ! 426: else ! 427: printf("%-*s\t%s\n", HELPINDENT, ! 428: c->c_name, c->c_help); ! 429: } ! 430: } ! 431: ! 432: /* ! 433: * Call routine with argc, argv set from args (terminated by 0). ! 434: */ ! 435: /* VARARGS2 */ ! 436: call(routine, args) ! 437: int (*routine)(); ! 438: int args; ! 439: { ! 440: register int *argp; ! 441: register int argc; ! 442: ! 443: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 444: ; ! 445: (*routine)(argc, &args); ! 446: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.