common.c revision 55557
1168404Spjd/*- 2168404Spjd * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer 10168404Spjd * in this position and unchanged. 11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 12168404Spjd * notice, this list of conditions and the following disclaimer in the 13168404Spjd * documentation and/or other materials provided with the distribution. 14168404Spjd * 3. The name of the author may not be used to endorse or promote products 15168404Spjd * derived from this software without specific prior written permission 16168404Spjd * 17168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18168404Spjd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19168404Spjd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20168404Spjd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21168404Spjd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22219089Spjd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23277826Sdelphij * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24286766Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25260835Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26286764Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27168404Spjd * 28168404Spjd * $FreeBSD: head/lib/libfetch/common.c 55557 2000-01-07 12:58:40Z des $ 29168404Spjd */ 30168404Spjd 31168404Spjd#include <sys/param.h> 32168404Spjd#include <sys/socket.h> 33168404Spjd#include <sys/time.h> 34168404Spjd#include <netinet/in.h> 35168404Spjd 36168404Spjd#include <com_err.h> 37168404Spjd#include <errno.h> 38168404Spjd#include <netdb.h> 39168404Spjd#include <stdlib.h> 40168404Spjd#include <stdio.h> 41168404Spjd#include <string.h> 42168404Spjd#include <unistd.h> 43168404Spjd 44168404Spjd#include "fetch.h" 45168404Spjd#include "common.h" 46168404Spjd 47168404Spjd 48168404Spjd/*** Local data **************************************************************/ 49168404Spjd 50168404Spjd/* 51185029Spjd * Error messages for resolver errors 52185029Spjd */ 53168404Spjdstatic struct fetcherr _netdb_errlist[] = { 54168404Spjd { HOST_NOT_FOUND, FETCH_RESOLV, "Host not found" }, 55168404Spjd { TRY_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 56168404Spjd { NO_RECOVERY, FETCH_RESOLV, "Non-recoverable resolver failure" }, 57185029Spjd { NO_DATA, FETCH_RESOLV, "No address record" }, 58168404Spjd { -1, FETCH_UNKNOWN, "Unknown resolver error" } 59168404Spjd}; 60168404Spjd 61168404Spjdstatic int com_err_initialized; 62251631Sdelphij 63168404Spjd/*** Error-reporting functions ***********************************************/ 64168404Spjd 65168404Spjd/* 66251631Sdelphij * Initialize the common error library 67168404Spjd */ 68168404Spjdstatic void 69168404Spjd_fetch_init_com_err(void) 70168404Spjd{ 71168404Spjd initialize_ftch_error_table(); 72168404Spjd com_err_initialized = 1; 73168404Spjd} 74168404Spjd 75168404Spjd/* 76168404Spjd * Map error code to string 77168404Spjd */ 78168404Spjdstatic int 79185029Spjd_fetch_finderr(struct fetcherr *p, int e) 80168404Spjd{ 81251631Sdelphij int i; 82168404Spjd for (i = 0; p[i].num != -1; i++) 83168404Spjd if (p[i].num == e) 84168404Spjd break; 85286774Smav return i; 86286774Smav} 87286774Smav 88168404Spjd/* 89168404Spjd * Set error code 90168404Spjd */ 91168404Spjdvoid 92168404Spjd_fetch_seterr(struct fetcherr *p, int e) 93168404Spjd{ 94168404Spjd int n; 95168404Spjd 96168404Spjd if (!com_err_initialized) 97168404Spjd _fetch_init_com_err(); 98168404Spjd 99168404Spjd n = _fetch_finderr(p, e); 100168404Spjd fetchLastErrCode = p[n].cat; 101168404Spjd com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string); 102168404Spjd} 103168404Spjd 104168404Spjd/* 105168404Spjd * Set error code according to errno 106168404Spjd */ 107168404Spjdvoid 108268858Sdelphij_fetch_syserr(void) 109168404Spjd{ 110168404Spjd int e; 111168404Spjd e = errno; 112168404Spjd 113185029Spjd if (!com_err_initialized) 114286570Smav _fetch_init_com_err(); 115185029Spjd 116185029Spjd switch (errno) { 117185029Spjd case 0: 118185029Spjd fetchLastErrCode = FETCH_OK; 119185029Spjd break; 120185029Spjd case EPERM: 121168404Spjd case EACCES: 122168404Spjd case EROFS: 123168404Spjd case EAUTH: 124168404Spjd case ENEEDAUTH: 125251478Sdelphij fetchLastErrCode = FETCH_AUTH; 126168404Spjd break; 127168404Spjd case ENOENT: 128168404Spjd case EISDIR: /* XXX */ 129185029Spjd fetchLastErrCode = FETCH_UNAVAIL; 130219089Spjd break; 131258632Savg case ENOMEM: 132286763Smav fetchLastErrCode = FETCH_MEMORY; 133168404Spjd break; 134168404Spjd case EBUSY: 135297633Strasz case EAGAIN: 136168404Spjd fetchLastErrCode = FETCH_TEMP; 137168404Spjd break; 138168404Spjd case EEXIST: 139248572Ssmh fetchLastErrCode = FETCH_EXISTS; 140219089Spjd break; 141168404Spjd case ENOSPC: 142168404Spjd fetchLastErrCode = FETCH_FULL; 143272483Ssmh break; 144191902Skmacy case EADDRINUSE: 145240133Smm case EADDRNOTAVAIL: 146240133Smm case ENETDOWN: 147240133Smm case ENETUNREACH: 148240133Smm case ENETRESET: 149240133Smm case EHOSTUNREACH: 150240133Smm fetchLastErrCode = FETCH_NETWORK; 151240133Smm break; 152240133Smm case ECONNABORTED: 153286763Smav case ECONNRESET: 154286763Smav fetchLastErrCode = FETCH_ABORT; 155286763Smav break; 156286763Smav case ETIMEDOUT: 157168404Spjd fetchLastErrCode = FETCH_TIMEOUT; 158286763Smav break; 159286763Smav case ECONNREFUSED: 160286763Smav case EHOSTDOWN: 161286763Smav fetchLastErrCode = FETCH_DOWN; 162301997Skib break; 163301997Skib default: 164301997Skib fetchLastErrCode = FETCH_UNKNOWN; 165301997Skib } 166286625Smav com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e)); 167168404Spjd} 168258632Savg 169286763Smav 170286763Smav/* 171286763Smav * Emit status message 172286763Smav */ 173286763Smavint 174258632Savg_fetch_info(char *fmt, ...) 175286763Smav{ 176258632Savg va_list ap; 177286763Smav char *s; 178286763Smav 179286763Smav if (!com_err_initialized) 180286763Smav _fetch_init_com_err(); 181286763Smav 182286763Smav va_start(ap, fmt); 183286763Smav vasprintf(&s, fmt, ap); 184168404Spjd va_end(ap); 185168404Spjd 186168404Spjd if (s == NULL) { 187286763Smav com_err("libfetch", FETCH_MEMORY, ""); 188286763Smav return -1; 189286763Smav } else { 190208373Smm com_err("libfetch", FETCH_VERBOSE, "%s", s); 191208373Smm free(s); 192208373Smm return 0; 193208373Smm } 194286625Smav} 195208373Smm 196168404Spjd 197286625Smav/*** Network-related utility functions ***************************************/ 198286625Smav 199286625Smav/* 200286625Smav * Establish a TCP connection to the specified port on the specified host. 201286625Smav */ 202286625Smavint 203286625Smav_fetch_connect(char *host, int port, int verbose) 204286625Smav{ 205286625Smav struct sockaddr_in sin; 206286625Smav struct hostent *he; 207286625Smav int sd; 208286625Smav 209168404Spjd#ifndef NDEBUG 210168404Spjd fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); 211168404Spjd#endif 212168404Spjd 213168404Spjd if (verbose) 214258632Savg _fetch_info("looking up %s", host); 215258632Savg 216258632Savg /* look up host name */ 217258632Savg if ((he = gethostbyname(host)) == NULL) { 218258632Savg _netdb_seterr(h_errno); 219208373Smm return -1; 220287702Sdelphij } 221168404Spjd 222168404Spjd if (verbose) 223185029Spjd _fetch_info("connecting to %s:%d", host, port); 224185029Spjd 225185029Spjd /* set up socket address structure */ 226185029Spjd bzero(&sin, sizeof(sin)); 227286762Smav bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); 228286762Smav sin.sin_family = he->h_addrtype; 229286762Smav sin.sin_port = htons(port); 230185029Spjd 231185029Spjd /* try to connect */ 232185029Spjd if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { 233275780Sdelphij _fetch_syserr(); 234208373Smm return -1; 235208373Smm } 236208373Smm if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { 237242845Sdelphij _fetch_syserr(); 238269230Sdelphij close(sd); 239272483Ssmh return -1; 240185029Spjd } 241270759Ssmh 242275748Sdelphij return sd; 243270759Ssmh} 244270759Ssmh 245270759Ssmh 246270759Ssmh/* 247270759Ssmh * Read a line of text from a socket w/ timeout 248270759Ssmh */ 249272483Ssmh#define MIN_BUF_SIZE 1024 250270759Ssmh 251270759Ssmhint 252270759Ssmh_fetch_getln(int fd, char **buf, size_t *size, size_t *len) 253270759Ssmh{ 254185029Spjd struct timeval now, timeout, wait; 255275780Sdelphij fd_set readfds; 256273026Sdelphij int r; 257168473Spjd char c; 258217367Smdf 259168473Spjd if (*buf == NULL) { 260217367Smdf if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) { 261168473Spjd errno = ENOMEM; 262269230Sdelphij return -1; 263269230Sdelphij } 264269230Sdelphij *size = MIN_BUF_SIZE; 265273026Sdelphij } 266273026Sdelphij 267273026Sdelphij **buf = '\0'; 268273026Sdelphij *len = 0; 269270759Ssmh 270270759Ssmh if (fetchTimeout) { 271270759Ssmh gettimeofday(&timeout, NULL); 272270759Ssmh timeout.tv_sec += fetchTimeout; 273270759Ssmh FD_ZERO(&readfds); 274270759Ssmh } 275270759Ssmh 276270759Ssmh do { 277168404Spjd if (fetchTimeout) { 278270759Ssmh FD_SET(fd, &readfds); 279270759Ssmh gettimeofday(&now, NULL); 280270759Ssmh wait.tv_sec = timeout.tv_sec - now.tv_sec; 281270759Ssmh wait.tv_usec = timeout.tv_usec - now.tv_usec; 282270759Ssmh if (wait.tv_usec < 0) { 283270759Ssmh wait.tv_usec += 1000000; 284270759Ssmh wait.tv_sec--; 285270759Ssmh } 286270759Ssmh if (wait.tv_sec < 0) { 287270759Ssmh errno = ETIMEDOUT; 288270759Ssmh return -1; 289272483Ssmh } 290270759Ssmh r = select(fd+1, &readfds, NULL, NULL, &wait); 291272483Ssmh if (r == -1) { 292270759Ssmh if (errno == EINTR) 293270759Ssmh continue; 294270759Ssmh /* EBADF or EINVAL: shouldn't happen */ 295270759Ssmh return -1; 296270759Ssmh } 297270759Ssmh if (!FD_ISSET(fd, &readfds)) 298275748Sdelphij continue; 299275748Sdelphij } 300275748Sdelphij r = read(fd, &c, 1); 301275748Sdelphij if (r == 0) 302275748Sdelphij break; 303275748Sdelphij if (r == -1) { 304275748Sdelphij if (errno == EINTR) 305275748Sdelphij continue; 306275748Sdelphij /* any other error is bad news */ 307272483Ssmh return -1; 308270759Ssmh } 309168404Spjd (*buf)[*len] = c; 310185029Spjd *len += 1; 311168404Spjd if (*len == *size) { 312168404Spjd char *tmp; 313168404Spjd 314168404Spjd if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) { 315168404Spjd errno = ENOMEM; 316185029Spjd return -1; 317185029Spjd } 318185029Spjd *buf = tmp; 319185029Spjd *size = *size * 2 + 1; 320185029Spjd } 321185029Spjd } while (c != '\n'); 322185029Spjd 323185029Spjd return 0; 324168404Spjd} 325168404Spjd 326168404Spjd 327168404Spjd/*** Directory-related utility functions *************************************/ 328168404Spjd 329168404Spjdint 330168404Spjd_fetch_add_entry(struct url_ent **p, int *size, int *len, 331185029Spjd char *name, struct url_stat *stat) 332185029Spjd{ 333185029Spjd struct url_ent *tmp; 334185029Spjd 335185029Spjd if (*p == NULL) { 336185029Spjd#define INITIAL_SIZE 8 337185029Spjd if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) { 338185029Spjd errno = ENOMEM; 339168404Spjd _fetch_syserr(); 340168404Spjd return -1; 341168404Spjd } 342286763Smav *size = INITIAL_SIZE; 343286763Smav *len = 0; 344286763Smav#undef INITIAL_SIZE 345286763Smav } 346286763Smav 347286763Smav if (*len >= *size - 1) { 348286763Smav tmp = realloc(*p, *size * 2 * sizeof **p); 349286763Smav if (tmp == NULL) { 350286763Smav errno = ENOMEM; 351286763Smav _fetch_syserr(); 352286763Smav return -1; 353286763Smav } 354286766Smav *size *= 2; 355168404Spjd *p = tmp; 356168404Spjd } 357185029Spjd 358168404Spjd tmp = *p + *len; 359168404Spjd snprintf(tmp->name, MAXPATHLEN, "%s", name); 360168404Spjd bcopy(stat, &tmp->stat, sizeof *stat); 361168404Spjd 362168404Spjd (*len)++; 363185029Spjd (++tmp)->name[0] = 0; 364168404Spjd 365168404Spjd return 0; 366168404Spjd} 367168404Spjd