common.c revision 50476
140939Sdes/*- 240939Sdes * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 340939Sdes * All rights reserved. 440939Sdes * 540939Sdes * Redistribution and use in source and binary forms, with or without 640939Sdes * modification, are permitted provided that the following conditions 740939Sdes * are met: 840939Sdes * 1. Redistributions of source code must retain the above copyright 940939Sdes * notice, this list of conditions and the following disclaimer 1040939Sdes * in this position and unchanged. 1140939Sdes * 2. Redistributions in binary form must reproduce the above copyright 1240939Sdes * notice, this list of conditions and the following disclaimer in the 1340939Sdes * documentation and/or other materials provided with the distribution. 1440939Sdes * 3. The name of the author may not be used to endorse or promote products 1540939Sdes * derived from this software without specific prior written permission 1640939Sdes * 1740939Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1840939Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1940939Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2040939Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2140939Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2240939Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2340939Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2440939Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2540939Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2640939Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2740939Sdes * 2850476Speter * $FreeBSD: head/lib/libfetch/common.c 50476 1999-08-28 00:22:10Z peter $ 2940939Sdes */ 3040939Sdes 3141862Sdes#include <sys/param.h> 3240939Sdes#include <sys/socket.h> 3340939Sdes#include <netinet/in.h> 3440939Sdes 3540975Sdes#include <com_err.h> 3640939Sdes#include <errno.h> 3740939Sdes#include <netdb.h> 3841862Sdes#include <stdlib.h> 3941862Sdes#include <stdio.h> 4040939Sdes#include <string.h> 4140939Sdes#include <unistd.h> 4240939Sdes 4340939Sdes#include "fetch.h" 4440939Sdes#include "common.h" 4540939Sdes 4640975Sdes 4740939Sdes/*** Local data **************************************************************/ 4840939Sdes 4940939Sdes/* 5040939Sdes * Error messages for resolver errors 5140939Sdes */ 5240939Sdesstatic struct fetcherr _netdb_errlist[] = { 5340975Sdes { HOST_NOT_FOUND, FETCH_RESOLV, "Host not found" }, 5441862Sdes { TRY_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 5540975Sdes { NO_RECOVERY, FETCH_RESOLV, "Non-recoverable resolver failure" }, 5640975Sdes { NO_DATA, FETCH_RESOLV, "No address record" }, 5740975Sdes { -1, FETCH_UNKNOWN, "Unknown resolver error" } 5840939Sdes}; 5940939Sdes 6040975Sdesstatic int com_err_initialized; 6140939Sdes 6240939Sdes/*** Error-reporting functions ***********************************************/ 6340939Sdes 6440939Sdes/* 6540975Sdes * Initialize the common error library 6640975Sdes */ 6740975Sdesstatic void 6840975Sdes_fetch_init_com_err(void) 6940975Sdes{ 7040975Sdes initialize_ftch_error_table(); 7140975Sdes com_err_initialized = 1; 7240975Sdes} 7340975Sdes 7440975Sdes/* 7540939Sdes * Map error code to string 7640939Sdes */ 7740975Sdesstatic int 7840975Sdes_fetch_finderr(struct fetcherr *p, int e) 7940939Sdes{ 8040975Sdes int i; 8140975Sdes for (i = 0; p[i].num != -1; i++) 8240975Sdes if (p[i].num == e) 8340975Sdes break; 8440975Sdes return i; 8540939Sdes} 8640939Sdes 8740939Sdes/* 8840939Sdes * Set error code 8940939Sdes */ 9040939Sdesvoid 9140939Sdes_fetch_seterr(struct fetcherr *p, int e) 9240939Sdes{ 9340975Sdes int n; 9440975Sdes 9540975Sdes if (!com_err_initialized) 9640975Sdes _fetch_init_com_err(); 9740975Sdes 9840975Sdes n = _fetch_finderr(p, e); 9941862Sdes fetchLastErrCode = p[n].cat; 10041862Sdes com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string); 10140939Sdes} 10240939Sdes 10340939Sdes/* 10440939Sdes * Set error code according to errno 10540939Sdes */ 10640939Sdesvoid 10740939Sdes_fetch_syserr(void) 10840939Sdes{ 10941862Sdes int e; 11041862Sdes e = errno; 11140975Sdes 11240975Sdes if (!com_err_initialized) 11340975Sdes _fetch_init_com_err(); 11440975Sdes 11540975Sdes switch (errno) { 11640975Sdes case 0: 11741862Sdes fetchLastErrCode = FETCH_OK; 11840975Sdes break; 11940975Sdes case EPERM: 12040975Sdes case EACCES: 12140975Sdes case EROFS: 12240975Sdes case EAUTH: 12340975Sdes case ENEEDAUTH: 12441862Sdes fetchLastErrCode = FETCH_AUTH; 12540975Sdes break; 12640975Sdes case ENOENT: 12740975Sdes case EISDIR: /* XXX */ 12841862Sdes fetchLastErrCode = FETCH_UNAVAIL; 12940975Sdes break; 13040975Sdes case ENOMEM: 13141862Sdes fetchLastErrCode = FETCH_MEMORY; 13240975Sdes break; 13340975Sdes case EBUSY: 13440975Sdes case EAGAIN: 13541862Sdes fetchLastErrCode = FETCH_TEMP; 13640975Sdes break; 13740975Sdes case EEXIST: 13841862Sdes fetchLastErrCode = FETCH_EXISTS; 13940975Sdes break; 14040975Sdes case ENOSPC: 14141862Sdes fetchLastErrCode = FETCH_FULL; 14240975Sdes break; 14340975Sdes case EADDRINUSE: 14440975Sdes case EADDRNOTAVAIL: 14540975Sdes case ENETDOWN: 14640975Sdes case ENETUNREACH: 14740975Sdes case ENETRESET: 14840975Sdes case EHOSTUNREACH: 14941862Sdes fetchLastErrCode = FETCH_NETWORK; 15040975Sdes break; 15140975Sdes case ECONNABORTED: 15240975Sdes case ECONNRESET: 15341862Sdes fetchLastErrCode = FETCH_ABORT; 15440975Sdes break; 15540975Sdes case ETIMEDOUT: 15641862Sdes fetchLastErrCode = FETCH_TIMEOUT; 15740975Sdes break; 15840975Sdes case ECONNREFUSED: 15940975Sdes case EHOSTDOWN: 16041862Sdes fetchLastErrCode = FETCH_DOWN; 16140975Sdes break; 16240975Sdes default: 16341862Sdes fetchLastErrCode = FETCH_UNKNOWN; 16440975Sdes } 16541862Sdes com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e)); 16640939Sdes} 16740939Sdes 16840939Sdes 16941862Sdes/* 17041862Sdes * Emit status message 17141862Sdes */ 17241862Sdesint 17341862Sdes_fetch_info(char *fmt, ...) 17441862Sdes{ 17541862Sdes va_list ap; 17641862Sdes char *s; 17741862Sdes 17841862Sdes if (!com_err_initialized) 17941862Sdes _fetch_init_com_err(); 18041862Sdes 18141862Sdes va_start(ap, fmt); 18241862Sdes vasprintf(&s, fmt, ap); 18341862Sdes va_end(ap); 18441862Sdes 18541862Sdes if (s == NULL) { 18641862Sdes com_err("libfetch", FETCH_MEMORY, ""); 18741862Sdes return -1; 18841862Sdes } else { 18941862Sdes com_err("libfetch", FETCH_VERBOSE, "%s", s); 19041862Sdes free(s); 19141862Sdes return 0; 19241862Sdes } 19341862Sdes} 19441862Sdes 19541862Sdes 19640939Sdes/*** Network-related utility functions ***************************************/ 19740939Sdes 19840939Sdes/* 19940939Sdes * Establish a TCP connection to the specified port on the specified host. 20040939Sdes */ 20140939Sdesint 20241923Sdes_fetch_connect(char *host, int port, int verbose) 20340939Sdes{ 20440939Sdes struct sockaddr_in sin; 20540939Sdes struct hostent *he; 20640939Sdes int sd; 20740939Sdes 20840939Sdes#ifndef NDEBUG 20940939Sdes fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); 21040939Sdes#endif 21141862Sdes 21241862Sdes if (verbose) 21341862Sdes _fetch_info("looking up %s", host); 21440939Sdes 21540939Sdes /* look up host name */ 21640939Sdes if ((he = gethostbyname(host)) == NULL) { 21740939Sdes _netdb_seterr(h_errno); 21840939Sdes return -1; 21940939Sdes } 22040939Sdes 22141862Sdes if (verbose) 22241862Sdes _fetch_info("connecting to %s:%d", host, port); 22341862Sdes 22440939Sdes /* set up socket address structure */ 22540939Sdes bzero(&sin, sizeof(sin)); 22640939Sdes bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); 22740939Sdes sin.sin_family = he->h_addrtype; 22840939Sdes sin.sin_port = htons(port); 22940939Sdes 23040939Sdes /* try to connect */ 23140939Sdes if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { 23240939Sdes _fetch_syserr(); 23340939Sdes return -1; 23440939Sdes } 23540939Sdes if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { 23640939Sdes _fetch_syserr(); 23740939Sdes close(sd); 23840939Sdes return -1; 23940939Sdes } 24040939Sdes 24140939Sdes return sd; 24240939Sdes} 24341989Sdes 24441989Sdes 24541989Sdes/*** Directory-related utility functions *************************************/ 24641989Sdes 24741989Sdesint 24841989Sdes_fetch_add_entry(struct url_ent **p, int *size, int *len, 24941989Sdes char *name, struct url_stat *stat) 25041989Sdes{ 25141989Sdes struct url_ent *tmp; 25241989Sdes 25341989Sdes if (*p == NULL) { 25441989Sdes#define INITIAL_SIZE 8 25541989Sdes if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) { 25641989Sdes errno = ENOMEM; 25741989Sdes _fetch_syserr(); 25841989Sdes return -1; 25941989Sdes } 26041989Sdes *size = INITIAL_SIZE; 26141989Sdes *len = 0; 26241989Sdes#undef INITIAL_SIZE 26341989Sdes } 26441989Sdes 26541989Sdes if (*len >= *size - 1) { 26641989Sdes tmp = realloc(*p, *size * 2 * sizeof **p); 26741989Sdes if (tmp == NULL) { 26841989Sdes errno = ENOMEM; 26941989Sdes _fetch_syserr(); 27041989Sdes return -1; 27141989Sdes } 27241989Sdes *size *= 2; 27341989Sdes *p = tmp; 27441989Sdes } 27541989Sdes 27641989Sdes tmp = *p + *len; 27741989Sdes snprintf(tmp->name, MAXPATHLEN, "%s", name); 27841989Sdes bcopy(stat, &tmp->stat, sizeof *stat); 27941989Sdes 28041989Sdes (*len)++; 28141989Sdes (++tmp)->name[0] = 0; 28241989Sdes 28341989Sdes return 0; 28441989Sdes} 285