/* $Id: puf.c,v 1.10 2004/02/13 15:29:00 ossi Exp $ * * * puf 0.9 Copyright (C) 2000-2004 by Oswald Buddenhagen * based on puf 0.1.x (C) 1999,2000 by Anders Gavare * * You may modify and distribute this code under the terms of the GPL. * There is NO WARRANTY of any kind. See COPYING for details. * * puf.c - startup code and global functions * */ #include "puf.h" int verbose; char *progname; #ifdef DEBUG int debug; #endif #ifndef HAVE_STRDUP char * strdup(const char *s) { int l = strlen(s) + 1; char *rt = malloc(l); if (rt) memcpy(rt, s, l); return rt; } #endif #define FMTLEN 128 int errm(url_t *u, const char *msg, ...) { char *pt; va_list va; int rtv, lv; unsigned l, i, fl; char tbuf[2 * SHORTSTR + FMTLEN], fmt[SHORTSTR]; num_errors++; if (*msg == '!') { msg++; num_urls_fail++; rtv = RT_GIVEUP; lv = ERR; } else if (++u->attempt >= (unsigned)u->parm->opt->max_attempts) { num_urls_fail++; rtv = RT_GIVEUP; lv = ERR; } else { rtv = RT_RETRY; lv = WRN; } if (lv <= verbose) { snprintf(fmt, sizeof(fmt), rtv == RT_RETRY ? "%s warning: %s (try %d)\n" : "%s: %s\n", progname, msg, u->attempt); if ((pt = strstr(fmt, "$u"))) { if (u->port == 80) l = snprintf(tbuf + SHORTSTR + FMTLEN, SHORTSTR, "http://%s/%s", u->host->name, u->local_part); else l = snprintf(tbuf + SHORTSTR + FMTLEN, SHORTSTR, "http://%s:%i/%s", u->host->name, u->port, u->local_part); if (l >= SHORTSTR) { memcpy(tbuf + 2 * SHORTSTR + FMTLEN - 4, "...", 4); l = SHORTSTR - 1; } fl = (unsigned)(pt - fmt); memcpy(tbuf, fmt, fl); for (i = 0; i < l; i++) { if (tbuf[i + SHORTSTR + FMTLEN] == '%') tbuf[fl++] = '%'; tbuf[fl++] = tbuf[i + SHORTSTR + FMTLEN]; } strcpy(tbuf + fl, pt + 2); pt = tbuf; } else pt = fmt; va_start(va, msg); vfprintf(stderr, pt, va); va_end(va); } return rtv; } void dbp(const char *msg, ...) { char fmt[SHORTSTR]; va_list va; snprintf(fmt, SHORTSTR, "%s debug: %s", progname, msg); va_start(va, msg); vfprintf(stderr, fmt, va); va_end(va); } void dbpe(const char *msg, ...) { va_list va; va_start(va, msg); vfprintf(stderr, msg, va); va_end(va); } void prx(int lev, const char *msg, ...) { char fmt[SHORTSTR]; static const char *prfs[] = {" fatal", "", " warning", " info", " debug"}; va_list va; if (lev <= verbose) { snprintf(fmt, SHORTSTR, "%s%s: %s", progname, prfs[lev], msg); va_start(va, msg); vfprintf(stderr, fmt, va); va_end(va); } } /* print an error message and terminate */ void die(int ret, const char *msg, ...) { char fmt[SHORTSTR]; va_list va; snprintf(fmt, SHORTSTR, "\n%s: %s\n", progname, msg); va_start(va, msg); vfprintf(stderr, fmt, va); va_end(va); exit(ret); } #ifndef __DMALLOC_H__ /* allocate memory or ask user what to do, if none available */ void * mrealloc(void *ptr, size_t size) { void *t; static int asked = 0; if (size <= 0 || size > 100000) ierr("Internal error: Invalid memory allocation request."); if (!(t = realloc(ptr, size))) { if (!asked && isatty(0) && isatty(2)) { prx(0, "Out of memory. Strange things may happen. Continue [n]? "); if (getchar() != 'y') byebye("aborting"); asked++; } else prx(ERR, "Allocation of %d bytes failed!\n", size); } return t; } void * mmalloc(size_t size) { return mrealloc(0, size); } #endif static long crc32_tab[256]; static void init_hash(void) { int i, b; long by; for (i = 0; i < 256; i++) { for (by = i, b = 0; b < 8; b++) by = (by >> 1) ^ (-(by & 1) & 0xedb88320); crc32_tab[i] = by; } } /* this is the normal crc32 algorithm. the generated numbers are quite unique, but i don't know, if they are well dispersed, i.e., if they are adequate for a real hash table. */ int calc_hash(u_char * data, int len) { int i; long crc = 0xc0debabe; for (i = 0; i < len; i++, data++) crc = (crc >> 8) ^ crc32_tab[(crc & 255) ^ *data]; return (int)crc; } #ifdef USE_MAGIC void magck(const char *msg) { url_t *u; int i; for (u = urllist, i=0; u; u = u->next, i++) { if (!ichecken_url(u)) prx(ERR, "checksum error for url[%d] (%s/%s) in %s\n", i, u->host->name, u->local_part, msg); else if (!ichecken_gen(u->parm)) prx(ERR, "checksum error for url[%d]->parm (%s/%s) in %s\n", i, u->host->name, u->local_part, msg); else if (!ichecken_gen(u->parm->opt)) prx(ERR, "checksum error for url[%d]->parm->opt (%s/%s) in %s\n", i, u->host->name, u->local_part, msg); else continue; ierr("internal error"); } } #endif int main(int argc, char *argv[]) { #ifdef __DMALLOC_H__ url_t *u, *nu; host_t *h, *nh; hinfo_t *hi; #endif if (!isatty(1)) show_stat = 0; else printf(PACKAGE " v" VERSION " Copyright (C) 2000-2004 by Oswald Buddenhagen\n" " based on puf v0.1.x " "Copyright (C) 1999,2000 by Anders Gavare\n"); progname = strrchr(argv[0], '/'); if (progname) progname++; else progname = argv[0]; bind_addr.sin_family = AF_INET; /* the rest is already 0 */ srand(time(0)); init_hash(); init_user_agent(); getopts(argc, argv); setlocale(LC_TIME, "C"); /* some voodoo for strftime */ fetch_all(); #ifdef __DMALLOC_H__ for (u = urllist; u; u = nu) { nu = u->next; dbg(MEM, ("disposing http://%s/%s\n", u->host->name, u->local_part)); free(u); } for (hi = 0, h = hostlist; h; h = nh) { if (h->info != hi) { hi = h->info; if (hi) { dbg(MEM, ("disposing host info for '%s'\n", hi->name)); free(hi); } } nh = h->next; dbg(MEM, ("disposing host '%s'\n", h->name)); free(h); } #endif return 0; }