summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-16 13:38:00 +0100
committerGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-16 13:38:00 +0100
commit57f2fc4c766e65d2d7a601ab52c9b761957ba8db (patch)
tree032677066b6b9de8add32b8b412f17723116e1cd /src
parentc8787af0cf251521e63bbee5717fe0d11c657f7d (diff)
Adding libspy.
It needs to be used by smman as this will consume less cpu cycles than managing inotify events. When having a lot of logs, inotify events gets too annoying, thus the fact that we miss some of them. With libspy, files will be polled periodically, no matter the activity on them.
Diffstat (limited to 'src')
-rw-r--r--src/include/Spy.h25
-rw-r--r--src/lib/Makefile.mk12
-rw-r--r--src/lib/spy/spy_file.c208
-rw-r--r--src/lib/spy/spy_main.c157
-rw-r--r--src/lib/spy/spy_private.h44
5 files changed, 445 insertions, 1 deletions
diff --git a/src/include/Spy.h b/src/include/Spy.h
new file mode 100644
index 0000000..cc13da7
--- /dev/null
+++ b/src/include/Spy.h
@@ -0,0 +1,25 @@
1#ifndef SPY_H
2#define SPY_H
3#include <Eina.h>
4#include <Ecore.h>
5#include <Eio.h>
6
7extern int SPY_EVENT_LINE;
8
9typedef struct _Spy Spy;
10typedef struct _Spy_File Spy_File;
11typedef struct _Spy_Line Spy_Line;
12
13int spy_init(void);
14int spy_shutdown(void);
15
16Spy * spy_new(void);
17void spy_free(Spy *spy);
18
19Spy_File *spy_file_new(Spy *spy, const char *file);
20const char * spy_line_get(Spy_Line *sl);
21const char *spy_file_name_get(Spy_File *sf);
22void spy_file_data_set(Spy_File *sf, const void *data);
23const void *spy_file_data_get(Spy_File *sf);
24
25#endif
diff --git a/src/lib/Makefile.mk b/src/lib/Makefile.mk
index a4e2945..88771bb 100644
--- a/src/lib/Makefile.mk
+++ b/src/lib/Makefile.mk
@@ -1,10 +1,20 @@
1MAINTAINERCLEANFILES += src/lib/*.gc{no,da} 1MAINTAINERCLEANFILES += src/lib/*.gc{no,da}
2 2
3noinst_LTLIBRARIES = \ 3noinst_LTLIBRARIES = \
4src/lib/libconf.la 4src/lib/libconf.la \
5src/lib/libspy.la
5 6
6src_lib_libconf_la_SOURCES = \ 7src_lib_libconf_la_SOURCES = \
7src/lib/conf.c \ 8src/lib/conf.c \
8src/include/Conf.h 9src/include/Conf.h
9src_lib_libconf_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS) 10src_lib_libconf_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS)
10src_lib_libconf_la_LDFLAGS = $(LIBS_CFLAGS) 11src_lib_libconf_la_LDFLAGS = $(LIBS_CFLAGS)
12
13src_lib_libspy_la_SOURCES = \
14src/lib/spy/spy_file.c \
15src/lib/spy/spy_main.c \
16src/lib/spy/spy_private.h \
17src/include/Spy.h
18src_lib_libspy_la_CFLAGS = $(LIBS_CFLAGS) $(EXTRA_CPPFLAGS)
19src_lib_libspy_la_LDFLAGS = $(LIBS_CFLAGS)
20
diff --git a/src/lib/spy/spy_file.c b/src/lib/spy/spy_file.c
new file mode 100644
index 0000000..397862e
--- /dev/null
+++ b/src/lib/spy/spy_file.c
@@ -0,0 +1,208 @@
1#include "spy_private.h"
2
3static void
4_spy_file_job(void *data)
5{
6 spy_file_poll(data);
7}
8
9void
10_spy_file_line_free(void *d1,
11 void *d2 EINA_UNUSED)
12{
13 Spy_Line *sl = d1;
14
15 free((char *)sl->line);
16 free(sl);
17}
18
19void
20_spy_file_line_extract(Spy_File *sf)
21{
22 const char *s,
23 *p,
24 *p1;
25 size_t rm = 0;
26 Spy_Line *sl;
27
28 s = eina_strbuf_string_get(sf->read.buf);
29 p = s;
30
31 while ((p1=strchr(p, '\n')))
32 {
33 size_t l = p1 - p;
34 char *line;
35
36 rm += l;
37
38 if (!l)
39 goto end;
40
41 line = strndup(p, l);
42
43 DBG("Line = %s len=%zd", line, l);
44 sl = calloc(1, sizeof(Spy_Line));
45 if (!sl)
46 {
47 ERR("Failed to allocate Spy_Line");
48 free(line);
49 }
50
51 sl->sf = sf;
52 sl->line = line;
53 ecore_event_add(SPY_EVENT_LINE, sl, _spy_file_line_free, sl);
54 end:
55 p = p1 + 1;
56 }
57
58 eina_strbuf_remove(sf->read.buf, 0, rm);
59}
60
61void
62_spy_file_cb(void *data,
63 Ecore_Thread *thread EINA_UNUSED)
64{
65 Spy_File *sf;
66 size_t nbr = 0,
67 toread = 0,
68 left = 0;
69 char buf[512];
70
71 sf = data;
72 DBG("sf[%p]", sf);
73
74 sf->read.fd = fopen(sf->name, "r");
75 if (!sf->read.fd)
76 {
77 ERR("Failed to open %s : %s", sf->name, strerror(errno));
78 return;
79 }
80
81 fseeko(sf->read.fd, sf->read.offset, SEEK_SET);
82 left = sf->read.length;
83
84 while (nbr != (size_t)sf->read.length)
85 {
86 toread = (left < 512) ? left : 512;
87
88 if (fread(buf, toread, 1, sf->read.fd) != 1)
89 {
90 ERR("Error while reading file %s : %s",
91 sf->name, strerror(errno));
92 fclose(sf->read.fd);
93 return;
94 }
95 eina_strbuf_append_length(sf->read.buf, buf, toread);
96 _spy_file_line_extract(sf);
97 nbr += toread;
98 }
99 fclose(sf->read.fd);
100 sf->read.fd = NULL;
101}
102
103void
104_spy_file_end_cb(void *data,
105 Ecore_Thread *thread EINA_UNUSED)
106{
107 Spy_File *sf;
108
109 sf = data;
110 DBG("sf[%p]", sf);
111
112 ecore_timer_thaw(sf->poll.timer);
113 ecore_timer_reset(sf->poll.timer);
114
115 ecore_job_add(_spy_file_job, sf);
116}
117
118void
119_spy_file_cancel_cb(void *data EINA_UNUSED,
120 Ecore_Thread *thread EINA_UNUSED)
121{}
122
123Eina_Bool
124spy_file_poll(void *data)
125{
126 Spy_File *sf;
127 off_t size,
128 toread;
129 struct stat st;
130 Ecore_Thread *et;
131
132 sf = data;
133 DBG("spy_file[%p] file[%s]", sf, sf->name);
134
135 /* We should have different actions made depending on error type. */
136 if (stat(sf->name, &st))
137 {
138 ERR("Failed to get size of %s : %s", sf->name, strerror(errno));
139 return EINA_TRUE;
140 }
141
142 size = st.st_size;
143DBG("size=%zu", size);
144 if (sf->poll.size == size)
145 return EINA_TRUE;
146
147 /* File has been trunc! */
148 if (sf->poll.size > size)
149 {
150 DBG("spy_file[%p] File trunc!", sf);
151 sf->poll.size = 0;
152
153 if (!size)
154 return EINA_TRUE;
155 }
156
157 /* We have data to read! */
158 DBG("spy_file[%p] File activity!", sf);
159
160 toread = size - sf->poll.size;
161
162 DBG("spy_file[%p] len_old=%zu len_new=%zu toread=%zu",
163 sf, sf->poll.size, size, toread);
164
165 sf->read.offset = sf->poll.size;
166 sf->read.length = toread;
167
168
169 et = ecore_thread_run(_spy_file_cb,
170 _spy_file_end_cb,
171 _spy_file_cancel_cb,
172 sf);
173 if (!et)
174 {
175 ERR("Failed to create reading thread");
176 return EINA_TRUE;
177 }
178
179 ecore_timer_freeze(sf->poll.timer);
180 sf->poll.size = size;
181 return EINA_TRUE;
182}
183
184const char *
185spy_line_get(Spy_Line *sl)
186{
187 return sl->line;
188}
189
190
191const char *
192spy_file_name_get(Spy_File *sf)
193{
194 return sf->name;
195}
196
197void
198spy_file_data_set(Spy_File *sf,
199 const void *data)
200{
201 sf->data = (const void *)data;
202}
203
204const void *
205spy_file_data_get(Spy_File *sf)
206{
207 return sf->data;
208}
diff --git a/src/lib/spy/spy_main.c b/src/lib/spy/spy_main.c
new file mode 100644
index 0000000..8084050
--- /dev/null
+++ b/src/lib/spy/spy_main.c
@@ -0,0 +1,157 @@
1#include "spy_private.h"
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <unistd.h>
5
6static int _spy_init_count = 0;
7int _spy_log_dom_global = -1;
8
9int SPY_EVENT_LINE = 0;
10
11Spy *
12spy_new(void)
13{
14 Spy *spy;
15
16 spy = calloc(1, sizeof(Spy));
17 DBG("spy[%p]", spy);
18 return spy;
19}
20
21void
22spy_free(Spy *spy)
23{
24 Eina_Inlist *l;
25 Spy_File *sf;
26 EINA_SAFETY_ON_NULL_RETURN(spy);
27
28 EINA_INLIST_FOREACH_SAFE(spy->files, l, sf)
29 {
30 free((char *)sf->name);
31 ecore_timer_del(sf->poll.timer);
32 eina_strbuf_free(sf->read.buf);
33 }
34 free(spy);
35}
36
37Spy_File *
38spy_file_new(Spy *spy, const char *file)
39{
40 Spy_File *sf;
41 struct stat st;
42
43 DBG("spy[%p] file[%s]", spy, file);
44
45 if (access(file, R_OK))
46 {
47 ERR("Failed to access %s : %s", file, strerror(errno));
48 return EINA_FALSE;
49 }
50
51 sf = calloc(1, sizeof(Spy_File));
52 if (!sf)
53 {
54 ERR("Failed to allocate Spy_File structure");
55 return EINA_FALSE;
56 }
57
58 sf->name = (const char *)strdup(file);
59 if (!sf->name)
60 {
61 ERR("Failed to dupe string \"%s\"", file);
62 goto free_sf;
63 }
64
65 if (stat(file, &st))
66 {
67 ERR("Failed to get size of %s : %s", file, strerror(errno));
68 goto free_name;
69 }
70
71 sf->read.buf = eina_strbuf_new();
72 if (!sf->read.buf)
73 {
74 ERR("Failed to create stringbuffer");
75 goto free_name;
76 }
77
78 sf->poll.size = st.st_size;
79 sf->poll.timer = ecore_timer_add(5.0, spy_file_poll, sf);
80
81 spy->files = eina_inlist_append(spy->files, EINA_INLIST_GET(sf));
82 DBG("spy_file[%p] size[%zd]", sf, st.st_size);
83 return sf;
84
85free_name:
86 free((char *)sf->name);
87free_sf:
88 free(sf);
89 return NULL;
90}
91
92
93int
94spy_init(void)
95{
96 if (++_spy_init_count != 1)
97 return _spy_init_count;
98
99 if (!eina_init())
100 {
101 fprintf(stderr, "Spy can not initialize Eina\n");
102 return --_spy_init_count;
103 }
104
105 _spy_log_dom_global = eina_log_domain_register("spy", EINA_COLOR_RED);
106 if (_spy_log_dom_global < 0)
107 {
108 EINA_LOG_ERR("Spy can not create a general log domain");
109 goto shutdown_eina;
110 }
111
112 if (!ecore_init())
113 {
114 ERR("Can not initialize Ecore");
115 goto unregister_log_domain;
116 }
117
118 if (!eio_init())
119 {
120 ERR("Can not initialize Eio");
121 goto shutdown_ecore;
122 }
123
124 SPY_EVENT_LINE = ecore_event_type_new();
125
126 return _spy_init_count;
127
128shutdown_ecore:
129 ecore_shutdown();
130unregister_log_domain:
131 eina_log_domain_unregister(_spy_log_dom_global);
132 _spy_log_dom_global = -1;
133shutdown_eina:
134 eina_shutdown();
135 return --_spy_init_count;
136}
137
138
139int
140spy_shutdown(void)
141{
142 if (_spy_init_count <= 0)
143 {
144 fprintf(stderr, "Spy init count not greater than 0 in shutdown.");
145 return 0;
146 }
147
148 if (--_spy_init_count != 0)
149 return _spy_init_count;
150
151 eio_shutdown();
152 ecore_shutdown();
153 eina_log_domain_unregister(_spy_log_dom_global);
154 _spy_log_dom_global = -1;
155 eina_shutdown();
156 return _spy_init_count;
157}
diff --git a/src/lib/spy/spy_private.h b/src/lib/spy/spy_private.h
new file mode 100644
index 0000000..287ea44
--- /dev/null
+++ b/src/lib/spy/spy_private.h
@@ -0,0 +1,44 @@
1#include <Spy.h>
2
3extern int _spy_log_dom_global;
4
5#define ERR(...) EINA_LOG_DOM_ERR(_spy_log_dom_global, __VA_ARGS__)
6#define DBG(...) EINA_LOG_DOM_DBG(_spy_log_dom_global, __VA_ARGS__)
7#define NFO(...) EINA_LOG_DOM_INFO(_spy_log_dom_global, __VA_ARGS__)
8#define WRN(...) EINA_LOG_DOM_WARN(_spy_log_dom_global, __VA_ARGS__)
9#define CRI(...) EINA_LOG_DOM_CRIT(_spy_log_dom_global, __VA_ARGS__)
10
11struct _Spy
12{
13 Eina_Inlist *files;
14};
15
16
17struct _Spy_File
18{
19 EINA_INLIST;
20 const char *name;
21 const void *data;
22
23 struct
24 {
25 Ecore_Timer *timer;
26 off_t size;
27 } poll;
28
29 struct
30 {
31 FILE *fd;
32 off_t offset,
33 length;
34 Eina_Strbuf *buf;
35 } read;
36};
37
38struct _Spy_Line
39{
40 Spy_File *sf;
41 const char *line;
42};
43
44Eina_Bool spy_file_poll(void *data);