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