Annotation of cci/usr/src/ucb/ftp/ftp.c, revision 1.1.1.1

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: 
                     31: /*
                     32:        Changes made to this file :
                     33: 
                     34:        (1) recvrequest() :
                     35:                a. Move the logic to check if the local file is successfully
                     36:                   opened before sending the RETR cmd to remote server. Just 
                     37:                   to make sure user ftp is ready to accept data from server
                     38:                   before the RETR cmd is sent.
                     39:                b. Add logic to report actual no of bytes received from server
                     40:                   and actual size of new file. They are different because ftp
                     41:                   user program strips '\n' characters.
                     42:                c. Fix for 1st char. lost when print out error message to 
                     43:                   indicate local cannot be opened.
                     44:        
                     45:                d. If you try to retrieve something into a local file, and you
                     46:                   don't have the write permission on the file, it should test
                     47:                   whether you have write permission on the directory contain-
                     48:                   ing the file.  But, previously, if the local file is a path
                     49:                   name containing slashes, it does a test on a null pathname
                     50:                   rather than on the containing directory. This is wrong.
                     51: 
                     52:        (2) empty():    Peter P. 07/02/85
                     53:                @  removed because no routine uses it. Peter P. 07/02/85
                     54: 
                     55:        (3) getreply(): Peter P. 07/02/85
                     56:                a. Prevent the reply getter to get more replies than necessary.
                     57:                   only one reply is gotten per call to this routine.
                     58: */
                     59: 
                     60: struct hostent *
                     61: hookup(host, port)
                     62:        char *host;
                     63:        int port;
                     64: {
                     65:        register struct hostent *hp;
                     66:        int s, len;
                     67: 
                     68:        bzero((char *)&hisctladdr, sizeof (hisctladdr));
                     69:        hp = gethostbyname(host);
                     70:        if (hp == NULL) {
                     71:                static struct hostent def;
                     72:                static struct in_addr defaddr;
                     73:                static char namebuf[128];
                     74:                int inet_addr();
                     75: 
                     76:                defaddr.s_addr = inet_addr(host);
                     77:                if (defaddr.s_addr == -1) {
                     78:                        fprintf(stderr, "%s: Unknown host.\n", host);
                     79:                        return (0);
                     80:                }
                     81:                strcpy(namebuf, host);
                     82:                def.h_name = namebuf;
                     83:                hostname = namebuf;
                     84:                def.h_addr = (char *)&defaddr;
                     85:                def.h_length = sizeof (struct in_addr);
                     86:                def.h_addrtype = AF_INET;
                     87:                def.h_aliases = 0;
                     88:                hp = &def;
                     89:        }
                     90:        hostname = hp->h_name;
                     91:        hisctladdr.sin_family = hp->h_addrtype;
                     92:        s = socket(hp->h_addrtype, SOCK_STREAM, 0, 0);
                     93:        if (s < 0) {
                     94:                perror("ftp: socket");
                     95:                return (0);
                     96:        }
                     97:        if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) {
                     98:                perror("ftp: bind");
                     99:                goto bad;
                    100:        }
                    101:        bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length);
                    102:        hisctladdr.sin_port = port;
                    103:        if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) {
                    104:                perror("ftp: connect");
                    105:                goto bad;
                    106:        }
                    107:        len = sizeof (myctladdr);
                    108:        if (getsockname(s, (char *)&myctladdr, &len) < 0) {
                    109:                perror("ftp: getsockname");
                    110:                goto bad;
                    111:        }
                    112:        cin = fdopen(s, "r");
                    113:        cout = fdopen(s, "w");
                    114:        if (cin == NULL || cout == NULL) {
                    115:                fprintf(stderr, "ftp: fdopen failed.\n");
                    116:                if (cin)
                    117:                        fclose(cin);
                    118:                if (cout)
                    119:                        fclose(cout);
                    120:                goto bad;
                    121:        }
                    122:        if (verbose)
                    123:                printf("Connected to %s.\n", hp->h_name);
                    124:        (void) getreply(0);             /* read startup message from server */
                    125:        return (hp);
                    126: bad:
                    127:        close(s);
                    128:        return ((struct hostent *)0);
                    129: }
                    130: 
                    131: login(hp)
                    132:        struct hostent *hp;
                    133: {
                    134:        char acct[80];
                    135:        char *user, *pass;
                    136:        int n;
                    137: 
                    138:        user = pass = 0;
                    139:        ruserpass(hp->h_name, &user, &pass);
                    140:        n = command("USER %s", user);
                    141:        if (n == CONTINUE)
                    142:                n = command("PASS %s", pass);
                    143:        if (n == CONTINUE) {
                    144:                printf("Account: "); (void) fflush(stdout);
                    145:                (void) fgets(acct, sizeof(acct) - 1, stdin);
                    146:                acct[strlen(acct) - 1] = '\0';
                    147:                n = command("ACCT %s", acct);
                    148:        }
                    149:        if (n != COMPLETE) {
                    150:                fprintf(stderr, "Login failed.\n");
                    151:                return (0);
                    152:        }
                    153:        return (1);
                    154: }
                    155: 
                    156: /*VARARGS 1*/
                    157: command(fmt, args)
                    158:        char *fmt;
                    159: {
                    160: 
                    161:        if (debug) {
                    162:                printf("---> ");
                    163:                _doprnt(fmt, &args, stdout);
                    164:                printf("\n");
                    165:                (void) fflush(stdout);
                    166:        }
                    167:        if (cout == NULL) {
                    168:                perror ("No control connection for command");
                    169:                return (0);
                    170:        }
                    171:        _doprnt(fmt, &args, cout);
                    172:        fprintf(cout, "\r\n");
                    173:        (void) fflush(cout);
                    174:        return (getreply(!strcmp(fmt, "QUIT")));
                    175: }
                    176: 
                    177: #include <ctype.h>
                    178: 
                    179: getreply(expecteof)
                    180:        int expecteof;
                    181: {
                    182:        register int n;
                    183:        register char c;
                    184:        register int code, dig;
                    185:        int originalcode = 0, continuation = 0;
                    186: 
                    187:        for (;;) {
                    188:                dig = n = code = 0;
                    189:                while ((c = getc(cin)) != '\n') {
                    190:                        dig++;
                    191:                        if (c == EOF) {
                    192:                                if (expecteof)
                    193:                                        return (0);
                    194:                                lostpeer();
                    195:                                exit(1);
                    196:                        }
                    197:                        if (verbose && c != '\r' ||
                    198:                            (n == '5' && dig > 4))
                    199:                                putchar(c);
                    200:                        if (dig < 4 && isdigit(c))
                    201:                                code = code * 10 + (c - '0');
                    202:                        if (dig == 4 && c == '-')
                    203:                                continuation++;
                    204:                        if (n == 0)
                    205:                                n = c;
                    206:                }
                    207:                if (verbose || n == '5') {
                    208:                        putchar(c);
                    209:                        (void) fflush (stdout);
                    210:                }
                    211:                if (continuation && code != originalcode) {
                    212:                        if (originalcode == 0)
                    213:                                originalcode = code;
                    214:                        continue;
                    215:                }
                    216: /*             if (expecteof || empty(cin))    Peter 07/02/85 */
                    217:                        return (n - '0');
                    218:        }
                    219: }
                    220: 
                    221: /*     not called by anyone anymore...         Peter P. 07/02/85
                    222: empty(f)
                    223:        FILE *f;
                    224: {
                    225:        long mask;
                    226:        struct timeval t;
                    227: 
                    228:        if (f->_cnt > 0)
                    229:                return (0);
                    230:        mask = (1 << fileno(f));
                    231:        t.tv_sec = t.tv_usec = 0;
                    232:        (void) select(20, &mask, 0, 0, &t);
                    233:        return (mask == 0);
                    234: }
                    235: */
                    236: 
                    237: jmp_buf        sendabort;
                    238: 
                    239: abortsend()
                    240: {
                    241: 
                    242:        longjmp(sendabort, 1);
                    243: }
                    244: 
                    245: sendrequest(cmd, local, remote)
                    246:        char *cmd, *local, *remote;
                    247: {
                    248:        FILE *fin, *dout, *popen();
                    249:        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
                    250:        char buf[BUFSIZ];
                    251:        long bytes = 0, hashbytes = sizeof (buf);
                    252:        long wscnt = 0;
                    253:        register int c, d;
                    254:        struct stat st;
                    255:        struct timeval start, stop;
                    256: 
                    257:        closefunc = NULL;
                    258:        if (setjmp(sendabort))
                    259:                goto bad;
                    260:        oldintr = signal(SIGINT, abortsend);
                    261:        if (strcmp(local, "-") == 0)
                    262:                fin = stdin;
                    263:        else if (*local == '|') {
                    264:                fin = popen(local + 1, "r");
                    265:                if (fin == NULL) {
                    266:                        perror(local + 1);
                    267:                        goto bad;
                    268:                }
                    269:                closefunc = pclose;
                    270:        } else {
                    271:                fin = fopen(local, "r");
                    272:                if (fin == NULL) {
                    273:                        perror(local);
                    274:                        goto bad;
                    275:                }
                    276:                closefunc = fclose;
                    277:                if (fstat(fileno(fin), &st) < 0 ||
                    278:                    (st.st_mode&S_IFMT) != S_IFREG) {
                    279:                        fprintf(stderr, "%s: not a plain file.", local);
                    280:                        goto bad;
                    281:                }
                    282:        }
                    283:        if (initconn())
                    284:                goto bad;
                    285:        if (remote) {
                    286:                if (command("%s %s", cmd, remote) != PRELIM)
                    287:                        goto bad;
                    288:        } else
                    289:                if (command("%s", cmd) != PRELIM)
                    290:                        goto bad;
                    291:        dout = dataconn("w");
                    292:        if (dout == NULL)
                    293:                goto bad;
                    294:        gettimeofday(&start, (struct timezone *)0);
                    295:        switch (type) {
                    296: 
                    297:        case TYPE_I:
                    298:        case TYPE_L:
                    299:                errno = d = 0;
                    300:                while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
                    301:                        if ((d = write(fileno (dout), buf, c)) < 0)
                    302:                                break;
                    303:                        bytes += c;
                    304:                        if (hash) {
                    305:                                putchar('#');
                    306:                                fflush(stdout);
                    307:                        }
                    308:                }
                    309:                wscnt = bytes;
                    310:                if (hash && bytes > 0) {
                    311:                        putchar('\n');
                    312:                        fflush(stdout);
                    313:                }
                    314:                if (c < 0)
                    315:                        perror(local);
                    316:                if (d < 0)
                    317:                        perror("netout");
                    318:                break;
                    319: 
                    320:        case TYPE_A:
                    321:                while ((c = getc(fin)) != EOF) {
                    322:                        wscnt++;
                    323:                        if (c == '\n') {
                    324:                                while (hash && (bytes >= hashbytes)) {
                    325:                                        putchar('#');
                    326:                                        fflush(stdout);
                    327:                                        hashbytes += sizeof (buf);
                    328:                                }
                    329:                                if (ferror(dout))
                    330:                                        break;
                    331:                                putc('\r', dout);
                    332:                                bytes++;
                    333:                        }
                    334:                        putc(c, dout);
                    335:                        bytes++;
                    336:                        if (c == '\r') {
                    337:                                putc('\0', dout);
                    338:                                bytes++;
                    339:                        }
                    340:                }
                    341:                if (hash) {
                    342:                        if (bytes < hashbytes)
                    343:                                putchar('#');
                    344:                        putchar('\n');
                    345:                        fflush(stdout);
                    346:                }
                    347:                if (ferror(fin))
                    348:                        perror(local);
                    349:                if (ferror(dout))
                    350:                        perror("netout");
                    351:                break;
                    352:        }
                    353:        if (closefunc != NULL)
                    354:                (*closefunc)(fin);
                    355:        (void) fclose(dout);
                    356:        (void) getreply(0);
                    357: done:
                    358:        gettimeofday(&stop, (struct timezone *)0);
                    359:        signal(SIGINT, oldintr);
                    360:        if (bytes > 0 && verbose) { 
                    361:                if (fin != stdin)
                    362:                        printf("Actual size of %s is %d bytes\n", local, wscnt);
                    363:                ptransfer("sent", bytes, &start, &stop);
                    364:        }
                    365:        return;
                    366: bad:
                    367:        if (data >= 0)
                    368:                (void) close(data), data = -1;
                    369:        if (closefunc != NULL && fin != NULL)
                    370:                (*closefunc)(fin);
                    371:        goto done;
                    372: }
                    373: 
                    374: jmp_buf        recvabort;
                    375: 
                    376: abortrecv()
                    377: {
                    378: 
                    379:        longjmp(recvabort, 1);
                    380: }
                    381: 
                    382: recvrequest(cmd, local, remote, mode)
                    383:        char *cmd, *local, *remote, *mode;
                    384: {
                    385:        FILE *fout, *din, *popen();
                    386:        int (*closefunc)(), pclose(), fclose(), (*oldintr)();
                    387:        char buf[BUFSIZ];
                    388:        long wrcnt = 0;
                    389:        long bytes = 0, hashbytes = sizeof (buf);
                    390:        register int c, d;
                    391:        struct timeval start, stop;
                    392: 
                    393:        din = NULL;
                    394:        closefunc = NULL;
                    395:        if (setjmp(recvabort))
                    396:                goto bad;
                    397:        oldintr = signal(SIGINT, abortrecv);
                    398:        if (strcmp(local, "-") && *local != '|')
                    399:                if (access(local, 2) < 0) {
                    400:                    if (errno == ENOENT) {
                    401:                        char *dir = rindex(local, '/');
                    402: 
                    403:                        if (dir != NULL)
                    404:                                *dir = 0;
                    405:                        if (access(dir ? local : ".", 2) < 0) {
                    406:                                perror(local);
                    407:                                goto bad;
                    408:                        }
                    409:                        if (dir != NULL)
                    410:                                *dir = '/';
                    411:                   } 
                    412:                   else {
                    413:                        perror(local);
                    414:                        goto bad;
                    415:                   }
                    416:                }
                    417:        if (strcmp(local, "-") == 0)
                    418:                fout = stdout;
                    419:        else if (*local == '|') {
                    420:                fout = popen(local + 1, "w");
                    421:                closefunc = pclose;
                    422:        } else {
                    423:                fout = fopen(local, mode);
                    424:                closefunc = fclose;
                    425:        }
                    426:        if (fout == NULL) {
                    427:                if (*local == '|') perror(local + 1);
                    428:                        else perror(local);
                    429:                goto bad;
                    430:        }
                    431:        if (initconn())
                    432:                goto bad;
                    433:        if (remote) {
                    434:                if (command("%s %s", cmd, remote) != PRELIM)
                    435:                        goto bad;
                    436:        } else
                    437:                if (command("%s", cmd) != PRELIM)
                    438:                        goto bad;
                    439:        din = dataconn("r");
                    440:        if (din == NULL)
                    441:                goto bad;
                    442:        gettimeofday(&start, (struct timezone *)0);
                    443:        switch (type) {
                    444: 
                    445:        case TYPE_I:
                    446:        case TYPE_L:
                    447:                errno = d = 0;
                    448:                while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
                    449:                        if ((d = write(fileno(fout), buf, c)) < 0)
                    450:                                break;
                    451:                        bytes += d;
                    452:                        if (hash) {
                    453:                                putchar('#');
                    454:                                fflush(stdout);
                    455:                        }
                    456:                }
                    457:                wrcnt = bytes;
                    458:                if (hash && bytes > 0) {
                    459:                        putchar('\n');
                    460:                        fflush(stdout);
                    461:                }
                    462:                if (c < 0)
                    463:                        perror("netin");
                    464:                if (d < 0)
                    465:                        perror(local);
                    466:                break;
                    467: 
                    468:        case TYPE_A:
                    469:                while ((c = getc(din)) != EOF) {
                    470:                        bytes++;
                    471:                        if (c == '\r') {
                    472:                                while (hash && (bytes >= hashbytes)) {
                    473:                                        putchar('#');
                    474:                                        fflush(stdout);
                    475:                                        hashbytes += sizeof (buf);
                    476:                                }
                    477:                                c = getc(din);
                    478:                                bytes++;
                    479:                                if (c != '\n') {
                    480:                                        if (ferror (fout))
                    481:                                                break;
                    482:                                        putc ('\r', fout);
                    483:                                        wrcnt++;
                    484:                                }
                    485:                                if (c == '\0') {
                    486:                                        continue;
                    487:                                }
                    488:                        }
                    489:                        putc (c, fout);
                    490:                        wrcnt++;
                    491:                }
                    492:                if (hash) {
                    493:                        if (bytes < hashbytes)
                    494:                                putchar('#');
                    495:                        putchar('\n');
                    496:                        fflush(stdout);
                    497:                }
                    498:                if (ferror (din))
                    499:                        perror ("netin");
                    500:                if (ferror (fout))
                    501:                        perror (local);
                    502:                break;
                    503:        }
                    504:        (void) fclose(din);
                    505:        if (closefunc != NULL)
                    506:                (*closefunc)(fout);
                    507:        (void) getreply(0);
                    508: done:
                    509:        gettimeofday(&stop, (struct timezone *)0);
                    510:        signal(SIGINT, oldintr);
                    511:        if (bytes > 0 && verbose) {
                    512:                ptransfer("received", bytes, &start, &stop);
                    513:                if (fout != stdout)
                    514:                        printf("Actual size of %s is %d bytes\n", local, wrcnt);
                    515:        }
                    516:        return;
                    517: bad:
                    518:        if (data >= 0) {
                    519: /*
                    520: /*             if (din != NULL) {
                    521: /*                     printf("\nstart drainning..\n");
                    522: /*                     if (!empty(din))
                    523: /*                             for(;;) { c=getc(din);
                    524: /*                                     if (c == EOF) break;
                    525: /*                             }
                    526: /*             }
                    527: /*             (void) getreply(0);
                    528: /**/
                    529:                (void) close(data), data = -1;
                    530:        }
                    531:        if (closefunc != NULL && fout != NULL)
                    532:                (*closefunc)(fout);
                    533:        goto done;
                    534: }
                    535: 
                    536: /*
                    537:  * Need to start a listen on the data channel
                    538:  * before we send the command, otherwise the
                    539:  * server's connect may fail.
                    540:  */
                    541: static int sendport = -1;
                    542: 
                    543: initconn()
                    544: {
                    545:        register char *p, *a;
                    546:        int result, len;
                    547: 
                    548: noport:
                    549:        data_addr = myctladdr;
                    550:        if (sendport)
                    551:                data_addr.sin_port = 0; /* let system pick one */ 
                    552:        if (data != -1)
                    553:                (void) close (data);
                    554:        data = socket(AF_INET, SOCK_STREAM, 0, 0);
                    555:        if (data < 0) {
                    556:                perror("ftp: socket");
                    557:                return (1);
                    558:        }
                    559:        if (!sendport)
                    560:                if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) {
                    561:                        perror("ftp: setsockopt (resuse address)");
                    562:                        goto bad;
                    563:                }
                    564:        if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
                    565:                perror("ftp: bind");
                    566:                goto bad;
                    567:        }
                    568:        if (options & SO_DEBUG &&
                    569:            setsockopt(data, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
                    570:                perror("ftp: setsockopt (ignored)");
                    571:        len = sizeof (data_addr);
                    572:        if (getsockname(data, (char *)&data_addr, &len) < 0) {
                    573:                perror("ftp: getsockname");
                    574:                goto bad;
                    575:        }
                    576:        if (listen(data, 1) < 0) {
                    577:                perror("ftp: listen");
                    578:                goto bad;
                    579:        }
                    580:        if (sendport) {
                    581:                a = (char *)&data_addr.sin_addr;
                    582:                p = (char *)&data_addr.sin_port;
                    583: #define        UC(b)   (((int)b)&0xff)
                    584:                result =
                    585:                    command("PORT %d,%d,%d,%d,%d,%d",
                    586:                      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
                    587:                      UC(p[0]), UC(p[1]));
                    588:                if (result == ERROR && sendport == -1) {
                    589:                        sendport = 0;
                    590:                        goto noport;
                    591:                }
                    592:                return (result != COMPLETE);
                    593:        }
                    594:        return (0);
                    595: bad:
                    596:        (void) close(data), data = -1;
                    597:        return (1);
                    598: }
                    599: 
                    600: FILE *
                    601: dataconn(mode)
                    602:        char *mode;
                    603: {
                    604:        struct sockaddr_in from;
                    605:        int s, fromlen = sizeof (from);
                    606: 
                    607:        s = accept(data, &from, &fromlen, 0);
                    608:        if (s < 0) {
                    609:                perror("ftp: accept");
                    610:                (void) close(data), data = -1;
                    611:                return (NULL);
                    612:        }
                    613:        (void) close(data);
                    614:        data = s;
                    615:        return (fdopen(data, mode));
                    616: }
                    617: 
                    618: ptransfer(direction, bytes, t0, t1)
                    619:        char *direction;
                    620:        long bytes;
                    621:        struct timeval *t0, *t1;
                    622: {
                    623:        struct timeval td;
                    624:        long ms;
                    625:        float bs;
                    626: 
                    627:        tvsub(&td, t1, t0);
                    628:        ms = (td.tv_sec * 1000) + (td.tv_usec / 1000);
                    629: #define        nz(x)   ((x) == 0 ? 1 : (x))
                    630:        bs = ((bytes * NBBY * 1000) / (float) nz(ms)) / NBBY;
                    631:        printf("%ld bytes %s in %d.%02d seconds (%.2g Kbytes/s)\n",
                    632:                bytes, direction, td.tv_sec, td.tv_usec / 10000, bs / 1024.);
                    633: }
                    634: 
                    635: tvadd(tsum, t0)
                    636:        struct timeval *tsum, *t0;
                    637: {
                    638: 
                    639:        tsum->tv_sec += t0->tv_sec;
                    640:        tsum->tv_usec += t0->tv_usec;
                    641:        if (tsum->tv_usec > 1000000)
                    642:                tsum->tv_sec++, tsum->tv_usec -= 1000000;
                    643: }
                    644: 
                    645: tvsub(tdiff, t1, t0)
                    646:        struct timeval *tdiff, *t1, *t0;
                    647: {
                    648: 
                    649:        tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
                    650:        tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
                    651:        if (tdiff->tv_usec < 0)
                    652:                tdiff->tv_sec--, tdiff->tv_usec += 1000000;
                    653: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.