diff options
Diffstat (limited to 'lib/libfetch')
| -rw-r--r-- | lib/libfetch/Makefile | 55 | ||||
| -rw-r--r-- | lib/libfetch/README | 17 | ||||
| -rw-r--r-- | lib/libfetch/common.c | 284 | ||||
| -rw-r--r-- | lib/libfetch/common.h | 59 | ||||
| -rw-r--r-- | lib/libfetch/fetch.3 | 220 | ||||
| -rw-r--r-- | lib/libfetch/fetch.c | 231 | ||||
| -rw-r--r-- | lib/libfetch/fetch.h | 71 | ||||
| -rw-r--r-- | lib/libfetch/fetch_err.et | 50 | ||||
| -rw-r--r-- | lib/libfetch/file.c | 87 | ||||
| -rw-r--r-- | lib/libfetch/ftp.c | 280 | ||||
| -rw-r--r-- | lib/libfetch/ftp.errors | 80 | ||||
| -rw-r--r-- | lib/libfetch/http.c | 87 | ||||
| -rw-r--r-- | lib/libfetch/http.errors | 76 |
13 files changed, 426 insertions, 1171 deletions
diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile index 0be36ffbfd157..2afd8bbb623d7 100644 --- a/lib/libfetch/Makefile +++ b/lib/libfetch/Makefile @@ -1,50 +1,53 @@ -# $Id: Makefile,v 1.10 1998/12/16 10:24:52 des Exp $ +# $Id$ LIB= fetch -CFLAGS+= -I. -Wall -pedantic -.if !defined(DEBUG) -CFLAGS+= -DNDEBUG -.endif -SRCS= fetch.c common.c ftp.c http.c file.c fetch_err.c \ - fetch_err.h ftperr.h httperr.h +CFLAGS+= -I. -Wall -pedantic -DNDEBUG +SRCS= fetch.c ftp.c http.c file.c +DPSRCS= ftperr.c httperr.c MAN3= fetch.3 -CLEANFILES= fetch_err.c fetch_err.h ftperr.h httperr.h +CLEANFILES= ${DPSRCS} SHLIB_MAJOR= 1 SHLIB_MINOR= 0 +beforedepend: ${DPSRCS} + beforeinstall: ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/fetch.h \ ${DESTDIR}/usr/include - ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 fetch_err.h \ - ${DESTDIR}/usr/include -ftperr.h: ftp.errors - @echo "static struct fetcherr _ftp_errlist[] = {" > ${.TARGET} +ftperr.c: ftp.errors + @echo "struct ftperr {" \ > ${.TARGET} + @echo " const int num;" \ >> ${.TARGET} + @echo " const char *string;" \ >> ${.TARGET} + @echo "};" \ >> ${.TARGET} + @echo "static struct ftperr _ftp_errlist[] = {" \ >> ${.TARGET} @cat ${.ALLSRC} \ | grep -v ^# \ | sort \ - | while read NUM CAT STRING; do \ - echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \ + | while read NUM STRING; do \ + echo " { $${NUM}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { -1, FETCH_UNKNOWN, \"Unknown FTP error\" }" >> ${.TARGET} + @echo " { -1, \"Unknown FTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} -httperr.h: http.errors - @echo "static struct fetcherr _http_errlist[] = {" > ${.TARGET} +httperr.c: http.errors + @echo "struct httperr {" \ > ${.TARGET} + @echo " const int num;" \ >> ${.TARGET} + @echo " const char *string;" \ >> ${.TARGET} + @echo "};" \ >> ${.TARGET} + @echo "static struct httperr _http_errlist[] = {" \ >> ${.TARGET} @cat ${.ALLSRC} \ | grep -v ^# \ | sort \ - | while read NUM CAT STRING; do \ - echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \ + | while read NUM STRING; do \ + echo " { $${NUM}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { -1, FETCH_UNKNOWN, \"Unknown HTTP error\" }" >> ${.TARGET} + @echo " { -1, \"Unknown HTTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} -hdrs: fetch_err.h - -.ORDER: fetch_err.c fetch_err.h -fetch_err.c fetch_err.h: fetch_err.et - compile_et ${.ALLSRC} - .include <bsd.lib.mk> + +.if !exists(${DEPENDFILE}) +${OBJS} ${POBJS} ${SOBJS}: ${DPSRCS} +.endif diff --git a/lib/libfetch/README b/lib/libfetch/README index 7b8537618ccac..ce50f569c294e 100644 --- a/lib/libfetch/README +++ b/lib/libfetch/README @@ -3,8 +3,19 @@ library and provide a new, unified backend for all fetch(1), pkg_add(1) and sysinstall(8). Note that this is very much work in progress. It compiles (with a few -warnings), but there is much left to be implemented. Comments, patches -etc. of all kinds are welcome, but please don't commit anything -without talking to me first. +warnings), but there is much left to be implemented. Amongst other +items: + + * The man page needs work. Really. I mean it. Now. + + * HTTP authentication doesn't work. I'm not sure if I bungled http.c + or fubared base64.c (which was ripped from MIT fetch(1)). + + * The library needs a decent interface for reporting errors. I've + started on something (sending back an error code in the url_t that + was sent in) but we're Not There (tm) yet. + +Comments, patches etc. of all kinds are welcome, but please don't +commit anything without talking to me first. -- Dag-Erling C. Smørgrav (des@FreeBSD.org) diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c deleted file mode 100644 index e3dab8dfc28a8..0000000000000 --- a/lib/libfetch/common.c +++ /dev/null @@ -1,284 +0,0 @@ -/*- - * Copyright (c) 1998 Dag-Erling Coïdan Smørgrav - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: common.c,v 1.4 1998/12/18 14:32:48 des Exp $ - */ - -#include <sys/param.h> -#include <sys/socket.h> -#include <netinet/in.h> - -#include <com_err.h> -#include <errno.h> -#include <netdb.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "fetch.h" -#include "common.h" - - -/*** Local data **************************************************************/ - -/* - * Error messages for resolver errors - */ -static struct fetcherr _netdb_errlist[] = { - { HOST_NOT_FOUND, FETCH_RESOLV, "Host not found" }, - { TRY_AGAIN, FETCH_TEMP, "Transient resolver failure" }, - { NO_RECOVERY, FETCH_RESOLV, "Non-recoverable resolver failure" }, - { NO_DATA, FETCH_RESOLV, "No address record" }, - { -1, FETCH_UNKNOWN, "Unknown resolver error" } -}; - -static int com_err_initialized; - -/*** Error-reporting functions ***********************************************/ - -/* - * Initialize the common error library - */ -static void -_fetch_init_com_err(void) -{ - initialize_ftch_error_table(); - com_err_initialized = 1; -} - -/* - * Map error code to string - */ -static int -_fetch_finderr(struct fetcherr *p, int e) -{ - int i; - for (i = 0; p[i].num != -1; i++) - if (p[i].num == e) - break; - return i; -} - -/* - * Set error code - */ -void -_fetch_seterr(struct fetcherr *p, int e) -{ - int n; - - if (!com_err_initialized) - _fetch_init_com_err(); - - n = _fetch_finderr(p, e); - fetchLastErrCode = p[n].cat; - com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string); -} - -/* - * Set error code according to errno - */ -void -_fetch_syserr(void) -{ - int e; - e = errno; - - if (!com_err_initialized) - _fetch_init_com_err(); - - switch (errno) { - case 0: - fetchLastErrCode = FETCH_OK; - break; - case EPERM: - case EACCES: - case EROFS: - case EAUTH: - case ENEEDAUTH: - fetchLastErrCode = FETCH_AUTH; - break; - case ENOENT: - case EISDIR: /* XXX */ - fetchLastErrCode = FETCH_UNAVAIL; - break; - case ENOMEM: - fetchLastErrCode = FETCH_MEMORY; - break; - case EBUSY: - case EAGAIN: - fetchLastErrCode = FETCH_TEMP; - break; - case EEXIST: - fetchLastErrCode = FETCH_EXISTS; - break; - case ENOSPC: - fetchLastErrCode = FETCH_FULL; - break; - case EADDRINUSE: - case EADDRNOTAVAIL: - case ENETDOWN: - case ENETUNREACH: - case ENETRESET: - case EHOSTUNREACH: - fetchLastErrCode = FETCH_NETWORK; - break; - case ECONNABORTED: - case ECONNRESET: - fetchLastErrCode = FETCH_ABORT; - break; - case ETIMEDOUT: - fetchLastErrCode = FETCH_TIMEOUT; - break; - case ECONNREFUSED: - case EHOSTDOWN: - fetchLastErrCode = FETCH_DOWN; - break; - default: - fetchLastErrCode = FETCH_UNKNOWN; - } - com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e)); -} - - -/* - * Emit status message - */ -int -_fetch_info(char *fmt, ...) -{ - va_list ap; - char *s; - - if (!com_err_initialized) - _fetch_init_com_err(); - - va_start(ap, fmt); - vasprintf(&s, fmt, ap); - va_end(ap); - - if (s == NULL) { - com_err("libfetch", FETCH_MEMORY, ""); - return -1; - } else { - com_err("libfetch", FETCH_VERBOSE, "%s", s); - free(s); - return 0; - } -} - - -/*** Network-related utility functions ***************************************/ - -/* - * Establish a TCP connection to the specified port on the specified host. - */ -int -_fetch_connect(char *host, int port, int verbose) -{ - struct sockaddr_in sin; - struct hostent *he; - int sd; - -#ifndef NDEBUG - fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); -#endif - - if (verbose) - _fetch_info("looking up %s", host); - - /* look up host name */ - if ((he = gethostbyname(host)) == NULL) { - _netdb_seterr(h_errno); - return -1; - } - - if (verbose) - _fetch_info("connecting to %s:%d", host, port); - - /* set up socket address structure */ - bzero(&sin, sizeof(sin)); - bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); - sin.sin_family = he->h_addrtype; - sin.sin_port = htons(port); - - /* try to connect */ - if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { - _fetch_syserr(); - return -1; - } - if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { - _fetch_syserr(); - close(sd); - return -1; - } - - return sd; -} - - -/*** Directory-related utility functions *************************************/ - -int -_fetch_add_entry(struct url_ent **p, int *size, int *len, - char *name, struct url_stat *stat) -{ - struct url_ent *tmp; - - if (*p == NULL) { -#define INITIAL_SIZE 8 - if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) { - errno = ENOMEM; - _fetch_syserr(); - return -1; - } - *size = INITIAL_SIZE; - *len = 0; -#undef INITIAL_SIZE - } - - if (*len >= *size - 1) { - tmp = realloc(*p, *size * 2 * sizeof **p); - if (tmp == NULL) { - errno = ENOMEM; - _fetch_syserr(); - return -1; - } - *size *= 2; - *p = tmp; - } - - tmp = *p + *len; - snprintf(tmp->name, MAXPATHLEN, "%s", name); - bcopy(stat, &tmp->stat, sizeof *stat); - - (*len)++; - (++tmp)->name[0] = 0; - - return 0; -} diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h deleted file mode 100644 index 0a1154885b787..0000000000000 --- a/lib/libfetch/common.h +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 1998 Dag-Erling Coïdan Smørgrav - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: common.h,v 1.4 1998/12/18 14:32:48 des Exp $ - */ - -#ifndef _COMMON_H_INCLUDED -#define _COMMON_H_INCLUDED - -/* Structure used for error message lists */ -#define ERRCAT_ -struct fetcherr { - const int num, cat; - const char *string; -}; - -void _fetch_seterr(struct fetcherr *, int); -void _fetch_syserr(void); -int _fetch_info(char *fmt, ...); -int _fetch_connect(char *, int, int); -int _fetch_add_entry(struct url_ent **p, int *size, int *len, - char *name, struct url_stat *stat); - -#define _ftp_seterr(n) _fetch_seterr(_ftp_errlist, n) -#define _http_seterr(n) _fetch_seterr(_http_errlist, n) -#define _netdb_seterr(n) _fetch_seterr(_netdb_errlist, n) -#define _url_seterr(n) _fetch_seterr(_url_errlist, n) - -#ifndef NDEBUG -#define DEBUG(x) do x; while (0) -#else -#define DEBUG(x) do { } while (0) -#endif - -#endif diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3 index 16dec553ecfc1..c23d0677b8271 100644 --- a/lib/libfetch/fetch.3 +++ b/lib/libfetch/fetch.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: fetch.3,v 1.6 1998/12/16 15:29:03 des Exp $ +.\" $Id: fetch.3,v 1.1.1.1 1998/07/09 16:52:43 des Exp $ .\" .Dd July 1, 1998 .Dt FETCH 3 @@ -30,74 +30,44 @@ .Sh NAME .Nm fetchGetURL , .Nm fetchPutURL , -.Nm fetchStatURL , -.Nm fetchListURL , .Nm fetchParseURL , +.Nm fetchFreeURL , .Nm fetchGet , .Nm fetchPut , -.Nm fetchStat , -.Nm fetchList , .Nm fetchGetFile , .Nm fetchPutFile , -.Nm fetchStatFile , -.Nm fetchListFile , .Nm fetchGetHTTP , .Nm fetchPutHTTP , -.Nm fetchStatHTTP , -.Nm fetchListHTTP , .Nm fetchGetFTP , .Nm fetchPutFTP -.Nm fetchStatFTP -.Nm fetchListFTP , .Nd file transfer library .Sh SYNOPSIS -.Fd #include <sys/param.h> -.Fd #include <stdio.h> .Fd #include <fetch.h> .Ft FILE * .Fn fetchGetURL "char *URL" "char *flags" .Ft FILE * .Fn fetchPutURL "char *URL" "char *flags" -.Ft int -.Fn fetchStatURL "char *URL" "struct url_stat *us" "char *flags" -.Ft struct url_ent * -.Fn fetchListURL "char *URL" "char *flags" -.Ft struct url * +.Ft url_t * .Fn fetchParseURL "char *URL" "char *flags" +.Ft void +.Fn fetchFreeURL "url_t *u" .Ft FILE * -.Fn fetchGet "struct url *URL" "char *flags" +.Fn fetchGet "url_t *URL" "char *flags" .Ft FILE * -.Fn fetchPut "struct url *URL" "char *flags" -.Ft int -.Fn fetchStat "struct url *URL" "struct url_stat *us" "char *flags" -.Ft struct url_ent * -.Fn fetchList "struct url *" "char *flags" +.Fn fetchPut "url_t *URL" "char *flags" .Ft FILE * -.Fn fetchGetFile "struct url *u" "char *flags" +.Fn fetchGetFile "url_t *u" "char *flags" .Ft FILE * -.Fn fetchPutFile "struct url *u" "char *flags" -.Ft int -.Fn fetchStatFile "struct url *URL" "struct url_stat *us" "char *flags" -.Ft struct url_ent * -.Fn fetchListFile "struct url *" "char *flags" +.Fn fetchPutFile "url_t *u" "char *flags" .Ft FILE * -.Fn fetchGetHTTP "struct url *u" "char *flags" +.Fn fetchGetHTTP "url_t *u" "char *flags" .Ft FILE * -.Fn fetchPutHTTP "struct url *u" "char *flags" -.Ft int -.Fn fetchStatHTTP "struct url *URL" "struct url_stat *us" "char *flags" -.Ft struct url_ent * -.Fn fetchListHTTP "struct url *" "char *flags" +.Fn fetchPutHTTP "url_t *u" "char *flags" .Ft FILE * -.Fn fetchGetFTP "struct url *u" "char *flags" +.Fn fetchGetFTP "url_t *u" "char *flags" .Ft FILE * -.Fn fetchPutFTP "struct url *u" "char *flags" -.Ft int -.Fn fetchStatFTP "struct url *URL" "struct url_stat *us" "char *flags" -.Ft struct url_ent * -.Fn fetchListFTP "struct url *" "char *flags" +.Fn fetchPutFTP "url_t *u" "char *flags" .Sh DESCRIPTION -.Pp These functions implement a high-level library for retrieving and uploading files using Uniform Resource Locators (URLs). .Pp @@ -114,42 +84,6 @@ argument is a string of characters which specify transfer options. The meaning of the individual flags is scheme-dependent, and is detailed in the appropriate section below. .Pp -.Fn fetchStatURL -attempts to obtain the requested document's metadata and fill in the -structure pointed to by it's second argument. The -.Fa url_stat -structure is defined as follows in -.Aq Pa fetch.h : -.Bd -literal -struct url_stat { - off_t size; - time_t atime; - time_t mtime; -}; -.Ed -.Pp -.Fn fetchListURL -attempts to list the contents of the directory pointed to by the URL -provided. If successful, it returns a malloced array of -.Fa url_ent -structures. The -.Fa url_ent -structure is defined as follows in -.Aq Pa fetch.h : -.Bd -literal -struct url_ent { - char name[MAXPATHLEN]; - struct url_stat stat; -}; -.Ed -.Pp -The list is terminated by an entry with an empty name. -.Pp -The pointer returned by -.Fn fetchListURL -should be freed using -.Fn free . -.Pp .Fn fetchParseURL takes a URL in the form of a null-terminated string and splits it into its components function according to the Common Internet Scheme Syntax @@ -166,21 +100,19 @@ and <document> components. The pointer returned by .Fn fetchParseURL should be freed using -.Fn free . +.Fn fetchFreeURL . .Pp -.Fn fetchGet , -.Fn fetchPut +.Fn fetchGet and -.Fn fetchStat +.Fn fetchPut are similar to -.Fn fetchGetURL , -.Fn fetchPutURL +.Fn fetchGetURL and -.Fn fetchStatURL , +.Fn fetchPutURL , except that they expect a pre-parsed URL in the form of a pointer to -a -.Fa struct url -rather than a string. +an +.Fa url_t +structure rather than a string. .Pp All of the .Fn fetchGetXXX @@ -244,66 +176,18 @@ is currently unimplemented. .Sh RETURN VALUES .Fn fetchParseURL returns a pointer to a -.Fa struct url -containing the individual components of the URL. If it is +.Fa url_t +structure containing the individual components of the URL. If it is unable to allocate memory, or the URL is syntactically incorrect, .Fn fetchParseURL returns a NULL pointer. .Pp -The -.Fn fetchStat -functions return 0 on success and -1 on failure. +.Fn fetchFreeURL +does not return any value. .Pp All other functions return a stream pointer which may be used to -access the requested document, or NULL if an error occurred. -.Pp -.Nm Libfetch -uses the Common Error Library -.Nm ( libcom_err ) -to report errors. The error code passed to -.Fn com_err -is one of: -.Bl -tag -width Er -.It Bq Er FETCH_ABORT -Operation aborted -.It Bq Er FETCH_AUTH -Authentication failed -.It Bq Er FETCH_DOWN -Service unavailable -.It Bq Er FETCH_EXISTS -File exists -.It Bq Er FETCH_FULL -File system full -.It Bq Er FETCH_INFO -Informational response -.It Bq Er FETCH_MEMORY -Insufficient memory -.It Bq Er FETCH_MOVED -File has moved -.It Bq Er FETCH_NETWORK -Network error -.It Bq Er FETCH_OK -No error -.It Bq Er FETCH_PROTO -Protocol error -.It Bq Er FETCH_RESOLV -Resolver error -.It Bq Er FETCH_SERVER -Server error -.It Bq Er FETCH_TEMP -Temporary error -.It Bq Er FETCH_TIMEOUT -Operation timed out -.It Bq Er FETCH_UNAVAIL -File is not available -.It Bq Er FETCH_UNKNOWN -Unknown error -.It Bq Er FETCH_URL -Invalid URL -.El -.Pp -The accompanying error message includes a protocol-specific error code -and message, e.g. "File is not available (404 Not Found)" +access the requested document. Upon failure of any kind, they return a +NULL pointer. .Sh ENVIRONMENT The FTP and HTTP related functions use the .Ev HTTP_PROXY @@ -312,7 +196,6 @@ and environment variables, respectively, as the address of a proxy server to use for transferring files. .Sh SEE ALSO -.Xr com_err 3 , .Xr fetch 1 , .Xr ftpio 3 .Rs @@ -333,14 +216,13 @@ to use for transferring files. .%B File Transfer Protocol .%O RFC959 .Re +.Sh DIAGNOSTICS +Add later. .Sh NOTES -The -.Nm fetch -library uses the Common Error library, and applications which link -with -.Nm libfetch -must therefore also link with -.Nm libcom_err . +Some parts of the library are not yet implemented. The most notable +examples of this are +.Fn fetchPutHTTP +and proxy support for the FTP access method. .Sh HISTORY The .Nm fetch @@ -352,27 +234,18 @@ The library was mostly written by .An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org with numerous suggestions from -.An Jordan K. Hubbard Aq jkh@FreeBSD.org , -.An Eugene Skepner Aq eu@qub.com +.An Jordan K. Hubbard Aq jkh@FreeBSD.org and other FreeBSD developers. -It replaces the older +It incorporates the older .Nm ftpio -library written by -.An Poul-Henning Kamp Aq pkh@FreeBSD.org -and +library, which was originally written by +.Nm Poul-Henning Kamp Aq pkh@FreeBSD.org +and later turned inside out by .An Jordan K. Hubbard Aq jkh@FreeBSD.org . .Pp This manual page was written by .An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org .Sh BUGS -Some parts of the library are not yet implemented. The most notable -examples of this are -.Fn fetchPutHTTP , -.Fn fetchStatHTTP , -.Fn fetchListHTTP , -.Fn fetchListFTP , -and FTP proxy support. -.Pp There's no way to select a proxy at run-time other than setting the .Ev HTTP_PROXY or @@ -386,21 +259,6 @@ code; as far as I can determine, .Nm libfetch handles HTTP/1.1 basic authentication correctly as outlined in RFC2068, but I haven't been able to find an HTTP server that honors -the Authentication: header field. Also, -.Nm libfetch -does not attempt to interpret and respond to authentication requests -from the HTTP server. -.Pp -No attempt is made to encode spaces etc. within URLs. Spaces in the -document part of an URLshould be replaced with "%20" in HTTP URLs and -"\\ " in FTP URLs. -.Pp -Error numbers are unique only within a certain context; the error -codes used for FTP and HTTP overlap, as do those used for resolver and -system errors. For instance, error code 202 means "Command not -implemented, superfluous at this site" in an FTP context and -"Accepted" in an HTTP context. -.Pp -The man page is poorly written and produces badly formatted text. +the Authentication: header field. .Pp Tons of other stuff. diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c index d8d2443787ced..54421a25b1ef7 100644 --- a/lib/libfetch/fetch.c +++ b/lib/libfetch/fetch.c @@ -25,48 +25,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: fetch.c,v 1.7 1998/12/16 10:24:54 des Exp $ + * $Id: fetch.c,v 1.3 1998/07/11 21:29:07 des Exp $ */ #include <sys/param.h> -#include <sys/errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> #include <ctype.h> +#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include "fetch.h" -#include "common.h" +#ifndef NDEBUG +#define DEBUG(x) do x; while (0) +#else +#define DEBUG(x) do { } while (0) +#endif int fetchLastErrCode; +const char *fetchLastErrText; - -/*** Local data **************************************************************/ - -/* - * Error messages for parser errors - */ -#define URL_MALFORMED 1 -#define URL_BAD_SCHEME 2 -#define URL_BAD_PORT 3 -static struct fetcherr _url_errlist[] = { - { URL_MALFORMED, FETCH_URL, "Malformed URL" }, - { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" }, - { URL_BAD_PORT, FETCH_URL, "Invalid server port" }, - { -1, FETCH_UNKNOWN, "Unknown parser error" } -}; - - -/*** Public API **************************************************************/ - -/* - * Select the appropriate protocol for the URL scheme, and return a - * read-only stream connected to the document referenced by the URL. - */ FILE * -fetchGet(struct url *URL, char *flags) +fetchGet(url_t *URL, char *flags) { if (strcasecmp(URL->scheme, "file") == 0) return fetchGetFile(URL, flags); @@ -74,18 +60,12 @@ fetchGet(struct url *URL, char *flags) return fetchGetHTTP(URL, flags); else if (strcasecmp(URL->scheme, "ftp") == 0) return fetchGetFTP(URL, flags); - else { - _url_seterr(URL_BAD_SCHEME); - return NULL; - } + else return NULL; + } -/* - * Select the appropriate protocol for the URL scheme, and return a - * write-only stream connected to the document referenced by the URL. - */ FILE * -fetchPut(struct url *URL, char *flags) +fetchPut(url_t *URL, char *flags) { if (strcasecmp(URL->scheme, "file") == 0) return fetchPutFile(URL, flags); @@ -93,57 +73,14 @@ fetchPut(struct url *URL, char *flags) return fetchPutHTTP(URL, flags); else if (strcasecmp(URL->scheme, "ftp") == 0) return fetchPutFTP(URL, flags); - else { - _url_seterr(URL_BAD_SCHEME); - return NULL; - } -} - -/* - * Select the appropriate protocol for the URL scheme, and return the - * size of the document referenced by the URL if it exists. - */ -int -fetchStat(struct url *URL, struct url_stat *us, char *flags) -{ - if (strcasecmp(URL->scheme, "file") == 0) - return fetchStatFile(URL, us, flags); - else if (strcasecmp(URL->scheme, "http") == 0) - return fetchStatHTTP(URL, us, flags); - else if (strcasecmp(URL->scheme, "ftp") == 0) - return fetchStatFTP(URL, us, flags); - else { - _url_seterr(URL_BAD_SCHEME); - return -1; - } -} - -/* - * Select the appropriate protocol for the URL scheme, and return a - * list of files in the directory pointed to by the URL. - */ -struct url_ent * -fetchList(struct url *URL, char *flags) -{ - if (strcasecmp(URL->scheme, "file") == 0) - return fetchListFile(URL, flags); - else if (strcasecmp(URL->scheme, "http") == 0) - return fetchListHTTP(URL, flags); - else if (strcasecmp(URL->scheme, "ftp") == 0) - return fetchListFTP(URL, flags); - else { - _url_seterr(URL_BAD_SCHEME); - return NULL; - } + else return NULL; } -/* - * Attempt to parse the given URL; if successful, call fetchGet(). - */ +/* get URL */ FILE * fetchGetURL(char *URL, char *flags) { - struct url *u; + url_t *u; FILE *f; if ((u = fetchParseURL(URL)) == NULL) @@ -151,18 +88,16 @@ fetchGetURL(char *URL, char *flags) f = fetchGet(u, flags); - free(u); + fetchFreeURL(u); return f; } -/* - * Attempt to parse the given URL; if successful, call fetchPut(). - */ +/* put URL */ FILE * fetchPutURL(char *URL, char *flags) { - struct url *u; + url_t *u; FILE *f; if ((u = fetchParseURL(URL)) == NULL) @@ -170,73 +105,32 @@ fetchPutURL(char *URL, char *flags) f = fetchPut(u, flags); - free(u); + fetchFreeURL(u); return f; } /* - * Attempt to parse the given URL; if successful, call fetchStat(). - */ -int -fetchStatURL(char *URL, struct url_stat *us, char *flags) -{ - struct url *u; - int s; - - if ((u = fetchParseURL(URL)) == NULL) - return -1; - - s = fetchStat(u, us, flags); - - free(u); - return s; -} - -/* - * Attempt to parse the given URL; if successful, call fetchList(). - */ -struct url_ent * -fetchListURL(char *URL, char *flags) -{ - struct url *u; - struct url_ent *ue; - - if ((u = fetchParseURL(URL)) == NULL) - return NULL; - - ue = fetchList(u, flags); - - free(u); - return ue; -} - -/* * Split an URL into components. URL syntax is: * method:[//[user[:pwd]@]host[:port]]/[document] * This almost, but not quite, RFC1738 URL syntax. */ -struct url * +url_t * fetchParseURL(char *URL) { char *p, *q; - struct url *u; + url_t *u; int i; - /* allocate struct url */ - if ((u = calloc(1, sizeof(struct url))) == NULL) { - errno = ENOMEM; - _fetch_syserr(); + /* allocate url_t */ + if ((u = calloc(1, sizeof(url_t))) == NULL) return NULL; - } /* scheme name */ for (i = 0; *URL && (*URL != ':'); URL++) if (i < URL_SCHEMELEN) u->scheme[i++] = *URL; - if (!URL[0] || (URL[1] != '/')) { - _url_seterr(URL_BAD_SCHEME); + if (!URL[0] || (URL[1] != '/')) goto ouch; - } else URL++; if (URL[1] != '/') { p = URL; @@ -245,7 +139,7 @@ fetchParseURL(char *URL) else URL += 2; p = strpbrk(URL, "/@"); - if (p && *p == '@') { + if (*p == '@') { /* username */ for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) if (i < URL_USERLEN) @@ -270,31 +164,18 @@ fetchParseURL(char *URL) for (q = ++p; *q && (*q != '/'); q++) if (isdigit(*q)) u->port = u->port * 10 + (*q - '0'); - else { - /* invalid port */ - _url_seterr(URL_BAD_PORT); - goto ouch; - } + else return 0; /* invalid port */ while (*p && (*p != '/')) p++; } nohost: /* document */ - if (*p) { - struct url *t; - t = realloc(u, sizeof(*u)+strlen(p)-1); - if (t == NULL) { - errno = ENOMEM; - _fetch_syserr(); - goto ouch; - } - u = t; - strcpy(u->doc, p); - } else { - u->doc[0] = '/'; - u->doc[1] = 0; - } + if (*p) + u->doc = strdup(p); + u->doc = strdup(*p ? p : "/"); + if (!u->doc) + goto ouch; DEBUG(fprintf(stderr, "scheme: [\033[1m%s\033[m]\n" @@ -312,3 +193,45 @@ ouch: free(u); return NULL; } + +void +fetchFreeURL(url_t *u) +{ + if (u) { + if (u->doc) + free(u->doc); + free(u); + } +} + +int +fetchConnect(char *host, int port) +{ + struct sockaddr_in sin; + struct hostent *he; + int sd; + +#ifndef NDEBUG + fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); +#endif + + /* look up host name */ + if ((he = gethostbyname(host)) == NULL) + return -1; + + /* set up socket address structure */ + bzero(&sin, sizeof(sin)); + bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + + /* try to connect */ + if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) + return -1; + if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { + close(sd); + return -1; + } + + return sd; +} diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h index 2e33245503cc7..377edad2acc8b 100644 --- a/lib/libfetch/fetch.h +++ b/lib/libfetch/fetch.h @@ -25,13 +25,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: fetch.h,v 1.7 1998/12/16 10:24:55 des Exp $ + * $Id: fetch.h,v 1.3 1998/07/11 21:29:08 des Exp $ */ #ifndef _FETCH_H_INCLUDED #define _FETCH_H_INCLUDED -#include <fetch_err.h> +#include <sys/param.h> +#include <stdio.h> #define _LIBFETCH_VER "libfetch/1.0" @@ -39,57 +40,41 @@ #define URL_USERLEN 256 #define URL_PWDLEN 256 -struct url { - char scheme[URL_SCHEMELEN+1]; - char user[URL_USERLEN+1]; - char pwd[URL_PWDLEN+1]; - char host[MAXHOSTNAMELEN+1]; - int port; - char doc[2]; +struct url_s { + char scheme[URL_SCHEMELEN+1]; + char user[URL_USERLEN+1]; + char pwd[URL_PWDLEN+1]; + char host[MAXHOSTNAMELEN+1]; + char *doc; + int port; }; -struct url_stat { - off_t size; - time_t atime; - time_t mtime; -}; - -struct url_ent { - char name[MAXPATHLEN]; - struct url_stat stat; -}; +typedef struct url_s url_t; /* FILE-specific functions */ -FILE *fetchGetFile(struct url *, char *); -FILE *fetchPutFile(struct url *, char *); -int fetchStatFile(struct url *, struct url_stat *, char *); -struct url_ent *fetchListFile(struct url *, char *); +FILE *fetchGetFile(url_t *, char *); +FILE *fetchPutFile(url_t *, char *); /* HTTP-specific functions */ -char *fetchContentType(FILE *); -FILE *fetchGetHTTP(struct url *, char *); -FILE *fetchPutHTTP(struct url *, char *); -int fetchStatHTTP(struct url *, struct url_stat *, char *); -struct url_ent *fetchListHTTP(struct url *, char *); +char *fetchContentType(FILE *); +FILE *fetchGetHTTP(url_t *, char *); +FILE *fetchPutHTTP(url_t *, char *); /* FTP-specific functions */ -FILE *fetchGetFTP(struct url *, char *); -FILE *fetchPutFTP(struct url *, char *); -int fetchStatFTP(struct url *, struct url_stat *, char *); -struct url_ent *fetchListFTP(struct url *, char *); +FILE *fetchGetFTP(url_t *, char *); +FILE *fetchPutFTP(url_t *, char *); /* Generic functions */ -struct url *fetchParseURL(char *); -FILE *fetchGetURL(char *, char *); -FILE *fetchPutURL(char *, char *); -int fetchStatURL(char *, struct url_stat *, char *); -struct url_ent *fetchListURL(char *, char *); -FILE *fetchGet(struct url *, char *); -FILE *fetchPut(struct url *, char *); -int fetchStat(struct url *, struct url_stat *, char *); -struct url_ent *fetchList(struct url *, char *); +int fetchConnect(char *, int); +url_t *fetchParseURL(char *); +void fetchFreeURL(url_t *); +FILE *fetchGetURL(char *, char *); +FILE *fetchPutURL(char *, char *); +FILE *fetchGet(url_t *, char *); +FILE *fetchPut(url_t *, char *); -/* Last error code */ -extern int fetchLastErrCode; +/* Error code and string */ +extern int fetchLastErrCode; +extern const char *fetchLastErrText; #endif diff --git a/lib/libfetch/fetch_err.et b/lib/libfetch/fetch_err.et deleted file mode 100644 index 2e247a6006aa5..0000000000000 --- a/lib/libfetch/fetch_err.et +++ /dev/null @@ -1,50 +0,0 @@ -#- -# Copyright (c) 1998 Dag-Erling Coïdan Smørgrav -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer -# in this position and unchanged. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# $Id: fetch_err.et,v 1.1 1998/11/06 22:14:08 des Exp $ -# -et ftch - ec FETCH_ABORT, "Operation aborted" - ec FETCH_AUTH, "Authentication failed" - ec FETCH_DOWN, "Service unavailable" - ec FETCH_EXISTS, "File exists" - ec FETCH_FULL, "File system full" - ec FETCH_INFO, "Informational response" - ec FETCH_MEMORY, "Insufficient memory" - ec FETCH_MOVED, "File has moved" - ec FETCH_NETWORK, "Network error" - ec FETCH_OK, "No error" - ec FETCH_PROTO, "Protocol error" - ec FETCH_RESOLV, "Resolver error" - ec FETCH_SERVER, "Server error" - ec FETCH_TEMP, "Temporary error" - ec FETCH_TIMEOUT, "Operation timed out" - ec FETCH_UNAVAIL, "File is not available" - ec FETCH_UNKNOWN, "Unknown error" - ec FETCH_URL, "Invalid URL" - ec FETCH_VERBOSE, "" -end diff --git a/lib/libfetch/file.c b/lib/libfetch/file.c index 15cb043f52b14..0c685ef34f815 100644 --- a/lib/libfetch/file.c +++ b/lib/libfetch/file.c @@ -25,98 +25,25 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: file.c,v 1.3 1998/12/16 10:24:55 des Exp $ + * $Id$ */ -#include <sys/param.h> -#include <sys/stat.h> - -#include <dirent.h> #include <stdio.h> #include <string.h> #include "fetch.h" -#include "common.h" FILE * -fetchGetFile(struct url *u, char *flags) +fetchGetFile(url_t *u, char *flags) { - FILE *f; - - f = fopen(u->doc, "r"); - - if (f == NULL) - _fetch_syserr(); - return f; + flags = flags; /* unused */ + return fopen(u->doc, "r"); } FILE * -fetchPutFile(struct url *u, char *flags) +fetchPutFile(url_t *u, char *flags) { - FILE *f; - if (strchr(flags, 'a')) - f = fopen(u->doc, "a"); - else - f = fopen(u->doc, "w"); - - if (f == NULL) - _fetch_syserr(); - return f; -} - -static int -_fetch_stat_file(char *fn, struct url_stat *us) -{ - struct stat sb; - - if (stat(fn, &sb) == -1) { - _fetch_syserr(); - return -1; - } - us->size = sb.st_size; - us->atime = sb.st_atime; - us->mtime = sb.st_mtime; - return 0; -} - -int -fetchStatFile(struct url *u, struct url_stat *us, char *flags) -{ - return _fetch_stat_file(u->doc, us); -} - -struct url_ent * -fetchListFile(struct url *u, char *flags) -{ - DIR *dir; - struct dirent *de; - struct url_stat us; - struct url_ent *ue; - int size, len; - char fn[MAXPATHLEN], *p; - int l; - - if ((dir = opendir(u->doc)) == NULL) { - _fetch_syserr(); - return NULL; - } - - ue = NULL; - strncpy(fn, u->doc, sizeof fn - 2); - fn[sizeof fn - 2] = 0; - strcat(fn, "/"); - p = strchr(fn, 0); - l = sizeof fn - strlen(fn) - 1; - - while ((de = readdir(dir)) != NULL) { - strncpy(p, de->d_name, l - 1); - p[l - 1] = 0; - if (_fetch_stat_file(fn, &us) == -1) - /* should I return a partial result, or abort? */ - break; - _fetch_add_entry(&ue, &size, &len, de->d_name, &us); - } - - return ue; + return fopen(u->doc, "a"); + else return fopen(u->doc, "w"); } diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 10e27b45ae939..d66b7c3f74940 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: ftp.c,v 1.11 1998/12/18 14:32:48 des Exp $ + * $Id: ftp.c,v 1.4 1998/07/12 22:34:39 des Exp $ */ /* @@ -55,30 +55,30 @@ * */ -#include <sys/param.h> +#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <sys/errno.h> #include <ctype.h> +#include <errno.h> +#include <netdb.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #include <unistd.h> #include "fetch.h" -#include "common.h" -#include "ftperr.h" +#include "ftperr.c" +#define FTP_DEFAULT_TO_ANONYMOUS #define FTP_ANONYMOUS_USER "ftp" #define FTP_ANONYMOUS_PASSWORD "ftp" #define FTP_DEFAULT_PORT 21 #define FTP_OPEN_DATA_CONNECTION 150 #define FTP_OK 200 -#define FTP_FILE_STATUS 213 -#define FTP_SERVICE_READY 220 #define FTP_PASSIVE_MODE 227 #define FTP_LOGGED_IN 230 #define FTP_FILE_ACTION_OK 250 @@ -87,44 +87,84 @@ #define ENDL "\r\n" -static struct url cached_host; +static url_t cached_host; static FILE *cached_socket; -static char _ftp_last_reply[1024]; +static char *_ftp_last_reply; + +/* + * Map error code to string + */ +static const char * +_ftp_errstring(int e) +{ + struct ftperr *p = _ftp_errlist; + + while ((p->num != -1) && (p->num != e)) + p++; + + return p->string; +} + +/* + * Set error code + */ +static void +_ftp_seterr(int e) +{ + fetchLastErrCode = e; + fetchLastErrText = _ftp_errstring(e); +} + +/* + * Set error code according to errno + */ +static void +_ftp_syserr(void) +{ + fetchLastErrCode = errno; + fetchLastErrText = strerror(errno); +} /* * Get server response, check that first digit is a '2' */ static int -_ftp_chkerr(FILE *s) +_ftp_chkerr(FILE *s, int *e) { char *line; size_t len; + if (e) + *e = 0; + do { if (((line = fgetln(s, &len)) == NULL) || (len < 4)) { - _fetch_syserr(); + _ftp_syserr(); return -1; } - } while (len >= 4 && line[3] == '-'); + } while (line[3] == '-'); - while (len && isspace(line[len-1])) - len--; - snprintf(_ftp_last_reply, sizeof(_ftp_last_reply), - "%*.*s", (int)len, (int)len, line); + _ftp_last_reply = line; #ifndef NDEBUG fprintf(stderr, "\033[1m<<< "); - fprintf(stderr, "%*.*s\n", (int)len, (int)len, line); + fprintf(stderr, "%*.*s", (int)len, (int)len, line); fprintf(stderr, "\033[m"); #endif - if (len < 4 || !isdigit(line[1]) || !isdigit(line[1]) + if (!isdigit(line[1]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' ')) { + _ftp_seterr(-1); return -1; } - return (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0'); + _ftp_seterr((line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0')); + + if (e) + *e = fetchLastErrCode; + + return (line[0] == '2') - 1; } /* @@ -134,6 +174,7 @@ static int _ftp_cmd(FILE *f, char *fmt, ...) { va_list ap; + int e; va_start(ap, fmt); vfprintf(f, fmt, ap); @@ -144,7 +185,8 @@ _ftp_cmd(FILE *f, char *fmt, ...) #endif va_end(ap); - return _ftp_chkerr(f); + _ftp_chkerr(f, &e); + return e; } /* @@ -154,31 +196,28 @@ static FILE * _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) { struct sockaddr_in sin; - int e, sd = -1, l; + int sd = -1, l; char *s; FILE *df; /* change directory */ if (((s = strrchr(file, '/')) != NULL) && (s != file)) { *s = 0; - if ((e = _ftp_cmd(cf, "CWD %s" ENDL, file)) != FTP_FILE_ACTION_OK) { + if (_ftp_cmd(cf, "CWD %s" ENDL, file) != FTP_FILE_ACTION_OK) { *s = '/'; - _ftp_seterr(e); return NULL; } *s++ = '/'; } else { - if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK) { - _ftp_seterr(e); + if (_ftp_cmd(cf, "CWD /" ENDL) != FTP_FILE_ACTION_OK) return NULL; - } } /* s now points to file name */ /* open data socket */ if ((sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - _fetch_syserr(); + _ftp_syserr(); return NULL; } @@ -188,7 +227,7 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) int i; /* send PASV command */ - if ((e = _ftp_cmd(cf, "PASV" ENDL)) != FTP_PASSIVE_MODE) + if (_ftp_cmd(cf, "PASV" ENDL) != FTP_PASSIVE_MODE) goto ouch; /* find address and port number. The reply to the PASV command @@ -213,8 +252,7 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) goto sysouch; /* make the server initiate the transfer */ - e = _ftp_cmd(cf, "%s %s" ENDL, oper, s); - if (e != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; } else { @@ -237,16 +275,13 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) goto sysouch; a = ntohl(sin.sin_addr.s_addr); p = ntohs(sin.sin_port); - e = _ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL, - (a >> 24) & 0xff, (a >> 16) & 0xff, - (a >> 8) & 0xff, a & 0xff, - (p >> 8) & 0xff, p & 0xff); - if (e != FTP_OK) + if (_ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL, + (a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff, + (p >> 8) & 0xff, p & 0xff) != FTP_OK) goto ouch; /* make the server initiate the transfer */ - e = _ftp_cmd(cf, "%s %s" ENDL, oper, s); - if (e != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; /* accept the incoming connection and go to town */ @@ -261,12 +296,8 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) return df; sysouch: - _fetch_syserr(); - close(sd); - return NULL; - + _ftp_syserr(); ouch: - _ftp_seterr(e); close(sd); return NULL; } @@ -275,7 +306,7 @@ ouch: * Log on to FTP server */ static FILE * -_ftp_connect(char *host, int port, char *user, char *pwd, int verbose) +_ftp_connect(char *host, int port, char *user, char *pwd) { int sd, e, pp = FTP_DEFAULT_PORT; char *p, *q; @@ -289,29 +320,28 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) } if (q) *q = 0; - sd = _fetch_connect(p, pp, verbose); + sd = fetchConnect(p, pp); if (q) *q = ':'; } else { /* no proxy, go straight to target */ - sd = _fetch_connect(host, port, verbose); + sd = fetchConnect(host, port); } /* check connection */ if (sd == -1) { - _fetch_syserr(); + _ftp_syserr(); return NULL; } /* streams make life easier */ if ((f = fdopen(sd, "r+")) == NULL) { - _fetch_syserr(); - close(sd); - return NULL; + _ftp_syserr(); + goto ouch; } /* expect welcome message */ - if ((e = _ftp_chkerr(f)) != FTP_SERVICE_READY) + if (_ftp_chkerr(f, NULL) == -1) goto fouch; /* send user name and password */ @@ -329,7 +359,7 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) /* did the server request an account? */ if (e == FTP_NEED_ACCOUNT) - goto fouch; + /* help! */ ; /* we should be done by now */ if (e != FTP_LOGGED_IN) @@ -337,17 +367,19 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) /* might as well select mode and type at once */ #ifdef FTP_FORCE_STREAM_MODE - if ((e = _ftp_cmd(f, "MODE S" ENDL)) != FTP_OK) /* default is S */ - goto fouch; + if (_ftp_cmd(f, "MODE S" ENDL) != FTP_OK) /* default is S */ + goto ouch; #endif - if ((e = _ftp_cmd(f, "TYPE I" ENDL)) != FTP_OK) /* default is A */ - goto fouch; + if (_ftp_cmd(f, "TYPE I" ENDL) != FTP_OK) /* default is A */ + goto ouch; /* done */ return f; +ouch: + close(sd); + return NULL; fouch: - _ftp_seterr(e); fclose(f); return NULL; } @@ -358,7 +390,7 @@ fouch: static void _ftp_disconnect(FILE *f) { - (void)_ftp_cmd(f, "QUIT" ENDL); + _ftp_cmd(f, "QUIT" ENDL); fclose(f); } @@ -366,7 +398,7 @@ _ftp_disconnect(FILE *f) * Check if we're already connected */ static int -_ftp_isconnected(struct url *url) +_ftp_isconnected(url_t *url) { return (cached_socket && (strcmp(url->host, cached_host.host) == 0) @@ -376,145 +408,53 @@ _ftp_isconnected(struct url *url) } /* - * Check the cache, reconnect if no luck + * FTP session */ static FILE * -_ftp_cached_connect(struct url *url, char *flags) +fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) { - FILE *cf; + FILE *cf = NULL; + int e; - cf = NULL; - /* set default port */ if (!url->port) url->port = FTP_DEFAULT_PORT; - /* try to use previously cached connection */ - if (_ftp_isconnected(url)) - if (_ftp_cmd(cached_socket, "NOOP" ENDL) != -1) + /* try to use previously cached connection; there should be a 226 waiting */ + if (_ftp_isconnected(url)) { + _ftp_chkerr(cached_socket, &e); + if (e > 0) cf = cached_socket; + } /* connect to server */ if (!cf) { - cf = _ftp_connect(url->host, url->port, url->user, url->pwd, - (strchr(flags, 'v') != NULL)); + cf = _ftp_connect(url->host, url->port, url->user, url->pwd); if (!cf) return NULL; if (cached_socket) _ftp_disconnect(cached_socket); cached_socket = cf; - memcpy(&cached_host, url, sizeof(struct url)); + memcpy(&cached_host, url, sizeof(url_t)); } - return cf; -} - -/* - * Get file - */ -FILE * -fetchGetFTP(struct url *url, char *flags) -{ - FILE *cf; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return NULL; - /* initiate the transfer */ - return _ftp_transfer(cf, "RETR", url->doc, "r", - (flags && strchr(flags, 'p'))); + return _ftp_transfer(cf, oper, url->doc, mode, (flags && strchr(flags, 'p'))); } /* - * Put file + * Itsy bitsy teeny weenie */ FILE * -fetchPutFTP(struct url *url, char *flags) -{ - FILE *cf; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return NULL; - - /* initiate the transfer */ - return _ftp_transfer(cf, (flags && strchr(flags, 'a')) ? "APPE" : "STOR", - url->doc, "w", (flags && strchr(flags, 'p'))); -} - -/* - * Get file stats - */ -int -fetchStatFTP(struct url *url, struct url_stat *us, char *flags) +fetchGetFTP(url_t *url, char *flags) { - FILE *cf; - char *ln, *s; - struct tm tm; - time_t t; - int e; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return -1; - - /* change directory */ - if (((s = strrchr(url->doc, '/')) != NULL) && (s != url->doc)) { - *s = 0; - if ((e = _ftp_cmd(cf, "CWD %s" ENDL, url->doc)) != FTP_FILE_ACTION_OK) { - *s = '/'; - goto ouch; - } - *s++ = '/'; - } else { - if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK) - goto ouch; - } - - /* s now points to file name */ - - if (_ftp_cmd(cf, "SIZE %s" ENDL, s) != FTP_FILE_STATUS) - goto ouch; - for (ln = _ftp_last_reply + 4; *ln && isspace(*ln); ln++) - /* nothing */ ; - for (us->size = 0; *ln && isdigit(*ln); ln++) - us->size = us->size * 10 + *ln - '0'; - if (*ln && !isspace(*ln)) { - _ftp_seterr(999); /* XXX should signal a FETCH_PROTO error */ - return -1; - } - - if ((e = _ftp_cmd(cf, "MDTM %s" ENDL, s)) != FTP_FILE_STATUS) - goto ouch; - for (ln = _ftp_last_reply + 4; *ln && isspace(*ln); ln++) - /* nothing */ ; - t = time(NULL); - us->mtime = localtime(&t)->tm_gmtoff; - sscanf(ln, "%04d%02d%02d%02d%02d%02d", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - /* XXX should check the return value from sscanf */ - tm.tm_mon--; - tm.tm_year -= 1900; - tm.tm_isdst = -1; - tm.tm_gmtoff = 0; - us->mtime += mktime(&tm); - us->atime = us->mtime; - return 0; - -ouch: - _ftp_seterr(e); - return -1; + return fetchXxxFTP(url, "RETR", "r", flags); } -/* - * List a directory - */ -extern void warnx(char *, ...); -struct url_ent * -fetchListFTP(struct url *url, char *flags) +FILE * +fetchPutFTP(url_t *url, char *flags) { - warnx("fetchListFTP(): not implemented"); - return NULL; + if (flags && strchr(flags, 'a')) + return fetchXxxFTP(url, "APPE", "w", flags); + else return fetchXxxFTP(url, "STOR", "w", flags); } diff --git a/lib/libfetch/ftp.errors b/lib/libfetch/ftp.errors index d7816d28dedac..53a87f04d7b24 100644 --- a/lib/libfetch/ftp.errors +++ b/lib/libfetch/ftp.errors @@ -1,44 +1,44 @@ -# $Id: ftp.errors,v 1.1.1.1 1998/07/09 16:52:43 des Exp $ +# $Id: ftp.errors,v 1.3 1997/02/22 15:06:47 peter Exp $ # # This list is taken from RFC 959. # It probably needs a going over. # -110 OK Restart marker reply -120 TEMP Service ready in a few minutes -125 OK Data connection already open; transfer starting -150 OK File status okay; about to open data connection -200 OK Command okay -202 PROTO Command not implemented, superfluous at this site -211 INFO System status, or system help reply -212 INFO Directory status -213 INFO File status -214 INFO Help message -215 INFO Set system type -220 OK Service ready for new user -221 OK Service closing control connection -225 OK Data connection open; no transfer in progress -226 OK Requested file action successful -227 OK Entering Passive Mode -230 OK User logged in, proceed -250 OK Requested file action okay, completed -257 OK File/directory created -331 AUTH User name okay, need password -332 AUTH Need account for login -350 OK Requested file action pending further information -421 DOWN Service not available, closing control connection -425 NETWORK Can't open data connection -426 ABORT Connection closed; transfer aborted -450 UNAVAIL File unavailable (e.g., file busy) -451 SERVER Requested action aborted: local error in processing -452 FULL Insufficient storage space in system -500 PROTO Syntax error, command unrecognized -501 PROTO Syntax error in parameters or arguments -502 PROTO Command not implemented -503 PROTO Bad sequence of commands -504 PROTO Command not implemented for that parameter -530 AUTH Not logged in -532 AUTH Need account for storing files -550 UNAVAIL File unavailable (e.g., file not found, no access) -551 PROTO Requested action aborted. Page type unknown -552 FULL Exceeded storage allocation -553 EXISTS File name not allowed +110 Restart marker reply +120 Service ready in a few minutes +125 Data connection already open; transfer starting +150 File status okay; about to open data connection +200 Command okay +202 Command not implemented, superfluous at this site +211 System status, or system help reply +212 Directory status +213 File status +214 Help message +215 Set system type +220 Service ready for new user +221 Service closing control connection +225 Data connection open; no transfer in progress +226 Requested file action successful +227 Entering Passive Mode +230 User logged in, proceed +250 Requested file action okay, completed +257 File/directory created +331 User name okay, need password +332 Need account for login +350 Requested file action pending further information +421 Service not available, closing control connection +425 Can't open data connection +426 Connection closed; transfer aborted +450 File unavailable (e.g., file busy) +451 Requested action aborted: local error in processing +452 Insufficient storage space in system +500 Syntax error, command unrecognized +501 Syntax error in parameters or arguments +502 Command not implemented +503 Bad sequence of commands +504 Command not implemented for that parameter +530 Not logged in +532 Need account for storing files +550 File unavailable (e.g., file not found, no access) +551 Requested action aborted. Page type unknown +552 Exceeded storage allocation +553 File name not allowed diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 0d5804a885c40..9ce86a9c8f0f1 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: http.c,v 1.10 1998/12/18 14:32:48 des Exp $ + * $Id: http.c,v 1.4 1998/07/12 22:34:40 des Exp $ */ /* @@ -61,9 +61,15 @@ * SUCH DAMAGE. */ #include <sys/param.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include <netinet/in.h> #include <err.h> #include <ctype.h> +#include <netdb.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -71,8 +77,13 @@ #include <unistd.h> #include "fetch.h" -#include "common.h" -#include "httperr.h" +#include "httperr.c" + +#ifndef NDEBUG +#define DEBUG(x) do x; while (0) +#else +#define DEBUG(x) do { } while (0) +#endif extern char *__progname; @@ -92,6 +103,20 @@ struct cookie }; /* + * Look up error code + */ +static const char * +_http_errstring(int e) +{ + struct httperr *p = _http_errlist; + + while ((p->num != -1) && (p->num != e)) + p++; + + return p->string; +} + +/* * Send a formatted line; optionally echo to terminal */ static int @@ -288,19 +313,17 @@ _http_auth(char *usr, char *pwd) } /* - * Retrieve a file by HTTP + * retrieve a file by HTTP */ FILE * -fetchGetHTTP(struct url *URL, char *flags) +fetchGetHTTP(url_t *URL, char *flags) { - int sd = -1, e, i, enc = ENC_NONE, verbose; + int sd = -1, err, i, enc = ENC_NONE; struct cookie *c; - char *ln, *p, *px, *q; + char *ln, *p, *q; FILE *f, *cf; size_t len; - verbose = (strchr(flags, 'v') != NULL); - /* allocate cookie */ if ((c = calloc(1, sizeof(struct cookie))) == NULL) return NULL; @@ -310,11 +333,13 @@ fetchGetHTTP(struct url *URL, char *flags) URL->port = 80; /* default HTTP port */ /* attempt to connect to proxy server */ - if ((px = getenv("HTTP_PROXY")) != NULL) { - char host[MAXHOSTNAMELEN]; + if (getenv("HTTP_PROXY")) { + char *px, host[MAXHOSTNAMELEN]; int port = 3128; /* XXX I think 3128 is default... check? */ + size_t len; /* measure length */ + px = getenv("HTTP_PROXY"); len = strcspn(px, ":"); /* get port (atoi is a little too tolerant perhaps?) */ @@ -328,12 +353,12 @@ fetchGetHTTP(struct url *URL, char *flags) host[len] = 0; /* connect */ - sd = _fetch_connect(host, port, verbose); + sd = fetchConnect(host, port); } /* if no proxy is configured or could be contacted, try direct */ if (sd == -1) { - if ((sd = _fetch_connect(URL->host, URL->port, verbose)) == -1) + if ((sd = fetchConnect(URL->host, URL->port)) == -1) goto ouch; } @@ -343,9 +368,6 @@ fetchGetHTTP(struct url *URL, char *flags) c->real_f = f; /* send request (proxies require absolute form, so use that) */ - if (verbose) - _fetch_info("requesting http://%s:%d%s", - URL->host, URL->port, URL->doc); _http_cmd(f, "GET http://%s:%d%s HTTP/1.1" ENDL, URL->host, URL->port, URL->doc); @@ -375,12 +397,13 @@ fetchGetHTTP(struct url *URL, char *flags) p++; if (!isdigit(*p)) goto fouch; - e = atoi(p); - DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", e)); + err = atoi(p); + DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", err)); /* add code to handle redirects later */ - if (e != 200) { - _http_seterr(e); + if (err != 200) { + fetchLastErrCode = err; + fetchLastErrText = _http_errstring(err); goto fouch; } @@ -434,38 +457,16 @@ ouch: if (sd >= 0) close(sd); free(c); - _http_seterr(999); /* XXX do this properly RSN */ return NULL; fouch: fclose(f); free(c); - _http_seterr(999); /* XXX do this properly RSN */ return NULL; } FILE * -fetchPutHTTP(struct url *URL, char *flags) +fetchPutHTTP(url_t *URL, char *flags) { warnx("fetchPutHTTP(): not implemented"); return NULL; } - -/* - * Get an HTTP document's metadata - */ -int -fetchStatHTTP(struct url *url, struct url_stat *us, char *flags) -{ - warnx("fetchStatHTTP(): not implemented"); - return -1; -} - -/* - * List a directory - */ -struct url_ent * -fetchListHTTP(struct url *url, char *flags) -{ - warnx("fetchListHTTP(): not implemented"); - return NULL; -} diff --git a/lib/libfetch/http.errors b/lib/libfetch/http.errors index 26907d538adc8..c0e35391d18e6 100644 --- a/lib/libfetch/http.errors +++ b/lib/libfetch/http.errors @@ -1,41 +1,41 @@ -# $Id: http.errors,v 1.1.1.1 1998/07/09 16:52:44 des Exp $ +# $Id$ # # This list is taken from RFC 2068. # -100 OK Continue -101 OK Switching Protocols -200 OK OK -201 OK Created -202 OK Accepted -203 INFO Non-Authoritative Information -204 OK No Content -205 OK Reset Content -206 OK Partial Content -300 MOVED Multiple Choices -301 MOVED Moved Permanently -302 MOVED Moved Temporarily -303 MOVED See Other -304 OK Not Modified -305 INFO Use Proxy -400 PROTO Bad Request -401 AUTH Unauthorized -402 AUTH Payment Required -403 AUTH Forbidden -404 UNAVAIL Not Found -405 PROTO Method Not Allowed -406 PROTO Not Acceptable -407 AUTH Proxy Authentication Required -408 TIMEOUT Request Time-out -409 EXISTS Conflict -410 UNAVAIL Gone -411 PROTO Length Required -412 SERVER Precondition Failed -413 PROTO Request Entity Too Large -414 PROTO Request-URI Too Large -415 PROTO Unsupported Media Type -500 SERVER Internal Server Error -501 PROTO Not Implemented -502 SERVER Bad Gateway -503 TEMP Service Unavailable -504 TIMEOUT Gateway Time-out -505 PROTO HTTP Version not supported +100 Continue +101 Switching Protocols +200 OK +201 Created +202 Accepted +203 Non-Authoritative Information +204 No Content +205 Reset Content +206 Partial Content +300 Multiple Choices +301 Moved Permanently +302 Moved Temporarily +303 See Other +304 Not Modified +305 Use Proxy +400 Bad Request +401 Unauthorized +402 Payment Required +403 Forbidden +404 Not Found +405 Method Not Allowed +406 Not Acceptable +407 Proxy Authentication Required +408 Request Time-out +409 Conflict +410 Gone +411 Length Required +412 Precondition Failed +413 Request Entity Too Large +414 Request-URI Too Large +415 Unsupported Media Type +500 Internal Server Error +501 Not Implemented +502 Bad Gateway +503 Service Unavailable +504 Gateway Time-out +505 HTTP Version not supported |
