110297Ssam #ifndef lint 2*11352Ssam static char sccsid[] = "@(#)main.c 4.5 (Berkeley) 03/01/83"; 310297Ssam #endif 410297Ssam 510297Ssam /* 610297Ssam * FTP User Program -- Command Interface. 710297Ssam */ 8*11352Ssam #include <sys/param.h> 910297Ssam #include <sys/socket.h> 1010297Ssam #include <sys/ioctl.h> 1110297Ssam 1210297Ssam #include <signal.h> 1310297Ssam #include <stdio.h> 1410297Ssam #include <errno.h> 1510297Ssam #include <ctype.h> 1610297Ssam #include <netdb.h> 17*11352Ssam #include <pwd.h> 1810297Ssam 1910297Ssam #include "ftp.h" 2010297Ssam #include "ftp_var.h" 2110297Ssam 2210297Ssam int intr(); 2310297Ssam int lostpeer(); 24*11352Ssam extern char *home; 2510297Ssam 2610297Ssam main(argc, argv) 2710297Ssam char *argv[]; 2810297Ssam { 2910297Ssam register char *cp; 3010297Ssam int top; 31*11352Ssam struct passwd *pw; 32*11352Ssam char homedir[MAXPATHLEN]; 3310297Ssam 3410297Ssam sp = getservbyname("ftp", "tcp"); 3510297Ssam if (sp == 0) { 3610297Ssam fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); 3710297Ssam exit(1); 3810297Ssam } 3911351Ssam doglob = 1; 4011351Ssam autologin = 1; 4110297Ssam argc--, argv++; 4210297Ssam while (argc > 0 && **argv == '-') { 4310297Ssam for (cp = *argv + 1; *cp; cp++) 4410297Ssam switch (*cp) { 4510297Ssam 4610297Ssam case 'd': 4710297Ssam options |= SO_DEBUG; 4810297Ssam debug++; 4910297Ssam break; 5010297Ssam 5110297Ssam case 'v': 5210297Ssam verbose++; 5310297Ssam break; 5410297Ssam 5510297Ssam case 't': 5610297Ssam trace++; 5710297Ssam break; 5810297Ssam 5910297Ssam case 'i': 6010297Ssam interactive++; 6110297Ssam break; 6210297Ssam 6310297Ssam case 'n': 6410297Ssam autologin = 0; 6510297Ssam break; 6610297Ssam 6711351Ssam case 'g': 6811351Ssam doglob = 0; 6911351Ssam break; 7011351Ssam 7110297Ssam default: 7210297Ssam fprintf(stderr, 7310297Ssam "ftp: %c: unknown option\n", *cp); 7410297Ssam exit(1); 7510297Ssam } 7610297Ssam argc--, argv++; 7710297Ssam } 7810297Ssam fromatty = isatty(fileno(stdin)); 7910297Ssam /* 8010297Ssam * Set up defaults for FTP. 8110297Ssam */ 8210297Ssam strcpy(typename, "ascii"), type = TYPE_A; 8310297Ssam strcpy(formname, "non-print"), form = FORM_N; 8410297Ssam strcpy(modename, "stream"), mode = MODE_S; 8510297Ssam strcpy(structname, "file"), stru = STRU_F; 8611227Ssam strcpy(bytename, "8"), bytesize = 8; 8710297Ssam if (fromatty) 8810297Ssam verbose++; 89*11352Ssam /* 90*11352Ssam * Set up the home directory in case we're globbing. 91*11352Ssam */ 92*11352Ssam pw = getpwnam(getlogin()); 93*11352Ssam if (pw == NULL) 94*11352Ssam pw = getpwuid(getuid()); 95*11352Ssam if (pw != NULL) { 96*11352Ssam home = homedir; 97*11352Ssam strcpy(home, pw->pw_dir); 98*11352Ssam } 9910297Ssam if (argc > 0) { 10010297Ssam if (setjmp(toplevel)) 10110297Ssam exit(0); 10210297Ssam sigset(SIGINT, intr); 10310297Ssam sigset(SIGPIPE, lostpeer); 10410297Ssam setpeer(argc + 1, argv - 1); 10510297Ssam } 10610297Ssam top = setjmp(toplevel) == 0; 10710297Ssam if (top) { 10810297Ssam sigset(SIGINT, intr); 10910297Ssam sigset(SIGPIPE, lostpeer); 11010297Ssam } 11110297Ssam for (;;) { 11210297Ssam cmdscanner(top); 11310297Ssam top = 1; 11410297Ssam } 11510297Ssam } 11610297Ssam 11710297Ssam intr() 11810297Ssam { 11910297Ssam 12010297Ssam longjmp(toplevel, 1); 12110297Ssam } 12210297Ssam 12310297Ssam lostpeer() 12410297Ssam { 12510297Ssam extern FILE *cout; 12610297Ssam extern int data; 12710297Ssam 12810297Ssam if (connected) { 12910297Ssam if (cout != NULL) { 13011239Ssam shutdown(fileno(cout), 1+1); 13110297Ssam fclose(cout); 13210297Ssam cout = NULL; 13310297Ssam } 13410297Ssam if (data >= 0) { 13511239Ssam shutdown(data, 1+1); 13610297Ssam (void) close(data); 13710297Ssam data = -1; 13810297Ssam } 13910297Ssam connected = 0; 14010297Ssam } 14110297Ssam longjmp(toplevel, 1); 14210297Ssam } 14310297Ssam 14410297Ssam char * 14510297Ssam tail(filename) 14610297Ssam char *filename; 14710297Ssam { 14810297Ssam register char *s; 14910297Ssam 15010297Ssam while (*filename) { 15110297Ssam s = rindex(filename, '/'); 15210297Ssam if (s == NULL) 15310297Ssam break; 15410297Ssam if (s[1]) 15510297Ssam return (s + 1); 15610297Ssam *s = '\0'; 15710297Ssam } 15810297Ssam return (filename); 15910297Ssam } 16010297Ssam 16110297Ssam /* 16210297Ssam * Command parser. 16310297Ssam */ 16410297Ssam cmdscanner(top) 16510297Ssam int top; 16610297Ssam { 16710297Ssam register struct cmd *c; 16810297Ssam struct cmd *getcmd(); 16910297Ssam extern struct cmd cmdtab[]; 17010297Ssam extern int help(); 17110297Ssam 17210297Ssam if (!top) 17310297Ssam putchar('\n'); 17410297Ssam for (;;) { 17510297Ssam if (fromatty) { 17610297Ssam printf("ftp> "); 17710297Ssam fflush(stdout); 17810297Ssam } 17910297Ssam if (gets(line) == 0) 18010297Ssam break; 18110297Ssam if (line[0] == 0) 18210297Ssam break; 18310297Ssam makeargv(); 18410297Ssam c = getcmd(margv[0]); 18510297Ssam if (c == (struct cmd *)-1) { 18610297Ssam printf("?Ambiguous command\n"); 18710297Ssam continue; 18810297Ssam } 18910297Ssam if (c == 0) { 19010297Ssam printf("?Invalid command\n"); 19110297Ssam continue; 19210297Ssam } 19310297Ssam (*c->c_handler)(margc, margv); 19410297Ssam if (bell && c->c_bell) 19510297Ssam putchar(CTRL(g)); 19610297Ssam if (c->c_handler != help) 19710297Ssam break; 19810297Ssam } 19910297Ssam longjmp(toplevel, 0); 20010297Ssam } 20110297Ssam 20210297Ssam struct cmd * 20310297Ssam getcmd(name) 20410297Ssam register char *name; 20510297Ssam { 20610297Ssam register char *p, *q; 20710297Ssam register struct cmd *c, *found; 20810297Ssam register int nmatches, longest; 20910297Ssam 21010297Ssam longest = 0; 21110297Ssam nmatches = 0; 21210297Ssam found = 0; 21310297Ssam for (c = cmdtab; p = c->c_name; c++) { 21410297Ssam for (q = name; *q == *p++; q++) 21510297Ssam if (*q == 0) /* exact match? */ 21610297Ssam return (c); 21710297Ssam if (!*q) { /* the name was a prefix */ 21810297Ssam if (q - name > longest) { 21910297Ssam longest = q - name; 22010297Ssam nmatches = 1; 22110297Ssam found = c; 22210297Ssam } else if (q - name == longest) 22310297Ssam nmatches++; 22410297Ssam } 22510297Ssam } 22610297Ssam if (nmatches > 1) 22710297Ssam return ((struct cmd *)-1); 22810297Ssam return (found); 22910297Ssam } 23010297Ssam 23110297Ssam /* 23210297Ssam * Slice a string up into argc/argv. 23310297Ssam */ 23410297Ssam makeargv() 23510297Ssam { 23610297Ssam char **argp; 23710297Ssam char *slurpstring(); 23810297Ssam 23910297Ssam margc = 0; 24010297Ssam argp = margv; 24110297Ssam stringbase = line; /* scan from first of buffer */ 24210297Ssam argbase = argbuf; /* store from first of buffer */ 24310297Ssam while (*argp++ = slurpstring()) 24410297Ssam margc++; 24510297Ssam } 24610297Ssam 24710297Ssam /* 24810297Ssam * Parse string into argbuf; 24910297Ssam * implemented with FSM to 25010297Ssam * handle quoting and strings 25110297Ssam */ 25210297Ssam char * 25310297Ssam slurpstring() 25410297Ssam { 25510297Ssam int got_one = 0; 25610297Ssam register char *sb = stringbase; 25710297Ssam register char *ap = argbase; 25810297Ssam char *tmp = argbase; /* will return this if token found */ 25910297Ssam 26010297Ssam S0: 26110297Ssam switch (*sb) { 26210297Ssam 26310297Ssam case '\0': 26410297Ssam goto OUT; 26510297Ssam 26610297Ssam case ' ': 26710297Ssam case '\t': 26810297Ssam sb++; goto S0; 26910297Ssam 27010297Ssam default: 27110297Ssam goto S1; 27210297Ssam } 27310297Ssam 27410297Ssam S1: 27510297Ssam switch (*sb) { 27610297Ssam 27710297Ssam case ' ': 27810297Ssam case '\t': 27910297Ssam case '\0': 28010297Ssam goto OUT; /* end of token */ 28110297Ssam 28210297Ssam case '\\': 28310297Ssam sb++; goto S2; /* slurp next character */ 28410297Ssam 28510297Ssam case '"': 28610297Ssam sb++; goto S3; /* slurp quoted string */ 28710297Ssam 28810297Ssam default: 28910297Ssam *ap++ = *sb++; /* add character to token */ 29010297Ssam got_one = 1; 29110297Ssam goto S1; 29210297Ssam } 29310297Ssam 29410297Ssam S2: 29510297Ssam switch (*sb) { 29610297Ssam 29710297Ssam case '\0': 29810297Ssam goto OUT; 29910297Ssam 30010297Ssam default: 30110297Ssam *ap++ = *sb++; 30210297Ssam got_one = 1; 30310297Ssam goto S1; 30410297Ssam } 30510297Ssam 30610297Ssam S3: 30710297Ssam switch (*sb) { 30810297Ssam 30910297Ssam case '\0': 31010297Ssam goto OUT; 31110297Ssam 31210297Ssam case '"': 31310297Ssam sb++; goto S1; 31410297Ssam 31510297Ssam default: 31610297Ssam *ap++ = *sb++; 31710297Ssam got_one = 1; 31810297Ssam goto S3; 31910297Ssam } 32010297Ssam 32110297Ssam OUT: 32210297Ssam if (got_one) 32310297Ssam *ap++ = '\0'; 32410297Ssam argbase = ap; /* update storage pointer */ 32510297Ssam stringbase = sb; /* update scan pointer */ 32610297Ssam if (got_one) 32710297Ssam return(tmp); 32810297Ssam return((char *)0); 32910297Ssam } 33010297Ssam 33110297Ssam #define HELPINDENT (sizeof ("directory")) 33210297Ssam 33310297Ssam /* 33410297Ssam * Help command. 33510297Ssam * Call each command handler with argc == 0 and argv[0] == name. 33610297Ssam */ 33710297Ssam help(argc, argv) 33810297Ssam int argc; 33910297Ssam char *argv[]; 34010297Ssam { 34110297Ssam register struct cmd *c; 34210297Ssam 34310297Ssam if (argc == 1) { 34410297Ssam register int i, j, w; 34510297Ssam int columns, width = 0, lines; 34610297Ssam extern int NCMDS; 34710297Ssam 34810297Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 34910297Ssam for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { 35010297Ssam int len = strlen(c->c_name); 35110297Ssam 35210297Ssam if (len > width) 35310297Ssam width = len; 35410297Ssam } 35510297Ssam width = (width + 8) &~ 7; 35610297Ssam columns = 80 / width; 35710297Ssam if (columns == 0) 35810297Ssam columns = 1; 35910297Ssam lines = (NCMDS + columns - 1) / columns; 36010297Ssam for (i = 0; i < lines; i++) { 36110297Ssam for (j = 0; j < columns; j++) { 36210297Ssam c = cmdtab + j * lines + i; 36310297Ssam printf("%s", c->c_name); 36410297Ssam if (c + lines >= &cmdtab[NCMDS]) { 36510297Ssam printf("\n"); 36610297Ssam break; 36710297Ssam } 36810297Ssam w = strlen(c->c_name); 36910297Ssam while (w < width) { 37010297Ssam w = (w + 8) &~ 7; 37110297Ssam putchar('\t'); 37210297Ssam } 37310297Ssam } 37410297Ssam } 37510297Ssam return; 37610297Ssam } 37710297Ssam while (--argc > 0) { 37810297Ssam register char *arg; 37910297Ssam arg = *++argv; 38010297Ssam c = getcmd(arg); 38110297Ssam if (c == (struct cmd *)-1) 38210297Ssam printf("?Ambiguous help command %s\n", arg); 38310297Ssam else if (c == (struct cmd *)0) 38410297Ssam printf("?Invalid help command %s\n", arg); 38510297Ssam else 38610297Ssam printf("%-*s\t%s\n", HELPINDENT, 38710297Ssam c->c_name, c->c_help); 38810297Ssam } 38910297Ssam } 39010297Ssam 39110297Ssam /* 39210297Ssam * Call routine with argc, argv set from args (terminated by 0). 39310297Ssam */ 39410297Ssam /* VARARGS2 */ 39510297Ssam call(routine, args) 39610297Ssam int (*routine)(); 39710297Ssam int args; 39810297Ssam { 39910297Ssam register int *argp; 40010297Ssam register int argc; 40110297Ssam 40210297Ssam for (argc = 0, argp = &args; *argp++ != 0; argc++) 40310297Ssam ; 40410297Ssam (*routine)(argc, &args); 40510297Ssam } 406