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

Defined functions

command defined in line 511; used 1 times
get defined in line 339; used 2 times
getcmd defined in line 543; used 3 times
getusage defined in line 412; used 2 times
help defined in line 606; used 5 times
intr defined in line 484; used 2 times
main defined in line 100; never used
makeargv defined in line 575; used 6 times
modecmd defined in line 195; used 2 times
put defined in line 250; used 2 times
putusage defined in line 329; used 2 times
quit defined in line 598; used 3 times
setascii defined in line 233; used 2 times
setbinary defined in line 228; used 2 times
setmode defined in line 238; used 3 times
setpeer defined in line 136; used 3 times
setrexmt defined in line 421; used 2 times
settimeout defined in line 447; used 2 times
settrace defined in line 632; used 2 times
setverbose defined in line 639; used 2 times
status defined in line 471; used 2 times
tail defined in line 491; used 5 times

Defined variables

ashelp defined in line 75; used 1 times
  • in line 88
bnhelp defined in line 76; used 1 times
  • in line 87
chelp defined in line 66; used 1 times
  • in line 79
cmdtab defined in line 78; used 2 times
connected defined in line 42; used 8 times
copyright defined in line 8; never used
f defined in line 38; used 11 times
hhelp defined in line 68; used 1 times
  • in line 91
hostname defined in line 134; used 9 times
ihelp defined in line 74; used 1 times
  • in line 90
line defined in line 44; used 18 times
margc defined in line 45; used 8 times
margv defined in line 46; used 8 times
maxtimeout defined in line 445; used 3 times
mhelp defined in line 71; used 1 times
  • in line 80
mode defined in line 43; used 13 times
modes defined in line 185; used 2 times
port defined in line 39; used 9 times
prompt defined in line 47; used 1 times
qhelp defined in line 67; used 1 times
  • in line 83
rexmtval defined in line 419; used 5 times
rhelp defined in line 70; used 1 times
  • in line 82
sccsid defined in line 14; never used
shelp defined in line 69; used 1 times
  • in line 81
sin defined in line 37; used 29 times
sp defined in line 50; used 3 times
sthelp defined in line 72; used 1 times
  • in line 86
thelp defined in line 65; used 1 times
  • in line 85
toplevel defined in line 48; used 3 times
trace defined in line 40; used 11 times
verbose defined in line 41; used 10 times
vhelp defined in line 64; used 1 times
  • in line 84
xhelp defined in line 73; used 1 times
  • in line 89

Defined struct's

cmd defined in line 58; used 20 times
modes defined in line 182; used 2 times
  • in line 198(2)

Defined macros

HELPINDENT defined in line 56; used 1 times
TIMEOUT defined in line 35; used 2 times
Last modified: 1986-02-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2959
Valid CSS Valid XHTML 1.0 Strict