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