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