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