Mercurial > wflogs-daemon
comparison src/wflogs-config.cpp @ 2:400b1de6e1c6
allow multiple config contexts
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 17 May 2013 10:32:12 -0700 |
parents | 0aa1171aebd2 |
children | 37eace15ef87 |
comparison
equal
deleted
inserted
replaced
1:964c1127ae65 | 2:400b1de6e1c6 |
---|---|
1 /* | 1 /* |
2 | 2 |
3 Copyright (c) 2007 Carl Byington - 510 Software Group, released under | 3 Copyright (c) 2013 Carl Byington - 510 Software Group, released under |
4 the GPL version 3 or any later version at your choice available at | 4 the GPL version 3 or any later version at your choice available at |
5 http://www.gnu.org/licenses/gpl-3.0.txt | 5 http://www.gnu.org/licenses/gpl-3.0.txt |
6 | 6 |
7 */ | 7 */ |
8 | 8 |
32 | 32 |
33 | 33 |
34 | 34 |
35 //////////////////////////////////////////////// | 35 //////////////////////////////////////////////// |
36 // | 36 // |
37 CONFIG::CONFIG() { | 37 CONTEXT::CONTEXT(const char *nam) { |
38 reference_count = 0; | 38 name = nam; |
39 fd = -1; | 39 fd = -1; |
40 len = 0; | 40 len = 0; |
41 fdo = -1; | 41 fdo = -1; |
42 generation = 0; | |
43 load_time = 0; | |
44 period = 120; | 42 period = 120; |
45 versions = 3; | 43 versions = 3; |
46 output = NULL; | 44 output = NULL; |
47 tempin = NULL; | 45 tempin = NULL; |
48 wflogs = NULL; | 46 wflogs = NULL; |
49 fn = NULL; | 47 fn = NULL; |
50 pattern = NULL; | 48 pattern = NULL; |
51 } | 49 } |
52 | 50 |
53 | 51 |
54 CONFIG::~CONFIG() { | 52 CONTEXT::~CONTEXT() { |
55 } | 53 free_all(); |
56 | 54 } |
57 | 55 |
58 void CONFIG::sleep(int duration, time_t &previous) { | 56 |
59 ::sleep(duration); | 57 void CONTEXT::dump() { |
60 time_t now = time(NULL); | 58 printf("context %s {\n", name); |
61 previous = now; | 59 printf(" period %d; \n", period); |
62 } | 60 printf(" versions %d; \n", versions); |
63 | 61 printf(" output \"%s\";\n", output); |
64 | 62 printf(" tempin \"%s\";\n", tempin); |
65 void CONFIG::free_all() { | 63 printf(" wflogs \"%s\";\n", wflogs); |
66 regfree(&re); | 64 printf(" file \"%s\";\n", fn); |
67 close(); | 65 printf(" pattern \"%s\";\n", pattern); |
68 closeo(); | 66 printf("};\n\n"); |
69 } | 67 } |
70 | 68 |
71 | 69 |
72 void CONFIG::openo(bool msg) { | 70 void CONTEXT::openo(bool msg) { |
73 open_time = time(NULL); | 71 open_time = time(NULL); |
74 fdo = ::creat(tempin, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | 72 fdo = ::creat(tempin, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
75 if (fdo == -1) { | 73 if (fdo == -1) { |
76 if (msg) { | 74 if (msg) { |
77 char buf[maxlen]; | 75 char buf[maxlen]; |
80 } | 78 } |
81 } | 79 } |
82 } | 80 } |
83 | 81 |
84 | 82 |
85 void CONFIG::open(bool msg) { | 83 void CONTEXT::open(bool msg) { |
86 fd = ::open(fn, O_RDONLY); | 84 fd = ::open(fn, O_RDONLY); |
87 len = 0; | 85 len = 0; |
88 if (fd == -1) { | 86 if (fd == -1) { |
89 if (msg) { | 87 if (msg) { |
90 char buf[maxlen]; | 88 char buf[maxlen]; |
101 if (fstat(fd, &openfdstat)) { | 99 if (fstat(fd, &openfdstat)) { |
102 close(); | 100 close(); |
103 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", fn); | 101 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", fn); |
104 tokp->token_error(buf); | 102 tokp->token_error(buf); |
105 } | 103 } |
106 // specify that this fd gets closed on exec, so that selinux | 104 // specify that this fd gets closed on exec, so that wflogs |
107 // won't complain about iptables trying to read log files. | 105 // won't have access to it. |
108 int oldflags = fcntl(fd, F_GETFD, 0); | 106 int oldflags = fcntl(fd, F_GETFD, 0); |
109 if (oldflags >= 0) { | 107 if (oldflags >= 0) { |
110 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC); | 108 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC); |
111 } | 109 } |
112 } | 110 } |
113 } | 111 } |
114 | 112 |
115 | 113 |
116 bool CONFIG::write(char *p) { | 114 bool CONTEXT::write(char *p) { |
117 // p points to \0 at end of buf, may be destroyed | 115 // p points to \0 at end of buf, may be destroyed |
118 if (failedo()) { | 116 if (failedo()) { |
119 openo(false); | 117 openo(false); |
120 if (failedo()) return false; | 118 if (failedo()) return false; |
121 } | 119 } |
122 *p = '\n'; | 120 *p = '\n'; |
123 ::write(fdo, buf, p-buf+1); | 121 ::write(fdo, buf, p-buf+1); |
124 } | 122 } |
125 | 123 |
126 | 124 |
127 bool CONFIG::read() { | 125 bool CONTEXT::read() { |
128 if (failed()) { | 126 if (failed()) { |
129 open(false); | 127 open(false); |
130 if (failed()) return false; | 128 if (failed()) return false; |
131 } | 129 } |
132 int n = ::read(fd, buf+len, buflen-len); | 130 int n = ::read(fd, buf+len, buflen-len); |
162 check_wflog(); | 160 check_wflog(); |
163 return have; | 161 return have; |
164 } | 162 } |
165 | 163 |
166 | 164 |
167 void CONFIG::closeo() { | 165 void CONTEXT::closeo() { |
168 if (fdo != -1) ::close(fdo); | 166 if (fdo != -1) ::close(fdo); |
169 fdo = -1; | 167 fdo = -1; |
170 } | 168 } |
171 | 169 |
172 | 170 |
173 void CONFIG::close() { | 171 void CONTEXT::close() { |
174 if (debug_syslog > 1) { | 172 if (debug_syslog > 1) { |
175 snprintf(buf, sizeof(buf), "syslog file %s closed", fn); | 173 snprintf(buf, sizeof(buf), "syslog file %s closed", fn); |
176 my_syslog(buf); | 174 my_syslog(buf); |
177 } | 175 } |
178 if (fd != -1) ::close(fd); | 176 if (fd != -1) ::close(fd); |
179 fd = -1; | 177 fd = -1; |
180 } | 178 } |
181 | 179 |
182 | 180 |
183 void CONFIG::process(char *p) { | 181 void CONTEXT::process(char *p) { |
184 // p points to \0 at end of buf, may be destroyed | 182 // p points to \0 at end of buf, may be destroyed |
185 if (pattern) { | 183 if (pattern) { |
186 if (0 == regexec(&re, buf, 0, NULL, 0)) { | 184 if (0 == regexec(&re, buf, 0, NULL, 0)) { |
187 if (debug_syslog > 2) { | 185 if (debug_syslog > 2) { |
188 my_syslog(buf); // show lines with matches | 186 my_syslog(buf); // show lines with matches |
191 } | 189 } |
192 } | 190 } |
193 } | 191 } |
194 | 192 |
195 | 193 |
196 void CONFIG::check_wflog() { | 194 void CONTEXT::check_wflog() { |
197 time_t now = time(NULL); | 195 time_t now = time(NULL); |
198 if ((fdo != -1) && (open_time + period < now)) { | 196 if ((fdo != -1) && (open_time + period < now)) { |
199 closeo(); | 197 closeo(); |
200 // rename previous wflog html output files | 198 // rename previous wflog html output files |
201 char buf[maxlen]; | 199 char buf[maxlen]; |
214 openo(false); | 212 openo(false); |
215 } | 213 } |
216 } | 214 } |
217 | 215 |
218 | 216 |
217 void CONTEXT::free_all() { | |
218 regfree(&re); | |
219 close(); | |
220 closeo(); | |
221 } | |
222 | |
223 | |
224 //////////////////////////////////////////////// | |
225 // | |
226 CONFIG::CONFIG() { | |
227 reference_count = 0; | |
228 generation = 0; | |
229 load_time = 0; | |
230 } | |
231 | |
232 | |
233 CONFIG::~CONFIG() { | |
234 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | |
235 CONTEXT *c = *i; | |
236 delete c; | |
237 } | |
238 } | |
239 | |
240 | |
219 void CONFIG::dump() { | 241 void CONFIG::dump() { |
220 int level = 0; | 242 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { |
221 char indent[maxlen]; | 243 CONTEXTP c = *i; |
222 int i = min(maxlen-1, level*4); | 244 c->dump(); |
223 memset(indent, ' ', i); | 245 } |
224 indent[i] = '\0'; | 246 } |
225 printf("%s period %d; \n", indent, period); | 247 |
226 printf("%s versions %d; \n", indent, versions); | 248 |
227 printf("%s output \"%s\";\n", indent, output); | 249 bool CONFIG::read() { |
228 printf("%s tempin \"%s\";\n", indent, tempin); | 250 bool rc = false; |
229 printf("%s wflogs \"%s\";\n", indent, wflogs); | 251 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { |
230 printf("%s file \"%s\";\n", indent, fn); | 252 CONTEXT *c = *i; |
231 printf("%s pattern \"%s\";\n", indent, pattern); | 253 rc |= c->read(); |
254 } | |
255 } | |
256 | |
257 void CONFIG::sleep(int duration, time_t &previous) { | |
258 ::sleep(duration); | |
259 time_t now = time(NULL); | |
260 previous = now; | |
261 } | |
262 | |
263 | |
264 void CONFIG::free_all() { | |
265 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | |
266 CONTEXT *c = *i; | |
267 c->free_all(); | |
268 } | |
232 } | 269 } |
233 | 270 |
234 | 271 |
235 //////////////////////////////////////////////// | 272 //////////////////////////////////////////////// |
236 // helper to discard the strings held by a string_set | 273 // helper to discard the strings held by a string_set |
281 return false; | 318 return false; |
282 } | 319 } |
283 | 320 |
284 | 321 |
285 //////////////////////////////////////////////// | 322 //////////////////////////////////////////////// |
286 // parse a config file | 323 // |
287 // | 324 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); |
288 bool load_conf(CONFIG &dc, const char *fn) { | 325 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { |
289 TOKEN tok(fn, &dc.config_files); | 326 const char *name = tok.next(); |
290 dc.set_token(tok); | 327 if (!tsa(tok, token_lbrace)) return false; |
328 CONTEXTP con = new CONTEXT(name); | |
329 con->set_token(tok); | |
291 while (true) { | 330 while (true) { |
292 const char *have = tok.next(); | 331 const char *have = tok.next(); |
293 if (!have) break; | 332 if (!have) break; |
333 if (have == token_rbrace) break; // done | |
294 if (have == token_period) { | 334 if (have == token_period) { |
295 have = tok.next(); | 335 have = tok.next(); |
296 dc.set_period(atoi(have)); | 336 con->set_period(atoi(have)); |
297 if (!tsa(tok, token_semi)) return false; | 337 if (!tsa(tok, token_semi)) return false; |
298 } | 338 } |
299 else if (have == token_versions) { | 339 else if (have == token_versions) { |
300 have = tok.next(); | 340 have = tok.next(); |
301 dc.set_versions(atoi(have)); | 341 con->set_versions(atoi(have)); |
302 if (!tsa(tok, token_semi)) return false; | 342 if (!tsa(tok, token_semi)) return false; |
303 } | 343 } |
304 else if (have == token_output) { | 344 else if (have == token_output) { |
305 dc.set_output(tok.next()); | 345 con->set_output(tok.next()); |
306 if (!tsa(tok, token_semi)) return false; | 346 if (!tsa(tok, token_semi)) return false; |
307 } | 347 } |
308 else if (have == token_tempin) { | 348 else if (have == token_tempin) { |
309 dc.set_tempin(tok.next()); | 349 con->set_tempin(tok.next()); |
310 if (!tsa(tok, token_semi)) return false; | 350 if (!tsa(tok, token_semi)) return false; |
311 } | 351 } |
312 else if (have == token_wflogs) { | 352 else if (have == token_wflogs) { |
313 dc.set_wflogs(tok.next()); | 353 con->set_wflogs(tok.next()); |
314 if (!tsa(tok, token_semi)) return false; | 354 if (!tsa(tok, token_semi)) return false; |
315 } | 355 } |
316 else if (have == token_file) { | 356 else if (have == token_file) { |
317 dc.set_file(tok.next()); | 357 con->set_file(tok.next()); |
318 if (!tsa(tok, token_semi)) return false; | 358 if (!tsa(tok, token_semi)) return false; |
319 } | 359 } |
320 else if (have == token_pattern) { | 360 else if (have == token_pattern) { |
321 dc.pattern = tok.next(); | 361 con->pattern = tok.next(); |
322 int rc = regcomp(&dc.re, dc.pattern, REG_ICASE | REG_EXTENDED); | 362 int rc = regcomp(&con->re, con->pattern, REG_ICASE | REG_EXTENDED); |
323 if (rc) { | 363 if (rc) { |
324 char bu[maxlen]; | 364 char bu[maxlen]; |
325 regerror(rc, &dc.re, bu, maxlen); | 365 regerror(rc, &con->re, bu, maxlen); |
326 char buf[maxlen]; | 366 char buf[maxlen]; |
327 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", dc.pattern, bu); | 367 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", con->pattern, bu); |
328 tok.token_error(buf); | 368 tok.token_error(buf); |
329 dc.pattern = NULL; | 369 con->pattern = NULL; |
330 } | 370 } |
331 | 371 |
332 if (!tsa(tok, token_semi)) return false; | 372 if (!tsa(tok, token_semi)) return false; |
333 } | 373 } |
334 else { | 374 else { |
335 tok.token_error("statement", have); | 375 tok.token_error("period/versions/output/tempin/wflogs/file/pattern", have); |
336 return false; | 376 return false; |
337 } | 377 } |
338 } | 378 } |
379 if (!tsa(tok, token_semi)) { | |
380 delete con; | |
381 return false; | |
382 } | |
383 dc.add_context(con); | |
339 return true; | 384 return true; |
340 } | 385 } |
341 | 386 |
342 | 387 |
343 //////////////////////////////////////////////// | 388 //////////////////////////////////////////////// |
389 // parse a config file | |
390 // | |
391 bool load_conf(CONFIG &dc, const char *fn) { | |
392 int count = 0; | |
393 TOKEN tok(fn, &dc.config_files); | |
394 while (true) { | |
395 const char *have = tok.next(); | |
396 if (!have) break; | |
397 if (have == token_context) { | |
398 if (!parse_context(tok, dc, NULL)) { | |
399 tok.token_error("load_conf() failed to parse context"); | |
400 return false; | |
401 } | |
402 else count++; | |
403 } | |
404 else { | |
405 tok.token_error(token_context, have); | |
406 return false; | |
407 } | |
408 } | |
409 tok.token_error("load_conf() found %d contexts in %s", count, fn); | |
410 return (!dc.contexts.empty()); | |
411 } | |
412 | |
413 | |
414 //////////////////////////////////////////////// | |
344 // init the tokens | 415 // init the tokens |
345 // | 416 // |
346 void token_init() { | 417 void token_init() { |
418 token_context = register_string("context"); | |
347 token_file = register_string("file"); | 419 token_file = register_string("file"); |
348 token_include = register_string("include"); | 420 token_include = register_string("include"); |
349 token_lbrace = register_string("{"); | 421 token_lbrace = register_string("{"); |
350 token_output = register_string("output"); | 422 token_output = register_string("output"); |
351 token_pattern = register_string("pattern"); | 423 token_pattern = register_string("pattern"); |