xref: /freebsd/lib/libfetch/common.c (revision a1763027376379e4df9fbbcb46f9096dca1e1f0e)
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 */
63a1763027SDag-Erling Smørgrav static 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
1570fba3a00SDag-Erling Smørgrav _fetch_info(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 /*
171842a95ccSDag-Erling Smørgrav  * Establish a TCP connection to the specified port on the specified host.
172842a95ccSDag-Erling Smørgrav  */
173842a95ccSDag-Erling Smørgrav int
17428c645cfSHajimu UMEMOTO _fetch_connect(char *host, int port, int af, int verbose)
175842a95ccSDag-Erling Smørgrav {
17628c645cfSHajimu UMEMOTO     char pbuf[10];
17728c645cfSHajimu UMEMOTO     struct addrinfo hints, *res, *res0;
17828c645cfSHajimu UMEMOTO     int sd, err;
179842a95ccSDag-Erling Smørgrav 
180ec894321SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port));
181842a95ccSDag-Erling Smørgrav 
1820fba3a00SDag-Erling Smørgrav     if (verbose)
1830fba3a00SDag-Erling Smørgrav 	_fetch_info("looking up %s", host);
1840fba3a00SDag-Erling Smørgrav 
18528c645cfSHajimu UMEMOTO     /* look up host name and set up socket address structure */
18628c645cfSHajimu UMEMOTO     snprintf(pbuf, sizeof(pbuf), "%d", port);
18728c645cfSHajimu UMEMOTO     memset(&hints, 0, sizeof(hints));
18828c645cfSHajimu UMEMOTO     hints.ai_family = af;
18928c645cfSHajimu UMEMOTO     hints.ai_socktype = SOCK_STREAM;
19028c645cfSHajimu UMEMOTO     hints.ai_protocol = 0;
19128c645cfSHajimu UMEMOTO     if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
19228c645cfSHajimu UMEMOTO 	_netdb_seterr(err);
193842a95ccSDag-Erling Smørgrav 	return -1;
194842a95ccSDag-Erling Smørgrav     }
195842a95ccSDag-Erling Smørgrav 
1960fba3a00SDag-Erling Smørgrav     if (verbose)
1970fba3a00SDag-Erling Smørgrav 	_fetch_info("connecting to %s:%d", host, port);
1980fba3a00SDag-Erling Smørgrav 
199842a95ccSDag-Erling Smørgrav     /* try to connect */
200a1763027SDag-Erling Smørgrav     for (sd = -1, res = res0; res; res = res->ai_next) {
20128c645cfSHajimu UMEMOTO 	if ((sd = socket(res->ai_family, res->ai_socktype,
202a1763027SDag-Erling Smørgrav 			 res->ai_protocol)) == -1)
20328c645cfSHajimu UMEMOTO 	    continue;
204a1763027SDag-Erling Smørgrav 	if (connect(sd, res->ai_addr, res->ai_addrlen) != -1)
20528c645cfSHajimu UMEMOTO 	    break;
206842a95ccSDag-Erling Smørgrav 	close(sd);
20728c645cfSHajimu UMEMOTO 	sd = -1;
20828c645cfSHajimu UMEMOTO     }
2097487ef62SHajimu UMEMOTO     freeaddrinfo(res0);
210a1763027SDag-Erling Smørgrav     if (sd == -1) {
21128c645cfSHajimu UMEMOTO 	_fetch_syserr();
212842a95ccSDag-Erling Smørgrav 	return -1;
213842a95ccSDag-Erling Smørgrav     }
214842a95ccSDag-Erling Smørgrav 
215842a95ccSDag-Erling Smørgrav     return sd;
216842a95ccSDag-Erling Smørgrav }
217ce71b736SDag-Erling Smørgrav 
218ce71b736SDag-Erling Smørgrav 
219fc6e9e65SDag-Erling Smørgrav /*
220fc6e9e65SDag-Erling Smørgrav  * Read a line of text from a socket w/ timeout
221fc6e9e65SDag-Erling Smørgrav  */
222fc6e9e65SDag-Erling Smørgrav #define MIN_BUF_SIZE 1024
223fc6e9e65SDag-Erling Smørgrav 
224fc6e9e65SDag-Erling Smørgrav int
225fc6e9e65SDag-Erling Smørgrav _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
226fc6e9e65SDag-Erling Smørgrav {
227fc6e9e65SDag-Erling Smørgrav     struct timeval now, timeout, wait;
228fc6e9e65SDag-Erling Smørgrav     fd_set readfds;
229fc6e9e65SDag-Erling Smørgrav     int r;
230fc6e9e65SDag-Erling Smørgrav     char c;
231fc6e9e65SDag-Erling Smørgrav 
232fc6e9e65SDag-Erling Smørgrav     if (*buf == NULL) {
233fc6e9e65SDag-Erling Smørgrav 	if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) {
234fc6e9e65SDag-Erling Smørgrav 	    errno = ENOMEM;
235fc6e9e65SDag-Erling Smørgrav 	    return -1;
236fc6e9e65SDag-Erling Smørgrav 	}
237fc6e9e65SDag-Erling Smørgrav 	*size = MIN_BUF_SIZE;
238fc6e9e65SDag-Erling Smørgrav     }
239fc6e9e65SDag-Erling Smørgrav 
240fc6e9e65SDag-Erling Smørgrav     **buf = '\0';
241fc6e9e65SDag-Erling Smørgrav     *len = 0;
242fc6e9e65SDag-Erling Smørgrav 
243fc6e9e65SDag-Erling Smørgrav     if (fetchTimeout) {
244fc6e9e65SDag-Erling Smørgrav 	gettimeofday(&timeout, NULL);
245fc6e9e65SDag-Erling Smørgrav 	timeout.tv_sec += fetchTimeout;
246fc6e9e65SDag-Erling Smørgrav 	FD_ZERO(&readfds);
247fc6e9e65SDag-Erling Smørgrav     }
248fc6e9e65SDag-Erling Smørgrav 
249fc6e9e65SDag-Erling Smørgrav     do {
250fc6e9e65SDag-Erling Smørgrav 	if (fetchTimeout) {
251fc6e9e65SDag-Erling Smørgrav 	    FD_SET(fd, &readfds);
252fc6e9e65SDag-Erling Smørgrav 	    gettimeofday(&now, NULL);
253fc6e9e65SDag-Erling Smørgrav 	    wait.tv_sec = timeout.tv_sec - now.tv_sec;
254fc6e9e65SDag-Erling Smørgrav 	    wait.tv_usec = timeout.tv_usec - now.tv_usec;
255fc6e9e65SDag-Erling Smørgrav 	    if (wait.tv_usec < 0) {
256fc6e9e65SDag-Erling Smørgrav 		wait.tv_usec += 1000000;
257fc6e9e65SDag-Erling Smørgrav 		wait.tv_sec--;
258fc6e9e65SDag-Erling Smørgrav 	    }
259fc6e9e65SDag-Erling Smørgrav 	    if (wait.tv_sec < 0) {
260fc6e9e65SDag-Erling Smørgrav 		errno = ETIMEDOUT;
261fc6e9e65SDag-Erling Smørgrav 		return -1;
262fc6e9e65SDag-Erling Smørgrav 	    }
263fc6e9e65SDag-Erling Smørgrav 	    r = select(fd+1, &readfds, NULL, NULL, &wait);
264fc6e9e65SDag-Erling Smørgrav 	    if (r == -1) {
265fc6e9e65SDag-Erling Smørgrav 		if (errno == EINTR)
266fc6e9e65SDag-Erling Smørgrav 		    continue;
267fc6e9e65SDag-Erling Smørgrav 		/* EBADF or EINVAL: shouldn't happen */
268fc6e9e65SDag-Erling Smørgrav 		return -1;
269fc6e9e65SDag-Erling Smørgrav 	    }
270fc6e9e65SDag-Erling Smørgrav 	    if (!FD_ISSET(fd, &readfds))
271fc6e9e65SDag-Erling Smørgrav 		continue;
272fc6e9e65SDag-Erling Smørgrav 	}
273fc6e9e65SDag-Erling Smørgrav 	r = read(fd, &c, 1);
274fc6e9e65SDag-Erling Smørgrav 	if (r == 0)
275fc6e9e65SDag-Erling Smørgrav 	    break;
276fc6e9e65SDag-Erling Smørgrav 	if (r == -1) {
277fc6e9e65SDag-Erling Smørgrav 	    if (errno == EINTR)
278fc6e9e65SDag-Erling Smørgrav 		continue;
279fc6e9e65SDag-Erling Smørgrav 	    /* any other error is bad news */
280fc6e9e65SDag-Erling Smørgrav 	    return -1;
281fc6e9e65SDag-Erling Smørgrav 	}
282fc6e9e65SDag-Erling Smørgrav 	(*buf)[*len] = c;
283fc6e9e65SDag-Erling Smørgrav 	*len += 1;
284fc6e9e65SDag-Erling Smørgrav 	if (*len == *size) {
285fc6e9e65SDag-Erling Smørgrav 	    char *tmp;
286fc6e9e65SDag-Erling Smørgrav 
287fc6e9e65SDag-Erling Smørgrav 	    if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) {
288fc6e9e65SDag-Erling Smørgrav 		errno = ENOMEM;
289fc6e9e65SDag-Erling Smørgrav 		return -1;
290fc6e9e65SDag-Erling Smørgrav 	    }
291fc6e9e65SDag-Erling Smørgrav 	    *buf = tmp;
292fc6e9e65SDag-Erling Smørgrav 	    *size = *size * 2 + 1;
293fc6e9e65SDag-Erling Smørgrav 	}
294fc6e9e65SDag-Erling Smørgrav     } while (c != '\n');
295fc6e9e65SDag-Erling Smørgrav 
296ec894321SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m<<< %.*s\033[m", (int)*len, *buf));
297fc6e9e65SDag-Erling Smørgrav     return 0;
298fc6e9e65SDag-Erling Smørgrav }
299fc6e9e65SDag-Erling Smørgrav 
300fc6e9e65SDag-Erling Smørgrav 
301a1763027SDag-Erling Smørgrav /*
302a1763027SDag-Erling Smørgrav  * Write a line of text to a socket w/ timeout
303a1763027SDag-Erling Smørgrav  * XXX currently does not enforce timeout
304a1763027SDag-Erling Smørgrav  */
305a1763027SDag-Erling Smørgrav int
306a1763027SDag-Erling Smørgrav _fetch_putln(int fd, char *str, size_t len)
307a1763027SDag-Erling Smørgrav {
308a1763027SDag-Erling Smørgrav     struct iovec iov[2];
309a1763027SDag-Erling Smørgrav     ssize_t wlen;
310a1763027SDag-Erling Smørgrav 
311a1763027SDag-Erling Smørgrav     /* XXX should enforce timeout */
312a1763027SDag-Erling Smørgrav     iov[0].iov_base = str;
313a1763027SDag-Erling Smørgrav     iov[0].iov_len = len;
314a1763027SDag-Erling Smørgrav     iov[1].iov_base = ENDL;
315a1763027SDag-Erling Smørgrav     iov[1].iov_len = sizeof ENDL;
316a1763027SDag-Erling Smørgrav     wlen = writev(fd, iov, 2);
317a1763027SDag-Erling Smørgrav     DEBUG(fprintf(stderr, "\033[1m>>> %s\n\033[m", str));
318a1763027SDag-Erling Smørgrav     return (wlen != len);
319a1763027SDag-Erling Smørgrav }
320a1763027SDag-Erling Smørgrav 
321a1763027SDag-Erling Smørgrav 
322ce71b736SDag-Erling Smørgrav /*** Directory-related utility functions *************************************/
323ce71b736SDag-Erling Smørgrav 
324ce71b736SDag-Erling Smørgrav int
325ce71b736SDag-Erling Smørgrav _fetch_add_entry(struct url_ent **p, int *size, int *len,
326ce71b736SDag-Erling Smørgrav 		 char *name, struct url_stat *stat)
327ce71b736SDag-Erling Smørgrav {
328ce71b736SDag-Erling Smørgrav     struct url_ent *tmp;
329ce71b736SDag-Erling Smørgrav 
330ce71b736SDag-Erling Smørgrav     if (*p == NULL) {
331ce71b736SDag-Erling Smørgrav #define INITIAL_SIZE 8
332ce71b736SDag-Erling Smørgrav 	if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) {
333ce71b736SDag-Erling Smørgrav 	    errno = ENOMEM;
334ce71b736SDag-Erling Smørgrav 	    _fetch_syserr();
335ce71b736SDag-Erling Smørgrav 	    return -1;
336ce71b736SDag-Erling Smørgrav 	}
337ce71b736SDag-Erling Smørgrav 	*size = INITIAL_SIZE;
338ce71b736SDag-Erling Smørgrav 	*len = 0;
339ce71b736SDag-Erling Smørgrav #undef INITIAL_SIZE
340ce71b736SDag-Erling Smørgrav     }
341ce71b736SDag-Erling Smørgrav 
342ce71b736SDag-Erling Smørgrav     if (*len >= *size - 1) {
343ce71b736SDag-Erling Smørgrav 	tmp = realloc(*p, *size * 2 * sizeof **p);
344ce71b736SDag-Erling Smørgrav 	if (tmp == NULL) {
345ce71b736SDag-Erling Smørgrav 	    errno = ENOMEM;
346ce71b736SDag-Erling Smørgrav 	    _fetch_syserr();
347ce71b736SDag-Erling Smørgrav 	    return -1;
348ce71b736SDag-Erling Smørgrav 	}
349ce71b736SDag-Erling Smørgrav 	*size *= 2;
350ce71b736SDag-Erling Smørgrav 	*p = tmp;
351ce71b736SDag-Erling Smørgrav     }
352ce71b736SDag-Erling Smørgrav 
353ce71b736SDag-Erling Smørgrav     tmp = *p + *len;
354ce71b736SDag-Erling Smørgrav     snprintf(tmp->name, MAXPATHLEN, "%s", name);
355ce71b736SDag-Erling Smørgrav     bcopy(stat, &tmp->stat, sizeof *stat);
356ce71b736SDag-Erling Smørgrav 
357ce71b736SDag-Erling Smørgrav     (*len)++;
358ce71b736SDag-Erling Smørgrav     (++tmp)->name[0] = 0;
359ce71b736SDag-Erling Smørgrav 
360ce71b736SDag-Erling Smørgrav     return 0;
361ce71b736SDag-Erling Smørgrav }
362