|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)ftp.c 4.11 (Berkeley) 7/26/83"; ! 3: #endif ! 4: ! 5: #include <sys/param.h> ! 6: #include <sys/stat.h> ! 7: #include <sys/ioctl.h> ! 8: #include <sys/socket.h> ! 9: #include <sys/time.h> ! 10: ! 11: #include <netinet/in.h> ! 12: #include <arpa/ftp.h> ! 13: ! 14: #include <stdio.h> ! 15: #include <signal.h> ! 16: #include <errno.h> ! 17: #include <netdb.h> ! 18: ! 19: #include "ftp_var.h" ! 20: ! 21: struct sockaddr_in hisctladdr; ! 22: struct sockaddr_in data_addr; ! 23: int data = -1; ! 24: int connected; ! 25: struct sockaddr_in myctladdr; ! 26: ! 27: FILE *cin, *cout; ! 28: FILE *dataconn(); ! 29: ! 30: struct hostent * ! 31: hookup(host, port) ! 32: char *host; ! 33: int port; ! 34: { ! 35: register struct hostent *hp; ! 36: int s, len; ! 37: ! 38: bzero((char *)&hisctladdr, sizeof (hisctladdr)); ! 39: hp = gethostbyname(host); ! 40: if (hp == NULL) { ! 41: static struct hostent def; ! 42: static struct in_addr defaddr; ! 43: static char namebuf[128]; ! 44: int inet_addr(); ! 45: ! 46: defaddr.s_addr = inet_addr(host); ! 47: if (defaddr.s_addr == -1) { ! 48: fprintf(stderr, "%s: Unknown host.\n", host); ! 49: return (0); ! 50: } ! 51: strcpy(namebuf, host); ! 52: def.h_name = namebuf; ! 53: hostname = namebuf; ! 54: def.h_addr = (char *)&defaddr; ! 55: def.h_length = sizeof (struct in_addr); ! 56: def.h_addrtype = AF_INET; ! 57: def.h_aliases = 0; ! 58: hp = &def; ! 59: } ! 60: hostname = hp->h_name; ! 61: hisctladdr.sin_family = hp->h_addrtype; ! 62: s = socket(hp->h_addrtype, SOCK_STREAM, 0, 0); ! 63: if (s < 0) { ! 64: perror("ftp: socket"); ! 65: return (0); ! 66: } ! 67: if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { ! 68: perror("ftp: bind"); ! 69: goto bad; ! 70: } ! 71: bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length); ! 72: hisctladdr.sin_port = port; ! 73: if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { ! 74: perror("ftp: connect"); ! 75: goto bad; ! 76: } ! 77: len = sizeof (myctladdr); ! 78: if (getsockname(s, (char *)&myctladdr, &len) < 0) { ! 79: perror("ftp: getsockname"); ! 80: goto bad; ! 81: } ! 82: cin = fdopen(s, "r"); ! 83: cout = fdopen(s, "w"); ! 84: if (cin == NULL || cout == NULL) { ! 85: fprintf(stderr, "ftp: fdopen failed.\n"); ! 86: if (cin) ! 87: fclose(cin); ! 88: if (cout) ! 89: fclose(cout); ! 90: goto bad; ! 91: } ! 92: if (verbose) ! 93: printf("Connected to %s.\n", hp->h_name); ! 94: (void) getreply(0); /* read startup message from server */ ! 95: return (hp); ! 96: bad: ! 97: close(s); ! 98: return ((struct hostent *)0); ! 99: } ! 100: ! 101: login(hp) ! 102: struct hostent *hp; ! 103: { ! 104: char acct[80]; ! 105: char *user, *pass; ! 106: int n; ! 107: ! 108: user = pass = 0; ! 109: ruserpass(hp->h_name, &user, &pass); ! 110: n = command("USER %s", user); ! 111: if (n == CONTINUE) ! 112: n = command("PASS %s", pass); ! 113: if (n == CONTINUE) { ! 114: printf("Account: "); (void) fflush(stdout); ! 115: (void) fgets(acct, sizeof(acct) - 1, stdin); ! 116: acct[strlen(acct) - 1] = '\0'; ! 117: n = command("ACCT %s", acct); ! 118: } ! 119: if (n != COMPLETE) { ! 120: fprintf(stderr, "Login failed.\n"); ! 121: return (0); ! 122: } ! 123: return (1); ! 124: } ! 125: ! 126: /*VARARGS 1*/ ! 127: command(fmt, args) ! 128: char *fmt; ! 129: { ! 130: ! 131: if (debug) { ! 132: printf("---> "); ! 133: _doprnt(fmt, &args, stdout); ! 134: printf("\n"); ! 135: (void) fflush(stdout); ! 136: } ! 137: if (cout == NULL) { ! 138: perror ("No control connection for command"); ! 139: return (0); ! 140: } ! 141: _doprnt(fmt, &args, cout); ! 142: fprintf(cout, "\r\n"); ! 143: (void) fflush(cout); ! 144: return (getreply(!strcmp(fmt, "QUIT"))); ! 145: } ! 146: ! 147: #include <ctype.h> ! 148: ! 149: getreply(expecteof) ! 150: int expecteof; ! 151: { ! 152: register int c, n; ! 153: register int code, dig; ! 154: int originalcode = 0, continuation = 0; ! 155: ! 156: for (;;) { ! 157: dig = n = code = 0; ! 158: while ((c = getc(cin)) != '\n') { ! 159: dig++; ! 160: if (c == EOF) { ! 161: if (expecteof) ! 162: return (0); ! 163: lostpeer(); ! 164: exit(1); ! 165: } ! 166: if (verbose && c != '\r' || ! 167: (n == '5' && dig > 4)) ! 168: putchar(c); ! 169: if (dig < 4 && isdigit(c)) ! 170: code = code * 10 + (c - '0'); ! 171: if (dig == 4 && c == '-') ! 172: continuation++; ! 173: if (n == 0) ! 174: n = c; ! 175: } ! 176: if (verbose || n == '5') { ! 177: putchar(c); ! 178: (void) fflush (stdout); ! 179: } ! 180: if (continuation && code != originalcode) { ! 181: if (originalcode == 0) ! 182: originalcode = code; ! 183: continue; ! 184: } ! 185: if (expecteof || empty(cin)) ! 186: return (n - '0'); ! 187: } ! 188: } ! 189: ! 190: empty(f) ! 191: FILE *f; ! 192: { ! 193: long mask; ! 194: struct timeval t; ! 195: ! 196: if (f->_cnt > 0) ! 197: return (0); ! 198: mask = (1 << fileno(f)); ! 199: t.tv_sec = t.tv_usec = 0; ! 200: (void) select(20, &mask, 0, 0, &t); ! 201: return (mask == 0); ! 202: } ! 203: ! 204: jmp_buf sendabort; ! 205: ! 206: abortsend() ! 207: { ! 208: ! 209: longjmp(sendabort, 1); ! 210: } ! 211: ! 212: sendrequest(cmd, local, remote) ! 213: char *cmd, *local, *remote; ! 214: { ! 215: FILE *fin, *dout, *popen(); ! 216: int (*closefunc)(), pclose(), fclose(), (*oldintr)(); ! 217: char buf[BUFSIZ]; ! 218: long bytes = 0, hashbytes = sizeof (buf); ! 219: register int c, d; ! 220: struct stat st; ! 221: struct timeval start, stop; ! 222: ! 223: closefunc = NULL; ! 224: if (setjmp(sendabort)) ! 225: goto bad; ! 226: oldintr = signal(SIGINT, abortsend); ! 227: if (strcmp(local, "-") == 0) ! 228: fin = stdin; ! 229: else if (*local == '|') { ! 230: fin = popen(local + 1, "r"); ! 231: if (fin == NULL) { ! 232: perror(local + 1); ! 233: goto bad; ! 234: } ! 235: closefunc = pclose; ! 236: } else { ! 237: fin = fopen(local, "r"); ! 238: if (fin == NULL) { ! 239: perror(local); ! 240: goto bad; ! 241: } ! 242: closefunc = fclose; ! 243: if (fstat(fileno(fin), &st) < 0 || ! 244: (st.st_mode&S_IFMT) != S_IFREG) { ! 245: fprintf(stderr, "%s: not a plain file.", local); ! 246: goto bad; ! 247: } ! 248: } ! 249: if (initconn()) ! 250: goto bad; ! 251: if (remote) { ! 252: if (command("%s %s", cmd, remote) != PRELIM) ! 253: goto bad; ! 254: } else ! 255: if (command("%s", cmd) != PRELIM) ! 256: goto bad; ! 257: dout = dataconn("w"); ! 258: if (dout == NULL) ! 259: goto bad; ! 260: gettimeofday(&start, (struct timezone *)0); ! 261: switch (type) { ! 262: ! 263: case TYPE_I: ! 264: case TYPE_L: ! 265: errno = d = 0; ! 266: while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) { ! 267: if ((d = write(fileno (dout), buf, c)) < 0) ! 268: break; ! 269: bytes += c; ! 270: if (hash) { ! 271: putchar('#'); ! 272: fflush(stdout); ! 273: } ! 274: } ! 275: if (hash && bytes > 0) { ! 276: putchar('\n'); ! 277: fflush(stdout); ! 278: } ! 279: if (c < 0) ! 280: perror(local); ! 281: if (d < 0) ! 282: perror("netout"); ! 283: break; ! 284: ! 285: case TYPE_A: ! 286: while ((c = getc(fin)) != EOF) { ! 287: if (c == '\n') { ! 288: while (hash && (bytes >= hashbytes)) { ! 289: putchar('#'); ! 290: fflush(stdout); ! 291: hashbytes += sizeof (buf); ! 292: } ! 293: if (ferror(dout)) ! 294: break; ! 295: putc('\r', dout); ! 296: bytes++; ! 297: } ! 298: putc(c, dout); ! 299: bytes++; ! 300: if (c == '\r') { ! 301: putc('\0', dout); ! 302: bytes++; ! 303: } ! 304: } ! 305: if (hash) { ! 306: if (bytes < hashbytes) ! 307: putchar('#'); ! 308: putchar('\n'); ! 309: fflush(stdout); ! 310: } ! 311: if (ferror(fin)) ! 312: perror(local); ! 313: if (ferror(dout)) ! 314: perror("netout"); ! 315: break; ! 316: } ! 317: gettimeofday(&stop, (struct timezone *)0); ! 318: if (closefunc != NULL) ! 319: (*closefunc)(fin); ! 320: (void) fclose(dout); ! 321: (void) getreply(0); ! 322: done: ! 323: signal(SIGINT, oldintr); ! 324: if (bytes > 0 && verbose) ! 325: ptransfer("sent", bytes, &start, &stop); ! 326: return; ! 327: bad: ! 328: if (data >= 0) ! 329: (void) close(data), data = -1; ! 330: if (closefunc != NULL && fin != NULL) ! 331: (*closefunc)(fin); ! 332: goto done; ! 333: } ! 334: ! 335: jmp_buf recvabort; ! 336: ! 337: abortrecv() ! 338: { ! 339: ! 340: longjmp(recvabort, 1); ! 341: } ! 342: ! 343: recvrequest(cmd, local, remote, mode) ! 344: char *cmd, *local, *remote, *mode; ! 345: { ! 346: FILE *fout, *din, *popen(); ! 347: int (*closefunc)(), pclose(), fclose(), (*oldintr)(); ! 348: char buf[BUFSIZ]; ! 349: long bytes = 0, hashbytes = sizeof (buf); ! 350: register int c, d; ! 351: struct timeval start, stop; ! 352: ! 353: closefunc = NULL; ! 354: if (setjmp(recvabort)) ! 355: goto bad; ! 356: oldintr = signal(SIGINT, abortrecv); ! 357: if (strcmp(local, "-") && *local != '|') ! 358: if (access(local, 2) < 0) { ! 359: char *dir = rindex(local, '/'); ! 360: ! 361: if (dir != NULL) ! 362: *dir = 0; ! 363: if (access(dir ? dir : ".", 2) < 0) { ! 364: perror(local); ! 365: goto bad; ! 366: } ! 367: if (dir != NULL) ! 368: *dir = '/'; ! 369: } ! 370: if (initconn()) ! 371: goto bad; ! 372: if (remote) { ! 373: if (command("%s %s", cmd, remote) != PRELIM) ! 374: goto bad; ! 375: } else ! 376: if (command("%s", cmd) != PRELIM) ! 377: goto bad; ! 378: if (strcmp(local, "-") == 0) ! 379: fout = stdout; ! 380: else if (*local == '|') { ! 381: fout = popen(local + 1, "w"); ! 382: closefunc = pclose; ! 383: } else { ! 384: fout = fopen(local, mode); ! 385: closefunc = fclose; ! 386: } ! 387: if (fout == NULL) { ! 388: perror(local + 1); ! 389: goto bad; ! 390: } ! 391: din = dataconn("r"); ! 392: if (din == NULL) ! 393: goto bad; ! 394: gettimeofday(&start, (struct timezone *)0); ! 395: switch (type) { ! 396: ! 397: case TYPE_I: ! 398: case TYPE_L: ! 399: errno = d = 0; ! 400: while ((c = read(fileno(din), buf, sizeof (buf))) > 0) { ! 401: if ((d = write(fileno(fout), buf, c)) < 0) ! 402: break; ! 403: bytes += c; ! 404: if (hash) { ! 405: putchar('#'); ! 406: fflush(stdout); ! 407: } ! 408: } ! 409: if (hash && bytes > 0) { ! 410: putchar('\n'); ! 411: fflush(stdout); ! 412: } ! 413: if (c < 0) ! 414: perror("netin"); ! 415: if (d < 0) ! 416: perror(local); ! 417: break; ! 418: ! 419: case TYPE_A: ! 420: while ((c = getc(din)) != EOF) { ! 421: if (c == '\r') { ! 422: while (hash && (bytes >= hashbytes)) { ! 423: putchar('#'); ! 424: fflush(stdout); ! 425: hashbytes += sizeof (buf); ! 426: } ! 427: bytes++; ! 428: if ((c = getc(din)) != '\n') { ! 429: if (ferror (fout)) ! 430: break; ! 431: putc ('\r', fout); ! 432: } ! 433: if (c == '\0') { ! 434: bytes++; ! 435: continue; ! 436: } ! 437: } ! 438: putc (c, fout); ! 439: bytes++; ! 440: } ! 441: if (hash) { ! 442: if (bytes < hashbytes) ! 443: putchar('#'); ! 444: putchar('\n'); ! 445: fflush(stdout); ! 446: } ! 447: if (ferror (din)) ! 448: perror ("netin"); ! 449: if (ferror (fout)) ! 450: perror (local); ! 451: break; ! 452: } ! 453: gettimeofday(&stop, (struct timezone *)0); ! 454: (void) fclose(din); ! 455: if (closefunc != NULL) ! 456: (*closefunc)(fout); ! 457: (void) getreply(0); ! 458: done: ! 459: signal(SIGINT, oldintr); ! 460: if (bytes > 0 && verbose) ! 461: ptransfer("received", bytes, &start, &stop); ! 462: return; ! 463: bad: ! 464: if (data >= 0) ! 465: (void) close(data), data = -1; ! 466: if (closefunc != NULL && fout != NULL) ! 467: (*closefunc)(fout); ! 468: goto done; ! 469: } ! 470: ! 471: /* ! 472: * Need to start a listen on the data channel ! 473: * before we send the command, otherwise the ! 474: * server's connect may fail. ! 475: */ ! 476: static int sendport = -1; ! 477: ! 478: initconn() ! 479: { ! 480: register char *p, *a; ! 481: int result, len; ! 482: ! 483: noport: ! 484: data_addr = myctladdr; ! 485: if (sendport) ! 486: data_addr.sin_port = 0; /* let system pick one */ ! 487: if (data != -1) ! 488: (void) close (data); ! 489: data = socket(AF_INET, SOCK_STREAM, 0, 0); ! 490: if (data < 0) { ! 491: perror("ftp: socket"); ! 492: return (1); ! 493: } ! 494: if (!sendport) ! 495: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) { ! 496: perror("ftp: setsockopt (resuse address)"); ! 497: goto bad; ! 498: } ! 499: if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) { ! 500: perror("ftp: bind"); ! 501: goto bad; ! 502: } ! 503: if (options & SO_DEBUG && ! 504: setsockopt(data, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 505: perror("ftp: setsockopt (ignored)"); ! 506: len = sizeof (data_addr); ! 507: if (getsockname(data, (char *)&data_addr, &len) < 0) { ! 508: perror("ftp: getsockname"); ! 509: goto bad; ! 510: } ! 511: if (listen(data, 1) < 0) { ! 512: perror("ftp: listen"); ! 513: goto bad; ! 514: } ! 515: if (sendport) { ! 516: a = (char *)&data_addr.sin_addr; ! 517: p = (char *)&data_addr.sin_port; ! 518: #define UC(b) (((int)b)&0xff) ! 519: result = ! 520: command("PORT %d,%d,%d,%d,%d,%d", ! 521: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), ! 522: UC(p[0]), UC(p[1])); ! 523: if (result == ERROR && sendport == -1) { ! 524: sendport = 0; ! 525: goto noport; ! 526: } ! 527: return (result != COMPLETE); ! 528: } ! 529: return (0); ! 530: bad: ! 531: (void) close(data), data = -1; ! 532: return (1); ! 533: } ! 534: ! 535: FILE * ! 536: dataconn(mode) ! 537: char *mode; ! 538: { ! 539: struct sockaddr_in from; ! 540: int s, fromlen = sizeof (from); ! 541: ! 542: s = accept(data, &from, &fromlen, 0); ! 543: if (s < 0) { ! 544: perror("ftp: accept"); ! 545: (void) close(data), data = -1; ! 546: return (NULL); ! 547: } ! 548: (void) close(data); ! 549: data = s; ! 550: return (fdopen(data, mode)); ! 551: } ! 552: ! 553: ptransfer(direction, bytes, t0, t1) ! 554: char *direction; ! 555: long bytes; ! 556: struct timeval *t0, *t1; ! 557: { ! 558: struct timeval td; ! 559: long ms; ! 560: float bs; ! 561: ! 562: tvsub(&td, t1, t0); ! 563: ms = (td.tv_sec * 1000) + (td.tv_usec / 1000); ! 564: #define nz(x) ((x) == 0 ? 1 : (x)) ! 565: bs = ((bytes * NBBY * 1000) / (float) nz(ms)) / NBBY; ! 566: printf("%ld bytes %s in %d.%02d seconds (%.2g Kbytes/s)\n", ! 567: bytes, direction, td.tv_sec, td.tv_usec / 10000, bs / 1024.); ! 568: } ! 569: ! 570: tvadd(tsum, t0) ! 571: struct timeval *tsum, *t0; ! 572: { ! 573: ! 574: tsum->tv_sec += t0->tv_sec; ! 575: tsum->tv_usec += t0->tv_usec; ! 576: if (tsum->tv_usec > 1000000) ! 577: tsum->tv_sec++, tsum->tv_usec -= 1000000; ! 578: } ! 579: ! 580: tvsub(tdiff, t1, t0) ! 581: struct timeval *tdiff, *t1, *t0; ! 582: { ! 583: ! 584: tdiff->tv_sec = t1->tv_sec - t0->tv_sec; ! 585: tdiff->tv_usec = t1->tv_usec - t0->tv_usec; ! 586: if (tdiff->tv_usec < 0) ! 587: tdiff->tv_sec--, tdiff->tv_usec += 1000000; ! 588: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.