diff options
author | jkh <jkh@FreeBSD.org> | 1995-07-30 09:33:31 +0000 |
---|---|---|
committer | jkh <jkh@FreeBSD.org> | 1995-07-30 09:33:31 +0000 |
commit | 782b43871131b7fd0a0f0d61e0259ba53abdc148 (patch) | |
tree | 9b729bf55edeb4c5048aa69b7ef53bbc088bbb51 /usr.sbin/pkg_install | |
parent | e01c747916f2222da20856e1a7ff37577fa76eb9 (diff) | |
download | FreeBSD-src-782b43871131b7fd0a0f0d61e0259ba53abdc148.zip FreeBSD-src-782b43871131b7fd0a0f0d61e0259ba53abdc148.tar.gz |
Totally eliminate the dependency on libftp (which will be removed from the
FreeBSD source tree) and switch to the internal ftp routines developed
by Poul-Henning and used in sysinstall.
Diffstat (limited to 'usr.sbin/pkg_install')
-rw-r--r-- | usr.sbin/pkg_install/lib/file.c | 86 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/ftp.c | 440 | ||||
-rw-r--r-- | usr.sbin/pkg_install/lib/ftp.h | 29 |
3 files changed, 505 insertions, 50 deletions
diff --git a/usr.sbin/pkg_install/lib/file.c b/usr.sbin/pkg_install/lib/file.c index 55ba9d5..c8f4988 100644 --- a/usr.sbin/pkg_install/lib/file.c +++ b/usr.sbin/pkg_install/lib/file.c @@ -1,5 +1,5 @@ #ifndef lint -static const char *rcsid = "$Id: file.c,v 1.11 1995/06/24 10:12:59 asami Exp $"; +static const char *rcsid = "$Id: file.c,v 1.12 1995/07/30 01:44:44 ache Exp $"; #endif /* @@ -23,7 +23,7 @@ static const char *rcsid = "$Id: file.c,v 1.11 1995/06/24 10:12:59 asami Exp $"; */ #include "lib.h" -#include <FtpLibrary.h> +#include "ftp.h" #include <pwd.h> /* Quick check to see if a file exists */ @@ -161,52 +161,26 @@ fileURLFilename(char *fname, char *where, int max) return fname; } -/* - * Callback functions for fileGetURL - GetIO is called on I/O requests - * and GetAbort when the transfer aborts. - */ - -/* Something they can use to keep track of the action */ -Boolean connectionAborted = FALSE; - -static int -_fileGetIO(FTP *ftp, int n, char *s ) -{ - printf("In IO: %s\n", s); - return 0; -} - -static int -_fileGetAbort(FTP *ftp, int n, char *s ) -{ - /* No access or not found, exclude network or host unreachable */ - if (abs(n) == 550 && FtpBadReply550(s)) { - connectionAborted = TRUE; - return 1; - } - return 0; -} - #define HOSTNAME_MAX 64 - /* - * Try and fetch a file by URL, returning the name of the local - * copy if fetched successfully. + * Try and fetch a file by URL, returning the fd of open + * file if fetched successfully. */ char * fileGetURL(char *fname) { - static char out[FILENAME_MAX]; - char *cp; char host[HOSTNAME_MAX], file[FILENAME_MAX], dir[FILENAME_MAX]; - char pword[HOSTNAME_MAX + 40], *uname; + char pword[HOSTNAME_MAX + 40], *uname, *cp; + static char tmpl[40]; struct passwd *pw; - FTP *ftp; - int i; + FTP_t ftp; + int fd, fd2, i; + char ch; if (!isURL(fname)) return NULL; + ftp = FtpInit(); cp = fileURLHost(fname, host, HOSTNAME_MAX); if (!*cp) { whinge("URL `%s' has bad host part!", fname); @@ -219,10 +193,6 @@ fileGetURL(char *fname) return NULL; } - FtpSetErrorHandler(&FtpInit, _fileGetAbort); - FtpSetFlag(&FtpInit, FTP_REST); - FtpSetTimeout(&FtpInit, 60); /* XXX this may be too short */ - /* Maybe change to ftp if this doesn't work */ uname = "anonymous"; @@ -237,7 +207,10 @@ fileGetURL(char *fname) if (Verbose) printf("Trying to fetch %s from %s.\n", file, host); - FtpLogin(&ftp, host, uname, pword, NULL); + FtpOpen(ftp, host, uname, pword); + /* XXX - Currently undocumented - XXX */ + if (getenv("FTP_PASSIVE")) + FtpPassive(ftp, TRUE); strcpy(dir, file); for (i = strlen(dir); i && dir[i] != '/'; i--); @@ -245,18 +218,31 @@ fileGetURL(char *fname) if (dir[0]) FtpChdir(ftp, dir); - FtpBinary(ftp); - + FtpBinary(ftp, TRUE); + fd = FtpGet(ftp, basename_of(file)); + if (fd < 0) { + whinge("Unable to get `%s' over ftp!", file); + return NULL; + } if ((cp = getenv("PKG_TMPDIR")) != NULL) - sprintf(out, "%s/instpkg-XXXXXX.tgz", cp); + sprintf(tmpl, "%s/instpkg-XXXXXX.tgz", cp); else - strcpy(out, "/var/tmp/instpkg-XXXXXX.tgz"); - - FtpGet(ftp, basename_of(file), out); - FtpBye(ftp); - if (connectionAborted) + strcpy(tmpl, "/var/tmp/instpkg-XXXXXX.tgz"); + cp = mktemp(tmpl); + if (!cp) { + whinge("Unable to make temporary filename from template: %s!", tmpl); return NULL; - return out; + } + fd2 = open(cp, O_CREAT | O_WRONLY); + if (fd2 < 0) { + whinge("Unable to create a temporary file for ftp: %s", tmpl); + return NULL; + } + while (read(fd, &ch, 1) == 1) + write(fd, &ch, 1); + FtpEof(ftp); + FtpClose(ftp); + return tmpl; } char * diff --git a/usr.sbin/pkg_install/lib/ftp.c b/usr.sbin/pkg_install/lib/ftp.c new file mode 100644 index 0000000..99c34d4 --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.c @@ -0,0 +1,440 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $Id: ftp.c,v 1.14 1995/06/11 19:29:55 rgrimes Exp $ + * + * Return values have been sanitized: + * -1 error, but you (still) have a session. + * -2 error, your session is dead. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <netdb.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include "ftp.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* Handy global for us to stick the port # */ +int FtpPort; + +#ifndef STANDALONE_FTP +#include "sysinstall.h" +#endif /*STANDALONE_FTP*/ + +static void +debug(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + va_list ap; + va_start(ap, fmt); +#ifdef STANDALONE_FTP + strcpy(p,"LIBFTP: "); + (void) vsnprintf(p+strlen(p), sizeof p - strlen(p), fmt, ap); + va_end(ap); + write(ftp->fd_debug,p,strlen(p)); +#else + if (isDebug()) { + (void) vsnprintf(p, sizeof p - strlen(p), fmt, ap); + msgDebug(p); + } +#endif +} + +static int +writes(int fd, char *s) +{ + int i = strlen(s); + if (i != write(fd,s,i)) + return -2; + return 0; +} + +static __inline char* +get_a_line(FTP_t ftp) +{ + static char buf[BUFSIZ]; + int i,j; + + for(i=0;i<BUFSIZ;) { + j = read(ftp->fd_ctrl,buf+i,1); + if (j != 1) + return 0; + if (buf[i] == '\r' || buf[i] == '\n') { + if (!i) + continue; + buf[i] = '\0'; + debug(ftp, "received <%s>\n",buf); + return buf; + } + i++; + } + return buf; +} + +static int +get_a_number(FTP_t ftp, char **q) +{ + char *p; + int i = -1,j; + + while(1) { + p = get_a_line(ftp); + if (!p) + return -2; + if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]))) + continue; + if (i == -1 && p[3] == '-') { + i = strtol(p, 0, 0); + continue; + } + if (p[3] != ' ' && p[3] != '\t') + continue; + j = strtol(p, 0, 0); + if (i == -1) { + if (q) *q = p+4; + return j; + } else if (j == i) { + if (q) *q = p+4; + return j; + } + } +} + +static int +zap(FTP_t ftp) +{ + int i; + + i = writes(ftp->fd_ctrl,"QUIT\r\n"); + if (isDebug()) + msgDebug("Zapping ftp connection on %d returns %d\n", ftp->fd_ctrl, i); + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = init; + return -2; +} + +static int +botch(FTP_t ftp, char *func, char *state) +{ + debug(ftp, "Botch: %s called outside state %s\n",func,state); + return -2; +} + +static int +cmd(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + int i; + + va_list ap; + va_start(ap, fmt); + (void) vsnprintf(p, sizeof p, fmt, ap); + va_end(ap); + + debug(ftp, "send <%s>\n",p); + strcat(p,"\r\n"); + if (writes(ftp->fd_ctrl,p)) + return -2; + i = get_a_number(ftp,0); + return i; +} + +FTP_t +FtpInit() +{ + FTP_t ftp; + + ftp = malloc(sizeof *ftp); + if (!ftp) + return ftp; + memset(ftp, 0, sizeof *ftp); + ftp->fd_ctrl = -1; + ftp->fd_xfer = -1; + ftp->fd_debug = -1; + ftp->state = init; + return ftp; +} + +#ifdef STANDALONE_FTP +void +FtpDebug(FTP_t ftp, int i) +{ + ftp->fd_debug = i; +} +#endif + +int +FtpOpen(FTP_t ftp, char *host, char *user, char *passwd) +{ + struct hostent *he = NULL; + struct sockaddr_in sin; + int s; + unsigned long temp; + int i; + + if (ftp->state != init) + return botch(ftp,"FtpOpen","init"); + + if (!user) + user = "ftp"; + + if (!passwd) + passwd = "??@??(FreeBSD:libftp)"; /* XXX */ + + debug(ftp, "FtpOpen(ftp, %s, %s, %s)\n", host, user, passwd); + + temp = inet_addr(host); + if (temp != INADDR_NONE) { + debug(ftp, "Using dotted IP address `%s'\n", host); + ftp->addrtype = sin.sin_family = AF_INET; + sin.sin_addr.s_addr = temp; + } + else { + debug(ftp, "Trying to resolve `%s'\n", host); + he = gethostbyname(host); + if (!he) { + debug(ftp, "Lookup of `%s' failed!\n", host); + return zap(ftp); + } + ftp->addrtype = sin.sin_family = he->h_addrtype; + bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + } + + sin.sin_port = htons(FtpPort ? FtpPort : 21); + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + { + debug(ftp, "Socket open failed: %s (%i)\n", strerror(errno), errno); + return zap(ftp); + } + + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + debug(ftp,"Connection failed: %s (%i)\n", strerror(errno), errno); + (void)close(s); + return zap(ftp); + } + + ftp->fd_ctrl = s; + + debug(ftp, "open (%d)\n",get_a_number(ftp,0)); + + i = cmd(ftp,"USER %s",user); + if (i >= 300 && i < 400) + i = cmd(ftp,"PASS %s",passwd); + if (i >= 299 || i < 0) { + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + return zap(ftp); + } + ftp->state = isopen; + return 0; +} + +void +FtpClose(FTP_t ftp) +{ + if (ftp->state != init) + return; + + if (ftp->state != isopen) + botch(ftp,"FtpClose","open or init"); + + debug(ftp, "FtpClose(ftp)\n"); + zap(ftp); +} + +int +FtpChdir(FTP_t ftp, char *dir) +{ + int i; + if (ftp->state != isopen) + return botch(ftp,"FtpChdir","open"); + i = cmd(ftp,"CWD %s",dir); + if (i < 0) + return i; + else if (i != 250) + return -1; + return 0; +} + +int +FtpGet(FTP_t ftp, char *file) +{ + int i,s; + char *q; + unsigned char addr[64]; + struct sockaddr_in sin; + u_long a; + + debug(ftp, "FtpGet(ftp,%s)\n",file); + if (ftp->state != isopen) + return botch(ftp,"FtpGet","open"); + if(ftp->binary) { + i = cmd(ftp,"TYPE I"); + if (i < 0) + return zap(ftp); + if (i > 299) + return -1; + } else { + return -1; + } + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + return zap(ftp); + + if (ftp->passive) { + debug(ftp, "send <%s>\n","PASV"); + if (writes(ftp->fd_ctrl,"PASV\r\n")) + return zap(ftp); + i = get_a_number(ftp,&q); + if (i < 0) + return zap(ftp); + if (i != 227) + return zap(ftp); + while (*q && !isdigit(*q)) + q++; + if (!*q) + return zap(ftp); + q--; + for(i=0;i<6;i++) { + q++; + addr[i] = strtol(q,&q,10); + } + + sin.sin_family = ftp->addrtype; + bcopy(addr, (char *)&sin.sin_addr, 4); + bcopy(addr+4, (char *)&sin.sin_port, 2); + debug(ftp, "Opening active socket to %s : %u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + + debug(ftp, "Connecting to %s:%u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + (void)close(s); + debug(ftp, "connect: %s (%d)\n", strerror(errno), errno); + return -1; + } + ftp->fd_xfer = s; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + if (isDebug()) + msgDebug("FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->state = xfer; + return s; + } else { + i = sizeof sin; + getsockname(ftp->fd_ctrl,(struct sockaddr *)&sin,&i); + sin.sin_port = 0; + i = sizeof sin; + if (bind(s,(struct sockaddr *)&sin, i) < 0) { + close (s); + debug(ftp,"bind failed %d\n",errno); + return zap(ftp); + } + getsockname(s,(struct sockaddr *)&sin,&i); + if (listen(s,1) < 0) { + close (s); + debug(ftp,"listen failed %d\n",errno); + return zap(ftp); + } + a = ntohl(sin.sin_addr.s_addr); + i = cmd(ftp,"PORT %d,%d,%d,%d,%d,%d", + (a >> 24) & 0xff, + (a >> 16) & 0xff, + (a >> 8) & 0xff, + a & 0xff, + (ntohs(sin.sin_port) >> 8) & 0xff, + ntohs(sin.sin_port) & 0xff); + if (i != 200) + return -1; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + if (isDebug()) + msgDebug("FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->fd_xfer = accept(s, 0, 0); + if (ftp->fd_xfer < 0) { + close(s); + return zap(ftp); + } + ftp->state = xfer; + close(s); + return(ftp->fd_xfer); + } +} + +int +FtpEOF(FTP_t ftp) +{ + int i; + + if (ftp->state != xfer) + return botch(ftp,"FtpEOF","xfer"); + debug(ftp, "FtpEOF(ftp)\n"); + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = isopen; + i = get_a_number(ftp,0); + if (i < 0) + return zap(ftp); + else if (i != 250 && i != 226) + return -1; + else + return 0; +} + +#ifdef STANDALONE_FTP + +/* main.c */ +int +main(int argc, char **argv) +{ + FTP_t ftp; + int i; + char c; + + ftp = FtpInit(); + if (!ftp) + err(1, "FtpInit()"); + + FtpDebug(ftp, 1); + i = FtpOpen(ftp, "freefall.cdrom.com", "ftp", "phk-libftp@"); + FtpBinary(ftp, 1); + FtpPassive(ftp, 0); + FtpChdir(ftp, "/pub"); + FtpChdir(ftp, "FreeBSD"); + i = FtpGet(ftp, "README"); + while (1 == read(i, &c, 1)) + putchar(c); + FtpEOF(ftp); + return 0; +} + +#endif /*STANDALONE_FTP*/ diff --git a/usr.sbin/pkg_install/lib/ftp.h b/usr.sbin/pkg_install/lib/ftp.h new file mode 100644 index 0000000..f1e35d6 --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.h @@ -0,0 +1,29 @@ +#ifndef _FTP_H_INCLUDE +#define _FTP_H_INCLUDE + +typedef struct { + enum {init, isopen, xfer} state; + int fd_ctrl; + int fd_xfer; + int fd_debug; + int binary; + int passive; + int addrtype; + char *host; + char *file; +} *FTP_t; + +FTP_t FtpInit(); +int FtpOpen(FTP_t, char *host, char *user, char *passwd); +#define FtpBinary(ftp,bool) { (ftp)->binary = (bool); } +#define FtpPassive(ftp,bool) { (ftp)->passive = (bool); } +#ifndef STANDALONE_FTP +#define FtpDebug(ftp, bool) { (ftp)->fd_debug = (bool); } +#endif +int FtpChdir(FTP_t, char *); +int FtpGet(FTP_t, char *); +int FtpEOF(FTP_t); +void FtpClose(FTP_t); + +#endif +/* _FTP_H_INCLUDE */ |