Mercurial > wflogs-daemon
comparison src/wflogs-config.cpp @ 0:0aa1171aebd2 stable-1-0-0
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 15 May 2013 13:15:59 -0700 |
parents | |
children | 400b1de6e1c6 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0aa1171aebd2 |
---|---|
1 /* | |
2 | |
3 Copyright (c) 2007 Carl Byington - 510 Software Group, released under | |
4 the GPL version 3 or any later version at your choice available at | |
5 http://www.gnu.org/licenses/gpl-3.0.txt | |
6 | |
7 */ | |
8 | |
9 #include "includes.h" | |
10 #include <fcntl.h> | |
11 #include <sys/socket.h> | |
12 #include <netinet/in.h> | |
13 #include <arpa/inet.h> | |
14 #include <netdb.h> | |
15 #include <limits.h> | |
16 | |
17 const char *token_context; | |
18 const char *token_file; | |
19 const char *token_include; | |
20 const char *token_lbrace; | |
21 const char *token_output; | |
22 const char *token_pattern; | |
23 const char *token_period; | |
24 const char *token_rbrace; | |
25 const char *token_semi; | |
26 const char *token_tempin; | |
27 const char *token_versions; | |
28 const char *token_wflogs; | |
29 | |
30 string_set all_strings;// owns all the strings, only modified by the config loader thread | |
31 const int maxlen = 1000; // used for snprintf buffers | |
32 | |
33 | |
34 | |
35 //////////////////////////////////////////////// | |
36 // | |
37 CONFIG::CONFIG() { | |
38 reference_count = 0; | |
39 fd = -1; | |
40 len = 0; | |
41 fdo = -1; | |
42 generation = 0; | |
43 load_time = 0; | |
44 period = 120; | |
45 versions = 3; | |
46 output = NULL; | |
47 tempin = NULL; | |
48 wflogs = NULL; | |
49 fn = NULL; | |
50 pattern = NULL; | |
51 } | |
52 | |
53 | |
54 CONFIG::~CONFIG() { | |
55 } | |
56 | |
57 | |
58 void CONFIG::sleep(int duration, time_t &previous) { | |
59 ::sleep(duration); | |
60 time_t now = time(NULL); | |
61 previous = now; | |
62 } | |
63 | |
64 | |
65 void CONFIG::free_all() { | |
66 regfree(&re); | |
67 close(); | |
68 closeo(); | |
69 } | |
70 | |
71 | |
72 void CONFIG::openo(bool msg) { | |
73 open_time = time(NULL); | |
74 fdo = ::creat(tempin, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | |
75 if (fdo == -1) { | |
76 if (msg) { | |
77 char buf[maxlen]; | |
78 snprintf(buf, sizeof(buf), "wflogs tempin file %s not writeable", tempin); | |
79 tokp->token_error(buf); | |
80 } | |
81 } | |
82 } | |
83 | |
84 | |
85 void CONFIG::open(bool msg) { | |
86 fd = ::open(fn, O_RDONLY); | |
87 len = 0; | |
88 if (fd == -1) { | |
89 if (msg) { | |
90 char buf[maxlen]; | |
91 snprintf(buf, sizeof(buf), "syslog file %s not readable", fn); | |
92 tokp->token_error(buf); | |
93 } | |
94 } | |
95 else { | |
96 if (debug_syslog > 1) { | |
97 snprintf(buf, sizeof(buf), "syslog file %s opened", fn); | |
98 my_syslog(buf); | |
99 } | |
100 if (msg) lseek(fd, 0, SEEK_END); | |
101 if (fstat(fd, &openfdstat)) { | |
102 close(); | |
103 snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", fn); | |
104 tokp->token_error(buf); | |
105 } | |
106 // specify that this fd gets closed on exec, so that selinux | |
107 // won't complain about iptables trying to read log files. | |
108 int oldflags = fcntl(fd, F_GETFD, 0); | |
109 if (oldflags >= 0) { | |
110 fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC); | |
111 } | |
112 } | |
113 } | |
114 | |
115 | |
116 bool CONFIG::write(char *p) { | |
117 // p points to \0 at end of buf, may be destroyed | |
118 if (failedo()) { | |
119 openo(false); | |
120 if (failedo()) return false; | |
121 } | |
122 *p = '\n'; | |
123 ::write(fdo, buf, p-buf+1); | |
124 } | |
125 | |
126 | |
127 bool CONFIG::read() { | |
128 if (failed()) { | |
129 open(false); | |
130 if (failed()) return false; | |
131 } | |
132 int n = ::read(fd, buf+len, buflen-len); | |
133 bool have = (n > 0); | |
134 if (have) { | |
135 len += n; | |
136 while (true) { | |
137 char *p = (char*)memchr(buf, '\n', len); | |
138 if (!p) break; | |
139 n = p-buf; | |
140 *p = '\0'; | |
141 process(p); // process null terminated string, but may destroy the null | |
142 len -= n+1; | |
143 memmove(buf, p+1, len); | |
144 } | |
145 // no <lf> in a full buffer | |
146 if (len == buflen) len = 0; | |
147 } | |
148 else { | |
149 // check for file close | |
150 struct stat filenamest; | |
151 if (0 == stat(fn, &filenamest)) { | |
152 if ((filenamest.st_dev != openfdstat.st_dev) || | |
153 (filenamest.st_ino != openfdstat.st_ino)) { | |
154 close(); | |
155 } | |
156 } | |
157 else { | |
158 // filename no longer exists | |
159 close(); | |
160 } | |
161 } | |
162 check_wflog(); | |
163 return have; | |
164 } | |
165 | |
166 | |
167 void CONFIG::closeo() { | |
168 if (fdo != -1) ::close(fdo); | |
169 fdo = -1; | |
170 } | |
171 | |
172 | |
173 void CONFIG::close() { | |
174 if (debug_syslog > 1) { | |
175 snprintf(buf, sizeof(buf), "syslog file %s closed", fn); | |
176 my_syslog(buf); | |
177 } | |
178 if (fd != -1) ::close(fd); | |
179 fd = -1; | |
180 } | |
181 | |
182 | |
183 void CONFIG::process(char *p) { | |
184 // p points to \0 at end of buf, may be destroyed | |
185 if (pattern) { | |
186 if (0 == regexec(&re, buf, 0, NULL, 0)) { | |
187 if (debug_syslog > 2) { | |
188 my_syslog(buf); // show lines with matches | |
189 } | |
190 write(p); | |
191 } | |
192 } | |
193 } | |
194 | |
195 | |
196 void CONFIG::check_wflog() { | |
197 time_t now = time(NULL); | |
198 if ((fdo != -1) && (open_time + period < now)) { | |
199 closeo(); | |
200 // rename previous wflog html output files | |
201 char buf[maxlen]; | |
202 char fn1[maxlen]; | |
203 char fn2[maxlen]; | |
204 for (int i=1; i<versions; i++) { | |
205 int j = versions - 1 - i; | |
206 int k = j + 1; | |
207 snprintf(fn1, maxlen, output, j); | |
208 snprintf(fn2, maxlen, output, k); | |
209 snprintf(buf, maxlen, "mv \"%s\" \"%s\"", fn1, fn2); | |
210 system(buf); | |
211 } | |
212 snprintf(buf, maxlen, wflogs, fn1); | |
213 system(buf); | |
214 openo(false); | |
215 } | |
216 } | |
217 | |
218 | |
219 void CONFIG::dump() { | |
220 int level = 0; | |
221 char indent[maxlen]; | |
222 int i = min(maxlen-1, level*4); | |
223 memset(indent, ' ', i); | |
224 indent[i] = '\0'; | |
225 printf("%s period %d; \n", indent, period); | |
226 printf("%s versions %d; \n", indent, versions); | |
227 printf("%s output \"%s\";\n", indent, output); | |
228 printf("%s tempin \"%s\";\n", indent, tempin); | |
229 printf("%s wflogs \"%s\";\n", indent, wflogs); | |
230 printf("%s file \"%s\";\n", indent, fn); | |
231 printf("%s pattern \"%s\";\n", indent, pattern); | |
232 } | |
233 | |
234 | |
235 //////////////////////////////////////////////// | |
236 // helper to discard the strings held by a string_set | |
237 // | |
238 void discard(string_set &s) { | |
239 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { | |
240 free((void*)*i); | |
241 } | |
242 s.clear(); | |
243 } | |
244 | |
245 | |
246 //////////////////////////////////////////////// | |
247 // helper to register a string in a string set | |
248 // | |
249 const char* register_string(string_set &s, const char *name) { | |
250 string_set::const_iterator i = s.find(name); | |
251 if (i != s.end()) return *i; | |
252 char *x = strdup(name); | |
253 s.insert(x); | |
254 return x; | |
255 } | |
256 | |
257 | |
258 //////////////////////////////////////////////// | |
259 // register a global string | |
260 // | |
261 const char* register_string(const char *name) { | |
262 return register_string(all_strings, name); | |
263 } | |
264 | |
265 | |
266 //////////////////////////////////////////////// | |
267 // clear all global strings, helper for valgrind checking | |
268 // | |
269 void clear_strings() { | |
270 discard(all_strings); | |
271 } | |
272 | |
273 | |
274 //////////////////////////////////////////////// | |
275 // | |
276 bool tsa(TOKEN &tok, const char *token); | |
277 bool tsa(TOKEN &tok, const char *token) { | |
278 const char *have = tok.next(); | |
279 if (have == token) return true; | |
280 tok.token_error(token, have); | |
281 return false; | |
282 } | |
283 | |
284 | |
285 //////////////////////////////////////////////// | |
286 // parse a config file | |
287 // | |
288 bool load_conf(CONFIG &dc, const char *fn) { | |
289 TOKEN tok(fn, &dc.config_files); | |
290 dc.set_token(tok); | |
291 while (true) { | |
292 const char *have = tok.next(); | |
293 if (!have) break; | |
294 if (have == token_period) { | |
295 have = tok.next(); | |
296 dc.set_period(atoi(have)); | |
297 if (!tsa(tok, token_semi)) return false; | |
298 } | |
299 else if (have == token_versions) { | |
300 have = tok.next(); | |
301 dc.set_versions(atoi(have)); | |
302 if (!tsa(tok, token_semi)) return false; | |
303 } | |
304 else if (have == token_output) { | |
305 dc.set_output(tok.next()); | |
306 if (!tsa(tok, token_semi)) return false; | |
307 } | |
308 else if (have == token_tempin) { | |
309 dc.set_tempin(tok.next()); | |
310 if (!tsa(tok, token_semi)) return false; | |
311 } | |
312 else if (have == token_wflogs) { | |
313 dc.set_wflogs(tok.next()); | |
314 if (!tsa(tok, token_semi)) return false; | |
315 } | |
316 else if (have == token_file) { | |
317 dc.set_file(tok.next()); | |
318 if (!tsa(tok, token_semi)) return false; | |
319 } | |
320 else if (have == token_pattern) { | |
321 dc.pattern = tok.next(); | |
322 int rc = regcomp(&dc.re, dc.pattern, REG_ICASE | REG_EXTENDED); | |
323 if (rc) { | |
324 char bu[maxlen]; | |
325 regerror(rc, &dc.re, bu, maxlen); | |
326 char buf[maxlen]; | |
327 snprintf(buf, sizeof(buf), "pattern %s not valid - %s", dc.pattern, bu); | |
328 tok.token_error(buf); | |
329 dc.pattern = NULL; | |
330 } | |
331 | |
332 if (!tsa(tok, token_semi)) return false; | |
333 } | |
334 else { | |
335 tok.token_error("statement", have); | |
336 return false; | |
337 } | |
338 } | |
339 return true; | |
340 } | |
341 | |
342 | |
343 //////////////////////////////////////////////// | |
344 // init the tokens | |
345 // | |
346 void token_init() { | |
347 token_file = register_string("file"); | |
348 token_include = register_string("include"); | |
349 token_lbrace = register_string("{"); | |
350 token_output = register_string("output"); | |
351 token_pattern = register_string("pattern"); | |
352 token_period = register_string("period"); | |
353 token_rbrace = register_string("}"); | |
354 token_semi = register_string(";"); | |
355 token_tempin = register_string("tempin"); | |
356 token_versions = register_string("versions"); | |
357 token_wflogs = register_string("wflogs"); | |
358 } |