Code

Improve and generalize the ignorelist functionality.
[collectd.git] / src / config_list.c
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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) */