summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-18 14:07:27 +0100
committerGuillaume Friloux <guillaume.friloux@gmail.com>2013-12-18 14:07:27 +0100
commitdbb099df5455a2932b9ed3b12258cff8faca513b (patch)
tree34ed6643ddf96c7864139bc6fd3e9f02def16139 /src
parent2c55710a9d04323fc698f49047432b3e231d2ca7 (diff)
Rewrite of smman.
Diffstat (limited to 'src')
-rw-r--r--src/bin/Makefile.mk11
-rw-r--r--src/bin/conf.c85
-rw-r--r--src/bin/config.c40
-rw-r--r--src/bin/filter.c35
-rw-r--r--src/bin/logfiles.c194
-rw-r--r--src/bin/logmessages.c171
-rw-r--r--src/bin/main.c128
-rw-r--r--src/bin/rules.c307
-rw-r--r--src/bin/send.c257
-rw-r--r--src/bin/smman.h163
-rw-r--r--src/bin/spy.c349
-rw-r--r--src/bin/utils.c47
12 files changed, 186 insertions, 1601 deletions
diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk
index 3767425..169a3ff 100644
--- a/src/bin/Makefile.mk
+++ b/src/bin/Makefile.mk
@@ -1,18 +1,13 @@
1MAINTAINERCLEANFILES += \ 1MAINTAINERCLEANFILES += \
2src/bin/sds_horodatage/*.gc{no,da} 2src/bin/*.gc{no,da}
3 3
4bin_PROGRAMS += \ 4bin_PROGRAMS += \
5src/bin/smman 5src/bin/smman
6 6
7src_bin_smman_SOURCES = \ 7src_bin_smman_SOURCES = \
8src/bin/conf.c \
9src/bin/utils.c \
10src/bin/logfiles.c \
11src/bin/logmessages.c \
12src/bin/main.c \ 8src/bin/main.c \
13src/bin/rules.c \ 9src/bin/config.c \
14src/bin/send.c \ 10src/bin/smman.h
15src/bin/spy.c
16src_bin_smman_CPPFLAGS = @BIN_CFLAGS@ $(EXTRA_CPPFLAGS) 11src_bin_smman_CPPFLAGS = @BIN_CFLAGS@ $(EXTRA_CPPFLAGS)
17src_bin_smman_LDFLAGS = @BIN_LIBS@ 12src_bin_smman_LDFLAGS = @BIN_LIBS@
18src_bin_smman_LDADD = \ 13src_bin_smman_LDADD = \
diff --git a/src/bin/conf.c b/src/bin/conf.c
deleted file mode 100644
index c185f61..0000000
--- a/src/bin/conf.c
+++ /dev/null
@@ -1,85 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20#include <Conf.h>
21
22/**
23 * @brief This function will init libconf and ask to load our configuration
24 * file
25 *
26 * @return 0
27 */
28int conf_load(void)
29{
30 struct libconfig myconf;
31
32 strcpy(global_ESserver, "http://127.0.0.1:9200/logstash/events/");
33 strcpy(global_rulesdir, "/etc/smman/rules.d/");
34 strcpy(global_conf, "/etc/smman/smman.conf");
35 strcpy(global_type, "syslog");
36 gethostname(global_host, sizeof(global_host));
37
38 einadom_rules = eina_log_domain_register("smman_rules" , EINA_COLOR_LIGHTRED);
39 einadom_spy = eina_log_domain_register("smman_spy" , EINA_COLOR_LIGHTRED);
40 einadom_logfiles = eina_log_domain_register("smman_logfiles", EINA_COLOR_LIGHTRED);
41 einadom_send = eina_log_domain_register("smman_send" , EINA_COLOR_LIGHTRED);
42 einadom_conf = eina_log_domain_register("smman_conf" , EINA_COLOR_LIGHTRED);
43
44 libconfig_init(global_conf, &myconf);
45 libconfig_load(&myconf);
46
47 libconfig_list(&myconf, conf_load_var);
48
49 libconfig_free(&myconf);
50 return(0);
51}
52
53/**
54 * @brief This function is a callback for libconf, and receives a variable +
55 * its value found in a configuration file
56 *
57 * @param variable (char *) Variable's name
58 * @param value (char *) Variable's value
59 *
60 * @return 0
61 */
62int conf_load_var(char *variable, char *value)
63{
64 if( !strcmp(variable, "server") )
65 {
66 EINA_LOG_DOM_DBG(einadom_conf, "Setting ES server to %s", variable);
67 strcpy(global_ESserver, value);
68 }
69 else if( !strcmp(variable, "host") )
70 {
71 EINA_LOG_DOM_DBG(einadom_conf, "Setting default hostname to %s", variable);
72 strcpy(global_host, value);
73 }
74 else if( !strcmp(variable, "type") )
75 {
76 EINA_LOG_DOM_DBG(einadom_conf, "Setting default type to %s", variable);
77 strcpy(global_type, value);
78 }
79 else
80 {
81 EINA_LOG_DOM_ERR(einadom_conf, "Unknown config variable %s", variable);
82 }
83
84 return(0);
85}
diff --git a/src/bin/config.c b/src/bin/config.c
new file mode 100644
index 0000000..65b2637
--- /dev/null
+++ b/src/bin/config.c
@@ -0,0 +1,40 @@
1#include "smman.h"
2
3void
4config_done(void *data,
5 Conf *conf)
6{
7 Smman *smman;
8 Eina_Iterator *it;
9
10 smman = data;
11
12 it = eina_hash_iterator_tuple_new(conf_variables_get(conf));
13 while (eina_iterator_next(it, &data))
14 {
15 const char *variable,
16 *value;
17 Eina_Hash_Tuple *t = data;
18
19 variable = t->key;
20 value = t->data;
21
22 if (!strcmp("server", variable))
23 smman->cfg.server = strdup(value);
24 else if (!strcmp("host", variable))
25 smman->cfg.host = strdup(value);
26 }
27
28 DBG("Server = %s", smman->cfg.server);
29 DBG("Host = %s", smman->cfg.host);
30 eina_iterator_free(it);
31}
32
33void
34config_error(void *data EINA_UNUSED,
35 Conf *conf EINA_UNUSED,
36 const char *errstr)
37{
38 ERR("Failed to load /etc/smman/smman.conf : %s", errstr);
39 ecore_main_loop_quit();
40}
diff --git a/src/bin/filter.c b/src/bin/filter.c
new file mode 100644
index 0000000..f5095ed
--- /dev/null
+++ b/src/bin/filter.c
@@ -0,0 +1,35 @@
1#include "smman.h"
2
3void
4filter_load(void *data,
5 Rules *rules,
6 Rule *rule)
7{
8
9
10}
11
12void
13filter_load_done(void *data,
14 Rules *rules)
15{
16
17
18}
19
20
21void
22filter_load_error(void *data,
23 Rules *rules,
24 const char *errstr)
25{
26 Smman *smman;
27
28 smman = data;
29
30 if (smman->rules != rules)
31 return;
32
33 ERR("Failed to load rules : %s", errstr);
34 ecore_main_loop_quit();
35}
diff --git a/src/bin/logfiles.c b/src/bin/logfiles.c
deleted file mode 100644
index c8f08a8..0000000
--- a/src/bin/logfiles.c
+++ /dev/null
@@ -1,194 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23
24#include "smman.h"
25
26/**
27 * @brief Checks in the list of log files we are watching if we
28 * already watch a given logfile
29 *
30 * @param logfile (char *) Name of the logfile to check
31 *
32 * @return 0 if not found, 1 if found
33 */
34int logfiles_exist(char *logfile)
35{
36 Eina_List *l;
37 struct logfile *foundlogfile = NULL;
38 EINA_LIST_FOREACH(list_logfiles, l, foundlogfile)
39 {
40 if( !strcmp(foundlogfile->name, logfile) )
41 {
42 return(1);
43 }
44 }
45
46 return(0);
47}
48
49/**
50 * @brief Adds a logfile struct inside the logfiles list
51 *
52 * @param new_logfile (struct logfile *) structure to add
53 *
54 * @return 0 if not found, 1 if found
55 */
56int logfiles_add(struct logfile *new_logfile)
57{
58 list_logfiles = eina_list_append(list_logfiles, new_logfile);
59 return(0);
60}
61
62/**
63 * @brief Prints on stdout the list of logfiles. Only usefull for a bit of
64 * monitoring of what is going on
65 *
66 * @return 0 if not found, 1 if found
67 */
68int logfiles_print(void)
69{
70 Eina_List *l;
71 struct logfile *foundlogfile = NULL;
72 EINA_LIST_FOREACH(list_logfiles, l, foundlogfile)
73 {
74 EINA_LOG_DOM_INFO(einadom_logfiles, "Name = %s", foundlogfile->name);
75 }
76 return(0);
77}
78
79/**
80 * @brief Will alloc a new logfile structure and set given values
81 *
82 * @param new_logfile (struct logfile *) structure to alloc
83 * @param filename (char *) Name of the logfile
84 * @param cursor (fpos_t) Position of the cursor
85 * @param filesize (unsigned long long int) Size of the file
86 *
87 * @return 0
88 */
89int logfiles_new(struct logfile **new_logfile, char *filename, fpos_t cursor, unsigned long long int filesize)
90{
91 *new_logfile = malloc(sizeof(struct logfile));
92 (*new_logfile)->name = malloc(sizeof(char) * ( strlen(filename) + 1 ) );
93 strcpy( (*new_logfile)->name, filename);
94 (*new_logfile)->cursor = cursor;
95 (*new_logfile)->filesize = filesize;
96
97 return(0);
98}
99
100/**
101 * @brief This function will free an allocated logfile structure
102 *
103 * @param old_logfile (struct logfile **) structure to free
104 *
105 * @return 0
106 */
107int logfiles_del(struct logfile **old_logfile)
108{
109 if( !(*old_logfile) )
110 return(0);
111
112 if( (*old_logfile)->name )
113 free((*old_logfile)->name);
114
115 free((*old_logfile));
116 return(0);
117}
118
119/**
120 * @brief This function will get a cursor to the end of the file
121 *
122 * @param logfile (char *) logfile involved
123 * @param pos_end (fpos_t *) pointer used to store the position
124 *
125 * @return 0 or -1 if an error occur
126 */
127int logfiles_getend(char *logfile, fpos_t *pos_end)
128{
129 FILE *fp;
130
131 // We get our cursor pos
132 fp = fopen(logfile, "r");
133 if( !fp )
134 {
135 EINA_LOG_DOM_ERR(einadom_logfiles, "Can't open %s : %s", logfile, strerror(errno));
136 return(-1);
137 }
138 fseeko(fp, 0L, SEEK_END);
139 fgetpos(fp, pos_end);
140
141 fclose(fp);
142 return(0);
143}
144
145/**
146 * @brief This function will get a cursor to the begin of the file
147 *
148 * @param logfile (char *) logfile involved
149 * @param pos_begin (fpos_t *) pointer used to store the position
150 *
151 * @return 0 or -1 if an error occur
152 */
153int logfiles_getbegin(char *logfile, fpos_t *pos_begin)
154{
155 FILE *fp;
156
157 // We get our cursor pos
158 fp = fopen(logfile, "r");
159 if( !fp )
160 {
161 EINA_LOG_DOM_ERR(einadom_logfiles, "Can't open %s : %s", logfile, strerror(errno));
162 return(-1);
163 }
164 fgetpos(fp, pos_begin);
165
166 fclose(fp);
167 return(0);
168}
169
170/**
171 * @brief This function will get the size of a file
172 *
173 * @param logfile (char *) logfile involved
174 * @param filesize (unsigned long long int) pointer used to store the size
175 *
176 * @return 0 or -1 if an error occur
177 */
178int logfiles_getsize(char *logfile, unsigned long long int *filesize)
179{
180 struct stat64 st_buffer;
181 int retour;
182
183 retour = stat64(logfile, &st_buffer);
184
185 if( retour )
186 {
187 EINA_LOG_DOM_ERR(einadom_logfiles, "Can't get size of %s : %s", logfile, strerror(errno));
188 return(-1);
189 }
190
191 *filesize = st_buffer.st_size;
192
193 return(0);
194}
diff --git a/src/bin/logmessages.c b/src/bin/logmessages.c
deleted file mode 100644
index aece58c..0000000
--- a/src/bin/logmessages.c
+++ /dev/null
@@ -1,171 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20
21/**
22 * @brief This function will init a given logmessage structure with default values
23 *
24 * @param new_logmessage (struct logmessage **) struct to alloc
25 * @param message (char *) Log message to store in this structure
26 * @param logname (char *) Name of the log file
27 *
28 * @return 0
29 */
30int logmessages_new(struct logmessage **new_logmessage, char *message, char *logname)
31{
32 *new_logmessage = malloc(sizeof(struct logmessage));
33
34 if( message )
35 {
36 (*new_logmessage)->message = malloc( sizeof(char) * ( strlen(message) + 1) );
37 strcpy((*new_logmessage)->message, message);
38 }
39 else
40 {
41 (*new_logmessage)->message = malloc( sizeof(char) * (1) );
42 (*new_logmessage)->message[0] = 0;
43 }
44 (*new_logmessage)->source_path = malloc( sizeof(char) * ( strlen(logname) + 1 ) );
45 strcpy( (*new_logmessage)->source_path, logname);
46
47 (*new_logmessage)->source_host = malloc( sizeof(char) * ( strlen(global_host) + 1 ) );
48 strcpy( (*new_logmessage)->source_host, global_host);
49
50 (*new_logmessage)->type = malloc( sizeof(char) * ( strlen(global_type) + 1 ) );
51 strcpy( (*new_logmessage)->type, global_type);
52
53 (*new_logmessage)->timestamp = utils_date();
54
55 (*new_logmessage)->list_tags = NULL;
56 (*new_logmessage)->todel = 0;
57 return(0);
58}
59
60/**
61 * @brief This function will free everything allocated in the structure
62 *
63 * @param old_logmessage (struct logmessage **) struct to free
64 *
65 * @return 0
66 */
67int logmessages_free(struct logmessage **old_logmessage)
68{
69 char *ptr;
70 if( (*old_logmessage)->source_host )
71 free( (*old_logmessage)->source_host);
72 free( (*old_logmessage)->source_path);
73 free( (*old_logmessage)->type);
74 free( (*old_logmessage)->message);
75 free( (*old_logmessage)->timestamp);
76
77 EINA_LIST_FREE( (*old_logmessage)->list_tags, ptr)
78 free(ptr);
79 free( (*old_logmessage));
80 return(0);
81}
82
83/**
84 * @brief This function will set a given type to a given logmessage structure
85 *
86 * @param mylog (struct logmessage *) Structure to modify
87 * @param type (char *) Type to set
88 *
89 * @return 0
90 */
91int logmessages_set_type(struct logmessage *mylog, char *type)
92{
93 if( mylog->type )
94 free(mylog->type);
95
96 mylog->type = malloc( sizeof(char) * ( strlen(type) + 1 ) );
97 strcpy(mylog->type, type);
98 return(0);
99}
100
101/**
102 * @brief This function will set a given host to a given logmessage structure
103 *
104 * @param mylog (struct logmessage *) Structure to modify
105 * @param source_host (char *) Host to set
106 *
107 * @return 0
108 */
109int logmessages_set_sourcehost(struct logmessage *mylog, char *source_host)
110{
111 if( mylog->source_host )
112 free(mylog->source_host);
113
114 mylog->source_host = malloc( sizeof(char) * ( strlen(source_host) + 1 ) );
115 strcpy(mylog->source_host, source_host);
116 return(0);
117}
118
119/**
120 * @brief This function will add tags to the given logmessage structure.
121 * Tags has to be separated by a ","
122 *
123 * @param mylog (struct logmessage *) Structure to modify
124 * @param tag (char *) tag to add
125 *
126 * @return 0
127 */
128int logmessages_add_tag(struct logmessage *mylog, char *tag)
129{
130 char *ptr,
131 *ptr_delim;
132 int last = 0;
133 ptr = &tag[0];
134
135 while( 1 )
136 {
137 char *new_tag;
138 ptr_delim = strchr(ptr, ',');
139 if( !ptr_delim )
140 {
141 ptr_delim = &ptr[strlen(ptr)+1];
142 last = 1;
143 }
144 else ptr_delim[0] = 0;
145
146 new_tag = malloc( sizeof(char) * ( strlen(ptr) + 1 ) );
147 strcpy(new_tag, ptr);
148
149 mylog->list_tags = eina_list_append(mylog->list_tags, new_tag);
150
151 if( last ) break;
152 ptr_delim[0] = ',';
153 ptr = &ptr_delim[1];
154 }
155
156 return(0);
157}
158
159/**
160 * @brief This function will set a given value to the delete field
161 *
162 * @param mylog (struct logmessage *) Structure to modify
163 * @param value (int) value to set
164 *
165 * @return 0
166 */
167int logmessages_set_todel(struct logmessage *mylog, int value)
168{
169 mylog->todel = value;
170 return(0);
171}
diff --git a/src/bin/main.c b/src/bin/main.c
index 0e739ff..e7f0ece 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -18,60 +18,108 @@
18 18
19#include "smman.h" 19#include "smman.h"
20 20
21void _usage(char *progname) 21static const Ecore_Getopt optdesc = {
22 "smman",
23 "%prog",
24 PACKAGE_VERSION,
25 "(C) Guillaume Friloux <kuri@efl.so>",
26 "GPL v2.",
27 " _______ \n"
28 " | _ |.--------..--------..---.-..-----.\n"
29 " | 1___|| || || _ || |\n"
30 " |____ ||__|__|__||__|__|__||___._||__|__|\n"
31 " |: 1 | \n"
32 " |::.. . | \n"
33 " `-------' \n",
34 0,
35 {
36 ECORE_GETOPT_STORE_TRUE('d', "debug", "Runs smman in debug mode."),
37 ECORE_GETOPT_LICENSE('L', "license"),
38 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
39 ECORE_GETOPT_VERSION('V', "version"),
40 ECORE_GETOPT_HELP('h', "help"),
41 ECORE_GETOPT_SENTINEL
42 }
43}; /* ASCII ART : http://patorjk.com/software/taag/ - Font Cricket */
44
45
46Smman *
47init(void)
22{ 48{
23 printf(" _______ \n"); 49 Smman *smman;
24 printf(" | _ |.--------..--------..---.-..-----.\n"); 50
25 printf(" | 1___|| || || _ || |\n"); 51 smman_log_dom_global = eina_log_domain_register("smman", EINA_COLOR_YELLOW);
26 printf(" |____ ||__|__|__||__|__|__||___._||__|__|\n"); 52 if (smman_log_dom_global < 0)
27 printf(" |: 1 | \n"); 53 {
28 printf(" |::.. . | Usage for %s : \n", progname); 54 EINA_LOG_ERR("Smman can not create a general log domain");
29 printf(" `-------' \n"); 55 return NULL;
30 printf("\t--help\t\t-h :\tShow this help screen\n"); 56 }
31 printf("\t--version\t-v :\tShow revision version\n"); 57
32 printf("\n"); 58 smman = calloc(1, sizeof(Smman));
33 printf("\tDebugging : \n"); 59 if (!smman)
34 printf("\t\tEINA_LOG_LEVEL=5 %s\n", progname); 60 {
61 ERR("Failed to allocate smman structure");
62 return NULL;
63 }
64
65 smman->rules = rules_new("/etc/smman/rules.d/");
66 if (!smman->rules)
67 {
68 ERR("Failed to allocate new Rules structure");
69 return NULL;
70 }
71
72 return smman;
35} 73}
36 74
37int main(int argc, char **argv) 75int main(int argc, char **argv)
38{ 76{
39 int c; 77 Smman *smman;
78 Eina_Bool opt_quit = EINA_FALSE,
79 opt_debug = EINA_FALSE;
80 int opt_ind;
81
40 eina_init(); 82 eina_init();
41 ecore_init(); 83 ecore_init();
42 ecore_file_init();
43 84
44 send_connected = EINA_FALSE; 85 Ecore_Getopt_Value values[] = {
86 ECORE_GETOPT_VALUE_BOOL(opt_debug),
87 ECORE_GETOPT_VALUE_BOOL(opt_quit),
88 ECORE_GETOPT_VALUE_BOOL(opt_quit),
89 ECORE_GETOPT_VALUE_BOOL(opt_quit),
90 ECORE_GETOPT_VALUE_BOOL(opt_quit),
91 ECORE_GETOPT_VALUE_NONE
92 };
45 93
46 while (1) 94 opt_ind = ecore_getopt_parse(&optdesc, values, argc, argv);
95 if (opt_ind<0)
47 { 96 {
48 int option_index = 0; 97 EINA_LOG_ERR("Failed to parse args");
49 98 return 1;
50 static struct option long_options[] = {
51 {"help", 0, 0, 'h'},
52 {0, 0, 0, 0}
53 };
54
55 c = getopt_long(argc, argv, "h", long_options, &option_index);
56 if (c == -1) break;
57
58 switch (c)
59 {
60 case 'h':
61 _usage(argv[0]);
62 exit(0);
63 default:
64 break;
65 }
66 } 99 }
67 100
68 conf_load(); 101 if (opt_quit)
69 rules_load(); 102 return 0;
70 rules_print(); 103
71 spy_init(); 104 conf_init();
72 logfiles_print(); 105 rules_init();
106
107 smman = init();
108 if (!smman)
109 return 1;
110
111 conf_load("/etc/smman/smman.conf", config_done, config_error, smman);
112 rules_load(smman->rules, filter_load, filter_load_done,
113 filter_load_error, smman);
73 114
74 ecore_main_loop_begin(); 115 ecore_main_loop_begin();
75 116
117 rules_shutdown();
118 conf_shutdown();
119 ecore_shutdown();
120 eina_log_domain_unregister(smman_log_dom_global);
121 smman_log_dom_global = -1;
122 eina_shutdown();
123
76 return 0; 124 return 0;
77} 125}
diff --git a/src/bin/rules.c b/src/bin/rules.c
deleted file mode 100644
index fe3c6f5..0000000
--- a/src/bin/rules.c
+++ /dev/null
@@ -1,307 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20#include <Conf.h>
21
22struct rule *rules_temp; /**< Pointer to a rule, used so rules_load_rule_loadspec() knowns which rule rules_load_rule() is processing */
23
24/**
25 * @fn int rules_load(void)
26 * @brief List the rules directory and loads every rule in it
27 *
28 * @return 0 if no error, -1 if can't open rules dir
29 */
30int rules_load(void)
31{
32 DIR *fd;
33 struct dirent * entree;
34
35 list_rules = NULL;
36
37 // For every rule in rules directory, we will load it
38 fd = opendir(global_rulesdir);
39 if( !fd )
40 {
41 EINA_LOG_DOM_ERR(einadom_rules, "Can't open rules directory %s : %s", global_rulesdir, strerror(errno));
42 return(-1);
43 }
44 while((entree = readdir(fd)) != NULL)
45 {
46 if( !strcmp(entree->d_name, ".") ) continue;
47 if( !strcmp(entree->d_name, "..") ) continue;
48
49 EINA_LOG_DOM_DBG(einadom_rules, "Found rule file %s", entree->d_name);
50
51 rules_load_rule(entree->d_name);
52 }
53
54 closedir(fd);
55 return(0);
56}
57
58/**
59 * @fn int rules_load_rule(char *rule_name)
60 * @brief This function receives the name of a rule file, and ask for libconf
61 * to analyze it
62 *
63 * @param rule_name (char *) name of the rule (filename)
64 *
65 * @return 0
66 */
67int rules_load_rule(char *rule_name)
68{
69 char full_path[512];
70 struct libconfig myconf;
71
72 sprintf(full_path, "%s%s", global_rulesdir, rule_name);
73
74 libconfig_init(full_path, &myconf);
75 libconfig_load(&myconf);
76
77 // We have to make a new rule struct
78 rules_temp = malloc(sizeof(struct rule));
79
80 rules_temp->name = malloc(sizeof(char) * ( strlen(rule_name) + 1 ) );
81 strcpy(rules_temp->name, rule_name);
82
83 // We init default values for our struct
84 rules_temp->filename = NULL;
85 rules_temp->type = NULL;
86 rules_temp->source_host = NULL;
87 rules_temp->source_path = NULL;
88 rules_temp->tags = NULL;
89 rules_temp->todel = 0;
90 rules_temp->list_regex = NULL;
91
92 libconfig_list(&myconf, rules_load_rule_loadspec);
93
94 libconfig_free(&myconf);
95
96 // We insert our new rule in our eina rule list
97 list_rules = eina_list_append(list_rules, rules_temp);
98 return(0);
99}
100
101/**
102 * @fn int rules_load_rule_loadspec(char *variable, char *value)
103 * @brief This function is a callback used by libconf to send us
104 * every variable+value that libconf found in a rulefile
105 *
106 * @param variable (char *) variable's name
107 * @param value (char *) variable's value
108 *
109 * @return 0
110 */
111int rules_load_rule_loadspec(char *variable, char *value)
112{
113 if( !strcmp(variable, "filename") )
114 {
115 rules_temp->filename = malloc(sizeof(char) * ( strlen(value) + 1 ));
116 strcpy(rules_temp->filename, value);
117 }
118 else if( ( !strcmp(variable, "message") )
119 || ( !strcmp(variable, "message_match") )
120 || ( !strcmp(variable, "message_unmatch") )
121 )
122 {
123 struct regex *tmp_regex;
124 int ret;
125
126 tmp_regex = malloc(sizeof(struct regex));
127
128 ret = regcomp(&(tmp_regex->preg), value, REG_EXTENDED);
129 if( ret )
130 {
131 EINA_LOG_DOM_ERR(einadom_rules, "Regcomp failed to compile regexp %s", value);
132 free(tmp_regex);
133 return(0);
134 }
135
136 tmp_regex->message = malloc(sizeof(char) * ( strlen(value) + 1 ));
137 strcpy(tmp_regex->message, value);
138
139 if( !strcmp(variable, "message_unmatch") )
140 tmp_regex->must_match = 0;
141 else
142 tmp_regex->must_match = 1;
143
144 rules_temp->list_regex = eina_list_append(rules_temp->list_regex, tmp_regex);
145 }
146 else if( !strcmp(variable, "type") )
147 {
148 rules_temp->type = malloc(sizeof(char) * ( strlen(value) + 1 ));
149 strcpy(rules_temp->type, value);
150 }
151 else if( !strcmp(variable, "source_host") )
152 {
153 rules_temp->source_host = malloc(sizeof(char) * ( strlen(value) + 1 ));
154 strcpy(rules_temp->source_host, value);
155 }
156 else if( !strcmp(variable, "source_path") )
157 {
158 rules_temp->source_path = malloc(sizeof(char) * ( strlen(value) + 1 ));
159 strcpy(rules_temp->source_path, value);
160 }
161 else if( !strcmp(variable, "tags") )
162 {
163 rules_temp->tags = malloc(sizeof(char) * ( strlen(value) + 1 ));
164 strcpy(rules_temp->tags, value);
165 }
166 else if( !strcmp(variable, "delete") )
167 {
168 rules_temp->todel = atoi(value);
169 }
170 else
171 {
172 EINA_LOG_DOM_ERR(einadom_rules, "Unknown variable name %s", variable);
173 }
174 return(0);
175}
176
177
178/**
179 * @fn int rules_print(void)
180 * @brief This function will print to stdout every rules that is in
181 * the rules list.
182 *
183 * @return 0
184 */
185int rules_print(void)
186{
187 Eina_List *l;
188 struct rule *foundrule = NULL;
189
190 EINA_LIST_FOREACH(list_rules, l, foundrule)
191 {
192 EINA_LOG_DOM_INFO(einadom_rules,
193 "\n[%s]\n"
194 "\tfilename\t= %s\n"
195 "\ttype\t\t= %s\n"
196 "\tsource_host\t= %s\n"
197 "\tsource_path\t= %s\n"
198 "\ttags\t\t= %s\n"
199 "\tdelete\t= %d\n\n",
200 foundrule->name,
201 foundrule->filename,
202 foundrule->type,
203 foundrule->source_host,
204 foundrule->source_path,
205 foundrule->tags,
206 foundrule->todel);
207 }
208 return(0);
209}
210
211/**
212 * @fn int rules_list(int (*callback)(struct rule *foundrule))
213 * @brief This function will list every rule in the list, to send each
214 * item to the given callback
215 *
216 * @param callback (int *) Callback that will receive all the items
217 *
218 * @return 0
219 */
220int rules_list(int (*callback)(struct rule *foundrule))
221{
222 Eina_List *l;
223 struct rule *foundrule = NULL;
224
225 EINA_LIST_FOREACH(list_rules, l, foundrule)
226 {
227 callback(foundrule);
228 }
229 return(0);
230}
231
232
233/**
234 * @fn int rules_filtermessage(struct logmessage *new_logmessage)
235 * @brief This function will get a log message, and apply all the rules
236 * on it before giving it back and filtered
237 *
238 * @param new_logmessage (struct logmessage *)
239 *
240 * @return 0
241 */
242int rules_filtermessage(struct logmessage *new_logmessage)
243{
244 Eina_List *l, *l2;
245 struct rule *foundrule = NULL;
246 struct regex *foundregex = NULL;
247 int ret,
248 excluded = 0;
249
250 // We check each rules to see what we have to do
251 EINA_LIST_FOREACH(list_rules, l, foundrule)
252 {
253 // If filename is set, we check that our log is affected
254 // By this rule's filename
255 if( foundrule->filename )
256 {
257 ret = fnmatch(foundrule->filename, new_logmessage->source_path, FNM_NOESCAPE);
258 if( ret )
259 {
260 EINA_LOG_DOM_DBG(einadom_rules, "Log \"%s\" from \"%s\" is not affected by rule %s (filename exclude)", new_logmessage->message, new_logmessage->source_path, foundrule->name);
261 continue;
262 }
263 }
264
265 excluded = 0;
266
267 // For every regex affected to the rule, we apply it to the
268 // Log message we got to see if we have something to filter
269 EINA_LIST_FOREACH(foundrule->list_regex, l2, foundregex)
270 {
271 size_t nmatch = 2;
272 regmatch_t pmatch[2];
273
274 ret = regexec(&(foundregex->preg), new_logmessage->message,nmatch, pmatch, 0);
275
276 // If regexec returns 0, then the log message matches the regex.
277 // If regexec returns 1, then the log message doesnt match the regex.
278 // So if the regex must match (message= or message_match= in rule, so must_match=1) or musnt match (message_unmatch=, must_match=0),
279 // We can consider that the message must be filtered if regex returns something different than 'must_match'
280 if( ret == foundregex->must_match )
281 {
282 EINA_LOG_DOM_INFO(einadom_rules, "Log \"%s\" from \"%s\" is not affected by rule %s (message exclude : %s / %d / %d)", new_logmessage->message, new_logmessage->source_path, foundrule->name, foundregex->message, foundregex->must_match, ret);
283 excluded = 1;
284 break;
285 }
286 }
287
288 if( excluded )
289 continue;
290
291 // If we get here, then our log message have to be filtered
292
293 // If type is specified, then we have to override it
294 if( foundrule->type )
295 logmessages_set_type(new_logmessage, foundrule->type);
296
297 if( foundrule->source_host )
298 logmessages_set_sourcehost(new_logmessage, foundrule->source_host);
299
300 if( foundrule->tags )
301 logmessages_add_tag(new_logmessage, foundrule->tags);
302
303 if( foundrule->todel )
304 logmessages_set_todel(new_logmessage, 1);
305 }
306 return(0);
307}
diff --git a/src/bin/send.c b/src/bin/send.c
deleted file mode 100644
index 422e7b1..0000000
--- a/src/bin/send.c
+++ /dev/null
@@ -1,257 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20
21CURL *curl;
22CURLcode res;
23
24/**
25 * @brief This function will receive a logmessage to index,
26 * convert it into JSON data and send it to <a href=www.elasticsearch.com>ES</a>
27 *
28 * @param new_logmessage (struct logmessage *) Log message to index
29 *
30 * @see send_convJSON()
31 * @see struct logmessage
32 * @see send_toES
33 *
34 * @return 0
35 */
36int send_logmessage(struct logmessage *new_logmessage)
37{
38 Eina_List *l;
39 char *tag = NULL,
40 *tags = NULL,
41 *jsondata = NULL;
42 unsigned int size = 0,
43 i = 0;
44
45 // We check how much space we need to store tags
46 EINA_LIST_FOREACH(new_logmessage->list_tags, l, tag)
47 {
48 size += strlen(tag) + 3;
49 }
50
51 tags = malloc( sizeof(char) * ( size + 1 ) );
52 memset(tags, 0, size + 1);
53
54 EINA_LIST_FOREACH(new_logmessage->list_tags, l, tag)
55 {
56 if( i > 0 )
57 strcat(tags, ",");
58
59 strcat(tags, "\"");
60 strcat(tags, tag);
61 strcat(tags, "\"");
62 i++;
63 }
64 // We will build our JSON object from these values
65 send_convJSON(new_logmessage->source_host, new_logmessage->source_path, new_logmessage->type, new_logmessage->message, tags, new_logmessage->timestamp, &jsondata);
66
67 EINA_LOG_DOM_DBG(einadom_send, "JSON : %s", jsondata);
68
69 send_toES(jsondata);
70
71 free(jsondata);
72 free(tags);
73 return(0);
74}
75
76/**
77 * @brief This Function receives all needed vars to build the JSON data for <a href=www.elasticsearch.com>ES</a>.
78 * @warning This function will malloc jsondata, so dont do it yourself, and dont forget to free it!
79 *
80 * @param source_host (char *) Host that sent the logfile
81 * @param source_path (char *) Logfile name
82 * @param type (char *) Type for this log message
83 * @param message (char *) Log message
84 * @param tags (char *) list of tags, they must be already parsed in format "Tag1","Tag2","Tag3"
85 * @param timestamp (char *) Timestamp for the message
86 * @param jsondata (char **) Buffer that we will malloc and fill with generated JSON message
87 *
88 * @return 0
89 */
90int send_convJSON(char *source_host, char *source_path, char *type, char *message, char *tags, char *timestamp, char **jsondata)
91{
92 char *Esource_host = NULL,
93 *Esource_path = NULL,
94 *Etype = NULL,
95 *Emessage = NULL;
96
97 send_escape(source_host, &Esource_host);
98 send_escape(source_path, &Esource_path);
99 send_escape(type, &Etype);
100 send_escape(message, &Emessage);
101
102 *jsondata = malloc( sizeof(char) * (200 + strlen(Esource_host)*2 + strlen(Esource_path)*2 + strlen(Etype) + strlen(Emessage) + strlen(tags) + 30 + 1) );
103 sprintf(*jsondata,
104 "{"
105 " \"@source\" : \"file://%s%s\","
106 " \"@type\" : \"%s\","
107 " \"@tags\" : [ %s ],"
108 " \"@fields\" : { },"
109 " \"@message\" : \"%s\","
110 " \"@timestamp\" : \"%s\","
111 " \"@source_host\" : \"%s\","
112 " \"@source_path\" : \"%s\""
113 "}",
114 Esource_host, Esource_path, Etype, tags, Emessage, timestamp, Esource_host, Esource_path);
115
116 free(Esource_host);
117 free(Esource_path);
118 free(Etype);
119 free(Emessage);
120
121 return(0);
122}
123
124
125/**
126 * @brief This Function will escape all double quote so we dont get a parsing problem
127 * @warning This function will malloc dst, so dont do it yourself, and dont forget to free it!
128 *
129 * @param src (char *) buffer to escape
130 * @param dst (char **) Escaped buffer
131 *
132 * @return Pointer to escaped buffer
133 */
134char *send_escape(char *src, char **dst)
135{
136 unsigned i = 0,
137 j = 0,
138 len = strlen(src);
139 char tmp[len*2+1];
140
141 memset(tmp, 0, sizeof(tmp));
142
143 for( i = 0; i < len+1; i++)
144 {
145 if( src[i] == '"')
146 tmp[j++] = '\\';
147 tmp[j++] = src[i];
148 }
149 *dst = malloc( sizeof(char) * ( strlen(tmp) + 1 ) );
150 strcpy(*dst, tmp);
151 return(*dst);
152}
153
154/**
155 * @brief Inits the curl object, and set necessary params
156 *
157 * @return 0
158 */
159int send_init(void)
160{
161 curl = curl_easy_init();
162 if( !curl )
163 {
164 EINA_LOG_DOM_ERR(einadom_send, "Can't init curl.");
165 return(-1);
166 }
167 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, EINA_TRUE);
168 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, send_fromES);
169 curl_easy_setopt(curl, CURLOPT_URL, global_ESserver);
170 send_connected = EINA_TRUE;
171
172 return(0);
173}
174
175/**
176 * @brief Destroys the curl object
177 *
178 * @return 0
179 */
180int send_destroy(void)
181{
182 curl_easy_cleanup(curl);
183 return(0);
184}
185
186/**
187 * @brief This function will send a given JSON data to the configured
188 * JSON server
189 *
190 * @param jsondata (char *)
191 *
192 * @return 0
193 */
194int send_toES(char *jsondata)
195{
196/* ecore_con_url_post doesnt return any error if it cant send
197 which sucks for us. Waiting for patch coming for EFLs 1.1
198 Ecore_Con_Url *ecu;
199 Eina_Bool ret;
200
201 ecore_con_url_init();
202 ecu = ecore_con_url_new(global_ESserver);
203 if( !ecu )
204 {
205 EINA_LOG_DOM_ERR(einadom_send, "Can't init ecore_con_url_new()");
206 ecore_con_url_shutdown();
207 return(-1);
208 }
209
210 ret = ecore_con_url_post(ecu, jsondata, -1, "text/xml");
211 if( ret == EINA_FALSE )
212 {
213 EINA_LOG_DOM_ERR(einadom_send, "Can't send jsondata to ES");
214 ecore_con_url_shutdown();
215 return(-1);
216 }
217
218 ecore_con_url_free(ecu);
219 ecore_con_url_shutdown();
220*/
221 if( send_connected == EINA_FALSE )
222 {
223 send_init();
224 }
225
226 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsondata);
227 res = curl_easy_perform(curl);
228 if( res )
229 {
230 EINA_LOG_DOM_ERR(einadom_send, "Sending of JSON query failed, curl returned : %d", res);
231 send_destroy();
232 send_connected = EINA_FALSE;
233 }
234
235 return(0);
236}
237
238/**
239 * @brief This fonction will get response from <a href=www.elasticsearch.com>ES</A>
240 * after sending our JSON data. This function is a callback used by libcurl
241 *
242 * @param ptr (void *) To be defined
243 * @param size (size_t) To be defined
244 * @param nmemb (size_t) To be defined
245 * @param data (void *) To be defined
246 *
247 * @return Number of bytes received
248 */
249size_t send_fromES(void *ptr,
250 size_t size,
251 size_t nmemb,
252 void *data EINA_UNUSED)
253{
254 if( strncmp((char *)ptr, "{\"ok\":", 6) )
255 EINA_LOG_DOM_ERR(einadom_send, "Indexing of JSON data failed");
256 return(size * nmemb);
257}
diff --git a/src/bin/smman.h b/src/bin/smman.h
index 5cee0a8..62a273d 100644
--- a/src/bin/smman.h
+++ b/src/bin/smman.h
@@ -1,155 +1,32 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#ifdef HAVE_CONFIG_H 1#ifdef HAVE_CONFIG_H
20# include "config.h" 2# include <config.h>
21#endif 3#endif
22 4
23#include <Eina.h> 5#include <Eina.h>
24#include <Ecore.h> 6#include <Ecore.h>
25#include <Ecore_File.h> 7#include <Ecore_Getopt.h>
26#include <curl/curl.h> 8#include <Eio.h>
27 9#include <Conf.h>
28#include <dirent.h>
29#include <errno.h>
30#include <fnmatch.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <regex.h>
34#include <unistd.h>
35#include <libgen.h>
36#include <getopt.h>
37
38#ifndef GLOBALVARS
39#define GLOBALVARS
40char global_rulesdir[35], /**< Allows us to store the rules directory */
41 global_conf[35], /**< Allows us to store the configuration directory */
42 global_host[35], /**< Allows us to store the default hostname */
43 global_type[35], /**< Allows us to store the default type */
44 global_ESserver[128];/**< Allows us to store ElasticSearch server adress */
45
46/**
47 * @struct rule
48 * @brief This structure can handle a rule described in the rule directory
49 */
50struct rule
51{
52 char *name, /**< Rule's name (Guessed using the filename of the rule inside the rules directory) */
53 *filename,/**< It is the filename of the logfile(s) that match this rule (see this as a condition) */
54 *type,/**< Type we will apply to the matched log message (see this as an affectation) */
55 *source_host,/**< Host we will apply to the matched log message (see this as an affectation) */
56 *source_path,/**< Log path we will apply to the matched log message (its like renaming the log, without mv it) (see this as an affectation) */
57 *tags;/**< tags we will apply to the matched log message (see this as an affectation) */
58 int todel;/**< If set to something other than 0, every matched rule will not be indexed */
59 Eina_List *list_regex;/**< Regexps to apply to message we get from syslog, then match them (see this as a condition) */
60};
61
62/**
63 * @struct regex
64 * @brief This structure can handle a regex that will be compared to log messages
65 * in order to see if they are affected by a rule or not
66 */
67struct regex
68{
69 char *message;
70 int must_match;
71 regex_t preg;
72};
73 10
74/** 11int smman_log_dom_global;
75 * @struct logfile
76 * @brief This structure allows us to attach a cursor position to a logfile,
77 * which is necessary to find new log entries
78 */
79struct logfile
80{
81 char *name; /**< Name of the log file */
82 fpos_t cursor; /**< Position of the cursor inside this logfile */
83 unsigned long long int filesize; /**< File size, only help to see if a logfile is truncated, as far as i know */
84};
85 12
86/** 13typedef struct _Smman
87 * @struct logmessage
88 * @brief This structure Contains needed information about a logfile that is going
89 * to be JSONed for ES.
90 */
91struct logmessage
92{ 14{
93 char *source_host, /**< Hostname */ 15 Rules *rules;
94 *source_path, /**< Name of the logfile from where this message comes from */
95 *timestamp, /**< Date of the log */
96 *type, /**< Type of message */
97 *message; /**< Log message to index in ES */
98 Eina_List *list_tags; /**< List of tags associated to this message */
99 int todel; /**< If set to something other than 0, this message wont be indexed */
100};
101
102int einadom_rules, /**< Used for eina_log inside rules.c */
103 einadom_spy, /**< Used for eina_log inside spy.c */
104 einadom_logfiles, /**< Used for eina_log inside logfiles.c */
105 einadom_send, /**< Used for eina_log inside send.c */
106 einadom_conf; /**< Used for eina_log inside conf.c */
107
108Eina_List *list_rules; /**< Used to store all the rules in memory, in an eina list */
109Eina_List *list_logfiles; /**< Used to store all the logfiles watched, in an eina list */
110Ecore_File_Monitor *efm; /**< Used for file monitoring by ecore */
111
112unsigned char send_connected;
113#endif
114
115int conf_load(void);
116int conf_load_var(char *variable, char *value);
117
118int logfiles_exist(char *logfile);
119int logfiles_add(struct logfile *new_logfile);
120int logfiles_print(void);
121int logfiles_new(struct logfile **new_logfile, char *filename, fpos_t cursor, unsigned long long int filesize);
122int logfiles_del(struct logfile **old_logfile);
123int logfiles_getend(char *logfile, fpos_t *pos_end);
124int logfiles_getbegin(char *logfile, fpos_t *pos_begin);
125int logfiles_getsize(char *logfile, unsigned long long int *filesize);
126
127int logmessages_new(struct logmessage **new_logmessage, char *message, char *logname);
128int logmessages_free(struct logmessage **old_logmessage);
129int logmessages_set_type(struct logmessage *mylog, char *type);
130int logmessages_set_sourcehost(struct logmessage *mylog, char *source_host);
131int logmessages_add_tag(struct logmessage *mylog, char *tag);
132int logmessages_set_todel(struct logmessage *mylog, int value);
133
134int rules_load(void);
135int rules_load_rule(char *rule_name);
136int rules_load_rule_loadspec(char *variable, char *value);
137int rules_print(void);
138int rules_list(int (*callback)(struct rule *foundrule));
139int rules_filtermessage(struct logmessage *new_logmessage);
140 16
141int send_logmessage(struct logmessage *new_logmessage); 17 struct
142int send_convJSON(char *source_host, char *source_path, char *type, char *message, char *tags, char *timestamp, char **jsondata); 18 {
143char *send_escape(char *src, char **dst); 19 const char *server,
144int send_toES(char *jsondata); 20 *host;
145size_t send_fromES(void *ptr, size_t size, size_t nmemb, void *data); 21 } cfg;
146int send_init(void); 22} Smman;
147int send_destroy(void);
148 23
24#define ERR(...) EINA_LOG_DOM_ERR(smman_log_dom_global, __VA_ARGS__)
25#define DBG(...) EINA_LOG_DOM_DBG(smman_log_dom_global, __VA_ARGS__)
26#define NFO(...) EINA_LOG_DOM_INFO(smman_log_dom_global, __VA_ARGS__)
27#define WRN(...) EINA_LOG_DOM_WARN(smman_log_dom_global, __VA_ARGS__)
28#define CRI(...) EINA_LOG_DOM_CRIT(smman_log_dom_global, __VA_ARGS__)
149 29
150int spy_init(void);
151int spy_addwatcher(struct rule *foundrule);
152int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path);
153int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message);
154 30
155char * utils_date(void); 31void config_done(void *data, Conf *conf);
32void config_error(void *data, Conf *conf, const char *errstr);
diff --git a/src/bin/spy.c b/src/bin/spy.c
deleted file mode 100644
index 6d27fde..0000000
--- a/src/bin/spy.c
+++ /dev/null
@@ -1,349 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20#include <wordexp.h>
21
22
23/**
24 * @brief Will ask rules_list() to list all rules and tell spy_addwatcher()
25 * of every found rule so we can process it and monitor matching log files
26 *
27 * @return 0
28 */
29int spy_init(void)
30{
31 rules_list(spy_addwatcher);
32 return(0);
33}
34
35/**
36 * @brief Gets a rule in param, and will check for every matching
37 * files on the system
38 *
39 * @param foundrule (struct rule *) Rule found by rules_list()
40 *
41 * @return 0 if no error, -1 if any error
42 */
43int spy_addwatcher(struct rule *foundrule)
44{
45 wordexp_t p;
46 int ret;
47 unsigned int i;
48 char *ptr,
49 tmp[512];
50
51 if( !foundrule->filename )
52 return(0);
53
54 // As filenames can contain wildcards, we have to test
55 // Globbing
56 ret = wordexp(foundrule->filename, &p, 0);
57 if( ret )
58 {
59 EINA_LOG_DOM_ERR(einadom_spy, "l utilisation de wordexp() a echoue, il a renvoye %d", ret);
60 return(-1);
61 }
62
63 EINA_LOG_DOM_DBG(einadom_spy, "Found %zu results for %s", p.we_wordc, foundrule->filename);
64
65 // We now have a list of files (or a unique file) and we want to add them
66 // To our file list
67 for( i = 0; i < p.we_wordc; i++)
68 {
69 int exist = 0;
70
71 exist = logfiles_exist(p.we_wordv[i]);
72
73 if( !exist )
74 {
75 fpos_t pos_tmp;
76 struct logfile *new_logfile;
77 unsigned long long int filesize = 0;
78
79 // We get our cursor pos
80 logfiles_getend(p.we_wordv[i], &pos_tmp);
81 logfiles_getsize(p.we_wordv[i], &filesize);
82 logfiles_new(&new_logfile, p.we_wordv[i], pos_tmp, filesize);
83
84 logfiles_add(new_logfile);
85 efm = ecore_file_monitor_add(p.we_wordv[i],
86 (Ecore_File_Monitor_Cb)spy_event,
87 (void *)new_logfile);
88 }
89 }
90 wordfree(&p);
91
92 // We will check parent directory to see if a new file is created
93 // and matches one of the rules when a CREATE event is raised.
94 // This part sucks cause we only watch the last directory while
95 // The wildcard can englob multiple directories! (and so our code gets totally buggy)
96 strncpy(tmp, foundrule->filename, 512);
97 ptr = dirname(tmp);
98 efm = ecore_file_monitor_add(ptr,
99 (Ecore_File_Monitor_Cb)spy_event,
100 NULL);
101
102 return(0);
103}
104
105/**
106 * @brief ecore_main_loop() will call this function for every notification he gets from logfiles
107 * activity.
108 *
109 * @param data (void *) Data associated to the logfile in spy_addwatcher()
110 * @param em (Ecore_File_Monitor *) Not really used here.
111 * @param event (Ecore_File_Event) Event type
112 * @param path (const char *) Name of the file that raised the event
113 *
114 * @return ECORE_CALLBACK_RENEW
115 */
116int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path)
117{
118 struct logmessage *new_logmessage;
119 char message[4096];
120
121 EINA_LOG_DOM_DBG(einadom_spy, "Event on %s ! %p - %p", path, data, em);
122 message[0] = 0;
123
124 if( event == ECORE_FILE_EVENT_MODIFIED )
125 {
126 struct logfile *log = data;
127 fpos_t new_pos;
128 unsigned long long int filesize;
129 Eina_Counter *counter;
130 char *counterresult;
131 if( !log )
132 return(ECORE_CALLBACK_RENEW);
133 counter = eina_counter_new("MessageProcessingTime");
134 eina_counter_start(counter);
135 // If logfile got trunc, than size is different
136 logfiles_getsize((char *)path, &filesize);
137
138 if( filesize < log->filesize )
139 {
140 // If event is that file has been truncated, then there is
141 // nothing to read, we just set cursor to beginning
142 logfiles_getbegin((char *)path, &(log->cursor));
143 log->filesize = filesize;
144 return(ECORE_CALLBACK_RENEW);
145 }
146 log->filesize = filesize;
147
148 EINA_LOG_DOM_DBG(einadom_spy, "Event on %s !", path);
149
150 // We must take attention to the fact that the file might
151 // Have been truncated
152 spy_extract_new_lines(log->name, log->cursor, &new_pos, message);
153 log->cursor = new_pos;
154
155 // If nothing has been read, then file has been trunc and is empty
156 // So we do nothing
157 if( message[0] == 0 )
158 return(ECORE_CALLBACK_RENEW);
159
160 logmessages_new(&new_logmessage, message, log->name);
161
162 rules_filtermessage(new_logmessage);
163
164 // Now we only have to send this filtered message to ES
165 if( !new_logmessage->todel )
166 send_logmessage(new_logmessage);
167
168 // Message is sent, we can free our structure
169 logmessages_free(&new_logmessage);
170 eina_counter_stop(counter, 1);
171
172 counterresult = eina_counter_dump(counter);
173 EINA_LOG_DOM_DBG(einadom_spy, "Message processing time :\n%s", counterresult);
174 free(counterresult);
175 eina_counter_free(counter);
176 }
177 else if( event == ECORE_FILE_EVENT_DELETED_SELF
178 || event == ECORE_FILE_EVENT_DELETED_DIRECTORY
179 || event == ECORE_FILE_EVENT_DELETED_FILE
180 )
181 {
182 struct logfile *log = data,
183 *foundlog;
184 Eina_List *l;
185 EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been deleted!", path);
186
187 // If this file was one of the files we used to monitor,
188 // We must delete it from our list
189 EINA_LIST_FOREACH(list_logfiles, l, foundlog)
190 {
191 if( !strcmp(foundlog->name, path) )
192 {
193 list_logfiles = eina_list_remove(list_logfiles, log);
194 logfiles_del(&log);
195 break;
196 }
197 }
198 }
199 else if( event == ECORE_FILE_EVENT_CREATED_FILE
200 || event == ECORE_FILE_EVENT_CREATED_DIRECTORY
201 )
202 {
203 // A new log file has been made, we have to check if this file already is in our filelog
204 // And if a rule affects it.
205 // If so, we add it to our monitor
206 Eina_List *l;
207 struct rule *foundrule = NULL;
208 struct logfile *new_logfile = NULL;
209 fpos_t pos_tmp;
210 int ret,
211 got_it = 0;
212
213 EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been created!", path);
214
215 // If we already monitor this file, then we ignore it
216 // Which might be a problem btw. This thing shouldnt happen
217 EINA_LIST_FOREACH(list_logfiles, l, new_logfile)
218 {
219 if( !strcmp(new_logfile->name, path) )
220 return(ECORE_CALLBACK_RENEW);
221 }
222
223 EINA_LIST_FOREACH(list_rules, l, foundrule)
224 {
225 if( foundrule->filename )
226 {
227 unsigned long long int filesize;
228 ret = fnmatch(foundrule->filename, path, FNM_NOESCAPE);
229 if( ret )
230 continue;
231
232 // We get our cursor pos
233 logfiles_getbegin((char *)path, &pos_tmp);
234 logfiles_getsize((char *)path, &filesize);
235 logfiles_new(&new_logfile, (char *)path, pos_tmp, filesize);
236
237 logfiles_add(new_logfile);
238 efm = ecore_file_monitor_add(path,
239 (Ecore_File_Monitor_Cb)spy_event,
240 (void *)new_logfile);
241
242 got_it = 1;
243 break;
244 }
245 }
246
247 if( got_it )
248 {
249 // We must take attention to the fact that the file might
250 // Have been truncated
251 spy_extract_new_lines(new_logfile->name, new_logfile->cursor, &new_logfile->cursor, message);
252
253 // If nothing has been read, then file has been trunc and is empty
254 // So we do nothing
255 if( message[0] == 0 )
256 return(ECORE_CALLBACK_RENEW);
257
258 logmessages_new(&new_logmessage, message, new_logfile->name);
259 rules_filtermessage(new_logmessage);
260
261 // Now we only have to send this filtered message to ES
262 if( !new_logmessage->todel )
263 send_logmessage(new_logmessage);
264
265 // Message is sent, we can free our structure
266 logmessages_free(&new_logmessage);
267 }
268 }
269 else
270 {
271 EINA_LOG_DOM_DBG(einadom_spy, "WTF event on %s !", path);
272
273 }
274 return(ECORE_CALLBACK_RENEW);
275}
276
277
278
279/**
280 * @brief Gets the new log message that has been inserted. This function kind of sucks and has to
281 * be improved to really extract all the messages and send them to a callback that will
282 * process them intead of taking only one (which can cause a problem if we don't get
283 * one inotify per message logged).
284 *
285 * @param filename (char *) File that raised an event and should be read
286 * @param pos_cur (fpos_t) current cursor position for this file
287 * @param pos_new (fpos_t *) New position of the cursor after extracting the new message
288 * @param message (char *) message extracted from the logfile
289 *
290 * @return 0 or -1 if there is an error
291 */
292int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message)
293{
294 FILE *fp;
295 int ret;
296 fpos_t pos_begin;
297
298 fp = fopen(filename, "r");
299 if( !fp )
300 {
301 EINA_LOG_DOM_ERR(einadom_spy, "We haven't been able to open %s : %s", filename, strerror(errno));
302 return(-1);
303 }
304
305 fgetpos(fp, &pos_begin);
306
307
308 // If we can't set cursor, file has been truncated!
309 ret = fsetpos(fp, &pos_cur);
310 if( ret )
311 {
312 fsetpos(fp, &pos_begin);
313 *pos_new = pos_begin;
314 }
315 else *pos_new = pos_cur;
316
317 // This while is only here to avoid empty lines
318 while( 1 )
319 {
320 ret = fscanf(fp,"%4096[^\n]\n", message);
321
322 if( ret == EOF )
323 break;
324
325 // Didnt read anything
326 if( ret == 0)
327 {
328 char tmp[2];
329 EINA_LOG_DOM_DBG(einadom_spy, "Empty line hack");
330 ret = fread(tmp, 1, 1, fp);
331 if( ret != 1 )
332 EINA_LOG_DOM_DBG(einadom_spy, "WTF?!");
333 continue;
334 }
335 if( ret != 1 )
336 {
337 fgetpos(fp, pos_new);
338 break;
339 }
340 else
341 fgetpos(fp, pos_new);
342
343 // We have a message to log
344 break;
345 }
346
347 fclose(fp);
348 return(0);
349}
diff --git a/src/bin/utils.c b/src/bin/utils.c
deleted file mode 100644
index a9a9d4a..0000000
--- a/src/bin/utils.c
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 * Copyright © 2013 Guillaume Friloux <kuri@efl.so>
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#include "smman.h"
20#include <time.h>
21#include <stdio.h>
22
23/**
24 * @brief Gets us the current date, in the same format as logstash.
25 *
26 * @return Pointer to the date's string, or NULL if an error
27 * occured.
28 */
29char *
30utils_date(void)
31{
32 char *s;
33 time_t temps;
34 struct tm temp;
35
36 temps = time(NULL);
37 if (!localtime_r(&temps,&temp))
38 return NULL;
39
40 s = calloc(1, 28);
41 EINA_SAFETY_ON_NULL_RETURN_VAL(s, NULL);
42
43 sprintf(s,"%04d-%02d-%02dT%02d:%02d:%02d.000000Z",
44 (temp.tm_year)+1900,(temp.tm_mon)+1,temp.tm_mday,
45 temp.tm_hour,temp.tm_min,temp.tm_sec);
46 return s;
47}