Index: tags/v_1_4_2/hash.h =================================================================== --- tags/v_1_4_2/hash.h (revision 11) +++ tags/v_1_4_2/hash.h (revision 11) @@ -0,0 +1,13 @@ +#ifndef _HASH_H_ +#define _HASH_H_ + +typedef struct { +char *hostheader; +int fd; +} hash_element; + +int gethash(void *, hash_element *); +void inshash(hash_element, hash_element *); +int hashpjw(const void *, const int ); + +#endif Index: tags/v_1_4_2/config.h =================================================================== --- tags/v_1_4_2/config.h (revision 14) +++ tags/v_1_4_2/config.h (revision 14) @@ -0,0 +1,85 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include +#include +#include +#include + +#include "hash.h" +#include "skiplist.h" + +#define SHELL_PATH "/bin/sh" + +typedef struct { + char *port; + char *host; + char private_group[MAX_GROUP_NAME]; + int connected; + Skiplist *logfacilities; +} SpreadConfiguration; + +typedef struct { + char *filename; + int fd; +} LogFile; + + +typedef struct { + char *groupname; + LogFile *logfile; + int nmatches; + int rewritetimes; + char *rewritetimesformat; + regex_t match_expression[10]; /* only up to ten */ + char *vhostdir; + hash_element *hash; +} LogFacility; + +int config_init(char *); /* Initialize global structures */ + +char *config_get_spreaddaemon(SpreadConfiguration *); +SpreadConfiguration *config_new_spread_conf(void); +void config_set_spread_port(SpreadConfiguration *,char *); +void config_set_spread_host(SpreadConfiguration *, char *); +void config_add_spreadconf(SpreadConfiguration *); + +int config_foreach_spreadconf(int (*)(SpreadConfiguration *, void *), void *); + +LogFacility *config_new_logfacility(void); +void config_add_logfacility(SpreadConfiguration *, LogFacility *); +void config_set_logfacility_group(LogFacility *, char *); +void config_set_logfacility_filename(LogFacility *, char *); +void config_add_logfacility_match(LogFacility *, char *); +void config_set_logfacility_vhostdir(LogFacility *lf, char *vhd); +void config_set_logfaclity_rewritetimes_clf(LogFacility *lf); +void config_set_logfaclity_rewritetimes_user(LogFacility *lf, char *format); + +int config_foreach_logfacility(SpreadConfiguration *, + int (*)(LogFacility *, void *), void *); +char *config_process_message(SpreadConfiguration *sc, char *group, char *message, int *len); +void config_hup(void); /* config_close(); config_start(); */ +int config_close(void); /* Close files */ +int config_start(void); /* Open files and get ready to log */ + +int config_get_fd(SpreadConfiguration *sc, + char *group, char *message); /* -1 if no write */ + +#define YYSTYPE YYSTYPE +typedef char * YYSTYPE; +extern YYSTYPE yylval; +extern int yysemanticerr; + + +#endif + Index: tags/v_1_4_2/README =================================================================== --- tags/v_1_4_2/README (revision 6) +++ tags/v_1_4_2/README (revision 6) @@ -0,0 +1,21 @@ +This is a README file (for those that haven't already figured that out). + +Please read the LICENSE before using this software. + +This software works great for me. Other than the options seen with -h +there are a few tid bits of knowledge to know. + +Edit the makefile and uncomment/comment the right parts in the architecture +dependant sections. + +If you kill -HUP or kill the spreadlogd process, it will not actually +process the signal until after it has received its next message from +Spread. You can move you log files to new names and then kill -HUP +and it will reopen the log files. This is useful for seamless log rotation +without losing any messages. + +Spread is really cool. It is a poweful group communication toolkit +developed at the Center for Networking and Distributed Systems at the +Johns Hopkins University. http://www.spread.org/ and +http://www.cnds.jhu.edu/, respectively. + Index: tags/v_1_4_2/makefile =================================================================== --- tags/v_1_4_2/makefile (revision 7) +++ tags/v_1_4_2/makefile (revision 7) @@ -0,0 +1,52 @@ +CC=gcc +CFLAGS=-g -D__USE_LARGEFILE64 -Wall +INCLUDES=-I/usr/local/include + +#### BEGIN ARCH DEPENDANT SECTION #### +# For Linux +LDFLAGS=-L/usr/local/lib -L. +LIBS=-lsp -lskiplist + +# For Solaris +#LIBS=-lsp -lskiplist -lnsl -lsocket -lucb +#LDFLAGS=-L/usr/local/lib -L/usr/ucblib -R/usr/ucblib -L. +#BSDINCLUDES=-I/usr/ucbinclude +#### END ARCH DEPENDANT SECTION #### + +YACC=bison -y +LEX=flex + +OBJS=spreadlogd.o lex.yy.o y.tab.o config.o hash.o timefuncs.o +LSLOBJS=skiplist.o + +all: spreadlogd + +parser: lex.yy.c y.tab.c y.tab.h + +lex.yy.c: config_gram.l + $(LEX) config_gram.l +y.tab.c y.tab.h: config_gram.y + $(YACC) -d config_gram.y +lex.yy.o: lex.yy.c y.tab.h + $(CC) $(CFLAGS) $(INCLUDES) -c lex.yy.c +y.tab.o: y.tab.c config.h + $(CC) $(CFLAGS) $(INCLUDES) -c y.tab.c + +test.o: test.c + $(CC) $(CFLAGS) $(BSDINCLUDES) $(INCLUDES) -c $< + +config.o: config.c + $(CC) $(CFLAGS) $(BSDINCLUDES) $(INCLUDES) -c $< +hash.o: hash.c + $(CC) $(CFLAGS) $(BSDINCLUDES) $(INCLUDES) -c $< +.c.o: $*.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< + +libskiplist.a: $(LSLOBJS) + $(AR) cq libskiplist.a $(LSLOBJS) + +spreadlogd: libskiplist.a $(OBJS) + $(CC) -g -o $@ $(OBJS) $(LDFLAGS) $(LIBS) + +clean: + rm -f *~ *.o spreadlogd libskiplist.a y.tab.h y.tab.c lex.yy.c Index: tags/v_1_4_2/timefuncs.c =================================================================== --- tags/v_1_4_2/timefuncs.c (revision 13) +++ tags/v_1_4_2/timefuncs.c (revision 13) @@ -0,0 +1,89 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include + +#include "timefuncs.h" + +#define MAXTIMESTRLEN 128 + +static char *apmonthnames[12] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +static char *strnchr(char *string, char chr, int len) { + char *cp=string; + while(len>0) { + if(*cp == chr) return cp; + cp++; len--; + } + return NULL; +} +void force_local_time(char *string, int *length, const int buffsize, + int style, char *format) { + char *cp, *cpend, *newcpend; + char timebuff[MAXTIMESTRLEN]; + int timestrlen, newtimestrlen; + int timz; + struct tm *t; + time_t secs; + struct timeval now; + struct timezone tz; + + cp = strnchr(string, '[', *length); + if(!cp) return; + cpend = strnchr(cp, ']', *length-(cp-string)); + if(!cpend) return; + cpend++; + timestrlen = cpend-cp; + gettimeofday(&now, &tz); + timz = tz.tz_minuteswest; + secs = now.tv_sec; + t = localtime(&secs); + if(style == NO_REWRITE_TIMES) + return; + else if(style == REWRITE_TIMES_IN_CLF) { + char sign = (timz > 0 ? '-' : '+'); + timz = (timz < 0)?(-timz):(timz); + snprintf(timebuff, sizeof(timebuff), "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]", + t->tm_mday, apmonthnames[t->tm_mon], t->tm_year+1900, + t->tm_hour, t->tm_min, t->tm_sec, + sign, timz / 60, timz % 60); + } else if((style == REWRITE_TIMES_FORMAT) && format) { + strftime(timebuff, sizeof(timebuff), format, t); + } + + /* No measure and squeeze it in there */ + newtimestrlen = strlen(timebuff); + newcpend = cp+newtimestrlen; + + if(newcpend != cpend) { + /* Ugh different size... this is going to me slower */ + int chunk = MIN(MIN(string+buffsize-cpend, string+buffsize-newcpend), + string+*length-cpend); + if(chunk>0) + memmove(newcpend, cpend, chunk); + *length += newcpend-cpend; + if(*length >= buffsize) { + newtimestrlen -= *length-buffsize; + *length = buffsize; + } + } + memcpy(cp, timebuff, newtimestrlen); + return; +} Index: tags/v_1_4_2/Artistic.txt =================================================================== --- tags/v_1_4_2/Artistic.txt (revision 19) +++ tags/v_1_4_2/Artistic.txt (revision 19) @@ -0,0 +1,124 @@ +The "Artistic License" + +Preamble + +The intent of this document is to state the conditions under which a Package +may be copied, such that the Copyright Holder maintains some semblance of +artistic control over the development of the package, while giving the users +of the package the right to use and distribute the Package in a more-or-less +customary fashion, plus the right to make reasonable modifications. + +Definitions + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes of + the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the basis + of media cost, duplication charges, time of people involved, and + so on. (You will not be required to justify it to the Copyright + Holder, but only to the computing community at large as a market + that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. It + also means that recipients of the item may redistribute it under + the same conditions they received it. + + 1. You may make and give away verbatim copies of the source form of the + Standard Version of this Package without restriction, provided that you + duplicate all of the original copyright notices and associated + disclaimers. + + 2. You may apply bug fixes, portability fixes and other modifications + derived from the Public Domain or from the Copyright Holder. A Package + modified in such a way shall still be considered the Standard Version. + + 3. You may otherwise modify your copy of this Package in any way, provided + that you insert a prominent notice in each changed file stating how and + when you changed that file, and provided that you do at least ONE of + the following: + + a. place your modifications in the Public Domain or otherwise make + them Freely Available, such as by posting said modifications to + Usenet or an equivalent medium, or placing the modifications on a + major archive site such as uunet.uu.net, or by allowing the + Copyright Holder to include your modifications in the Standard + Version of the Package. + b. use the modified Package only within your corporation or + organization. + c. rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and + provide a separate manual page for each non-standard executable + that clearly documents how it differs from the Standard Version. + d. make other distribution arrangements with the Copyright Holder. + + 4. You may distribute the programs of this Package in object code or + executable form, provided that you do at least ONE of the following: + + a. distribute a Standard Version of the executables and library + files, together with instructions (in the manual page or + equivalent) on where to get the Standard Version. + b. accompany the distribution with the machine-readable source of the + Package with your modifications. + c. give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + d. make other distribution arrangements with the Copyright Holder. + + 5. You may charge a reasonable copying fee for any distribution of this + Package. You may charge any fee you choose for support of this Package. + You may not charge a fee for this Package itself. However, you may + distribute this Package in aggregate with other (possibly commercial) + programs as part of a larger (possibly commercial) software + distribution provided that you do not advertise this Package as a + product of your own. You may embed this Package's interpreter within an + executable of yours (by linking); this shall be construed as a mere + form of aggregation, provided that the complete Standard Version of the + interpreter is so embedded. + + 6. The scripts and library files supplied as input to or produced as + output from the programs of this Package do not automatically fall + under the copyright of this Package, but belong to whomever generated + them, and may be sold commercially, and may be aggregated with this + Package. If such scripts or library files are aggregated with this + Package via the so-called "undump" or "unexec" methods of producing a + binary executable image, then distribution of such an image shall + neither be construed as a distribution of this Package nor shall it + fall under the restrictions of Paragraphs 3 and 4, provided that you do + not represent such an executable image as a Standard Version of this + Package. + + 7. C subroutines (or comparably compiled subroutines in other languages) + supplied by you and linked into this Package in order to emulate + subroutines and variables of the language defined by this Package shall + not be considered part of this Package, but are the equivalent of input + as in Paragraph 6, provided these subroutines do not change the + language in any way that would cause it to fail the regression tests + for the language. + + 8. Aggregation of this Package with a commercial distribution is always + permitted provided that the use of this Package is embedded; that is, + when no overt attempt is made to make this Package's interfaces visible + to the end user of the commercial distribution. Such use shall not be + construed as a distribution of this Package. + + 9. The name of the Copyright Holder may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + 10. THIS PACKAGE 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. + + The End Index: tags/v_1_4_2/config_gram.y =================================================================== --- tags/v_1_4_2/config_gram.y (revision 7) +++ tags/v_1_4_2/config_gram.y (revision 7) @@ -0,0 +1,107 @@ +%{ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#include "config.h" + +extern int line_num, semantic_errors; +extern int buffsize; +extern char *yytext; + +static SpreadConfiguration *current_sc = NULL; +static LogFacility *current_lf = NULL; + +int yyerror(char *str); + +#define NEW_SC_IFNEEDED if(!current_sc) current_sc=config_new_spread_conf(); + +#define NEW_LF_IFNEEDED if(!current_sc) current_sc=config_new_spread_conf(); \ + if(!current_lf) current_lf=config_new_logfacility(); +%} +%start Config +%token BUFFERSIZE SPREAD PORT HOST LOG GROUP FILENAME MATCH VHOSTGROUP VHOSTDIR +%token OPENBRACE CLOSEBRACE EQUALS STRING CLF REWRITETIMES +%% +Config : Globals SpreadConfs + { config_start(); } + +Globals : GlobalParam Globals + | + ; + +GlobalParam : BUFFERSIZE EQUALS STRING + { if(buffsize<0) { + buffsize = atoi($3); + } + } + +SpreadConfs : SpreadConf SpreadConfs + | SpreadConf + ; + +SpreadConf : SPREAD OPENBRACE SPparams LogStructs CLOSEBRACE + { config_add_spreadconf(current_sc); + current_sc = NULL; } + ; + +SPparams : SPparam SPparams + | + ; + +SPparam : PORT EQUALS STRING + { NEW_SC_IFNEEDED; + config_set_spread_port(current_sc, $3); } + | HOST EQUALS STRING + { NEW_SC_IFNEEDED; + config_set_spread_host(current_sc, $3); } + ; + +LogStructs : LogStruct LogStructs + | + ; + +LogStruct : LOG OPENBRACE Logparams CLOSEBRACE + { config_add_logfacility(current_sc, current_lf); + current_lf = NULL; } + ; + +Logparams : Logparams Logparam + | + ; + +Logparam : GROUP EQUALS STRING + { NEW_LF_IFNEEDED; + config_set_logfacility_group(current_lf, $3); } + | FILENAME EQUALS STRING + { NEW_LF_IFNEEDED; + config_set_logfacility_filename(current_lf, $3); } + | MATCH EQUALS STRING + { NEW_LF_IFNEEDED; + config_add_logfacility_match(current_lf, $3); } + | VHOSTDIR EQUALS STRING + { NEW_LF_IFNEEDED; + config_set_logfacility_vhostdir(current_lf, $3); } + | REWRITETIMES EQUALS CLF + { NEW_LF_IFNEEDED; +fprintf(stderr, "Setting logfacility to force local times in CLF\n"); + config_set_logfaclity_rewritetimes_clf(current_lf); } + | REWRITETIMES EQUALS STRING + { NEW_LF_IFNEEDED; + config_set_logfaclity_rewritetimes_user(current_lf, + $3); } + ; + + +%% +int yyerror(char *str) { + fprintf(stderr, "Parser error on or before line %d\n", line_num); + fprintf(stderr, "Offending token: %s\n", yytext); + return -1; +} Index: tags/v_1_4_2/skiplist.c =================================================================== --- tags/v_1_4_2/skiplist.c (revision 17) +++ tags/v_1_4_2/skiplist.c (revision 17) @@ -0,0 +1,486 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle for use in the + * Backhand project at The Center for Networking and Distributed Systems + * at The Johns Hopkins University. + * + * This is a skiplist implementation to be used for abstract structures + * and is release under the LGPL license version 2.1 or later. A copy + * of this license can be found at http://www.gnu.org/copyleft/lesser.html + * ====================================================================== +*/ + +#include +#include +#include + +#include "skiplist.h" + +#ifndef MIN +#define MIN(a,b) ((a 31) { /* Num bits in return of lrand48() */ + ph=0; + randseq = lrand48(); + } + ph++; + return ((randseq & (1 << (ph-1))) >> (ph-1)); +} + +void sli_init(Skiplist *sl) { + sl->compare = (SkiplistComparator)NULL; + sl->comparek = (SkiplistComparator)NULL; + sl->height=0; + sl->preheight=0; + sl->size=0; + sl->top = NULL; + sl->bottom = NULL; + sl->index = NULL; +} + +static int indexing_comp(void *a, void *b) { + assert(a); + assert(b); + return (void *)(((Skiplist *)a)->compare)>(void *)(((Skiplist *)b)->compare); +} +static int indexing_compk(void *a, void *b) { + assert(b); + return a>(void *)(((Skiplist *)b)->compare); +} + +void sl_init(Skiplist *sl) { + sli_init(sl); + sl->index = (Skiplist *)malloc(sizeof(Skiplist)); + sli_init(sl->index); + sl_set_compare(sl->index, indexing_comp, indexing_compk); +} + +void sl_set_compare(Skiplist *sl, + SkiplistComparator comp, + SkiplistComparator compk) { + if(sl->compare && sl->comparek) { + sl_add_index(sl, comp, compk); + } else { + sl->compare = comp; + sl->comparek = compk; + } +} + +void sl_add_index(Skiplist *sl, + SkiplistComparator comp, + SkiplistComparator compk) { + struct skiplistnode *m; + Skiplist *ni; + int icount=0; +#ifdef SLDEBUG + fprintf(stderr, "Adding index to %p\n", sl); +#endif + sl_find(sl->index, (void *)comp, &m); + if(m) return; /* Index already there! */ + ni = (Skiplist *)malloc(sizeof(Skiplist)); + sli_init(ni); + sl_set_compare(ni, comp, compk); + /* Build the new index... This can be expensive! */ + m = sl_insert(sl->index, ni); + while(m->prev) m=m->prev, icount++; + for(m=sl_getlist(sl); m; sl_next(sl, &m)) { + int j=icount-1; + struct skiplistnode *nsln; + nsln = sl_insert(ni, m->data); + /* skip from main index down list */ + while(j>0) m=m->nextindex, j--; + /* insert this node in the indexlist after m */ + nsln->nextindex = m->nextindex; + if(m->nextindex) m->nextindex->previndex = nsln; + nsln->previndex = m; + m->nextindex = nsln; + } +} + +struct skiplistnode *sl_getlist(Skiplist *sl) { + if(!sl->bottom) return NULL; + return sl->bottom->next; +} + +void *sl_find(Skiplist *sl, + void *data, + struct skiplistnode **iter) { + void *ret; + struct skiplistnode *aiter; + if(!sl->compare) return 0; + if(iter) + ret = sl_find_compare(sl, data, iter, sl->compare); + else + ret = sl_find_compare(sl, data, &aiter, sl->compare); + return ret; +} +void *sl_find_compare(Skiplist *sli, + void *data, + struct skiplistnode **iter, + SkiplistComparator comp) { + struct skiplistnode *m = NULL; + Skiplist *sl; + if(comp==sli->compare || !sli->index) { + sl = sli; + } else { + sl_find(sli->index, (void *)comp, &m); + assert(m); + sl=m->data; + } + sli_find_compare(sl, data, iter, sl->comparek); + return (*iter)?((*iter)->data):(*iter); +} +int sli_find_compare(Skiplist *sl, + void *data, + struct skiplistnode **ret, + SkiplistComparator comp) { + struct skiplistnode *m = NULL; + int count=0; + m = sl->top; + while(m) { + int compared = 1; + if(m->next) compared=comp(data, m->next->data); + if(compared == 0) { +#ifdef SL_DEBUG + printf("Looking -- found in %d steps\n", count); +#endif + m=m->next; + while(m->down) m=m->down; + *ret = m; + return count; + } + if((m->next == NULL) || (compared<0)) + m = m->down, count++; + else + m = m->next, count++; + } +#ifdef SL_DEBUG + printf("Looking -- not found in %d steps\n", count); +#endif + *ret = NULL; + return count; +} +void *sl_next(Skiplist *sl, struct skiplistnode **iter) { + if(!*iter) return NULL; + *iter = (*iter)->next; + return (*iter)?((*iter)->data):NULL; +} +void *sl_previous(Skiplist *sl, struct skiplistnode **iter) { + if(!*iter) return NULL; + *iter = (*iter)->prev; + return (*iter)?((*iter)->data):NULL; +} +struct skiplistnode *sl_insert(Skiplist *sl, + void *data) { + if(!sl->compare) return 0; + return sl_insert_compare(sl, data, sl->compare); +} + +struct skiplistnode *sl_insert_compare(Skiplist *sl, + void *data, + SkiplistComparator comp) { + struct skiplistnode *m, *p, *tmp, *ret=NULL, **stack; + int nh=1, ch, stacki; +#ifdef SLDEBUG + sl_print_struct(sl, "BI: "); +#endif + if(!sl->top) { + sl->height = 1; + sl->topend = sl->bottomend = sl->top = sl->bottom = + (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); + assert(sl->top); + sl->top->next = sl->top->data = sl->top->prev = + sl->top->up = sl->top->down = + sl->top->nextindex = sl->top->previndex = NULL; + sl->top->sl = sl; + } + if(sl->preheight) { + while(nh < sl->preheight && get_b_rand()) nh++; + } else { + while(nh <= sl->height && get_b_rand()) nh++; + } + /* Now we have the new hieght at which we wish to insert our new node */ + /* Let us make sure that our tree is a least that tall (grow if necessary)*/ + for(;sl->heightheight++) { + sl->top->up = + (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); + assert(sl->top); + sl->top->up->down = sl->top; + sl->top = sl->topend = sl->top->up; + sl->top->prev = sl->top->next = sl->top->nextindex = + sl->top->previndex = NULL; + sl->top->data = NULL; + sl->top->sl = sl; + } + ch = sl->height; + /* Find the node (or node after which we would insert) */ + /* Keep a stack to pop back through for insertion */ + m = sl->top; + stack = (struct skiplistnode **)malloc(sizeof(struct skiplistnode *)*(nh)); + stacki=0; + while(m) { + int compared=-1; + if(m->next) compared=comp(data, m->next->data); + if(compared == 0) { + free(stack); + return 0; + } + if((m->next == NULL) || (compared<0)) { + if(ch<=nh) { + /* push on stack */ + stack[stacki++] = m; + } + m = m->down; + ch--; + } else { + m = m->next; + } + } + /* Pop the stack and insert nodes */ + p = NULL; + for(;stacki>0;stacki--) { + m = stack[stacki-1]; + tmp = (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); + tmp->next = m->next; + if(m->next) m->next->prev=tmp; + tmp->prev = m; + tmp->up = NULL; + tmp->nextindex = tmp->previndex = NULL; + tmp->down = p; + if(p) p->up=tmp; + tmp->data = data; + tmp->sl = sl; + m->next = tmp; + /* This sets ret to the bottom-most node we are inserting */ + if(!p) ret=tmp; + p = tmp; + } + free(stack); + if(sl->index != NULL) { + /* this is a external insertion, we must insert into each index as well */ + struct skiplistnode *p, *ni, *li; + li=ret; + for(p = sl_getlist(sl->index); p; sl_next(sl->index, &p)) { + ni = sl_insert((Skiplist *)p->data, ret->data); + assert(ni); +#ifdef SLDEBUG + fprintf(stderr, "Adding %p to index %p\n", ret->data, p->data); +#endif + li->nextindex = ni; + ni->previndex = li; + li = ni; + } + } else { + sl->size++; + } +#ifdef SLDEBUG + sl_print_struct(sl, "AI: "); +#endif + return ret; +} +struct skiplistnode *sl_append(Skiplist *sl, void *data) { + int nh=1, ch, compared; + struct skiplistnode *lastnode, *nodeago; + if(sl->bottomend != sl->bottom) { + compared=sl->compare(data, sl->bottomend->prev->data); + /* If it doesn't belong at the end, then fail */ + if(compared<=0) return NULL; + } + if(sl->preheight) { + while(nh < sl->preheight && get_b_rand()) nh++; + } else { + while(nh <= sl->height && get_b_rand()) nh++; + } + /* Now we have the new hieght at which we wish to insert our new node */ + /* Let us make sure that our tree is a least that tall (grow if necessary)*/ + lastnode = sl->bottomend; + nodeago = NULL; + + if(!lastnode) return sl_insert(sl, data); + + for(;sl->heightheight++) { + sl->top->up = + (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); + assert(sl->top); + sl->top->up->down = sl->top; + sl->top = sl->top->up; + sl->top->prev = sl->top->next = sl->top->nextindex = + sl->top->previndex = NULL; + sl->top->data = NULL; + sl->top->sl = sl; + } + ch = sl->height; + while(nh) { + struct skiplistnode *anode; + anode = + (struct skiplistnode *)malloc(sizeof(struct skiplistnode)); + anode->next = lastnode; + anode->prev = lastnode->prev; + anode->up = NULL; + anode->down = nodeago; + if(lastnode->prev) { + if(lastnode == sl->bottom) + sl->bottom = anode; + else if (lastnode == sl->top) + sl->top = anode; + } + nodeago = anode; + lastnode = lastnode->up; + nh--; + } + sl->size++; + return sl->bottomend; +} +Skiplist *sl_concat(Skiplist *sl1, Skiplist *sl2) { + /* Check integrity! */ + int compared, eheight; + Skiplist temp; + struct skiplistnode *lbottom, *lbottomend, *b1, *e1, *b2, *e2; + if(sl1->bottomend == NULL || sl1->bottomend->prev == NULL) { + sl_remove_all(sl1, free); + temp = *sl1; + *sl1 = *sl2; + *sl2 = temp; + /* swap them so that sl2 can be freed normally upon return. */ + return sl1; + } + if(sl2->bottom == NULL || sl2->bottom->next == NULL) { + sl_remove_all(sl2, free); + return sl1; + } + compared = sl1->compare(sl1->bottomend->prev->data, sl2->bottom->data); + /* If it doesn't belong at the end, then fail */ + if(compared<=0) return NULL; + + /* OK now append sl2 onto sl1 */ + lbottom = lbottomend = NULL; + eheight = MIN(sl1->height, sl2->height); + b1 = sl1->bottom; e1 = sl1->bottomend; + b2 = sl2->bottom; e2 = sl2->bottomend; + while(eheight) { + e1->prev->next = b2; + b2->prev = e1->prev->next; + e2->prev->next = e1; + e1->prev = e2->prev; + e2->prev = NULL; + b2 = e2; + b1->down = lbottom; + e1->down = lbottomend; + if(lbottom) lbottom->up = b1; + if(lbottomend) lbottomend->up = e1; + + lbottom = b1; + lbottomend = e1; + } + /* Take the top of the longer one (if it is sl2) and make it sl1's */ + if(sl2->height > sl1->height) { + b1->up = b2->up; + e1->up = e2->up; + b1->up->down = b1; + e1->up->down = e1; + sl1->height = sl2->height; + sl1->top = sl2->top; + sl1->topend = sl2->topend; + } + + /* move the top pointer to here if it isn't there already */ + sl2->top = sl2->topend = b2; + sl2->top->up = NULL; /* If it isn't already */ + sl1->size += sl2->size; + sl_remove_all(sl2, free); + return sl1; +} +int sl_remove(Skiplist *sl, + void *data, FreeFunc myfree) { + if(!sl->compare) return 0; + return sl_remove_compare(sl, data, myfree, sl->comparek); +} +void sl_print_struct(Skiplist *sl, char *prefix) { + struct skiplistnode *p, *q; + fprintf(stderr, "Skiplist Structure (height: %d)\n", sl->height); + p = sl->bottom; + while(p) { + q = p; + fprintf(stderr, prefix); + while(q) { + fprintf(stderr, "%p ", q->data); + q=q->up; + } + fprintf(stderr, "\n"); + p=p->next; + } +} +int sli_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree) { + struct skiplistnode *p; + if(!m) return 0; + if(m->nextindex) sli_remove(m->nextindex->sl, m->nextindex, NULL); + else sl->size--; +#ifdef SLDEBUG + sl_print_struct(sl, "BR:"); +#endif + while(m->up) m=m->up; + while(m) { + p=m; + p->prev->next = p->next; /* take me out of the list */ + if(p->next) p->next->prev = p->prev; /* take me out of the list */ + m=m->down; + /* This only frees the actual data in the bottom one */ + if(!m && myfree && p->data) myfree(p->data); + free(p); + } + while(sl->top && sl->top->next == NULL) { + /* While the row is empty and we are not on the bottom row */ + p = sl->top; + sl->top = sl->top->down; /* Move top down one */ + if(sl->top) sl->top->up = NULL; /* Make it think its the top */ + free(p); + sl->height--; + } + if(!sl->top) sl->bottom = NULL; + assert(sl->height>=0); +#ifdef SLDEBUG + sl_print_struct(sl, "AR: "); +#endif + return sl->height; +} +int sl_remove_compare(Skiplist *sli, + void *data, + FreeFunc myfree, SkiplistComparator comp) { + struct skiplistnode *m; + Skiplist *sl; + if(comp==sli->comparek || !sli->index) { + sl = sli; + } else { + sl_find(sli->index, (void *)comp, &m); + assert(m); + sl=m->data; + } + sli_find_compare(sl, data, &m, comp); + while(m->previndex) m=m->previndex; + return sli_remove(sl, m, myfree); +} +void sl_remove_all(Skiplist *sl, FreeFunc myfree) { + /* This must remove even the place holder nodes (bottom though top) + because we specify in the API that one can free the Skiplist after + making this call without memory leaks */ + struct skiplistnode *m, *p, *u; + m=sl->bottom; + while(m) { + p = m->next; + if(myfree && p->data) myfree(p->data); + while(m) { + u = m->up; + free(m); + m=u; + } + m = p; + } + sl->top = sl->bottom = NULL; + sl->height = 0; + sl->size = 0; +} Index: tags/v_1_4_2/timefuncs.h =================================================================== --- tags/v_1_4_2/timefuncs.h (revision 7) +++ tags/v_1_4_2/timefuncs.h (revision 7) @@ -0,0 +1,21 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#ifndef _TIMEFUNCS_H_ +#define _TIMEFUNCS_H_ + +#define NO_REWRITE_TIMES 0 +#define REWRITE_TIMES_IN_CLF 1 +#define REWRITE_TIMES_FORMAT 2 + +void force_local_time(char *string, int *length, const int buffsize, + int style, char *format); + +#endif Index: tags/v_1_4_2/hash.c =================================================================== --- tags/v_1_4_2/hash.c (revision 18) +++ tags/v_1_4_2/hash.c (revision 18) @@ -0,0 +1,67 @@ +/* ====================================================================== + * Copyright (c) 2000 George Schlossnagle + * All rights reserved. + * The following code was written by George Schlossnagle + * This code was written to facilitate clustered logging via Spread, + * particularly in conjunction with the mod_log_spread module for Apache. + * More information on Spread can be found at http://www.spread.org/ + * More information on mod_log_spread can be found at + * http://www.backhand.org/mod_log_spread/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#include +#include +#include + +#include "hash.h" + +extern int nr_open; +static int myprime[20] = { + 3,5,7,11,13,17,23,31,37,41,43,47,53,59,61,67,71,73,83,87 +}; + +int gethash(void *hostheader, hash_element *hash) { + int a, i; + hash_element *elem; + a = hashpjw(hostheader,nr_open); + if(hash[a].fd == -1) return -1; /* return -1 if element is not here */ + for(i=0;ifd == -1) + return -1; + /*return fd if the element matches */ + if(!strcmp(hostheader,elem->hostheader)) + return elem->fd; + } + return -1; +} + +void inshash(hash_element b, hash_element *hash) { + int a, i; + a = hashpjw(b.hostheader,nr_open); + for(i=0;i> 5)) >> 1; + if ((tmp = (val & 0xf0000000)) != 0) { + val = val ^ (tmp >> 24); + val = val ^ tmp; + } + ptr++; + } + return (int) (val % size); +} + Index: tags/v_1_4_2/config_gram.l =================================================================== --- tags/v_1_4_2/config_gram.l (revision 7) +++ tags/v_1_4_2/config_gram.l (revision 7) @@ -0,0 +1,48 @@ +%{ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#include + +#include "config.h" +#include "y.tab.h" + +extern int line_num; +extern int semantic_errors; +%} +qstring \"[^\"]*\"|\'[^\']*\' +string [^ \t\r\n#{}]+ +%option noyywrap +%% +#.* {} /* Comments */ +[ \t\r] {} /* White space */ +\n { line_num++;} +"{" { return OPENBRACE; } +"}" { return CLOSEBRACE; } +"=" { return EQUALS; } +BufferSize { return BUFFERSIZE; } +Spread { return SPREAD; } +Port { return PORT; } +Host { return HOST; } +Log { return LOG; } +VhostGroup { return VHOSTGROUP; } +Group { return GROUP; } +File { return FILENAME; } +VhostDir { return VHOSTDIR; } +Match { return MATCH; } +RewriteTimestamp { return REWRITETIMES; } +CommonLogFormat { return CLF; } +{qstring} { int l = strlen(yytext); + yytext[l-1] = 0; + yylval = strdup(yytext+1); + return STRING; } +{string} { yylval = strdup(yytext); + return STRING; } +%% Index: tags/v_1_4_2/spreadlogd.c =================================================================== --- tags/v_1_4_2/spreadlogd.c (revision 16) +++ tags/v_1_4_2/spreadlogd.c (revision 16) @@ -0,0 +1,296 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle + * This code was written to facilitate clustered logging via Spread. + * More information on Spread can be found at http://www.spread.org/ + * Please refer to the LICENSE file before using this software. + * ====================================================================== +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#define SPREADLOGD_VERSION "1.4.2" + +extern char *optarg; +extern int optind, opterr, optopt; + +int verbose = 0; +int extralog = 0; +int terminate = 0; +int huplogs = 0; +int skiplocking = 0; +int buffsize = -1; +SpreadConfiguration **fds; +int fdsetsize; +int nr_open; + +static char *default_configfile = "/etc/spreadlogd.conf"; + +void usage(char *progname) { + fprintf(stderr, "%s\t\tVERSION: %s\n \ +\t-c configfile\t\t[default /etc/spreadlogd.conf]\n \ +\t-s\t\t\tskip locking (flock) files (NOT RECOMMENDED)\n \ +\t-v\t\t\tverbose mode\n \ +\t-x\t\t\tlog errors talking with spread\n \ +\t-D\t\t\tdo not daemonize (debug)\n \ +\t-V\t\t\tshow version information\n", progname, SPREADLOGD_VERSION); + exit(1); +} + +void sig_handler(int signum) { + /* Set a "hup my logs" flag */ + if(signum == SIGHUP) + huplogs = 1; + else if(signum == SIGTERM) + terminate = 1; +} + +int join(LogFacility *lf, void *vpfd) { + int ret; + int fd = *(int *)vpfd; + if((ret = SP_join(fd, lf->groupname)) == 0) { + if(verbose) + fprintf(stderr, "Joined %s.\n", lf->groupname); + } + return ret; +} + +int connectandjoin(SpreadConfiguration *sc, void *uv) { + int mbox; + int *tojoin = (int *)uv; + char sld[MAX_GROUP_NAME]; + snprintf(sld, MAX_GROUP_NAME, "sld-%05d", getpid()); + if(sc->connected || SP_connect(config_get_spreaddaemon(sc), + sld, 1, 0, &mbox, + sc->private_group) == ACCEPT_SESSION) { + if(!sc->connected) { + if(verbose) + fprintf(stderr, "Successfully connected to spread at %s%c%s\n", + (sc->host)?sc->host:"/tmp", + (sc->host)?':':'/', + sc->port); + fds[mbox] = sc; + } + sc->connected = 1; + if(*tojoin) + config_foreach_logfacility(sc, join, &mbox); + return mbox; + } else { + if(verbose) + fprintf(stderr, "Failed connection to spread at %s%c%s\n", + (sc->host)?sc->host:"/tmp", + (sc->host)?':':'/', + sc->port); + sc->connected = 0; + } + return -1; +} + +int establish_spread_connections() { + int tojoin = 1; + return config_foreach_spreadconf(connectandjoin, (void *)&tojoin); +} + +void handle_signals() { + if(terminate) { + if(extralog) fprintf(stderr, "Received SIGTERM, closing log files.\n"); + config_close(); + if(extralog) fprintf(stderr, "Log files closed, exiting.\n"); + exit(0); + } + if(huplogs) { + huplogs = 0; + config_hup(); + } +} +void daemonize(void) { + if(fork()!=0) exit(0); + setsid(); + if(fork()!=0) exit(0); +} +int getnropen(void) { + struct rlimit rlim; + getrlimit(RLIMIT_NOFILE, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_NOFILE, &rlim); + return rlim.rlim_cur; +} + +int main(int argc, char **argv) { +#ifdef SPREAD_VERSION + int mver, miver, pver; +#endif + char *configfile = default_configfile; + char *message; + int getoption, debug = 0; + struct sigaction signalaction; + sigset_t ourmask; + nr_open = getnropen(); + + fdsetsize = getdtablesize(); + fds = (SpreadConfiguration **)malloc(sizeof(SpreadConfiguration *)* + fdsetsize); + memset(fds, 0, sizeof(SpreadConfiguration *)*fdsetsize); + + while((getoption = getopt(argc, argv, "b:c:svxDV")) != -1) { + switch(getoption) { + case 'b': + buffsize = atoi(optarg); + case 'c': + configfile = optarg; + break; + case 's': + skiplocking = 1; + break; + case 'v': + verbose = 1; + break; + case 'x': + extralog = 1; + break; + case 'D': + debug = 1; + break; + default: + usage(argv[0]); + } + } + + /* Read our configuration */ + if(config_init(configfile)) exit(-1); + + if(buffsize<0) buffsize = 1024*8; /* 8k buffer (like Apache) */ + message = (char *)malloc(buffsize*sizeof(char)); + + if(verbose) { + fprintf(stderr, "running spreadlogd as %s\n\tconfigfile:\t\t%s\n\tdebug:\t\t%s\n\tverbose:\t\t%s\n\tlog spread errors:\t%s\n\tbuffer size:\t\t%d\n", + argv[0], + configfile, + (debug)?"YES":"NO", + (verbose)?"YES":"NO", + (extralog)?"YES":"NO", + buffsize); + } + + if(!debug) daemonize(); + + /* Set up HUP signal */ + signalaction.sa_handler = sig_handler; + sigemptyset(&signalaction.sa_mask); + signalaction.sa_flags = 0; + if(sigaction(SIGHUP, &signalaction, NULL)) { + fprintf(stderr, "An error occured while registering a SIGHUP handler\n"); + perror("sigaction"); + } + if(sigaction(SIGTERM, &signalaction, NULL)) { + fprintf(stderr, "An error occured while registering a SIGTERM handler\n"); + perror("sigaction"); + } + sigemptyset(&ourmask); + sigaddset(&ourmask, SIGHUP); + sigprocmask(SIG_UNBLOCK, &ourmask, NULL); + + /* Connect to spread */ + while(1) { + int fd, tojoin; + fd_set readset, exceptset, masterset; + sp_time lasttry, thistry, timediff; + service service_type; + char sender[MAX_GROUP_NAME]; + char *pmessage; + int len, num_groups, endian, logfd; + char groups[1][MAX_GROUP_NAME]; + int16 mess_type; +#ifdef DROP_RECV + service_type = DROP_RECV; +#endif + + establish_spread_connections(); + FD_ZERO(&masterset); + for(fd=0;fd 0) { + for(fd=0;fdconnected = 0; + retval = connectandjoin(thissc, &tojoin); + if(retval >= 0) + FD_SET(retval, &masterset); + else if(extralog) + fprintf(stderr, "Error connecting to spread daemon\n"); + } + } else if(Is_regular_mess(service_type)) { + logfd = config_get_fd(fds[fd], groups[0], message); + if(logfd<0) continue; + pmessage = config_process_message(fds[fd],groups[0], message, &len); + write(logfd, pmessage, len); + } +#ifdef DROP_RECV + /* Set DROP_RECV flag if we can */ + service_type = DROP_RECV; +#endif + } + } + handle_signals(); + thistry = E_get_time(); + timediff = E_sub_time(thistry, lasttry); + if(timediff.sec > 5) { + lasttry = thistry; + tojoin = 1; + config_foreach_spreadconf(connectandjoin, (void *)&tojoin); + FD_ZERO(&masterset); + for(i=0;i +* This code was written to facilitate clustered logging via Spread. +* More information on Spread can be found at http://www.spread.org/ +* Please refer to the LICENSE file before using this software. +* ====================================================================== +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "skiplist.h" +#include "timefuncs.h" + +extern FILE *yyin; +extern int buffsize; +extern int nr_open; + +int yyparse (void); +int line_num, semantic_errors; +static Skiplist logfiles; +static Skiplist spreaddaemons; +extern int verbose; +extern int skiplocking; +int logfile_compare(void *a, void *b) { + LogFile *ar = (LogFile *)a; + LogFile *br = (LogFile *)b; + return strcmp(ar->filename, br->filename); +} +int logfile_compare_key(void *a, void *b) { + LogFile *br = (LogFile *)b; + return strcmp(a, br->filename); +} +int spreadd_compare(void *a, void *b) { + SpreadConfiguration *ar = (SpreadConfiguration *)a; + SpreadConfiguration *br = (SpreadConfiguration *)b; + int temp; + if((temp = strcmp(ar->port, br->port))!=0) + return temp; + if((!ar->host) && (!br->host)) return 0; + if(!ar->host) return -1; + if(!br->host) return 1; + return strcmp(ar->host, br->host); +} +int spreadd_compare_key(void *a, void *b) { + SpreadConfiguration *br = (SpreadConfiguration *)b; + int temp; + if((temp = strcmp(a, br->port))!=0) + return temp; + if((!a) && (!br->host)) return 0; + if(!a) return -1; + if(!br->host) return 1; + return strcmp(a, br->host); +} +int facility_compare(void *a, void *b) { + LogFacility *ar = (LogFacility *)a; + LogFacility *br = (LogFacility *)b; + return strcmp(ar->groupname, br->groupname); +} +int facility_compare_key(void *a, void *b) { + LogFacility *br = (LogFacility *)b; + return strcmp(a, br->groupname); +} +int config_init(char *filename) { + int ret; + sl_init(&logfiles); + sl_set_compare(&logfiles, logfile_compare, logfile_compare_key); + sl_init(&spreaddaemons); + sl_set_compare(&spreaddaemons, spreadd_compare, spreadd_compare_key); + /* + sl_init(&logfacilities); + sl_set_compare(&logfacilities, facility_compare, facility_compare_key); + */ + yyin = fopen(filename, "r"); + if (!yyin) { + fprintf(stderr, "Couldn't open input file: %s\n", filename); + return -1; + } + ret = yyparse(); + fclose(yyin); + return ret; +} +char *config_get_spreaddaemon(SpreadConfiguration *sc) { + static char buffer[1024]; + if(sc->host) { + snprintf(buffer, 1024, "%s@%s", sc->port, sc->host); + } + else { + strncpy(buffer, sc->port, 1024); + } + return buffer; +} + +void config_set_spread_port(SpreadConfiguration *sc, char *newport) { + if(sc->port) free(sc->port); + sc->port = newport; +} +void config_set_spread_host(SpreadConfiguration *sc, char *newhost) { + if(sc->host) free(sc->host); + sc->host = newhost; +} +void config_add_spreadconf(SpreadConfiguration *sc) { + sl_insert(&spreaddaemons, sc); +} +SpreadConfiguration *config_new_spread_conf(void) { + SpreadConfiguration *newsc; + newsc = (SpreadConfiguration *)malloc(sizeof(SpreadConfiguration)); + newsc->host=NULL; + newsc->port=strdup("4803"); + newsc->connected = 0; + newsc->logfacilities = (Skiplist *)malloc(sizeof(Skiplist)); + sl_init(newsc->logfacilities); + sl_set_compare(newsc->logfacilities, + facility_compare, facility_compare_key); + return newsc; +} +LogFacility *config_new_logfacility(void) { + LogFacility *newlf; + newlf = malloc(sizeof(LogFacility)); + newlf->groupname=NULL; + newlf->logfile=NULL; + newlf->nmatches=0; + newlf->rewritetimes=NO_REWRITE_TIMES; + newlf->rewritetimesformat=NULL; + return newlf; +} +void config_add_logfacility(SpreadConfiguration *sc, LogFacility *lf) { + sl_insert(sc->logfacilities, lf); +} +void config_set_logfacility_group(LogFacility *lf, char *ng) { + if(lf->groupname) free(lf->groupname); + lf->groupname = ng; +} +void config_set_logfacility_filename(LogFacility *lf, char *nf) { + LogFile *logf; + logf = sl_find(&logfiles, nf, NULL); + lf->logfile = logf; + if(!lf->logfile) { + logf = (LogFile *)malloc(sizeof(LogFile)); + logf->filename = nf; + logf->fd = -1; + sl_insert(&logfiles, logf); + lf->logfile = logf; + } + else { + free(nf); + } +} +void config_set_logfacility_vhostdir(LogFacility *lf, char *vhd) { + int i; + lf->vhostdir = vhd; + lf->hash = (hash_element *) malloc (nr_open * sizeof(hash_element)); + fprintf( stderr, "\nZeroing vhost hash for usage!\n"); + for(i=0; i< nr_open; i++) { + lf->hash[i].fd = -1; + lf->hash[i].hostheader = NULL; + } + +} +void config_set_logfaclity_rewritetimes_clf(LogFacility *lf) { + lf->rewritetimes = REWRITE_TIMES_IN_CLF; +} +void config_set_logfaclity_rewritetimes_user(LogFacility *lf, char *format) { + lf->rewritetimes = REWRITE_TIMES_FORMAT; + if(lf->rewritetimesformat) { + free(lf->rewritetimesformat); + } + lf->rewritetimesformat = format; +} +void config_add_logfacility_match(LogFacility *lf, char *nm) { +#ifdef RE_SYNTAX_EGREP + const char *ret; +#else + int ret; +#endif + if(lf->nmatches>=10) { + fprintf(stderr, "Already 10 regex's on group\n"); + return; + } +#ifdef RE_SYNTAX_EGREP + re_set_syntax(RE_SYNTAX_EGREP); + if((ret = re_compile_pattern(nm, strlen(nm), + &lf->match_expression[lf->nmatches]))!=0) { + fprintf(stderr, ret); +#else +if((ret = regcomp(&lf->match_expression[lf->nmatches], nm, REG_EGREP))!=0) { + char errbuf[120]; + regerror(ret, &lf->match_expression[lf->nmatches], errbuf, sizeof errbuf); + fprintf(stderr, errbuf); +#endif + } else { + lf->nmatches++; + } +} + +int config_foreach_spreadconf(int (*func)(SpreadConfiguration *, void *), + void *closure) { + int i=0; + struct skiplistnode *iter; + SpreadConfiguration *sc; + iter = sl_getlist(&spreaddaemons); + if(!iter) return i; + sc = iter->data; + do { + if(func(sc, closure)==0) i++; + } while((sc = sl_next(&spreaddaemons, &iter))!=NULL); + return i; +} + +int config_foreach_logfacility(SpreadConfiguration *sc, + int (*func)(LogFacility *, void *), + void *closure) { + int i=0; + struct skiplistnode *iter; + LogFacility *lf; + iter = sl_getlist(sc->logfacilities); + if(!iter) return i; + lf = iter->data; + do { + if(func(lf, closure)==0) i++; + } while((lf = sl_next(sc->logfacilities, &iter))!=NULL); + return i; +} + +char *config_process_message(SpreadConfiguration *sc, char *group, + char *message, int *len) { + LogFacility *lf; + char *cp; + lf = sl_find(sc->logfacilities, group, NULL); + if(lf->rewritetimes) + force_local_time(message, len, buffsize, + lf->rewritetimes, lf->rewritetimesformat); + if(lf->vhostdir) { + cp=message; + while(*cp != ' ') { + cp++; + --*len; + } + --*len; + return cp+1; + } + return message; +} + +void config_hup(void) { + config_close(); + config_start(); +} + +int config_close(void) { + struct skiplistnode *sciter, *lfiter; + SpreadConfiguration *sc; + LogFacility *lf; + int i; + sciter = sl_getlist(&spreaddaemons); + if(!sciter) return 0; + sc = (SpreadConfiguration *)sciter->data; + /* For each spread configuration: */ + do { + lfiter = sl_getlist(sc->logfacilities); + if(!lfiter) return 0; + lf = (LogFacility *)lfiter->data; + /* For each log facility in that spread configuration: */ + do { + if(lf->vhostdir) { + for (i=0;i< nr_open;i++) { + if(lf->hash[i].fd>0) { + if(!skiplocking) flock(lf->hash[i].fd, LOCK_UN); + close(lf->hash[i].fd); + lf->hash[i].fd = -1; + } + } + } else if(lf->logfile->fd>0) { + if(!skiplocking) flock(lf->logfile->fd, LOCK_UN); + close(lf->logfile->fd); + lf->logfile->fd = -1; + } + } while((lf = sl_next(sc->logfacilities, &lfiter))!=NULL); + } while((sc = sl_next(&spreaddaemons, &sciter))!=NULL); + return 0; +} + +int open_pipe_log(char *filename) +{ + int pid, pfd[2]; + + if (pipe(pfd) < 0) + return -1; + if ((pid = fork()) < 0) + return -1; + else if (pid == 0) { + close(pfd[1]); + dup2(pfd[0], STDIN_FILENO); + close(pfd[0]); + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_IGN); + filename++; /* skip past leading '|' */ + execl(SHELL_PATH, SHELL_PATH, "-c", filename, (char *) 0); + } + else { + close(pfd[0]); + return pfd[1]; + } + return -1; +} +int config_start(void) { + struct skiplistnode *sciter, *lfiter; + SpreadConfiguration *sc; + LogFacility *lf; + sciter = sl_getlist(&spreaddaemons); + if(!sciter) return 0; + sc = (SpreadConfiguration *)sciter->data; + /* For each spread configuration: */ + do { + lfiter = sl_getlist(sc->logfacilities); + if(!lfiter) return 0; + lf = (LogFacility *)lfiter->data; + /* For each log facility in that spread configuration: */ + do { + if(lf->vhostdir) continue; + else if(lf->logfile->fd<0) { + if(lf->logfile->filename[0] == '|') { + lf->logfile->fd = open_pipe_log(lf->logfile->filename); + } + else { + lf->logfile->fd = open(lf->logfile->filename, +#ifdef __USE_LARGEFILE64 + O_CREAT|O_APPEND|O_WRONLY|O_LARGEFILE, +#else + O_CREAT|O_APPEND|O_WRONLY, +#endif + 00644); + } + } + if(!skiplocking) { + if(flock(lf->logfile->fd, LOCK_NB|LOCK_EX)==-1) { + fprintf(stderr, "Cannot lock %s, is another spreadlogd running?\n", + lf->logfile->filename); + exit(1); + } + } + if(verbose) { + fprintf(stderr, "LogFacility: %s\n\tFile: %s\n\tFD: %d\n\t%d regexs\n", + lf->groupname, lf->logfile->filename, + lf->logfile->fd, lf->nmatches); + } + } while((lf = sl_next(sc->logfacilities, &lfiter))!=NULL); + } while((sc = sl_next(&spreaddaemons, &sciter))!=NULL); + return 0; +} + +int config_get_fd(SpreadConfiguration *sc, char *group, char *message) { + LogFacility *lf; + int i, ret, slen, fd; + hash_element temp; + char *cp; + char fullpath[MAXPATHLEN]; + lf = sl_find(sc->logfacilities, group, NULL); + if(!lf) return -1; + if(lf->vhostdir) { + cp = message; + while(*cp != ' '){ + cp++; + } + *cp = '\0'; + if((fd = gethash(message, lf->hash)) < 0) { + temp.hostheader = strdup(message); + *cp = ' '; + snprintf(fullpath, MAXPATHLEN, "%s/%s", lf->vhostdir,temp.hostheader); + temp.fd = open(fullpath, +#ifdef __USE_LARGEFILE64 + O_CREAT|O_APPEND|O_WRONLY|O_LARGEFILE, +#else + O_CREAT|O_APPEND|O_WRONLY, +#endif + 00644); + if(!skiplocking) { + if(flock(temp.fd, LOCK_NB|LOCK_EX)==-1) { + fprintf(stderr, "Cannot lock %s, is another spreadlogd running?\n", + fullpath); + exit(1); + } + } + inshash(temp,lf->hash); + return temp.fd; + } + *cp = ' '; + return fd; + } + if(!lf->nmatches) return lf->logfile->fd; + slen = strlen(message); + for(i=0; inmatches; i++) { +#ifdef RE_SYNTAX_EGREP + if((ret = re_search(&lf->match_expression[i], + message, slen, 0, slen, NULL)) >= 0) + return lf->logfile->fd; + else if(ret==-2 && verbose) + fprintf(stderr, "Internal error in re_search.\n"); + else if(ret==-1 && verbose) + fprintf(stderr, "Failed match!\n"); +#else + if(!regexec(&lf->match_expression[i], message, 0, NULL, 0)) + return lf->logfile->fd; +#endif + } + return -1; +} + Index: tags/v_1_4_2/skiplist.h =================================================================== --- tags/v_1_4_2/skiplist.h (revision 19) +++ tags/v_1_4_2/skiplist.h (revision 19) @@ -0,0 +1,82 @@ +/* ====================================================================== + * Copyright (c) 2000 Theo Schlossnagle + * All rights reserved. + * The following code was written by Theo Schlossnagle for use in the + * Backhand project at The Center for Networking and Distributed Systems + * at The Johns Hopkins University. + * + * This is a skiplist implementation to be used for abstract structures + * and is release under the LGPL license version 2.1 or later. A copy + * of this license can be found at http://www.gnu.org/copyleft/lesser.html + * ====================================================================== +*/ + +#ifndef _SKIPLIST_P_H +#define _SKIPLIST_P_H + +/* This is a skiplist implementation to be used for abstract structures + within the Spread multicast and group communication toolkit + + This portion written by -- Theo Schlossnagle +*/ + +/* This is the function type that must be implemented per object type + that is used in a skiplist for comparisons to maintain order */ +typedef int (*SkiplistComparator)(void *, void *); +typedef void (*FreeFunc)(void *); + +struct skiplistnode; + +typedef struct _iskiplist { + SkiplistComparator compare; + SkiplistComparator comparek; + int height; + int preheight; + int size; + struct skiplistnode *top; + struct skiplistnode *bottom; + /* These two are needed for appending */ + struct skiplistnode *topend; + struct skiplistnode *bottomend; + struct _iskiplist *index; +} Skiplist; + +struct skiplistnode { + void *data; + struct skiplistnode *next; + struct skiplistnode *prev; + struct skiplistnode *down; + struct skiplistnode *up; + struct skiplistnode *previndex; + struct skiplistnode *nextindex; + Skiplist *sl; +}; + + +void sl_init(Skiplist *sl); +void sl_set_compare(Skiplist *sl, SkiplistComparator, + SkiplistComparator); +void sl_add_index(Skiplist *sl, SkiplistComparator, + SkiplistComparator); +struct skiplistnode *sl_getlist(Skiplist *sl); +void *sl_find_compare(Skiplist *sl, void *data, struct skiplistnode **iter, + SkiplistComparator func); +void *sl_find(Skiplist *sl, void *data, struct skiplistnode **iter); +void *sl_next(Skiplist *sl, struct skiplistnode **); +void *sl_previous(Skiplist *sl, struct skiplistnode **); + +struct skiplistnode *sl_insert_compare(Skiplist *sl, + void *data, SkiplistComparator comp); +struct skiplistnode *sl_insert(Skiplist *sl, void *data); +int sl_remove_compare(Skiplist *sl, void *data, + FreeFunc myfree, SkiplistComparator comp); +int sl_remove(Skiplist *sl, void *data, FreeFunc myfree); +int sli_remove(Skiplist *sl, struct skiplistnode *m, FreeFunc myfree); +void sl_remove_all(Skiplist *sl, FreeFunc myfree); + +int sli_find_compare(Skiplist *sl, + void *data, + struct skiplistnode **ret, + SkiplistComparator comp); + +#endif Index: tags/v_1_4_2/spreadlogd.conf =================================================================== --- tags/v_1_4_2/spreadlogd.conf (revision 7) +++ tags/v_1_4_2/spreadlogd.conf (revision 7) @@ -0,0 +1,60 @@ +# This is a sample spreadlogd.conf file + +# This will set the size of the preallocated buffer into which message +# are written (from spread). All messages larger than this are dropped. +# The default is 8192, but can be specified here as follows, but both +# can be overridden from the command line with a -b argument to +# spreadlogd + +BufferSize = 65536 + +Spread { +# Use the spread daemon on excalibur listening on port 3502 + Port = 3502 + Host = excalibur + Log { +# Rewrite incoming log lines so that the timestamps will reflect the time +# on the local machine. This will allow you web server to be slightly out +# sync with respect to time and still have monotonically time increasing logs + RewriteTimestamp = CommonLogFormat + Group = omniti + File = omniti.log + } +} + +Spread { + Port = 3333 + +# Leave out the Host directive and spread will try to establish a connection +# to the local spread daemon over a UNIX domain socket, which is faster. +# Host = localhost + +# Log { +# Group = "testing" +# File = "combined_log" +# This will make sure the every message logged with contain an IPv4 address. +# Match = "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" +# } + +# Log { +# Group = "fcibglobal" +# This will share the file with the above log statement (one file descriptor) +# File = combined_log +# } + +# Log { +# Group = apache-0003 +# This directory will contain one file for each of the apache vitual servers +# that gets hashed to '1' by mod_log_spread's $#vhost 'magic group'. +# Across you cluster there should be one such statement for every integer +# between 0 and VhostLoghashSize - 1. Be careful not to run out of open +# file descriptors (i.e., if you have a 100,000 virtual hosts, you'll probably +# run out of fd's on a single box.) +# VhostDir = /vhostdata1 +# } +# + Log { + Group = "test" + File = testlog + } +}