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