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