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: }