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