root/trunk/spreadlogd.c

Revision 2, 7.0 kB (checked in by jesus, 14 years ago)

Initial revision

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* ======================================================================
2  * Copyright (c) 2000 Theo Schlossnagle
3  * All rights reserved.
4  * The following code was written by Theo Schlossnagle <jesus@omniti.com>
5  * This code was written to facilitate clustered logging via Spread.
6  * More information on Spread can be found at http://www.spread.org/
7  * Please refer to the LICENSE file before using this software.
8  * ======================================================================
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <signal.h>
14 #include <unistd.h>
15 #include <sys/time.h>
16
17 #include <sp.h>
18
19 #include "config.h"
20
21 #define SPREADLOGD_VERSION "1.2"
22
23 extern char *optarg;
24 extern int optind, opterr, optopt;
25
26 int verbose = 0;
27 int extralog = 0;
28 int terminate = 0;
29 int huplogs = 0;
30 int skiplocking = 0;
31 int buffsize = -1;
32
33 SpreadConfiguration **fds;
34 int fdsetsize;
35
36 static char *default_configfile = "/etc/spreadlogd.conf";
37
38 void usage(char *progname) {
39   fprintf(stderr, "%s\t\tVERSION: %s\n \
40 \t-c configfile\t\t[default /etc/spreadlogd.conf]\n \
41 \t-s\t\t\tskip locking (flock) files (NOT RECOMMENDED)\n \
42 \t-v\t\t\tverbose mode\n \
43 \t-x\t\t\tlog errors talking with spread\n \
44 \t-D\t\t\tdo not daemonize (debug)\n \
45 \t-V\t\t\tshow version information\n", progname, SPREADLOGD_VERSION);
46   exit(1);
47 }
48
49 void sig_handler(int signum) {
50   /* Set a "hup my logs" flag */
51   if(signum == SIGHUP)
52     huplogs = 1;
53   else if(signum == SIGTERM)
54     terminate = 1;
55 }
56
57 int join(LogFacility *lf, void *vpfd) {
58   int ret;
59   int fd = *(int *)vpfd;
60   if((ret = SP_join(fd, lf->groupname)) == 0) {
61     if(verbose)
62       fprintf(stderr, "Joined %s.\n", lf->groupname);
63   }
64   return ret;
65 }
66
67 int connectandjoin(SpreadConfiguration *sc, void *uv) {
68   int mbox;
69   int *tojoin = (int *)uv;
70   char sld[MAX_GROUP_NAME];
71   snprintf(sld, MAX_GROUP_NAME, "sld-%05d", getpid());
72   if(sc->connected || SP_connect(config_get_spreaddaemon(sc),
73                                  sld, 1, 0, &mbox,
74                                  sc->private_group) == ACCEPT_SESSION) {
75     if(!sc->connected) {
76       if(verbose)
77         fprintf(stderr, "Successfully connected to spread at %s%c%s\n",
78                 (sc->host)?sc->host:"/tmp",
79                 (sc->host)?':':'/',
80                 sc->port);
81       fds[mbox] = sc;
82     }
83     sc->connected = 1;
84     if(*tojoin)
85       config_foreach_logfacility(sc, join, &mbox);
86     return 0;
87   } else {
88     if(verbose)
89       fprintf(stderr, "Failed connection to spread at %s%c%s\n",
90               (sc->host)?sc->host:"/tmp",
91               (sc->host)?':':'/',
92               sc->port);
93     sc->connected = 0;
94   }
95   return -1; 
96 }
97
98 int establish_spread_connections() {
99   int tojoin = 1;
100   return config_foreach_spreadconf(connectandjoin, (void *)&tojoin);
101 }
102
103 void handle_signals() {
104   if(terminate) {
105     if(extralog) fprintf(stderr, "Received SIGTERM, closing log files.\n");
106     config_close();
107     if(extralog) fprintf(stderr, "Log files closed, exiting.\n");
108     exit(0);
109   }
110   if(huplogs) {
111     huplogs = 0;
112     config_hup();
113   }
114 }
115 void daemonize(void) {
116   if(fork()!=0) exit(0);
117   setsid();
118   if(fork()!=0) exit(0);
119 }
120
121 int main(int argc, char **argv) {
122   char *configfile = default_configfile;
123   char *message;
124   int getoption, debug = 0;
125   struct sigaction signalaction;
126   sigset_t ourmask;
127
128   fdsetsize = getdtablesize();
129   fds = (SpreadConfiguration **)malloc(sizeof(SpreadConfiguration *)*
130                                        fdsetsize);
131   memset(fds, 0, sizeof(SpreadConfiguration *)*fdsetsize);
132
133   while((getoption = getopt(argc, argv, "b:c:svxDV")) != -1) {
134     switch(getoption) {
135     case 'b':
136       buffsize = atoi(optarg);
137     case 'c':
138       configfile = optarg;
139       break;
140     case 's':
141       skiplocking = 1;
142       break;
143     case 'v':
144       verbose = 1;
145       break;
146     case 'x':
147       extralog = 1;
148       break;
149     case 'D':
150       debug = 1;
151       break;
152     case 'V':
153       fprintf(stderr,
154               "(%s VERSION: %s) %s\nLinked against libsp VERSION: %.2f\n",
155               "spreadlogd", SPREADLOGD_VERSION, argv[0], SP_version());
156       exit(0);
157       break;
158     default:
159       usage(argv[0]);
160     }
161   }
162  
163   /* Read our configuration */
164   if(config_init(configfile)) exit(-1);
165
166   if(buffsize<0) buffsize = 1024*8; /* 8k buffer (like Apache) */
167   message = (char *)malloc(buffsize*sizeof(char));
168
169   if(verbose) {
170     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",
171             argv[0],
172             configfile,
173             (debug)?"YES":"NO",
174             (verbose)?"YES":"NO",
175             (extralog)?"YES":"NO",
176             buffsize);
177   }
178
179   if(!debug) daemonize();
180  
181   /* Set up HUP signal */
182   signalaction.sa_handler = sig_handler;
183   sigemptyset(&signalaction.sa_mask);
184   signalaction.sa_flags = 0;
185   if(sigaction(SIGHUP, &signalaction, NULL)) {
186     fprintf(stderr, "An error occured while registering a SIGHUP handler\n");
187     perror("sigaction");
188   }
189   if(sigaction(SIGTERM, &signalaction, NULL)) {
190     fprintf(stderr, "An error occured while registering a SIGTERM handler\n");
191     perror("sigaction");
192   }
193   sigemptyset(&ourmask);
194   sigaddset(&ourmask, SIGHUP);
195   sigprocmask(SIG_UNBLOCK, &ourmask, NULL);
196
197   /* Connect to spread */
198   while(1) {
199     int fd, tojoin;
200     fd_set readset, exceptset, masterset;
201     sp_time lasttry, thistry, timediff;
202     service service_type;
203     char sender[MAX_GROUP_NAME];
204     int len, num_groups, endian, logfd;
205     char groups[1][MAX_GROUP_NAME];
206     int16 mess_type;
207 #ifdef DROP_RECV
208     service_type = DROP_RECV;
209 #endif
210     establish_spread_connections();
211     FD_ZERO(&masterset);
212     for(fd=0;fd<fdsetsize;fd++) {
213       if(fds[fd]) {
214         fprintf(stderr, "Setting FD: %d\n", fd);
215         FD_SET(fd, &masterset);
216       }
217     }
218     lasttry = E_get_time();
219     while(1) {
220       /* Build out select */
221       struct timeval timeout;
222       readset = masterset;
223       exceptset = masterset;
224       timeout.tv_sec = 1L;
225       timeout.tv_usec = 0L;
226       if(select(fdsetsize, &readset, NULL, &exceptset, &timeout) > 0) {
227         for(fd=0;fd<fdsetsize;fd++)
228           if(FD_ISSET(fd, &readset) || FD_ISSET(fd, &exceptset)) {
229             len = SP_receive(fd, &service_type, sender,
230                              1, &num_groups, groups,
231                              &mess_type, &endian, buffsize, message);
232 #ifdef DROP_RECV
233             /* Set DROP_RECV flag if we can */
234             service_type = DROP_RECV;
235 #endif
236             /* Handle errors correctly */
237             if(len == ILLEGAL_SESSION || len == CONNECTION_CLOSED ||
238                len == ILLEGAL_MESSAGE || len == BUFFER_TOO_SHORT) {
239               if(extralog) {
240                 fprintf(stderr, "Error receiving from spread:\n\t");
241                 SP_error(len);
242               }
243               /* These are errors that require reestablishing a connection */
244               if(len == ILLEGAL_SESSION || len == CONNECTION_CLOSED) {
245                 /* So, let's try */
246                 SpreadConfiguration *thissc = fds[fd];
247                 thissc->connected = 0;
248                 connectandjoin(thissc, NULL);           
249               }
250             } else if(Is_regular_mess(mess_type)) {
251               logfd = config_get_fd(fds[fd], groups[0], message);
252               if(logfd<0) continue;
253               write(logfd, message, len);
254             }
255           }
256       }
257       handle_signals();
258       thistry = E_get_time();
259       timediff = E_sub_time(thistry, lasttry);
260       if(timediff.sec > 5) {
261         lasttry = thistry;
262         tojoin = 1;
263         config_foreach_spreadconf(connectandjoin, (void *)&tojoin);
264       }
265     }
266   }
267   return -1;
268 }
Note: See TracBrowser for help on using the browser.