1*9219Ssam /* main.c 4.3 82/11/14 */ 27769Ssam 37769Ssam /* 47769Ssam * TFTP User Program -- Command Interface. 57769Ssam */ 67769Ssam #include <sys/types.h> 77769Ssam #include <sys/socket.h> 8*9219Ssam 9*9219Ssam #include <netinet/in.h> 10*9219Ssam 117769Ssam #include <signal.h> 127769Ssam #include <stdio.h> 137769Ssam #include <errno.h> 147769Ssam #include <setjmp.h> 157769Ssam #include <ctype.h> 168384Ssam #include <netdb.h> 177769Ssam 18*9219Ssam struct sockaddr_in sin; 197769Ssam int f; 207769Ssam int trace; 217769Ssam int verbose; 227769Ssam int connected; 237769Ssam char mode[32]; 247769Ssam char line[200]; 257769Ssam int margc; 267769Ssam char *margv[20]; 277769Ssam char *prompt = "tftp"; 287769Ssam jmp_buf toplevel; 297769Ssam int intr(); 308384Ssam struct servent *sp; 317769Ssam 327769Ssam int quit(), help(), setverbose(), settrace(), status(); 337769Ssam int get(), put(), setpeer(), setmode(); 347769Ssam 357769Ssam #define HELPINDENT (sizeof("connect")) 367769Ssam 377769Ssam struct cmd { 387769Ssam char *name; 397769Ssam char *help; 407769Ssam int (*handler)(); 417769Ssam }; 427769Ssam 437769Ssam char vhelp[] = "toggle verbose mode"; 447769Ssam char thelp[] = "toggle packet tracing"; 457769Ssam char chelp[] = "connect to remote tftp"; 467769Ssam char qhelp[] = "exit tftp"; 477769Ssam char hhelp[] = "print help information"; 487769Ssam char shelp[] = "send file"; 497769Ssam char rhelp[] = "receive file"; 507769Ssam char mhelp[] = "set file transfer mode"; 517769Ssam char sthelp[] = "show current status"; 527769Ssam 537769Ssam struct cmd cmdtab[] = { 547769Ssam { "connect", chelp, setpeer }, 557769Ssam { "mode", mhelp, setmode }, 567769Ssam { "put", shelp, put }, 577769Ssam { "get", rhelp, get }, 587769Ssam { "quit", qhelp, quit }, 597769Ssam { "verbose", vhelp, setverbose }, 607769Ssam { "trace", thelp, settrace }, 617769Ssam { "status", sthelp, status }, 627769Ssam { "?", hhelp, help }, 637769Ssam 0 647769Ssam }; 657769Ssam 667769Ssam struct cmd *getcmd(); 677769Ssam char *tail(); 687769Ssam char *index(); 697769Ssam char *rindex(); 707769Ssam 717769Ssam main(argc, argv) 727769Ssam char *argv[]; 737769Ssam { 748384Ssam sp = getservbyname("tftp", "udp"); 758384Ssam if (sp == 0) { 768384Ssam fprintf(stderr, "tftp: udp/tftp: unknown service\n"); 778384Ssam exit(1); 788384Ssam } 79*9219Ssam f = socket(0, SOCK_DGRAM, 0, 0); 807769Ssam if (f < 0) { 817769Ssam perror("socket"); 827769Ssam exit(3); 837769Ssam } 847769Ssam strcpy(mode, "netascii"); 857769Ssam if (argc > 1) { 867769Ssam if (setjmp(toplevel) != 0) 877769Ssam exit(0); 887769Ssam setpeer(argc, argv); 897769Ssam } 907769Ssam setjmp(toplevel); 917769Ssam for (;;) 927769Ssam command(1); 937769Ssam } 947769Ssam 958384Ssam char *hostname; 968384Ssam char hnamebuf[32]; 977769Ssam 987769Ssam setpeer(argc, argv) 997769Ssam int argc; 1007769Ssam char *argv[]; 1017769Ssam { 1027769Ssam register int c; 1038384Ssam struct hostent *host; 1047769Ssam 1057769Ssam if (argc < 2) { 1067769Ssam strcpy(line, "Connect "); 1077769Ssam printf("(to) "); 1087769Ssam gets(&line[strlen(line)]); 1097769Ssam makeargv(); 1107769Ssam argc = margc; 1117769Ssam argv = margv; 1127769Ssam } 1137769Ssam if (argc > 3) { 1147769Ssam printf("usage: %s host-name [port]\n", argv[0]); 1157769Ssam return; 1167769Ssam } 1178384Ssam host = gethostbyname(argv[1]); 1188384Ssam if (host) { 119*9219Ssam sin.sin_family = host->h_addrtype; 1208384Ssam bcopy(host->h_addr, &sin.sin_addr, host->h_length); 1218384Ssam hostname = host->h_name; 1228384Ssam } else { 123*9219Ssam sin.sin_family = AF_INET; 1248384Ssam sin.sin_addr.s_addr = inet_addr(argv[1]); 1258384Ssam if (sin.sin_addr.s_addr == -1) { 1268384Ssam connected = 0; 1278384Ssam printf("%s: unknown host\n", argv[1]); 1288384Ssam return; 1298384Ssam } 1308384Ssam strcpy(hnamebuf, argv[1]); 1318384Ssam hostname = hnamebuf; 1327769Ssam } 1338384Ssam sin.sin_port = sp->s_port; 1347769Ssam if (argc == 3) { 1357769Ssam sin.sin_port = atoi(argv[2]); 1367769Ssam if (sin.sin_port < 0) { 1377769Ssam printf("%s: bad port number\n", argv[2]); 1387769Ssam connected = 0; 1397769Ssam return; 1407769Ssam } 1418384Ssam } 142*9219Ssam sin.sin_port = htons((u_short)sin.sin_port); 1437769Ssam connected = 1; 1447769Ssam } 1457769Ssam 1467769Ssam struct modes { 1477769Ssam char *m_name; 1487769Ssam char *m_mode; 1497769Ssam } modes[] = { 1507769Ssam { "ascii", "netascii" }, 1517769Ssam { "binary", "octect" }, 1527769Ssam { "mail", "mail" }, 1537769Ssam { 0, 0 } 1547769Ssam }; 1557769Ssam 1567769Ssam setmode(argc, argv) 1577769Ssam char *argv[]; 1587769Ssam { 1597769Ssam register struct modes *p; 1607769Ssam 1617769Ssam if (argc > 2) { 1627769Ssam char *sep; 1637769Ssam 1647769Ssam printf("usage: %s [", argv[0]); 1657769Ssam sep = " "; 1667769Ssam for (p = modes; p->m_name; p++) { 1677769Ssam printf("%s%s", sep, p->m_name); 1687769Ssam if (*sep == ' ') 1697769Ssam sep = " | "; 1707769Ssam } 1717769Ssam printf(" ]\n"); 1727769Ssam return; 1737769Ssam } 1747769Ssam if (argc < 2) { 1757769Ssam printf("Using %s mode to transfer files.\n", mode); 1767769Ssam return; 1777769Ssam } 1787769Ssam for (p = modes; p->m_name; p++) 1797769Ssam if (strcmp(argv[1], p->m_name) == 0) 1807769Ssam break; 1817769Ssam if (p->m_name) 1827769Ssam strcpy(mode, p->m_mode); 1837769Ssam else 1847769Ssam printf("%s: unknown mode\n", argv[1]); 1857769Ssam } 1867769Ssam 1877769Ssam /* 1887769Ssam * Send file(s). 1897769Ssam */ 1907769Ssam put(argc, argv) 1917769Ssam char *argv[]; 1927769Ssam { 1937769Ssam int fd; 1947769Ssam register int n, addr; 1957769Ssam register char *cp, *targ; 1967769Ssam 1977769Ssam if (argc < 2) { 1987769Ssam strcpy(line, "send "); 1997769Ssam printf("(file) "); 2007769Ssam gets(&line[strlen(line)]); 2017769Ssam makeargv(); 2027769Ssam argc = margc; 2037769Ssam argv = margv; 2047769Ssam } 2057769Ssam if (argc < 2) { 2067769Ssam putusage(argv[0]); 2077769Ssam return; 2087769Ssam } 2097769Ssam targ = argv[argc - 1]; 2107769Ssam if (index(argv[argc - 1], ':')) { 2118384Ssam char *cp; 2128384Ssam struct hostent *hp; 2137769Ssam 2147769Ssam for (n = 1; n < argc - 1; n++) 2157769Ssam if (index(argv[n], ':')) { 2167769Ssam putusage(argv[0]); 2177769Ssam return; 2187769Ssam } 2198384Ssam cp = argv[argc - 1]; 2208384Ssam targ = index(cp, ':'); 2217769Ssam *targ++ = 0; 2228384Ssam hp = gethostbyname(cp); 2238384Ssam if (hp == 0) { 2248384Ssam printf("%s: Unknown host.\n", cp); 2257769Ssam return; 2267769Ssam } 227*9219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 2288384Ssam sin.sin_family = hp->h_addrtype; 2297769Ssam connected = 1; 2308384Ssam hostname = hp->h_name; 2317769Ssam } 2327769Ssam if (!connected) { 2337769Ssam printf("No target machine specified.\n"); 2347769Ssam return; 2357769Ssam } 2367769Ssam sigset(SIGINT, intr); 2377769Ssam if (argc < 4) { 2387769Ssam cp = argc == 2 ? tail(targ) : argv[1]; 2397769Ssam fd = open(cp); 2407769Ssam if (fd < 0) { 2417769Ssam perror(cp); 2427769Ssam return; 2437769Ssam } 2447769Ssam sendfile(fd, targ); 2457769Ssam return; 2467769Ssam } 2477769Ssam cp = index(targ, '\0'); 2487769Ssam *cp++ = '/'; 2497769Ssam for (n = 1; n < argc - 1; n++) { 2507769Ssam strcpy(cp, tail(argv[n])); 2517769Ssam fd = open(argv[n], 0); 2527769Ssam if (fd < 0) { 2537769Ssam perror(argv[n]); 2547769Ssam continue; 2557769Ssam } 2567769Ssam sendfile(fd, targ); 2577769Ssam } 2587769Ssam } 2597769Ssam 2607769Ssam putusage(s) 2617769Ssam char *s; 2627769Ssam { 2637769Ssam printf("usage: %s file ... host:target, or\n", s); 2647769Ssam printf(" %s file ... target (when already connected)\n", s); 2657769Ssam } 2667769Ssam 2677769Ssam /* 2687769Ssam * Receive file(s). 2697769Ssam */ 2707769Ssam get(argc, argv) 2717769Ssam char *argv[]; 2727769Ssam { 2737769Ssam int fd; 2747769Ssam register int n, addr; 2757769Ssam register char *cp; 2767769Ssam char *src; 2777769Ssam 2787769Ssam if (argc < 2) { 2797769Ssam strcpy(line, "get "); 2807769Ssam printf("(files) "); 2817769Ssam gets(&line[strlen(line)]); 2827769Ssam makeargv(); 2837769Ssam argc = margc; 2847769Ssam argv = margv; 2857769Ssam } 2867769Ssam if (argc < 2) { 2877769Ssam getusage(argv[0]); 2887769Ssam return; 2897769Ssam } 2907769Ssam if (!connected) 2917769Ssam for (n = 1; n < argc - 1; n++) 2927769Ssam if (index(argv[n], ':') == 0) { 2937769Ssam getusage(argv[0]); 2947769Ssam return; 2957769Ssam } 2967769Ssam sigset(SIGINT, intr); 2977769Ssam for (n = 1; argc == 2 || n < argc - 1; n++) { 2987769Ssam src = index(argv[n], ':'); 2997769Ssam if (src == NULL) 3007769Ssam src = argv[n]; 3017769Ssam else { 3028384Ssam struct hostent *hp; 3038384Ssam 3047769Ssam *src++ = 0; 3058384Ssam hp = gethostbyname(argv[n]); 3068384Ssam if (hp == 0) { 3077769Ssam printf("%s: Unknown host.\n", argv[n]); 3087769Ssam continue; 3097769Ssam } 310*9219Ssam bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 3118384Ssam sin.sin_family = hp->h_addrtype; 3127769Ssam connected = 1; 3138384Ssam hostname = hp->h_name; 3147769Ssam } 3157769Ssam if (argc < 4) { 3167769Ssam cp = argc == 3 ? argv[2] : tail(src); 3177769Ssam fd = creat(cp, 0644); 3187769Ssam if (fd < 0) { 3197769Ssam perror(cp); 3207769Ssam return; 3217769Ssam } 3227769Ssam recvfile(fd, src); 3237769Ssam break; 3247769Ssam } 3257769Ssam cp = index(argv[argc - 1], '\0'); 3267769Ssam *cp++ = '/'; 3277769Ssam strcpy(cp, tail(src)); 3287769Ssam fd = creat(src, 0644); 3297769Ssam if (fd < 0) { 3307769Ssam perror(src); 3317769Ssam continue; 3327769Ssam } 3337769Ssam recvfile(fd, src); 3347769Ssam } 3357769Ssam } 3367769Ssam 3377769Ssam getusage(s) 3387769Ssam { 3397769Ssam printf("usage: %s host:file host:file ... file, or\n", s); 3407769Ssam printf(" %s file file ... file if connected\n", s); 3417769Ssam } 3427769Ssam 3437769Ssam status(argc, argv) 3447769Ssam char *argv[]; 3457769Ssam { 3467769Ssam if (connected) 3478384Ssam printf("Connected to %s.\n", hostname); 3487769Ssam else 3497769Ssam printf("Not connected.\n"); 3507769Ssam printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 3517769Ssam verbose ? "on" : "off", trace ? "on" : "off"); 3527769Ssam } 3537769Ssam 3547769Ssam intr() 3557769Ssam { 3567769Ssam longjmp(toplevel, -1); 3577769Ssam } 3587769Ssam 3597769Ssam char * 3607769Ssam tail(filename) 3617769Ssam char *filename; 3627769Ssam { 3637769Ssam register char *s; 3647769Ssam 3657769Ssam while (*filename) { 3667769Ssam s = rindex(filename, '/'); 3677769Ssam if (s == NULL) 3687769Ssam break; 3697769Ssam if (s[1]) 3707769Ssam return (s + 1); 3717769Ssam *s = '\0'; 3727769Ssam } 3737769Ssam return (filename); 3747769Ssam } 3757769Ssam 3767769Ssam /* 3777769Ssam * Command parser. 3787769Ssam */ 3797769Ssam command(top) 3807769Ssam int top; 3817769Ssam { 3827769Ssam register struct cmd *c; 3837769Ssam 3847769Ssam if (!top) 3857769Ssam putchar('\n'); 3867769Ssam else 3877769Ssam sigset(SIGINT, SIG_DFL); 3887769Ssam for (;;) { 3897769Ssam printf("%s> ", prompt); 3907769Ssam if (gets(line) == 0) 3917769Ssam break; 3927769Ssam if (line[0] == 0) 3937769Ssam break; 3947769Ssam makeargv(); 3957769Ssam c = getcmd(margv[0]); 3967769Ssam if (c == (struct cmd *)-1) { 3977769Ssam printf("?Ambiguous command\n"); 3987769Ssam continue; 3997769Ssam } 4007769Ssam if (c == 0) { 4017769Ssam printf("?Invalid command\n"); 4027769Ssam continue; 4037769Ssam } 4047769Ssam (*c->handler)(margc, margv); 4057769Ssam if (c->handler != help) 4067769Ssam break; 4077769Ssam } 4087769Ssam longjmp(toplevel, 1); 4097769Ssam } 4107769Ssam 4117769Ssam struct cmd * 4127769Ssam getcmd(name) 4137769Ssam register char *name; 4147769Ssam { 4157769Ssam register char *p, *q; 4167769Ssam register struct cmd *c, *found; 4177769Ssam register int nmatches, longest; 4187769Ssam 4197769Ssam longest = 0; 4207769Ssam nmatches = 0; 4217769Ssam found = 0; 4227769Ssam for (c = cmdtab; p = c->name; c++) { 4237769Ssam for (q = name; *q == *p++; q++) 4247769Ssam if (*q == 0) /* exact match? */ 4257769Ssam return (c); 4267769Ssam if (!*q) { /* the name was a prefix */ 4277769Ssam if (q - name > longest) { 4287769Ssam longest = q - name; 4297769Ssam nmatches = 1; 4307769Ssam found = c; 4317769Ssam } else if (q - name == longest) 4327769Ssam nmatches++; 4337769Ssam } 4347769Ssam } 4357769Ssam if (nmatches > 1) 4367769Ssam return ((struct cmd *)-1); 4377769Ssam return (found); 4387769Ssam } 4397769Ssam 4407769Ssam /* 4417769Ssam * Slice a string up into argc/argv. 4427769Ssam */ 4437769Ssam makeargv() 4447769Ssam { 4457769Ssam register char *cp; 4467769Ssam register char **argp = margv; 4477769Ssam 4487769Ssam margc = 0; 4497769Ssam for (cp = line; *cp;) { 4507769Ssam while (isspace(*cp)) 4517769Ssam cp++; 4527769Ssam if (*cp == '\0') 4537769Ssam break; 4547769Ssam *argp++ = cp; 4557769Ssam margc += 1; 4567769Ssam while (*cp != '\0' && !isspace(*cp)) 4577769Ssam cp++; 4587769Ssam if (*cp == '\0') 4597769Ssam break; 4607769Ssam *cp++ = '\0'; 4617769Ssam } 4627769Ssam *argp++ = 0; 4637769Ssam } 4647769Ssam 4657769Ssam /*VARARGS*/ 4667769Ssam quit() 4677769Ssam { 4687769Ssam exit(0); 4697769Ssam } 4707769Ssam 4717769Ssam /* 4727769Ssam * Help command. 4737769Ssam */ 4747769Ssam help(argc, argv) 4757769Ssam int argc; 4767769Ssam char *argv[]; 4777769Ssam { 4787769Ssam register struct cmd *c; 4797769Ssam 4807769Ssam if (argc == 1) { 4817769Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 4827769Ssam for (c = cmdtab; c->name; c++) 4837769Ssam printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 4847769Ssam return; 4857769Ssam } 4867769Ssam while (--argc > 0) { 4877769Ssam register char *arg; 4887769Ssam arg = *++argv; 4897769Ssam c = getcmd(arg); 4907769Ssam if (c == (struct cmd *)-1) 4917769Ssam printf("?Ambiguous help command %s\n", arg); 4927769Ssam else if (c == (struct cmd *)0) 4937769Ssam printf("?Invalid help command %s\n", arg); 4947769Ssam else 4957769Ssam printf("%s\n", c->help); 4967769Ssam } 4977769Ssam } 4987769Ssam 4997769Ssam /* 5007769Ssam * Call routine with argc, argv set from args (terminated by 0). 5017769Ssam */ 5027769Ssam /* VARARGS2 */ 5037769Ssam call(routine, args) 5047769Ssam int (*routine)(); 5057769Ssam int args; 5067769Ssam { 5077769Ssam register int *argp; 5087769Ssam register int argc; 5097769Ssam 5107769Ssam for (argc = 0, argp = &args; *argp++ != 0; argc++) 5117769Ssam ; 5127769Ssam (*routine)(argc, &args); 5137769Ssam } 5147769Ssam 5157769Ssam /*VARARGS*/ 5167769Ssam settrace() 5177769Ssam { 5187769Ssam trace = !trace; 5197769Ssam printf("Packet tracing %s.\n", trace ? "on" : "off"); 5207769Ssam } 5217769Ssam 5227769Ssam /*VARARGS*/ 5237769Ssam setverbose() 5247769Ssam { 5257769Ssam verbose = !verbose; 5267769Ssam printf("Verbose mode %s.\n", verbose ? "on" : "off"); 5277769Ssam } 528