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");