xref: /freebsd/lib/libfetch/common.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /*-
2  * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 
35 #include <com_err.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include "fetch.h"
44 #include "common.h"
45 
46 
47 /*** Local data **************************************************************/
48 
49 /*
50  * Error messages for resolver errors
51  */
52 static struct fetcherr _netdb_errlist[] = {
53     { HOST_NOT_FOUND,	FETCH_RESOLV,	"Host not found" },
54     { TRY_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
55     { NO_RECOVERY,	FETCH_RESOLV,	"Non-recoverable resolver failure" },
56     { NO_DATA,		FETCH_RESOLV,	"No address record" },
57     { -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
58 };
59 
60 static int com_err_initialized;
61 
62 /*** Error-reporting functions ***********************************************/
63 
64 /*
65  * Initialize the common error library
66  */
67 static void
68 _fetch_init_com_err(void)
69 {
70     initialize_ftch_error_table();
71     com_err_initialized = 1;
72 }
73 
74 /*
75  * Map error code to string
76  */
77 static int
78 _fetch_finderr(struct fetcherr *p, int e)
79 {
80     int i;
81     for (i = 0; p[i].num != -1; i++)
82 	if (p[i].num == e)
83 	    break;
84     return i;
85 }
86 
87 /*
88  * Set error code
89  */
90 void
91 _fetch_seterr(struct fetcherr *p, int e)
92 {
93     int n;
94 
95     if (!com_err_initialized)
96 	_fetch_init_com_err();
97 
98     n = _fetch_finderr(p, e);
99     fetchLastErrCode = p[n].cat;
100     com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string);
101 }
102 
103 /*
104  * Set error code according to errno
105  */
106 void
107 _fetch_syserr(void)
108 {
109     int e;
110     e = errno;
111 
112     if (!com_err_initialized)
113 	_fetch_init_com_err();
114 
115     switch (errno) {
116     case 0:
117 	fetchLastErrCode = FETCH_OK;
118 	break;
119     case EPERM:
120     case EACCES:
121     case EROFS:
122     case EAUTH:
123     case ENEEDAUTH:
124 	fetchLastErrCode = FETCH_AUTH;
125 	break;
126     case ENOENT:
127     case EISDIR: /* XXX */
128 	fetchLastErrCode = FETCH_UNAVAIL;
129 	break;
130     case ENOMEM:
131 	fetchLastErrCode = FETCH_MEMORY;
132 	break;
133     case EBUSY:
134     case EAGAIN:
135 	fetchLastErrCode = FETCH_TEMP;
136 	break;
137     case EEXIST:
138 	fetchLastErrCode = FETCH_EXISTS;
139 	break;
140     case ENOSPC:
141 	fetchLastErrCode = FETCH_FULL;
142 	break;
143     case EADDRINUSE:
144     case EADDRNOTAVAIL:
145     case ENETDOWN:
146     case ENETUNREACH:
147     case ENETRESET:
148     case EHOSTUNREACH:
149 	fetchLastErrCode = FETCH_NETWORK;
150 	break;
151     case ECONNABORTED:
152     case ECONNRESET:
153 	fetchLastErrCode = FETCH_ABORT;
154 	break;
155     case ETIMEDOUT:
156 	fetchLastErrCode = FETCH_TIMEOUT;
157 	break;
158     case ECONNREFUSED:
159     case EHOSTDOWN:
160 	fetchLastErrCode = FETCH_DOWN;
161 	break;
162     default:
163 	fetchLastErrCode = FETCH_UNKNOWN;
164     }
165     com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e));
166 }
167 
168 
169 /*
170  * Emit status message
171  */
172 int
173 _fetch_info(char *fmt, ...)
174 {
175     va_list ap;
176     char *s;
177 
178     if (!com_err_initialized)
179 	_fetch_init_com_err();
180 
181     va_start(ap, fmt);
182     vasprintf(&s, fmt, ap);
183     va_end(ap);
184 
185     if (s == NULL) {
186 	com_err("libfetch", FETCH_MEMORY, "");
187 	return -1;
188     } else {
189 	com_err("libfetch", FETCH_VERBOSE, "%s", s);
190 	free(s);
191 	return 0;
192     }
193 }
194 
195 
196 /*** Network-related utility functions ***************************************/
197 
198 /*
199  * Establish a TCP connection to the specified port on the specified host.
200  */
201 int
202 _fetch_connect(char *host, int port, int verbose)
203 {
204     struct sockaddr_in sin;
205     struct hostent *he;
206     int sd;
207 
208 #ifndef NDEBUG
209     fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port);
210 #endif
211 
212     if (verbose)
213 	_fetch_info("looking up %s", host);
214 
215     /* look up host name */
216     if ((he = gethostbyname(host)) == NULL) {
217 	_netdb_seterr(h_errno);
218 	return -1;
219     }
220 
221     if (verbose)
222 	_fetch_info("connecting to %s:%d", host, port);
223 
224     /* set up socket address structure */
225     bzero(&sin, sizeof(sin));
226     bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
227     sin.sin_family = he->h_addrtype;
228     sin.sin_port = htons(port);
229 
230     /* try to connect */
231     if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
232 	_fetch_syserr();
233 	return -1;
234     }
235     if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) {
236 	_fetch_syserr();
237 	close(sd);
238 	return -1;
239     }
240 
241     return sd;
242 }
243 
244 
245 /*** Directory-related utility functions *************************************/
246 
247 int
248 _fetch_add_entry(struct url_ent **p, int *size, int *len,
249 		 char *name, struct url_stat *stat)
250 {
251     struct url_ent *tmp;
252 
253     if (*p == NULL) {
254 #define INITIAL_SIZE 8
255 	if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) {
256 	    errno = ENOMEM;
257 	    _fetch_syserr();
258 	    return -1;
259 	}
260 	*size = INITIAL_SIZE;
261 	*len = 0;
262 #undef INITIAL_SIZE
263     }
264 
265     if (*len >= *size - 1) {
266 	tmp = realloc(*p, *size * 2 * sizeof **p);
267 	if (tmp == NULL) {
268 	    errno = ENOMEM;
269 	    _fetch_syserr();
270 	    return -1;
271 	}
272 	*size *= 2;
273 	*p = tmp;
274     }
275 
276     tmp = *p + *len;
277     snprintf(tmp->name, MAXPATHLEN, "%s", name);
278     bcopy(stat, &tmp->stat, sizeof *stat);
279 
280     (*len)++;
281     (++tmp)->name[0] = 0;
282 
283     return 0;
284 }
285