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