1 /**
2 * collectd - src/config_list.c
3 * Copyright (C) 2006 Lubos Stanek <lubek at users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/
6 * or modify it under the terms of the GNU General Public Li-
7 * cence as published by the Free Software Foundation; either
8 * version 2 of the Licence, or any later version.
9 *
10 * This program is distributed in the hope that it will be use-
11 * ful, but WITHOUT ANY WARRANTY; without even the implied war-
12 * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * Licence along with this program; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
18 * USA.
19 *
20 * Authors:
21 * Lubos Stanek <lubek at users.sourceforge.net>
22 **/
23 /**
24 * configlist handles plugin's list of configured collectable
25 * entries with global ignore action
26 **/
27 /**
28 * Usage:
29 *
30 * Define plugin's global variable of type configlist_t:
31 * configlist_t *myconfig_ignore;
32 * If you know the state of global ignore (IgnoreSelected),
33 * allocate the variable with:
34 * myconfig_ignore = configlist_create (YourKnownIgnore);
35 * If you do not know the state of the global ignore (IgnoreSelected),
36 * initialize the global variable and set the ignore flag later:
37 * myconfig_ignore = configlist_init ();
38 * Append single entries in your cf_register'ed callback function:
39 * configlist_add (myconfig_ignore, newentry);
40 * When you hit the IgnoreSelected config option,
41 * offer it to the list:
42 * configlist_ignore (myconfig_ignore, instantly_got_value_of_ignore);
43 * That ia all for the configlist initialization.
44 * Later during read and write (plugin's registered functions) get
45 * the information whether this entry would be collected or not:
46 * if (configlist_ignored (myconfig_ignore, thisentry))
47 * return;
48 **/
50 #include "common.h"
51 #include "utils_debug.h"
52 #include "config_list.h"
54 #define BUFSIZE 512
56 /* private prototypes */
58 struct configentry_s;
59 typedef struct configentry_s configentry_t;
61 struct configlist_s {
62 int ignore; /* ignore entries */
63 int num; /* number of entries */
64 configentry_t *next; /* pointer to the first entry */
65 };
67 struct configentry_s {
68 #if HAVE_REGEX_H
69 regex_t *rmatch; /* regular expression entry identification */
70 #endif
71 char *smatch; /* string entry identification */
72 configentry_t *next;
73 };
76 /* *** *** *** ********************************************* *** *** *** */
77 /* *** *** *** *** *** *** private functions *** *** *** *** *** *** */
78 /* *** *** *** ********************************************* *** *** *** */
80 #if HAVE_REGEX_H
81 static int configlist_regappend(configlist_t *conflist, const char *entry)
82 {
83 int rcompile;
84 regex_t *regtemp;
85 char regerr[BUFSIZE];
86 configentry_t *new;
88 /* create buffer */
89 if ((regtemp = malloc(sizeof(regex_t))) == NULL)
90 {
91 syslog (LOG_ERR, "cannot allocate new config entry");
92 regfree (regtemp);
93 return (0);
94 }
95 memset (regtemp, '\0', sizeof(regex_t));
97 /* compile regex */
98 if ((rcompile = regcomp (regtemp, entry, REG_EXTENDED)) != 0)
99 {
100 if (regerror(rcompile, regtemp, regerr, sizeof(regerr)))
101 syslog (LOG_ERR, "cannot compile regex %s: %i/%s",
102 entry, rcompile, regerr);
103 else
104 syslog (LOG_ERR, "cannot compile regex %s: %i",
105 entry, rcompile);
106 regfree (regtemp);
107 return (0);
108 }
109 DBG("regex compiled: %s - %i", entry, rcompile);
111 /* create new entry */
112 if ((new = malloc(sizeof(configentry_t))) == NULL)
113 {
114 syslog (LOG_ERR, "cannot allocate new config entry");
115 regfree (regtemp);
116 return (0);
117 }
118 memset (new, '\0', sizeof(configentry_t));
119 new->rmatch = regtemp;
120 #if COLLECTD_DEBUG
121 new->smatch = sstrdup(entry);
122 #endif
123 /* append new entry */
124 if (conflist->next == NULL)
125 {
126 conflist->next=new;
127 }
128 else
129 {
130 new->next=conflist->next;
131 conflist->next=new;
132 }
133 conflist->num++;
134 return (1);
135 } /* int configlist_regappend(configlist_t *conflist, const char *entry) */
136 #endif
138 static int configlist_strappend(configlist_t *conflist, const char *entry)
139 {
140 configentry_t *new;
142 /* create new entry */
143 if ((new = malloc(sizeof(configentry_t))) == NULL )
144 {
145 syslog (LOG_ERR, "cannot allocate new entry");
146 return (0);
147 }
148 memset (new, '\0', sizeof(configentry_t));
149 new->smatch = sstrdup(entry);
151 /* append new entry */
152 if (conflist->next == NULL)
153 {
154 conflist->next=new;
155 }
156 else
157 {
158 new->next=conflist->next;
159 conflist->next=new;
160 }
161 conflist->num++;
162 return (1);
163 } /* int configlist_strappend(configlist_t *conflist, const char *entry) */
165 #if HAVE_REGEX_H
166 /*
167 * check list for entry regex match
168 * return 1 if found
169 */
170 static int configentry_rmatch (configentry_t *confentry, const char *entry)
171 {
172 if (confentry == NULL)
173 return (0);
175 if (strlen (entry) == 0)
176 return (0);
178 if (confentry->rmatch == NULL)
179 return (0);
181 /* match regex */
182 if (regexec (confentry->rmatch, entry, 0, NULL, 0) == 0)
183 return (1);
185 return (0);
186 } /* int configentry_rmatch (configentry_t *confentry, const char *entry) */
187 #endif
189 /*
190 * check list for entry string match
191 * return 1 if found
192 */
193 static int configentry_smatch (configentry_t *confentry, const char *entry)
194 {
195 if (confentry == NULL)
196 return (0);
198 if (strlen (entry) == 0)
199 return (0);
201 if ((confentry->smatch != NULL && strcmp (entry, confentry->smatch) == 0))
202 return (1);
204 return (0);
205 } /* int configentry_smatch (configentry_t *confentry, const char *entry) */
208 /* *** *** *** ******************************************** *** *** *** */
209 /* *** *** *** *** *** *** public functions *** *** *** *** *** *** */
210 /* *** *** *** ******************************************** *** *** *** */
212 /*
213 * create the configlist_t with known ignore state
214 * return pointer to configlist_t
215 */
216 configlist_t *configlist_create (int ignore)
217 {
218 configlist_t *conflist;
220 if ((conflist = smalloc (sizeof (configlist_t))) == NULL)
221 {
222 syslog(LOG_ERR, "not enough memory to allocate configlist");
223 return (NULL);
224 }
225 DBG("configlist created 0x%p, ignore %i", (void *) conflist, ignore);
226 memset (conflist, '\0', sizeof (configlist_t));
228 if (ignore)
229 conflist->ignore = ignore;
231 return (conflist);
232 } /* configlist_t *configlist_create (int ignore) */
234 /*
235 * create configlist_t and initialize the ignore state to 0
236 * return pointer to configlist_t
237 */
238 configlist_t *configlist_init (void)
239 {
240 return (configlist_create (0));
241 } /* configlist_t *configlist_init (void) */
244 /*
245 * free memory used by configlist_t
246 */
247 void configlist_free (configlist_t *conflist)
248 {
249 configentry_t *this;
250 configentry_t *next;
252 DBG ("(conflist = 0x%p)", (void *) conflist);
254 if (conflist == NULL)
255 return;
257 for (this = conflist->next; this != NULL; this = next)
258 {
259 DBG ("free - confentry = 0x%p, numlist %i", (void *) this, conflist->num);
260 next = this->next;
261 conflist->num--;
262 #if HAVE_REGEX_H
263 if (this->rmatch != NULL)
264 {
265 regfree (this->rmatch);
266 this->rmatch = NULL;
267 }
268 #endif
269 if (this->smatch != NULL)
270 {
271 sfree (this->smatch);
272 this->smatch = NULL;
273 }
274 sfree (this);
275 }
276 #if COLLECTD_DEBUG
277 if (conflist->num != 0)
278 DBG ("after free numlist: %i", conflist->num);
279 #endif
280 conflist->num = 0;
281 sfree (conflist);
282 conflist = NULL;
283 } /* void configlist_destroy (configlist_t *conflist) */
285 /*
286 * set ignore state of the configlist_t
287 */
288 void configlist_ignore (configlist_t *conflist, int ignore)
289 {
290 if (conflist == NULL)
291 {
292 DBG("ignore call with configlist_t == NULL");
293 return;
294 }
296 conflist->ignore = ignore;
297 } /* void configlist_ignore (configlist_t *conflist, int ignore) */
299 /*
300 * get number of entries in the configlist_t
301 * return int number
302 */
303 int configlist_num (configlist_t *conflist)
304 {
305 if (conflist == NULL)
306 {
307 DBG("get num called with configlist_t == NULL");
308 return (0);
309 }
311 return (conflist->num);
312 } /* int configlist_num (configlist_t *conflist) */
314 /*
315 * append entry into configlist_t
316 * return 1 for success
317 */
318 int configlist_add (configlist_t *conflist, const char *entry)
319 {
320 #if HAVE_REGEX_H
321 char *entrytemp;
322 #endif
323 int restemp;
325 if (conflist == NULL)
326 {
327 DBG("add called with configlist_t == NULL");
328 return (0);
329 }
331 /* append nothing, report success */
332 if (strlen(entry) == 0)
333 {
334 DBG("not appending: empty entry");
335 return (1);
336 }
338 #if HAVE_REGEX_H
339 /* regex string is enclosed in "|...|" */
340 if (entry[0] == '|' && strlen(entry) > 2 && entry[strlen(entry) - 1] == '|')
341 {
342 entrytemp = smalloc(strlen(entry) - 2);
343 sstrncpy(entrytemp, &entry[1], strlen(entry) - 1);
344 DBG("to add regex entry: %s", entrytemp);
345 restemp = configlist_regappend(conflist, entrytemp);
346 sfree (entrytemp);
347 }
348 else
349 #endif
350 {
351 DBG("to add entry: %s", entry);
352 restemp = configlist_strappend(conflist, entry);
353 }
354 return (restemp);
355 } /* int configlist_add (configlist_t *conflist, const char *entry) */
357 /*
358 * check list for entry
359 * return 1 for ignored entry
360 */
361 int configlist_ignored (configlist_t *conflist, const char *entry)
362 {
363 configentry_t *traverse;
365 /* if no entries, collect all */
366 if (configlist_num(conflist) == 0)
367 return (0);
369 /* traverse list and check entries */
370 traverse = conflist->next;
371 while (traverse != NULL)
372 {
373 #if HAVE_REGEX_H
374 if (traverse->rmatch != NULL)
375 {
376 if (configentry_rmatch (traverse, entry))
377 return (conflist->ignore);
378 }
379 else
380 #endif
381 {
382 if (configentry_smatch (traverse, entry))
383 return (conflist->ignore);
384 }
385 traverse = traverse->next;
386 }
388 return (1 - conflist->ignore);
389 } /* int configlist_ignored (configlist_t *conflist, const char *entry) */