1*7769Ssam /* main.c 4.1 82/08/16 */ 2*7769Ssam 3*7769Ssam /* 4*7769Ssam * TFTP User Program -- Command Interface. 5*7769Ssam */ 6*7769Ssam #include <sys/types.h> 7*7769Ssam #include <net/in.h> 8*7769Ssam #include <sys/socket.h> 9*7769Ssam #include <signal.h> 10*7769Ssam #include <stdio.h> 11*7769Ssam #include <errno.h> 12*7769Ssam #include <setjmp.h> 13*7769Ssam #include <ctype.h> 14*7769Ssam 15*7769Ssam struct sockaddr_in sin = { AF_INET, IPPORT_TFTP }; 16*7769Ssam int f; 17*7769Ssam int options; 18*7769Ssam int trace; 19*7769Ssam int verbose; 20*7769Ssam int connected; 21*7769Ssam char mode[32]; 22*7769Ssam char line[200]; 23*7769Ssam int margc; 24*7769Ssam char *margv[20]; 25*7769Ssam char *prompt = "tftp"; 26*7769Ssam jmp_buf toplevel; 27*7769Ssam int intr(); 28*7769Ssam 29*7769Ssam int quit(), help(), setverbose(), settrace(), status(); 30*7769Ssam int get(), put(), setpeer(), setmode(); 31*7769Ssam 32*7769Ssam #define HELPINDENT (sizeof("connect")) 33*7769Ssam 34*7769Ssam struct cmd { 35*7769Ssam char *name; 36*7769Ssam char *help; 37*7769Ssam int (*handler)(); 38*7769Ssam }; 39*7769Ssam 40*7769Ssam char vhelp[] = "toggle verbose mode"; 41*7769Ssam char thelp[] = "toggle packet tracing"; 42*7769Ssam char chelp[] = "connect to remote tftp"; 43*7769Ssam char qhelp[] = "exit tftp"; 44*7769Ssam char hhelp[] = "print help information"; 45*7769Ssam char shelp[] = "send file"; 46*7769Ssam char rhelp[] = "receive file"; 47*7769Ssam char mhelp[] = "set file transfer mode"; 48*7769Ssam char sthelp[] = "show current status"; 49*7769Ssam 50*7769Ssam struct cmd cmdtab[] = { 51*7769Ssam { "connect", chelp, setpeer }, 52*7769Ssam { "mode", mhelp, setmode }, 53*7769Ssam { "put", shelp, put }, 54*7769Ssam { "get", rhelp, get }, 55*7769Ssam { "quit", qhelp, quit }, 56*7769Ssam { "verbose", vhelp, setverbose }, 57*7769Ssam { "trace", thelp, settrace }, 58*7769Ssam { "status", sthelp, status }, 59*7769Ssam { "?", hhelp, help }, 60*7769Ssam 0 61*7769Ssam }; 62*7769Ssam 63*7769Ssam struct cmd *getcmd(); 64*7769Ssam char *tail(); 65*7769Ssam char *index(); 66*7769Ssam char *rindex(); 67*7769Ssam 68*7769Ssam main(argc, argv) 69*7769Ssam char *argv[]; 70*7769Ssam { 71*7769Ssam register struct requestpkt *tp; 72*7769Ssam register int n; 73*7769Ssam 74*7769Ssam if (argc > 1 && !strcmp(argv[1], "-d")) { 75*7769Ssam options |= SO_DEBUG; 76*7769Ssam argc--, argv++; 77*7769Ssam } 78*7769Ssam f = socket(SOCK_DGRAM, 0, 0, options); 79*7769Ssam if (f < 0) { 80*7769Ssam perror("socket"); 81*7769Ssam exit(3); 82*7769Ssam } 83*7769Ssam #if vax || pdp11 84*7769Ssam sin.sin_port = htons(sin.sin_port); 85*7769Ssam #endif 86*7769Ssam strcpy(mode, "netascii"); 87*7769Ssam if (argc > 1) { 88*7769Ssam if (setjmp(toplevel) != 0) 89*7769Ssam exit(0); 90*7769Ssam setpeer(argc, argv); 91*7769Ssam } 92*7769Ssam setjmp(toplevel); 93*7769Ssam for (;;) 94*7769Ssam command(1); 95*7769Ssam } 96*7769Ssam 97*7769Ssam char host_name[100]; 98*7769Ssam 99*7769Ssam setpeer(argc, argv) 100*7769Ssam int argc; 101*7769Ssam char *argv[]; 102*7769Ssam { 103*7769Ssam register int c; 104*7769Ssam 105*7769Ssam if (argc < 2) { 106*7769Ssam strcpy(line, "Connect "); 107*7769Ssam printf("(to) "); 108*7769Ssam gets(&line[strlen(line)]); 109*7769Ssam makeargv(); 110*7769Ssam argc = margc; 111*7769Ssam argv = margv; 112*7769Ssam } 113*7769Ssam if (argc > 3) { 114*7769Ssam printf("usage: %s host-name [port]\n", argv[0]); 115*7769Ssam return; 116*7769Ssam } 117*7769Ssam sin.sin_addr.s_addr = rhost(&argv[1]); 118*7769Ssam if (sin.sin_addr.s_addr == (u_long)-1) { 119*7769Ssam printf("%s: unknown host\n", argv[1]); 120*7769Ssam connected = 0; 121*7769Ssam return; 122*7769Ssam } 123*7769Ssam if (argc == 3) { 124*7769Ssam sin.sin_port = atoi(argv[2]); 125*7769Ssam if (sin.sin_port < 0) { 126*7769Ssam printf("%s: bad port number\n", argv[2]); 127*7769Ssam connected = 0; 128*7769Ssam return; 129*7769Ssam } 130*7769Ssam #if vax || pdp11 131*7769Ssam sin.sin_port = htons(sin.sin_port); 132*7769Ssam #endif 133*7769Ssam } 134*7769Ssam strcpy(host_name, argv[1]); 135*7769Ssam connected = 1; 136*7769Ssam } 137*7769Ssam 138*7769Ssam struct modes { 139*7769Ssam char *m_name; 140*7769Ssam char *m_mode; 141*7769Ssam } modes[] = { 142*7769Ssam { "ascii", "netascii" }, 143*7769Ssam { "binary", "octect" }, 144*7769Ssam { "mail", "mail" }, 145*7769Ssam { 0, 0 } 146*7769Ssam }; 147*7769Ssam 148*7769Ssam setmode(argc, argv) 149*7769Ssam char *argv[]; 150*7769Ssam { 151*7769Ssam register struct modes *p; 152*7769Ssam 153*7769Ssam if (argc > 2) { 154*7769Ssam char *sep; 155*7769Ssam 156*7769Ssam printf("usage: %s [", argv[0]); 157*7769Ssam sep = " "; 158*7769Ssam for (p = modes; p->m_name; p++) { 159*7769Ssam printf("%s%s", sep, p->m_name); 160*7769Ssam if (*sep == ' ') 161*7769Ssam sep = " | "; 162*7769Ssam } 163*7769Ssam printf(" ]\n"); 164*7769Ssam return; 165*7769Ssam } 166*7769Ssam if (argc < 2) { 167*7769Ssam printf("Using %s mode to transfer files.\n", mode); 168*7769Ssam return; 169*7769Ssam } 170*7769Ssam for (p = modes; p->m_name; p++) 171*7769Ssam if (strcmp(argv[1], p->m_name) == 0) 172*7769Ssam break; 173*7769Ssam if (p->m_name) 174*7769Ssam strcpy(mode, p->m_mode); 175*7769Ssam else 176*7769Ssam printf("%s: unknown mode\n", argv[1]); 177*7769Ssam } 178*7769Ssam 179*7769Ssam /* 180*7769Ssam * Send file(s). 181*7769Ssam */ 182*7769Ssam put(argc, argv) 183*7769Ssam char *argv[]; 184*7769Ssam { 185*7769Ssam int fd; 186*7769Ssam register int n, addr; 187*7769Ssam register char *cp, *targ; 188*7769Ssam 189*7769Ssam if (argc < 2) { 190*7769Ssam strcpy(line, "send "); 191*7769Ssam printf("(file) "); 192*7769Ssam gets(&line[strlen(line)]); 193*7769Ssam makeargv(); 194*7769Ssam argc = margc; 195*7769Ssam argv = margv; 196*7769Ssam } 197*7769Ssam if (argc < 2) { 198*7769Ssam putusage(argv[0]); 199*7769Ssam return; 200*7769Ssam } 201*7769Ssam targ = argv[argc - 1]; 202*7769Ssam if (index(argv[argc - 1], ':')) { 203*7769Ssam char *hostname; 204*7769Ssam 205*7769Ssam for (n = 1; n < argc - 1; n++) 206*7769Ssam if (index(argv[n], ':')) { 207*7769Ssam putusage(argv[0]); 208*7769Ssam return; 209*7769Ssam } 210*7769Ssam hostname = argv[argc - 1]; 211*7769Ssam targ = index(hostname, ':'); 212*7769Ssam *targ++ = 0; 213*7769Ssam addr = rhost(&hostname); 214*7769Ssam if (addr == -1) { 215*7769Ssam printf("%s: Unknown host.\n", hostname); 216*7769Ssam return; 217*7769Ssam } 218*7769Ssam sin.sin_addr.s_addr = addr; 219*7769Ssam connected = 1; 220*7769Ssam strcpy(host_name, hostname); 221*7769Ssam } 222*7769Ssam if (!connected) { 223*7769Ssam printf("No target machine specified.\n"); 224*7769Ssam return; 225*7769Ssam } 226*7769Ssam sigset(SIGINT, intr); 227*7769Ssam if (argc < 4) { 228*7769Ssam cp = argc == 2 ? tail(targ) : argv[1]; 229*7769Ssam fd = open(cp); 230*7769Ssam if (fd < 0) { 231*7769Ssam perror(cp); 232*7769Ssam return; 233*7769Ssam } 234*7769Ssam sendfile(fd, targ); 235*7769Ssam return; 236*7769Ssam } 237*7769Ssam cp = index(targ, '\0'); 238*7769Ssam *cp++ = '/'; 239*7769Ssam for (n = 1; n < argc - 1; n++) { 240*7769Ssam strcpy(cp, tail(argv[n])); 241*7769Ssam fd = open(argv[n], 0); 242*7769Ssam if (fd < 0) { 243*7769Ssam perror(argv[n]); 244*7769Ssam continue; 245*7769Ssam } 246*7769Ssam sendfile(fd, targ); 247*7769Ssam } 248*7769Ssam } 249*7769Ssam 250*7769Ssam putusage(s) 251*7769Ssam char *s; 252*7769Ssam { 253*7769Ssam printf("usage: %s file ... host:target, or\n", s); 254*7769Ssam printf(" %s file ... target (when already connected)\n", s); 255*7769Ssam } 256*7769Ssam 257*7769Ssam /* 258*7769Ssam * Receive file(s). 259*7769Ssam */ 260*7769Ssam get(argc, argv) 261*7769Ssam char *argv[]; 262*7769Ssam { 263*7769Ssam int fd; 264*7769Ssam register int n, addr; 265*7769Ssam register char *cp; 266*7769Ssam char *src; 267*7769Ssam 268*7769Ssam if (argc < 2) { 269*7769Ssam strcpy(line, "get "); 270*7769Ssam printf("(files) "); 271*7769Ssam gets(&line[strlen(line)]); 272*7769Ssam makeargv(); 273*7769Ssam argc = margc; 274*7769Ssam argv = margv; 275*7769Ssam } 276*7769Ssam if (argc < 2) { 277*7769Ssam getusage(argv[0]); 278*7769Ssam return; 279*7769Ssam } 280*7769Ssam if (!connected) 281*7769Ssam for (n = 1; n < argc - 1; n++) 282*7769Ssam if (index(argv[n], ':') == 0) { 283*7769Ssam getusage(argv[0]); 284*7769Ssam return; 285*7769Ssam } 286*7769Ssam sigset(SIGINT, intr); 287*7769Ssam for (n = 1; argc == 2 || n < argc - 1; n++) { 288*7769Ssam src = index(argv[n], ':'); 289*7769Ssam if (src == NULL) 290*7769Ssam src = argv[n]; 291*7769Ssam else { 292*7769Ssam *src++ = 0; 293*7769Ssam addr = rhost(&argv[n]); 294*7769Ssam if (addr == -1) { 295*7769Ssam printf("%s: Unknown host.\n", argv[n]); 296*7769Ssam continue; 297*7769Ssam } 298*7769Ssam sin.sin_addr.s_addr = addr; 299*7769Ssam connected = 1; 300*7769Ssam strcpy(host_name, argv[n]); 301*7769Ssam } 302*7769Ssam if (argc < 4) { 303*7769Ssam cp = argc == 3 ? argv[2] : tail(src); 304*7769Ssam fd = creat(cp, 0644); 305*7769Ssam if (fd < 0) { 306*7769Ssam perror(cp); 307*7769Ssam return; 308*7769Ssam } 309*7769Ssam recvfile(fd, src); 310*7769Ssam break; 311*7769Ssam } 312*7769Ssam cp = index(argv[argc - 1], '\0'); 313*7769Ssam *cp++ = '/'; 314*7769Ssam strcpy(cp, tail(src)); 315*7769Ssam fd = creat(src, 0644); 316*7769Ssam if (fd < 0) { 317*7769Ssam perror(src); 318*7769Ssam continue; 319*7769Ssam } 320*7769Ssam recvfile(fd, src); 321*7769Ssam } 322*7769Ssam } 323*7769Ssam 324*7769Ssam getusage(s) 325*7769Ssam { 326*7769Ssam printf("usage: %s host:file host:file ... file, or\n", s); 327*7769Ssam printf(" %s file file ... file if connected\n", s); 328*7769Ssam } 329*7769Ssam 330*7769Ssam status(argc, argv) 331*7769Ssam char *argv[]; 332*7769Ssam { 333*7769Ssam if (connected) 334*7769Ssam printf("Connected to %s.\n", host_name); 335*7769Ssam else 336*7769Ssam printf("Not connected.\n"); 337*7769Ssam printf("Mode: %s Verbose: %s Tracing: %s\n", mode, 338*7769Ssam verbose ? "on" : "off", trace ? "on" : "off"); 339*7769Ssam } 340*7769Ssam 341*7769Ssam intr() 342*7769Ssam { 343*7769Ssam longjmp(toplevel, -1); 344*7769Ssam } 345*7769Ssam 346*7769Ssam char * 347*7769Ssam tail(filename) 348*7769Ssam char *filename; 349*7769Ssam { 350*7769Ssam register char *s; 351*7769Ssam 352*7769Ssam while (*filename) { 353*7769Ssam s = rindex(filename, '/'); 354*7769Ssam if (s == NULL) 355*7769Ssam break; 356*7769Ssam if (s[1]) 357*7769Ssam return (s + 1); 358*7769Ssam *s = '\0'; 359*7769Ssam } 360*7769Ssam return (filename); 361*7769Ssam } 362*7769Ssam 363*7769Ssam /* 364*7769Ssam * Command parser. 365*7769Ssam */ 366*7769Ssam command(top) 367*7769Ssam int top; 368*7769Ssam { 369*7769Ssam register struct cmd *c; 370*7769Ssam 371*7769Ssam if (!top) 372*7769Ssam putchar('\n'); 373*7769Ssam else 374*7769Ssam sigset(SIGINT, SIG_DFL); 375*7769Ssam for (;;) { 376*7769Ssam printf("%s> ", prompt); 377*7769Ssam if (gets(line) == 0) 378*7769Ssam break; 379*7769Ssam if (line[0] == 0) 380*7769Ssam break; 381*7769Ssam makeargv(); 382*7769Ssam c = getcmd(margv[0]); 383*7769Ssam if (c == (struct cmd *)-1) { 384*7769Ssam printf("?Ambiguous command\n"); 385*7769Ssam continue; 386*7769Ssam } 387*7769Ssam if (c == 0) { 388*7769Ssam printf("?Invalid command\n"); 389*7769Ssam continue; 390*7769Ssam } 391*7769Ssam (*c->handler)(margc, margv); 392*7769Ssam if (c->handler != help) 393*7769Ssam break; 394*7769Ssam } 395*7769Ssam longjmp(toplevel, 1); 396*7769Ssam } 397*7769Ssam 398*7769Ssam struct cmd * 399*7769Ssam getcmd(name) 400*7769Ssam register char *name; 401*7769Ssam { 402*7769Ssam register char *p, *q; 403*7769Ssam register struct cmd *c, *found; 404*7769Ssam register int nmatches, longest; 405*7769Ssam 406*7769Ssam longest = 0; 407*7769Ssam nmatches = 0; 408*7769Ssam found = 0; 409*7769Ssam for (c = cmdtab; p = c->name; c++) { 410*7769Ssam for (q = name; *q == *p++; q++) 411*7769Ssam if (*q == 0) /* exact match? */ 412*7769Ssam return (c); 413*7769Ssam if (!*q) { /* the name was a prefix */ 414*7769Ssam if (q - name > longest) { 415*7769Ssam longest = q - name; 416*7769Ssam nmatches = 1; 417*7769Ssam found = c; 418*7769Ssam } else if (q - name == longest) 419*7769Ssam nmatches++; 420*7769Ssam } 421*7769Ssam } 422*7769Ssam if (nmatches > 1) 423*7769Ssam return ((struct cmd *)-1); 424*7769Ssam return (found); 425*7769Ssam } 426*7769Ssam 427*7769Ssam /* 428*7769Ssam * Slice a string up into argc/argv. 429*7769Ssam */ 430*7769Ssam makeargv() 431*7769Ssam { 432*7769Ssam register char *cp; 433*7769Ssam register char **argp = margv; 434*7769Ssam 435*7769Ssam margc = 0; 436*7769Ssam for (cp = line; *cp;) { 437*7769Ssam while (isspace(*cp)) 438*7769Ssam cp++; 439*7769Ssam if (*cp == '\0') 440*7769Ssam break; 441*7769Ssam *argp++ = cp; 442*7769Ssam margc += 1; 443*7769Ssam while (*cp != '\0' && !isspace(*cp)) 444*7769Ssam cp++; 445*7769Ssam if (*cp == '\0') 446*7769Ssam break; 447*7769Ssam *cp++ = '\0'; 448*7769Ssam } 449*7769Ssam *argp++ = 0; 450*7769Ssam } 451*7769Ssam 452*7769Ssam /*VARARGS*/ 453*7769Ssam quit() 454*7769Ssam { 455*7769Ssam exit(0); 456*7769Ssam } 457*7769Ssam 458*7769Ssam /* 459*7769Ssam * Help command. 460*7769Ssam * Call each command handler with argc == 0 and argv[0] == name. 461*7769Ssam */ 462*7769Ssam help(argc, argv) 463*7769Ssam int argc; 464*7769Ssam char *argv[]; 465*7769Ssam { 466*7769Ssam register struct cmd *c; 467*7769Ssam 468*7769Ssam if (argc == 1) { 469*7769Ssam printf("Commands may be abbreviated. Commands are:\n\n"); 470*7769Ssam for (c = cmdtab; c->name; c++) 471*7769Ssam printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); 472*7769Ssam return; 473*7769Ssam } 474*7769Ssam while (--argc > 0) { 475*7769Ssam register char *arg; 476*7769Ssam arg = *++argv; 477*7769Ssam c = getcmd(arg); 478*7769Ssam if (c == (struct cmd *)-1) 479*7769Ssam printf("?Ambiguous help command %s\n", arg); 480*7769Ssam else if (c == (struct cmd *)0) 481*7769Ssam printf("?Invalid help command %s\n", arg); 482*7769Ssam else 483*7769Ssam printf("%s\n", c->help); 484*7769Ssam } 485*7769Ssam } 486*7769Ssam 487*7769Ssam /* 488*7769Ssam * Call routine with argc, argv set from args (terminated by 0). 489*7769Ssam */ 490*7769Ssam /* VARARGS2 */ 491*7769Ssam call(routine, args) 492*7769Ssam int (*routine)(); 493*7769Ssam int args; 494*7769Ssam { 495*7769Ssam register int *argp; 496*7769Ssam register int argc; 497*7769Ssam 498*7769Ssam for (argc = 0, argp = &args; *argp++ != 0; argc++) 499*7769Ssam ; 500*7769Ssam (*routine)(argc, &args); 501*7769Ssam } 502*7769Ssam 503*7769Ssam /*VARARGS*/ 504*7769Ssam settrace() 505*7769Ssam { 506*7769Ssam trace = !trace; 507*7769Ssam printf("Packet tracing %s.\n", trace ? "on" : "off"); 508*7769Ssam } 509*7769Ssam 510*7769Ssam /*VARARGS*/ 511*7769Ssam setverbose() 512*7769Ssam { 513*7769Ssam verbose = !verbose; 514*7769Ssam printf("Verbose mode %s.\n", verbose ? "on" : "off"); 515*7769Ssam } 516*7769Ssam 517