#if !defined(lint) static char rcs_id[] = "$Id: utils.c,v 2.0.1.8 1998/03/30 08:11:45 stefan Stab $"; #endif /* ** Utilities for http-analyze ** ** Copyright © 1996-1998 by Stefan Stapelberg, ** */ #include #include #include #include #include #include #include #include #if defined(unix) # include # include #else # if defined(WIN32) # include /* for the u_int, etc. types */ # include /* for other windows/watcom stuff */ # include /* for the F_OK, etc. symbolic constants */ # include # elif defined(NETWARE) # include # include # include # include /* for other windows/watcom stuff */ # include /* for the F_OK, etc. symbolic constants */ # endif #endif #include "config.h" #include "defs.h" #if !defined(FAST_CTYPE) # include #endif #if !defined(NO_UNAME) # include #endif #if defined(USE_STBLKSIZE) # include #endif #if defined(USE_FAST_MALLOC) # include #endif /* ** If you don't use fgets, BEST_IO_SIZE defines the optimum buffer ** size per read(2) system call. On my SGI Indy running IRIX 6.2 ** the optimum I/O buffer for files seems to be 64KB. If you ** define USE_STBLKSIZE, the scanner adapts to the best block ** size reported by fstat(2). */ #if !defined(USE_FGETS) && !defined(BEST_IO_SIZE) # define BEST_IO_SIZE (1024*64) #endif #if defined(NEED_WAITPID) static pid_t waitpid (pid_t const, int * const, int const); #endif #if !defined(USE_FGETS) /* ** Read a line from given file. ** On IRIX systems, this function is *much* faster than ** the fgets() function from the standard library. Your ** mileage may vary. */ static long blk_size = 0; /* best block size for I/O */ static char *fbuf = NULL; /* dynamically allocated I/O buffer */ int readLine(register char *bp, size_t maxsize, FILE * const lfp) { static int saweof = 0; /* set if EOF reached */ static int nleft = 0; /* numbers of chars left in fbuf or EOF */ static char *next = NULL; /* ptr to next char in fbuf */ register size_t cnt = 0; /* counter */ char *obp = bp; #if defined(USE_STBLKSIZE) struct stat stbuf; /* obtain best I/O size dynamically */ #endif if (saweof) { if (fbuf != NULL) { free(fbuf); fbuf = NULL; blk_size = 0L; } return -1; } if (!blk_size) { blk_size = BEST_IO_SIZE; #if defined(USE_STBLKSIZE) if (fstat(fileno(lfp), &stbuf) == 0) blk_size = stbuf.st_blksize; #endif if (blk_size < 1024) blk_size = 1024; } if (!fbuf) { if ((fbuf=(char *)malloc((size_t)blk_size)) == NULL) { prmsg(2, "Can't allocate %lu bytes for I/O buffer\n", (u_long)blk_size); saweof = 1; return -1; } if (verbose > 1) prmsg(0, "Best blocksize for I/O is %lu KB\n", (u_long)(blk_size/1024L)); } maxsize--; /* preserve space for '\0' byte below */ do { if (nleft == 0) { /* nothing left, read in a chunk of data */ if ((nleft = read(fileno(lfp), (void *)fbuf, (size_t)blk_size)) <= 0) { if (cnt) { /* output rest from previous chunk */ saweof = 1; /* remember EOF */ nleft = 0; break; } return -1; } next = fbuf; } /* copy until newline or at most N bytes */ for (cnt = MIN(maxsize, (size_t)nleft); cnt; cnt--) { nleft--; if ((*bp++ = *next++) == '\n') break; } if (cnt) { /* string terminated */ while (*(bp-1) == '\n' || *(bp-1) == '\r') *--bp = '\0'; break; } if (nleft > 0) { /* buffer overflow, terminate string */ *--bp = '\0'; break; } cnt = (size_t)(bp-obp); /* read continuation line */ maxsize -= cnt; nleft = 0; } /*CONSTCOND*/ while (1); return (int)(bp-obp); } #endif /* ** Save registration ID. */ int saveRegID(char * const fname, char * const company, char * const regID) { #if defined(WIN32) HKEY rHandle; DWORD rStat; if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, fname, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &rHandle, &rStat) == ERROR_SUCCESS) { if (RegSetValueEx(rHandle, "Company", NULL, REG_SZ, company, strlen(company)+1) == ERROR_SUCCESS && RegSetValueEx(rHandle, "Serial", NULL, REG_SZ, regID, strlen(regID)+1) == ERROR_SUCCESS) { RegCloseKey(rHandle); return 1; } RegCloseKey(rHandle); } return 0; #else FILE *fp = fopen(fname, "w"); if (fp != NULL) { (void) fprintf(fp, "ORG %s\n", company); (void) fprintf(fp, "ID %s\n", regID); (void) fclose(fp); return 1; } return 0; #endif } /* ** Read registration ID. */ static LIC_INFO license = { NULL, NULL }; LIC_INFO *getRegID(char *company, char *regID) { char lbuf[LBUFSIZE]; size_t len; FILE *fp; #if defined WIN32 HKEY rHandle; DWORD kType, bSize = LBUFSIZE; #endif if (license.regID && license.company) return (LIC_INFO *)&license; if (company != NULL && regID != NULL) { (void) sprintf(lbuf, "%.4095s", company); license.company = strsave(lbuf); (void) sprintf(lbuf, "%.4095s", regID); license.regID = strsave(lbuf); return (LIC_INFO *)&license; } #if defined WIN32 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGID_FILE, NULL, KEY_QUERY_VALUE, &rHandle) == ERROR_SUCCESS) { if (RegQueryValueEx(rHandle, "Company", NULL, &kType, lbuf, &bSize) == ERROR_SUCCESS) { bSize= LBUFSIZE; license.company = strsave(lbuf); if (RegQueryValueEx(rHandle, "Serial", NULL, &kType, lbuf, &bSize) == ERROR_SUCCESS) license.regID = strsave(lbuf); } RegCloseKey(rHandle); } #else if ((fp = fopen(REGID_FILE, "r")) != NULL) { while (fgets(lbuf, sizeof lbuf, fp) != NULL) { len = strlen(lbuf); if (lbuf[len-1] == '\n') lbuf[--len] = '\0'; if (len > 4 && strneq(lbuf, "ORG ", 4)) license.company = strsave(lbuf+4); else if (len > 3 && strneq(lbuf, "ID ", 3)) { license.regID = strsave(lbuf+3); } } (void) fclose(fp); } #endif #if defined(DEF_REGID) else { (void) sprintf(lbuf, "%.4095s", DEF_COMPANY); license.company = strsave(lbuf); (void) sprintf(lbuf, "%.4095s", DEF_REGID); license.regID = strsave(lbuf); } #endif if (!license.regID || !license.company) { license.regID = license.company = NULL; return NULL; } return (LIC_INFO *)&license; } /* ** Split string into arguments. ** Fields are separated by one or more tabs. */ int getargs(char *str, char **av, int const max) { int idx; for (idx=0; idx < max-1 && *str != '\0'; idx++) { while (*str == '\t' || *str == ' ') str++; av[idx] = str; while (*str && *str != '\t' && (idx || *str != ' ')) str++; if (*str == '\t' || *str == ' ') *str++ = '\0'; } av[idx] = NULL; return idx; } /* ** Parse a date string in format DD/MMM/YYYY:HH:MM:SS ** and fill in the elements of the LOGTIME structure. */ int setDate(LOGTIME * const tp, char const cp[]) { tp->hour = (u_short) ((cp[12]-'0') * 10 + (cp[13]-'0')); tp->min = (u_short) ((cp[15]-'0') * 10 + (cp[16]-'0')); tp->sec = (u_short) ((cp[18]-'0') * 10 + (cp[19]-'0')); tp->mday = (u_short) ((cp[0]-'0') * 10 + (cp[1]-'0')); if (tp->mday > 31 || cp[2] != '/') return 0; tp->year = (u_short) ((cp[7]-'0') * 1000 + (cp[8]-'0') * 100 + (cp[9]-'0') * 10 + (cp[10]-'0')); switch (cp[4]) { case 'a': /* jan, mar, may */ switch (cp[5]) { case 'n': tp->mon = 0; break; case 'r': tp->mon = 2; break; default: tp->mon = 4; break; } break; case 'u': /* jun, jul, aug */ switch (cp[5]) { case 'n': tp->mon = 5; break; case 'l': tp->mon = 6; break; default: tp->mon = 7; break; } break; case 'e': /* feb, sec, dec */ switch (cp[3]) { case 'F': tp->mon = 1; break; case 'S': tp->mon = 8; break; default: tp->mon = 11; break; } break; default: /* apr, oct, nov */ switch (cp[3]) { case 'A': tp->mon = 3; break; case 'O': tp->mon = 9; break; default: tp->mon = 10; break; } break; } return 1; } /* ** Compress a file using gzip. */ int compress(char * const file) { int status = 0; #if defined(WIN32) || defined(NETWARE) errno = 0; if ((status = spawnlp(P_WAIT, "gzip", "gzip", "-f", file, (char *)0)) != 0) prmsg(2, "Couldn't execute gzip (%s)\n", strerror(errno)); return !status; #else pid_t pid; (void) fflush(NULL); /* flush all stdio buffers */ errno = 0; if ((pid = fork()) < 0) { /* create a new process */ prmsg(2, "Couldn't spawn new process (%s)\n", strerror(errno)); return 0; } errno = 0; if (pid > 0) { /* parent process waits for child */ if ((int)waitpid(pid, &status, 0) < 0) { prmsg(1, "No children to wait for (%s)?!?\n", strerror(errno)); return 0; } return !WEXITSTATUS(status); } /* child executes gzip */ (void) execlp("gzip", "gzip", "-f", file, (char *)0); prmsg(2, "Couldn't execute gzip (%s)\n", strerror(errno)); return 0; #endif } /* ** Print a message. ** Level is 0 for informational messages, ** 1 for warnings, and 2 for fatal errors. */ #if !defined(STDERR_FILENO) # define STDERR_FILENO 2 #endif static char *msg_type[3] = { "[INFO]", "[WARNING]", "[FATAL]" }; /*PRINTFLIKE2*/ void prmsg(int const level, char * const fmt, ...) { extern char *progname; va_list ap; if (level) { if (!isatty(STDERR_FILENO)) (void) fprintf(stderr, "%s ", progname); (void) fprintf(stderr, "%s: ", msg_type[level%3]); } va_start(ap, fmt); (void) vfprintf(stderr, fmt, ap); va_end(ap); return; } /* ** For maximum portability and for the sake of speed, ** here is our own version of the strdup() function. */ char *strsave(register char *cp) { register char *np, *ep; for (ep=cp; *ep != '\0'; ep++) /* no-op */ ; if (ep == cp) /* allocate memory, copy string */ ep = NULL; else if ((ep = malloc((size_t)(ep-cp)+1)) != NULL) for (np=ep; (*np = *cp) != '\0'; np++, cp++) /* noop */ ; return ep; } /* ** Get hostname. Use whatever your system provides for this. ** If it does not return the full qualified domain name, ** overwrite the name in the configuration file. */ SRVINFO *myHostName(void) { static SRVINFO srvinfo = { NULL, NULL, NULL, NULL, NULL }; #if !defined(NO_UNAME) static struct utsname utbuf; #endif #if !defined(NO_GETHOSTNAME) static char hbuf[MEDIUMSIZE]; if (gethostname(hbuf, sizeof hbuf) == 0) { hbuf[MEDIUMSIZE-1] = '\0'; srvinfo.hostname = hbuf; } #endif #if !defined(NO_UNAME) if (uname(&utbuf) != -1) { srvinfo.hostname = utbuf.nodename; srvinfo.sysname = utbuf.sysname; srvinfo.release = utbuf.release; srvinfo.version = utbuf.version; srvinfo.machine = utbuf.machine; } /* fake uname(2), leave out hostname to use default */ #elif defined (WIN32) srvinfo.sysname = "Windows NT"; srvinfo.machine = "PC"; srvinfo.release = NULL; srvinfo.version = NULL; #elif defined (NETWARE) srvinfo.sysname = "Netware"; srvinfo.machine = "PC"; srvinfo.release = NULL; srvinfo.version = NULL; #else #error Please specify your platform/OS here or undefine NO_UNAME in config.h #endif if (!srvinfo.hostname || !*srvinfo.hostname) srvinfo.hostname = "local WWW server"; return (SRVINFO *)&srvinfo; } #if defined(NEED_STRERROR) /* ** Print error string from sys_errlist. */ char *strerror(int errcode) { if (errcode <= 0 || errcode >= sys_nerr) errcode = 0; /* unknown error */ return (char *)sys_errlist[errcode]; } #endif #if defined(NEED_WAITPID) /* ** Poor man's implementation of waitpid sufficient for us. */ /*ARGSUSED*/ static pid_t waitpid (pid_t const pid, int * const statptr, int const options) { pid_t rc; while ((rc=wait(statptr)) != pid && errno != ECHILD); /* noop */ ; return rc == pid ? pid : -1; } #endif #if defined(NEED_STRCASECMP) /* * Copyright (c) 1987 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */ static u_char charmap[] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', }; int strcasecmp(const char *s1, const char *s2) { register u_char *cm = charmap, *us1 = (u_char *)s1, *us2 = (u_char *)s2; while (cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return(cm[*us1] - cm[*--us2]); } int strncasecmp(const char *s1, const char *s2, register size_t n) { register u_char *cm = charmap, *us1 = (u_char *)s1, *us2 = (u_char *)s2; while (--n >= 0 && cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return(n < 0 ? 0 : cm[*us1] - cm[*--us2]); } #endif #if defined(NEED_GETOPT) /* * Copyright (c) 1987 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include /* * get option letter from argument vector */ int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt; /* character checked for validity */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define EMSG "" #define tell(s) { \ if (opterr) { \ fputs(*nargv, stderr); \ fputs(s, stderr); \ fputc(optopt, stderr); \ fputc((int)'\n', stderr); \ } \ return(BADCH); \ } int getopt(int nargc, char * const nargv[], const char * ostr) { static char *place = EMSG; /* option letter processing */ register char *oli; /* option letter list index */ if (!*place) { /* update scanning pointer */ if (optind >= nargc || *(place = nargv[optind]) != '-') return(EOF); if (place[1] && *++place == '-') { /* found "--" */ ++optind; return(EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { if (!*place) ++optind; tell(": illegal option -- "); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; tell(": option requires an argument -- "); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return(optopt); /* dump back option letter */ } #endif