xref: /freebsd/lib/libfetch/common.c (revision 38c7e4a631ce968b02e4a08944aabad9b57844e8)
1842a95ccSDag-Erling Smørgrav /*-
2842a95ccSDag-Erling Smørgrav  * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3842a95ccSDag-Erling Smørgrav  * All rights reserved.
4842a95ccSDag-Erling Smørgrav  *
5842a95ccSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
6842a95ccSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
7842a95ccSDag-Erling Smørgrav  * are met:
8842a95ccSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
9842a95ccSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
10842a95ccSDag-Erling Smørgrav  *    in this position and unchanged.
11842a95ccSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
12842a95ccSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
13842a95ccSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
14842a95ccSDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
15842a95ccSDag-Erling Smørgrav  *    derived from this software without specific prior written permission
16842a95ccSDag-Erling Smørgrav  *
17842a95ccSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18842a95ccSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19842a95ccSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20842a95ccSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21842a95ccSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22842a95ccSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23842a95ccSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24842a95ccSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25842a95ccSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26842a95ccSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27842a95ccSDag-Erling Smørgrav  *
287f3dea24SPeter Wemm  * $FreeBSD$
29842a95ccSDag-Erling Smørgrav  */
30842a95ccSDag-Erling Smørgrav 
310fba3a00SDag-Erling Smørgrav #include <sys/param.h>
32842a95ccSDag-Erling Smørgrav #include <sys/socket.h>
33fc6e9e65SDag-Erling Smørgrav #include <sys/time.h>
34a1763027SDag-Erling Smørgrav #include <sys/uio.h>
35842a95ccSDag-Erling Smørgrav #include <netinet/in.h>
36842a95ccSDag-Erling Smørgrav 
37842a95ccSDag-Erling Smørgrav #include <errno.h>
38842a95ccSDag-Erling Smørgrav #include <netdb.h>
39ba101983SDag-Erling Smørgrav #include <stdarg.h>
400fba3a00SDag-Erling Smørgrav #include <stdlib.h>
410fba3a00SDag-Erling Smørgrav #include <stdio.h>
42842a95ccSDag-Erling Smørgrav #include <string.h>
43842a95ccSDag-Erling Smørgrav #include <unistd.h>
44842a95ccSDag-Erling Smørgrav 
45842a95ccSDag-Erling Smørgrav #include "fetch.h"
46842a95ccSDag-Erling Smørgrav #include "common.h"
47842a95ccSDag-Erling Smørgrav 
48d8acd8dcSDag-Erling Smørgrav 
49842a95ccSDag-Erling Smørgrav /*** Local data **************************************************************/
50842a95ccSDag-Erling Smørgrav 
51842a95ccSDag-Erling Smørgrav /*
52842a95ccSDag-Erling Smørgrav  * Error messages for resolver errors
53842a95ccSDag-Erling Smørgrav  */
54842a95ccSDag-Erling Smørgrav static struct fetcherr _netdb_errlist[] = {
5528c645cfSHajimu UMEMOTO     { EAI_NODATA,	FETCH_RESOLV,	"Host not found" },
5628c645cfSHajimu UMEMOTO     { EAI_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
5728c645cfSHajimu UMEMOTO     { EAI_FAIL,		FETCH_RESOLV,	"Non-recoverable resolver failure" },
5828c645cfSHajimu UMEMOTO     { EAI_NONAME,	FETCH_RESOLV,	"No address record" },
59d8acd8dcSDag-Erling Smørgrav     { -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
60842a95ccSDag-Erling Smørgrav };
61842a95ccSDag-Erling Smørgrav 
62a1763027SDag-Erling Smørgrav /* End-of-Line */
6338c7e4a6SArchie Cobbs static const char ENDL[2] = "\r\n";
64a1763027SDag-Erling Smørgrav 
65842a95ccSDag-Erling Smørgrav 
66842a95ccSDag-Erling Smørgrav /*** Error-reporting functions ***********************************************/
67842a95ccSDag-Erling Smørgrav 
68842a95ccSDag-Erling Smørgrav /*
69842a95ccSDag-Erling Smørgrav  * Map error code to string
70842a95ccSDag-Erling Smørgrav  */
71ba101983SDag-Erling Smørgrav static struct fetcherr *
72d8acd8dcSDag-Erling Smørgrav _fetch_finderr(struct fetcherr *p, int e)
73842a95ccSDag-Erling Smørgrav {
74ba101983SDag-Erling Smørgrav     while (p->num != -1 && p->num != e)
75ba101983SDag-Erling Smørgrav 	p++;
76ba101983SDag-Erling Smørgrav     return p;
77842a95ccSDag-Erling Smørgrav }
78842a95ccSDag-Erling Smørgrav 
79842a95ccSDag-Erling Smørgrav /*
80842a95ccSDag-Erling Smørgrav  * Set error code
81842a95ccSDag-Erling Smørgrav  */
82842a95ccSDag-Erling Smørgrav void
83842a95ccSDag-Erling Smørgrav _fetch_seterr(struct fetcherr *p, int e)
84842a95ccSDag-Erling Smørgrav {
85ba101983SDag-Erling Smørgrav     p = _fetch_finderr(p, e);
86ba101983SDag-Erling Smørgrav     fetchLastErrCode = p->cat;
87ba101983SDag-Erling Smørgrav     snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
88842a95ccSDag-Erling Smørgrav }
89842a95ccSDag-Erling Smørgrav 
90842a95ccSDag-Erling Smørgrav /*
91842a95ccSDag-Erling Smørgrav  * Set error code according to errno
92842a95ccSDag-Erling Smørgrav  */
93842a95ccSDag-Erling Smørgrav void
94842a95ccSDag-Erling Smørgrav _fetch_syserr(void)
95842a95ccSDag-Erling Smørgrav {
960fba3a00SDag-Erling Smørgrav     int e;
970fba3a00SDag-Erling Smørgrav     e = errno;
98d8acd8dcSDag-Erling Smørgrav 
99d8acd8dcSDag-Erling Smørgrav     switch (errno) {
100d8acd8dcSDag-Erling Smørgrav     case 0:
1010fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_OK;
102d8acd8dcSDag-Erling Smørgrav 	break;
103d8acd8dcSDag-Erling Smørgrav     case EPERM:
104d8acd8dcSDag-Erling Smørgrav     case EACCES:
105d8acd8dcSDag-Erling Smørgrav     case EROFS:
106d8acd8dcSDag-Erling Smørgrav     case EAUTH:
107d8acd8dcSDag-Erling Smørgrav     case ENEEDAUTH:
1080fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_AUTH;
109d8acd8dcSDag-Erling Smørgrav 	break;
110d8acd8dcSDag-Erling Smørgrav     case ENOENT:
111d8acd8dcSDag-Erling Smørgrav     case EISDIR: /* XXX */
1120fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_UNAVAIL;
113d8acd8dcSDag-Erling Smørgrav 	break;
114d8acd8dcSDag-Erling Smørgrav     case ENOMEM:
1150fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_MEMORY;
116d8acd8dcSDag-Erling Smørgrav 	break;
117d8acd8dcSDag-Erling Smørgrav     case EBUSY:
118d8acd8dcSDag-Erling Smørgrav     case EAGAIN:
1190fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_TEMP;
120d8acd8dcSDag-Erling Smørgrav 	break;
121d8acd8dcSDag-Erling Smørgrav     case EEXIST:
1220fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_EXISTS;
123d8acd8dcSDag-Erling Smørgrav 	break;
124d8acd8dcSDag-Erling Smørgrav     case ENOSPC:
1250fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_FULL;
126d8acd8dcSDag-Erling Smørgrav 	break;
127d8acd8dcSDag-Erling Smørgrav     case EADDRINUSE:
128d8acd8dcSDag-Erling Smørgrav     case EADDRNOTAVAIL:
129d8acd8dcSDag-Erling Smørgrav     case ENETDOWN:
130d8acd8dcSDag-Erling Smørgrav     case ENETUNREACH:
131d8acd8dcSDag-Erling Smørgrav     case ENETRESET:
132d8acd8dcSDag-Erling Smørgrav     case EHOSTUNREACH:
1330fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_NETWORK;
134d8acd8dcSDag-Erling Smørgrav 	break;
135d8acd8dcSDag-Erling Smørgrav     case ECONNABORTED:
136d8acd8dcSDag-Erling Smørgrav     case ECONNRESET:
1370fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_ABORT;
138d8acd8dcSDag-Erling Smørgrav 	break;
139d8acd8dcSDag-Erling Smørgrav     case ETIMEDOUT:
1400fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_TIMEOUT;
141d8acd8dcSDag-Erling Smørgrav 	break;
142d8acd8dcSDag-Erling Smørgrav     case ECONNREFUSED:
143d8acd8dcSDag-Erling Smørgrav     case EHOSTDOWN:
1440fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_DOWN;
145d8acd8dcSDag-Erling Smørgrav 	break;
146d8acd8dcSDag-Erling Smørgrav     default:
1470fba3a00SDag-Erling Smørgrav 	fetchLastErrCode = FETCH_UNKNOWN;
148d8acd8dcSDag-Erling Smørgrav     }
149ba101983SDag-Erling Smørgrav     snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(e));
1500fba3a00SDag-Erling Smørgrav }
1510fba3a00SDag-Erling Smørgrav 
1520fba3a00SDag-Erling Smørgrav 
1530fba3a00SDag-Erling Smørgrav /*
1540fba3a00SDag-Erling Smørgrav  * Emit status message
1550fba3a00SDag-Erling Smørgrav  */
156ba101983SDag-Erling Smørgrav void
15738c7e4a6SArchie Cobbs _fetch_info(const char *fmt, ...)
1580fba3a00SDag-Erling Smørgrav {
1590fba3a00SDag-Erling Smørgrav     va_list ap;
1600fba3a00SDag-Erling Smørgrav 
1610fba3a00SDag-Erling Smørgrav     va_start(ap, fmt);
162ba101983SDag-Erling Smørgrav     vfprintf(stderr, fmt, ap);
1630fba3a00SDag-Erling Smørgrav     va_end(ap);
164a68f8b58SDag-Erling Smørgrav     fputc('\n', stderr);
165842a95ccSDag-Erling Smørgrav }
166842a95ccSDag-Erling Smørgrav 
167842a95ccSDag-Erling Smørgrav 
168842a95ccSDag-Erling Smørgrav /*** Network-related utility functions ***************************************/
169842a95ccSDag-Erling Smørgrav 
170842a95ccSDag-Erling Smørgrav /*
171e828ada7SDag-Erling Smørgrav  * Return the default port for a scheme
172e828ada7SDag-Erling Smørgrav  */
173e828ada7SDag-Erling Smørgrav int
17438c7e4a6SArchie Cobbs _fetch_default_port(const char *scheme)
175e828ada7SDag-Erling Smørgrav {
176e828ada7SDag-Erling Smørgrav     struct servent *se;
177e828ada7SDag-Erling Smørgrav 
178e828ada7SDag-Erling Smørgrav     if ((se = getservbyname(scheme, "tcp")) != NULL)
179e828ada7SDag-Erling Smørgrav 	return ntohs(se->s_port);
180e828ada7SDag-Erling Smørgrav     if (strcasecmp(scheme, SCHEME_FTP) == 0)
181e828ada7SDag-Erling Smørgrav 	return FTP_DEFAULT_PORT;
182e828ada7SDag-Erling Smørgrav     if (strcasecmp(scheme, SCHEME_HTTP) == 0)
183e828ada7SDag-Erling Smørgrav 	return HTTP_DEFAULT_PORT;
184e828ada7SDag-Erling Smørgrav     return 0;
185e828ada7SDag-Erling Smørgrav }
186e828ada7SDag-Erling Smørgrav 
187e828ada7SDag-Erling Smørgrav /*
188e828ada7SDag-Erling Smørgrav  * Return the default proxy port for a scheme
189e828ada7SDag-Erling Smørgrav  */
190e828ada7SDag-Erling Smørgrav int
19138c7e4a6SArchie Cobbs _fetch_default_proxy_port(const char *scheme)
192e828ada7SDag-Erling Smørgrav {
193e828ada7SDag-Erling Smørgrav     if (strcasecmp(scheme, SCHEME_FTP) == 0)
194e828ada7SDag-Erling Smørgrav 	return FTP_DEFAULT_PROXY_PORT;
195e828ada7SDag-Erling Smørgrav     if (strcasecmp(scheme, SCHEME_HTTP) == 0)
196e828ada7SDag-Erling Smørgrav 	return HTTP_DEFAULT_PROXY_PORT;
197e828ada7SDag-Erling Smørgrav     return 0;
198e828ada7SDag-Erling Smørgrav }
199e828ada7SDag-Erling Smørgrav 
200e828ada7SDag-Erling Smørgrav /*
201842a95ccSDag-Erling Smørgrav  * Establish a TCP connection to the specified port on the specified host.
202842a95ccSDag-Erling Smørgrav  */
203842a95ccSDag-Erling Smørgrav int
20438c7e4a6SArchie Cobbs _fetch_connect(const char *host, int port, int af, int verbose)
205842a95ccSDag-Erling Smørgrav {
20628c645cfSHajimu UMEMOTO     char pbuf[10];
20728c645cfSHajimu UMEMOTO     struct addrinfo hints, *res, *res0;
20828c645cfSHajimu UMEMOTO     int sd, err;
209842a95ccSDag-Erling Smørgrav 
210ec894321SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port));
211842a95ccSDag-Erling Smørgrav 
2120fba3a00SDag-Erling Smørgrav     if (verbose)
2130fba3a00SDag-Erling Smørgrav 	_fetch_info("looking up %s", host);
2140fba3a00SDag-Erling Smørgrav 
21528c645cfSHajimu UMEMOTO     /* look up host name and set up socket address structure */
21628c645cfSHajimu UMEMOTO     snprintf(pbuf, sizeof(pbuf), "%d", port);
21728c645cfSHajimu UMEMOTO     memset(&hints, 0, sizeof(hints));
21828c645cfSHajimu UMEMOTO     hints.ai_family = af;
21928c645cfSHajimu UMEMOTO     hints.ai_socktype = SOCK_STREAM;
22028c645cfSHajimu UMEMOTO     hints.ai_protocol = 0;
22128c645cfSHajimu UMEMOTO     if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
22228c645cfSHajimu UMEMOTO 	_netdb_seterr(err);
223842a95ccSDag-Erling Smørgrav 	return -1;
224842a95ccSDag-Erling Smørgrav     }
225842a95ccSDag-Erling Smørgrav 
2260fba3a00SDag-Erling Smørgrav     if (verbose)
2270fba3a00SDag-Erling Smørgrav 	_fetch_info("connecting to %s:%d", host, port);
2280fba3a00SDag-Erling Smørgrav 
229842a95ccSDag-Erling Smørgrav     /* try to connect */
230a1763027SDag-Erling Smørgrav     for (sd = -1, res = res0; res; res = res->ai_next) {
23128c645cfSHajimu UMEMOTO 	if ((sd = socket(res->ai_family, res->ai_socktype,
232a1763027SDag-Erling Smørgrav 			 res->ai_protocol)) == -1)
23328c645cfSHajimu UMEMOTO 	    continue;
234a1763027SDag-Erling Smørgrav 	if (connect(sd, res->ai_addr, res->ai_addrlen) != -1)
23528c645cfSHajimu UMEMOTO 	    break;
236842a95ccSDag-Erling Smørgrav 	close(sd);
23728c645cfSHajimu UMEMOTO 	sd = -1;
23828c645cfSHajimu UMEMOTO     }
2397487ef62SHajimu UMEMOTO     freeaddrinfo(res0);
240a1763027SDag-Erling Smørgrav     if (sd == -1) {
24128c645cfSHajimu UMEMOTO 	_fetch_syserr();
242842a95ccSDag-Erling Smørgrav 	return -1;
243842a95ccSDag-Erling Smørgrav     }
244842a95ccSDag-Erling Smørgrav 
245842a95ccSDag-Erling Smørgrav     return sd;
246842a95ccSDag-Erling Smørgrav }
247ce71b736SDag-Erling Smørgrav 
248ce71b736SDag-Erling Smørgrav 
249fc6e9e65SDag-Erling Smørgrav /*
250fc6e9e65SDag-Erling Smørgrav  * Read a line of text from a socket w/ timeout
251fc6e9e65SDag-Erling Smørgrav  */
252fc6e9e65SDag-Erling Smørgrav #define MIN_BUF_SIZE 1024
253fc6e9e65SDag-Erling Smørgrav 
254fc6e9e65SDag-Erling Smørgrav int
255fc6e9e65SDag-Erling Smørgrav _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
256fc6e9e65SDag-Erling Smørgrav {
257fc6e9e65SDag-Erling Smørgrav     struct timeval now, timeout, wait;
258fc6e9e65SDag-Erling Smørgrav     fd_set readfds;
259fc6e9e65SDag-Erling Smørgrav     int r;
260fc6e9e65SDag-Erling Smørgrav     char c;
261fc6e9e65SDag-Erling Smørgrav 
262fc6e9e65SDag-Erling Smørgrav     if (*buf == NULL) {
263fc6e9e65SDag-Erling Smørgrav 	if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) {
264fc6e9e65SDag-Erling Smørgrav 	    errno = ENOMEM;
265fc6e9e65SDag-Erling Smørgrav 	    return -1;
266fc6e9e65SDag-Erling Smørgrav 	}
267fc6e9e65SDag-Erling Smørgrav 	*size = MIN_BUF_SIZE;
268fc6e9e65SDag-Erling Smørgrav     }
269fc6e9e65SDag-Erling Smørgrav 
270fc6e9e65SDag-Erling Smørgrav     **buf = '\0';
271fc6e9e65SDag-Erling Smørgrav     *len = 0;
272fc6e9e65SDag-Erling Smørgrav 
273fc6e9e65SDag-Erling Smørgrav     if (fetchTimeout) {
274fc6e9e65SDag-Erling Smørgrav 	gettimeofday(&timeout, NULL);
275fc6e9e65SDag-Erling Smørgrav 	timeout.tv_sec += fetchTimeout;
276fc6e9e65SDag-Erling Smørgrav 	FD_ZERO(&readfds);
277fc6e9e65SDag-Erling Smørgrav     }
278fc6e9e65SDag-Erling Smørgrav 
279fc6e9e65SDag-Erling Smørgrav     do {
280fc6e9e65SDag-Erling Smørgrav 	if (fetchTimeout) {
281fc6e9e65SDag-Erling Smørgrav 	    FD_SET(fd, &readfds);
282fc6e9e65SDag-Erling Smørgrav 	    gettimeofday(&now, NULL);
283fc6e9e65SDag-Erling Smørgrav 	    wait.tv_sec = timeout.tv_sec - now.tv_sec;
284fc6e9e65SDag-Erling Smørgrav 	    wait.tv_usec = timeout.tv_usec - now.tv_usec;
285fc6e9e65SDag-Erling Smørgrav 	    if (wait.tv_usec < 0) {
286fc6e9e65SDag-Erling Smørgrav 		wait.tv_usec += 1000000;
287fc6e9e65SDag-Erling Smørgrav 		wait.tv_sec--;
288fc6e9e65SDag-Erling Smørgrav 	    }
289fc6e9e65SDag-Erling Smørgrav 	    if (wait.tv_sec < 0) {
290fc6e9e65SDag-Erling Smørgrav 		errno = ETIMEDOUT;
291fc6e9e65SDag-Erling Smørgrav 		return -1;
292fc6e9e65SDag-Erling Smørgrav 	    }
293fc6e9e65SDag-Erling Smørgrav 	    r = select(fd+1, &readfds, NULL, NULL, &wait);
294fc6e9e65SDag-Erling Smørgrav 	    if (r == -1) {
295a1bb3f48SDag-Erling Smørgrav 		if (errno == EINTR && fetchRestartCalls)
296fc6e9e65SDag-Erling Smørgrav 		    continue;
297fc6e9e65SDag-Erling Smørgrav 		/* EBADF or EINVAL: shouldn't happen */
298fc6e9e65SDag-Erling Smørgrav 		return -1;
299fc6e9e65SDag-Erling Smørgrav 	    }
300fc6e9e65SDag-Erling Smørgrav 	    if (!FD_ISSET(fd, &readfds))
301fc6e9e65SDag-Erling Smørgrav 		continue;
302fc6e9e65SDag-Erling Smørgrav 	}
303fc6e9e65SDag-Erling Smørgrav 	r = read(fd, &c, 1);
304fc6e9e65SDag-Erling Smørgrav 	if (r == 0)
305fc6e9e65SDag-Erling Smørgrav 	    break;
306fc6e9e65SDag-Erling Smørgrav 	if (r == -1) {
307a1bb3f48SDag-Erling Smørgrav 	    if (errno == EINTR && fetchRestartCalls)
308fc6e9e65SDag-Erling Smørgrav 		continue;
309fc6e9e65SDag-Erling Smørgrav 	    /* any other error is bad news */
310fc6e9e65SDag-Erling Smørgrav 	    return -1;
311fc6e9e65SDag-Erling Smørgrav 	}
312fc6e9e65SDag-Erling Smørgrav 	(*buf)[*len] = c;
313fc6e9e65SDag-Erling Smørgrav 	*len += 1;
314fc6e9e65SDag-Erling Smørgrav 	if (*len == *size) {
315fc6e9e65SDag-Erling Smørgrav 	    char *tmp;
316fc6e9e65SDag-Erling Smørgrav 
317fc6e9e65SDag-Erling Smørgrav 	    if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) {
318fc6e9e65SDag-Erling Smørgrav 		errno = ENOMEM;
319fc6e9e65SDag-Erling Smørgrav 		return -1;
320fc6e9e65SDag-Erling Smørgrav 	    }
321fc6e9e65SDag-Erling Smørgrav 	    *buf = tmp;
322fc6e9e65SDag-Erling Smørgrav 	    *size = *size * 2 + 1;
323fc6e9e65SDag-Erling Smørgrav 	}
324fc6e9e65SDag-Erling Smørgrav     } while (c != '\n');
325fc6e9e65SDag-Erling Smørgrav 
326ec894321SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m<<< %.*s\033[m", (int)*len, *buf));
327fc6e9e65SDag-Erling Smørgrav     return 0;
328fc6e9e65SDag-Erling Smørgrav }
329fc6e9e65SDag-Erling Smørgrav 
330fc6e9e65SDag-Erling Smørgrav 
331a1763027SDag-Erling Smørgrav /*
332a1763027SDag-Erling Smørgrav  * Write a line of text to a socket w/ timeout
333a1763027SDag-Erling Smørgrav  * XXX currently does not enforce timeout
334a1763027SDag-Erling Smørgrav  */
335a1763027SDag-Erling Smørgrav int
33638c7e4a6SArchie Cobbs _fetch_putln(int fd, const char *str, size_t len)
337a1763027SDag-Erling Smørgrav {
338a1763027SDag-Erling Smørgrav     struct iovec iov[2];
339a1763027SDag-Erling Smørgrav     ssize_t wlen;
340a1763027SDag-Erling Smørgrav 
341a1763027SDag-Erling Smørgrav     /* XXX should enforce timeout */
34238c7e4a6SArchie Cobbs     iov[0].iov_base = (char *)str;
343a1763027SDag-Erling Smørgrav     iov[0].iov_len = len;
34438c7e4a6SArchie Cobbs     iov[1].iov_base = (char *)ENDL;
345a1763027SDag-Erling Smørgrav     iov[1].iov_len = sizeof ENDL;
346a1763027SDag-Erling Smørgrav     wlen = writev(fd, iov, 2);
347a1763027SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m>>> %s\n\033[m", str));
348a1763027SDag-Erling Smørgrav     return (wlen != len);
349a1763027SDag-Erling Smørgrav }
350a1763027SDag-Erling Smørgrav 
351a1763027SDag-Erling Smørgrav 
352ce71b736SDag-Erling Smørgrav /*** Directory-related utility functions *************************************/
353ce71b736SDag-Erling Smørgrav 
354ce71b736SDag-Erling Smørgrav int
355ce71b736SDag-Erling Smørgrav _fetch_add_entry(struct url_ent **p, int *size, int *len,
35638c7e4a6SArchie Cobbs 		 const char *name, struct url_stat *stat)
357ce71b736SDag-Erling Smørgrav {
358ce71b736SDag-Erling Smørgrav     struct url_ent *tmp;
359ce71b736SDag-Erling Smørgrav 
360ce71b736SDag-Erling Smørgrav     if (*p == NULL) {
361ce71b736SDag-Erling Smørgrav #define INITIAL_SIZE 8
362ce71b736SDag-Erling Smørgrav 	if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) {
363ce71b736SDag-Erling Smørgrav 	    errno = ENOMEM;
364ce71b736SDag-Erling Smørgrav 	    _fetch_syserr();
365ce71b736SDag-Erling Smørgrav 	    return -1;
366ce71b736SDag-Erling Smørgrav 	}
367ce71b736SDag-Erling Smørgrav 	*size = INITIAL_SIZE;
368ce71b736SDag-Erling Smørgrav 	*len = 0;
369ce71b736SDag-Erling Smørgrav #undef INITIAL_SIZE
370ce71b736SDag-Erling Smørgrav     }
371ce71b736SDag-Erling Smørgrav 
372ce71b736SDag-Erling Smørgrav     if (*len >= *size - 1) {
373ce71b736SDag-Erling Smørgrav 	tmp = realloc(*p, *size * 2 * sizeof **p);
374ce71b736SDag-Erling Smørgrav 	if (tmp == NULL) {
375ce71b736SDag-Erling Smørgrav 	    errno = ENOMEM;
376ce71b736SDag-Erling Smørgrav 	    _fetch_syserr();
377ce71b736SDag-Erling Smørgrav 	    return -1;
378ce71b736SDag-Erling Smørgrav 	}
379ce71b736SDag-Erling Smørgrav 	*size *= 2;
380ce71b736SDag-Erling Smørgrav 	*p = tmp;
381ce71b736SDag-Erling Smørgrav     }
382ce71b736SDag-Erling Smørgrav 
383ce71b736SDag-Erling Smørgrav     tmp = *p + *len;
384ce71b736SDag-Erling Smørgrav     snprintf(tmp->name, MAXPATHLEN, "%s", name);
385ce71b736SDag-Erling Smørgrav     bcopy(stat, &tmp->stat, sizeof *stat);
386ce71b736SDag-Erling Smørgrav 
387ce71b736SDag-Erling Smørgrav     (*len)++;
388ce71b736SDag-Erling Smørgrav     (++tmp)->name[0] = 0;
389ce71b736SDag-Erling Smørgrav 
390ce71b736SDag-Erling Smørgrav     return 0;
391ce71b736SDag-Erling Smørgrav }
392