summaryrefslogtreecommitdiff
path: root/src/bin/spy.c
diff options
context:
space:
mode:
authorkuri igen <kuri@e4.enlightenment.org>2011-01-25 15:45:51 +0100
committerkuri igen <kuri@e4.enlightenment.org>2011-01-25 15:45:51 +0100
commitc2a6bb5b1a4ae437e11231ee637db262f78eb571 (patch)
tree426c0d60d5b551cb833db4463f6aa5bd1c43ec7f /src/bin/spy.c
Ajout des fichiers du projet smman
Diffstat (limited to 'src/bin/spy.c')
-rw-r--r--src/bin/spy.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/bin/spy.c b/src/bin/spy.c
new file mode 100644
index 0000000..9672d16
--- /dev/null
+++ b/src/bin/spy.c
@@ -0,0 +1,355 @@
1/*
2 * Copyright © 2011 ASP64 <guillaume.friloux@asp64.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19/**
20 * @file spy.c
21 * @brief Contains functions that monitors logfiles
22 * @author Guillaume Friloux <guillaume.friloux@asp64.com>
23 * @version 1.0
24 *
25 * @bug : In rules, use wildcards only for filenames, not directories
26 *
27 * Contains functions that monitors logfiles
28 */
29#include "spy.h"
30
31/**
32 * @fn int spy_init(void)
33 * @brief Will ask rules_list() to list all rules and tell spy_addwatcher()
34 * of every found rule so we can process it and monitor matching log files
35 *
36 * @return 0
37 */
38int spy_init(void)
39{
40 rules_list(spy_addwatcher);
41 return(0);
42}
43
44/**
45 * @fn int spy_addwatcher(struct rule *foundrule)
46 * @brief Gets a rule in param, and will check for every matching
47 * files on the system
48 *
49 * @param foundrule (struct rule *) Rule found by rules_list()
50 *
51 * @return 0 if no error, -1 if any error
52 */
53int spy_addwatcher(struct rule *foundrule)
54{
55 wordexp_t p;
56 int ret;
57 unsigned int i;
58 char *ptr,
59 tmp[512];
60
61 if( !foundrule->filename )
62 return(0);
63
64 // As filenames can contain wildcards, we have to test
65 // Globbing
66 ret = wordexp(foundrule->filename, &p, 0);
67 if( ret )
68 {
69 EINA_LOG_DOM_ERR(einadom_spy, "l utilisation de wordexp() a echoue, il a renvoye %d", ret);
70 return(-1);
71 }
72
73 EINA_LOG_DOM_DBG(einadom_spy, "Found %d results for %s", p.we_wordc, foundrule->filename);
74
75 // We now have a list of files (or a unique file) and we want to add them
76 // To our file list
77 for( i = 0; i < p.we_wordc; i++)
78 {
79 int exist = 0;
80
81 exist = logfiles_exist(p.we_wordv[i]);
82
83 if( !exist )
84 {
85 fpos_t pos_tmp;
86 struct logfile *new_logfile;
87 unsigned long long int filesize = 0;
88
89 // We get our cursor pos
90 logfiles_getend(p.we_wordv[i], &pos_tmp);
91 logfiles_getsize(p.we_wordv[i], &filesize);
92 logfiles_new(&new_logfile, p.we_wordv[i], pos_tmp, filesize);
93
94 logfiles_add(new_logfile);
95 efm = ecore_file_monitor_add(p.we_wordv[i],
96 (Ecore_File_Monitor_Cb)spy_event,
97 (void *)new_logfile);
98 }
99 }
100 wordfree(&p);
101
102 // We will check parent directory to see if a new file is created
103 // and matches one of the rules when a CREATE event is raised.
104 // This part sucks cause we only watch the last directory while
105 // The wildcard can englob multiple directories! (and so our code gets totally buggy)
106 strncpy(tmp, foundrule->filename, 512);
107 ptr = dirname(tmp);
108 efm = ecore_file_monitor_add(ptr,
109 (Ecore_File_Monitor_Cb)spy_event,
110 NULL);
111
112 return(0);
113}
114
115/**
116 * @fn int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path)
117 * @brief ecore_main_loop() will call this function for every notification he gets from logfiles
118 * activity.
119 *
120 * @param data (void *) Data associated to the logfile in spy_addwatcher()
121 * @param em (Ecore_File_Monitor *) Not really used here.
122 * @param event (Ecore_File_Event) Event type
123 * @param path (const char *) Name of the file that raised the event
124 *
125 * @return ECORE_CALLBACK_RENEW
126 */
127int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path)
128{
129 struct logmessage *new_logmessage;
130 char message[4096];
131
132 EINA_LOG_DOM_DBG(einadom_spy, "Event on %s ! %p - %p", path, data, em);
133 message[0] = 0;
134
135 if( event == ECORE_FILE_EVENT_MODIFIED )
136 {
137 struct logfile *log = data;
138 fpos_t new_pos;
139 unsigned long long int filesize;
140
141 if( !log )
142 return(ECORE_CALLBACK_RENEW);
143
144 // If logfile got trunc, than size is different
145 logfiles_getsize((char *)path, &filesize);
146
147 if( filesize < log->filesize )
148 {
149 // If event is that file has been truncated, then there is
150 // nothing to read, we just set cursor to beginning
151 logfiles_getbegin((char *)path, &(log->cursor));
152 log->filesize = filesize;
153 return(ECORE_CALLBACK_RENEW);
154 }
155 log->filesize = filesize;
156
157 EINA_LOG_DOM_DBG(einadom_spy, "Event on %s - %d !", path, log->cursor);
158
159 // We must take attention to the fact that the file might
160 // Have been truncated
161 spy_extract_new_lines(log->name, log->cursor, &new_pos, message);
162 log->cursor = new_pos;
163
164 // If nothing has been read, then file has been trunc and is empty
165 // So we do nothing
166 if( message[0] == 0 )
167 return(ECORE_CALLBACK_RENEW);
168
169 logmessages_new(&new_logmessage, message, log->name);
170
171
172 rules_filtermessage(new_logmessage);
173
174 // Now we only have to send this filtered message to ES
175 if( !new_logmessage->todel )
176 send_logmessage(new_logmessage);
177
178 // Message is sent, we can free our structure
179 logmessages_free(&new_logmessage);
180 }
181 else if( event == ECORE_FILE_EVENT_DELETED_SELF
182 || event == ECORE_FILE_EVENT_DELETED_DIRECTORY
183 || event == ECORE_FILE_EVENT_DELETED_FILE
184 )
185 {
186 struct logfile *log = data,
187 *foundlog;
188 Eina_List *l;
189 EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been deleted!", path);
190
191 // If this file was one of the files we used to monitor,
192 // We must delete it from our list
193 EINA_LIST_FOREACH(list_logfiles, l, foundlog)
194 {
195 if( !strcmp(foundlog->name, path) )
196 {
197 list_logfiles = eina_list_remove(list_logfiles, log);
198 logfiles_del(&log);
199 break;
200 }
201 }
202 }
203 else if( event == ECORE_FILE_EVENT_CREATED_FILE
204 || event == ECORE_FILE_EVENT_CREATED_DIRECTORY
205 )
206 {
207 // A new log file has been made, we have to check if this file already is in our filelog
208 // And if a rule affects it.
209 // If so, we add it to our monitor
210 Eina_List *l;
211 struct rule *foundrule = NULL;
212 struct logfile *new_logfile = NULL;
213 fpos_t pos_tmp;
214 int ret,
215 got_it = 0;
216
217 EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been created!", path);
218
219 // If we already monitor this file, then we ignore it
220 // Which might be a problem btw. This thing shouldnt happen
221 EINA_LIST_FOREACH(list_logfiles, l, new_logfile)
222 {
223 if( !strcmp(new_logfile->name, path) )
224 return(ECORE_CALLBACK_RENEW);
225
226 }
227
228 EINA_LIST_FOREACH(list_rules, l, foundrule)
229 {
230 if( foundrule->filename )
231 {
232 unsigned long long int filesize;
233 ret = fnmatch(foundrule->filename, path, FNM_NOESCAPE);
234 if( ret )
235 continue;
236
237 // We get our cursor pos
238 logfiles_getbegin((char *)path, &pos_tmp);
239 logfiles_getsize((char *)path, &filesize);
240 logfiles_new(&new_logfile, (char *)path, pos_tmp, filesize);
241
242 logfiles_add(new_logfile);
243 efm = ecore_file_monitor_add(path,
244 (Ecore_File_Monitor_Cb)spy_event,
245 (void *)new_logfile);
246
247 got_it = 1;
248 break;
249 }
250 }
251
252 if( got_it )
253 {
254 // We must take attention to the fact that the file might
255 // Have been truncated
256 spy_extract_new_lines(new_logfile->name, new_logfile->cursor, &new_logfile->cursor, message);
257
258 // If nothing has been read, then file has been trunc and is empty
259 // So we do nothing
260 if( message[0] == 0 )
261 return(ECORE_CALLBACK_RENEW);
262
263 logmessages_new(&new_logmessage, message, new_logfile->name);
264 rules_filtermessage(new_logmessage);
265
266 // Now we only have to send this filtered message to ES
267 if( !new_logmessage->todel )
268 send_logmessage(new_logmessage);
269
270 // Message is sent, we can free our structure
271 logmessages_free(&new_logmessage);
272 }
273 }
274 else
275 {
276 EINA_LOG_DOM_DBG(einadom_spy, "WTF event on %s !", path);
277
278 }
279 return(ECORE_CALLBACK_RENEW);
280}
281
282
283
284/**
285 * @fn int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message)
286 * @brief Gets the new log message that has been inserted. This function kind of sucks and has to
287 * be improved to really extract all the messages and send them to a callback that will
288 * process them intead of taking only one (which can cause a problem if we don't get
289 * one inotify per message logged).
290 *
291 * @param filename (char *) File that raised an event and should be read
292 * @param pos_cur (fpos_t) current cursor position for this file
293 * @param pos_new (fpos_t *) New position of the cursor after extracting the new message
294 * @param message (char *) message extracted from the logfile
295 *
296 * @return 0 or -1 if there is an error
297 */
298int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message)
299{
300 FILE *fp;
301 int ret;
302 fpos_t pos_begin;
303
304 fp = fopen(filename, "r");
305 if( !fp )
306 {
307 EINA_LOG_DOM_ERR(einadom_spy, "We haven't been able to open %s : %s", filename, strerror(errno));
308 return(-1);
309 }
310
311 fgetpos(fp, &pos_begin);
312
313
314 // If we can't set cursor, file has been truncated!
315 ret = fsetpos(fp, &pos_cur);
316 if( ret )
317 {
318 fsetpos(fp, &pos_begin);
319 *pos_new = pos_begin;
320 }
321 else *pos_new = pos_cur;
322
323 // This while is only here to avoid empty lines
324 while( 1 )
325 {
326 ret = fscanf(fp,"%4096[^\n]\n", message);
327
328 if( ret == EOF )
329 break;
330
331 // Didnt read anything
332 if( ret == 0)
333 {
334 char tmp[2];
335 EINA_LOG_DOM_DBG(einadom_spy, "Empty line hack");
336 ret = fread(tmp, 1, 1, fp);
337 if( ret != 1 )
338 EINA_LOG_DOM_DBG(einadom_spy, "WTF?!");
339 continue;
340 }
341 if( ret != 1 )
342 {
343 fgetpos(fp, pos_new);
344 EINA_LOG_DOM_DBG(einadom_spy, "Break! new_pos = %d", *pos_new);
345 break;
346 }
347 else
348 fgetpos(fp, pos_new);
349
350 // We have a message to log
351 }
352
353 fclose(fp);
354 return(0);
355}