Code

More improvementa on 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 pointer variable of type configlist_t:
31  *   configlist_t *myconfig_ignore;
32  * If you know the state of the 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,
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 is 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 /* private prototypes */
56 struct configentry_s;
57 typedef struct configentry_s configentry_t;
59 struct configlist_s {
60         int ignore;             /* ignore entries */
61         int num;                /* number of entries */
62         configentry_t *next;    /* pointer to the first entry */
63 };
65 struct configentry_s {
66 #if HAVE_REGEX_H
67         regex_t *rmatch;        /* regular expression entry identification */
68 #endif
69         char *smatch;           /* string entry identification */
70         configentry_t *next;
71 };
74 /* *** *** *** ********************************************* *** *** *** */
75 /* *** *** *** *** *** ***   private functions   *** *** *** *** *** *** */
76 /* *** *** *** ********************************************* *** *** *** */
78 #if HAVE_REGEX_H
79 static int configlist_regappend(configlist_t *conflist, const char *entry)
80 {
81         int rcompile;
82         regex_t *regtemp;
83         int errsize;
84         char *regerr = NULL;
85         configentry_t *new;
87         /* create buffer */
88         if ((regtemp = malloc(sizeof(regex_t))) == NULL)
89         {
90                 syslog (LOG_ERR, "cannot allocate new config entry");
91                 return (0);
92         }
93         memset (regtemp, '\0', sizeof(regex_t));
95         /* compile regex */
96         if ((rcompile = regcomp (regtemp, entry, REG_EXTENDED)) != 0)
97         {
98                 /* prepare message buffer */
99                 errsize = regerror(rcompile, regtemp, NULL, 0);
100                 if (errsize)
101                         regerr = smalloc(errsize);
102                 /* get error message */
103                 if (regerror(rcompile, regtemp, regerr, errsize))
104                         syslog (LOG_ERR, "cannot compile regex %s: %i/%s",
105                                         entry, rcompile, regerr);
106                 else
107                         syslog (LOG_ERR, "cannot compile regex %s: %i",
108                                         entry, rcompile);
109                 if (errsize)
110                         sfree (regerr);
111                 regfree (regtemp);
112                 return (0);
113         }
114         DBG("regex compiled: %s - %i", entry, rcompile);
116         /* create new entry */
117         if ((new = malloc(sizeof(configentry_t))) == NULL)
118         {
119                 syslog (LOG_ERR, "cannot allocate new config entry");
120                 regfree (regtemp);
121                 return (0);
122         }
123         memset (new, '\0', sizeof(configentry_t));
124         new->rmatch = regtemp;
126         /* append new entry */
127         if (conflist->next == NULL)
128         {
129                 conflist->next=new;
130         }
131         else
132         {
133                 new->next=conflist->next;
134                 conflist->next=new;             
135         }
136         conflist->num++;
137         return (1);
138 } /* int configlist_regappend(configlist_t *conflist, const char *entry) */
139 #endif
141 static int configlist_strappend(configlist_t *conflist, const char *entry)
143         configentry_t *new;
145         /* create new entry */
146         if ((new = malloc(sizeof(configentry_t))) == NULL )
147         {
148                 syslog (LOG_ERR, "cannot allocate new entry");
149                 return (0);
150         }
151         memset (new, '\0', sizeof(configentry_t));
152         new->smatch = sstrdup(entry);
154         /* append new entry */
155         if (conflist->next == NULL)
156         {
157                 conflist->next=new;
158         }
159         else
160         {
161                 new->next=conflist->next;
162                 conflist->next=new;             
163         }
164         conflist->num++;
165         return (1);
166 } /* int configlist_strappend(configlist_t *conflist, const char *entry) */
168 #if HAVE_REGEX_H
169 /*
170  * check list for entry regex match
171  * return 1 if found
172  */
173 static int configentry_rmatch (configentry_t *confentry, const char *entry)
175         if (confentry == NULL)
176                 return (0);
178         if (strlen (entry) == 0)
179                 return (0);
181         if (confentry->rmatch == NULL)
182                 return (0);
184         /* match regex */
185         if (regexec (confentry->rmatch, entry, 0, NULL, 0) == 0)
186                 return (1);
188         return (0);
189 } /* int configentry_rmatch (configentry_t *confentry, const char *entry) */
190 #endif
192 /*
193  * check list for entry string match
194  * return 1 if found
195  */
196 static int configentry_smatch (configentry_t *confentry, const char *entry)
198         if (confentry == NULL)
199                 return (0);
201         if (strlen (entry) == 0)
202                 return (0);
204         if ((confentry->smatch != NULL && strcmp (entry, confentry->smatch) == 0))
205                 return (1);
207         return (0);
208 } /* int configentry_smatch (configentry_t *confentry, const char *entry) */
211 /* *** *** *** ******************************************** *** *** *** */
212 /* *** *** *** *** *** ***   public functions   *** *** *** *** *** *** */
213 /* *** *** *** ******************************************** *** *** *** */
215 /*
216  * create the configlist_t with known ignore state
217  * return pointer to configlist_t
218  */
219 configlist_t *configlist_create (int ignore)
221         configlist_t *conflist;
223         if ((conflist = smalloc (sizeof (configlist_t))) == NULL)
224         {
225                 syslog(LOG_ERR, "not enough memory to allocate configlist");
226                 return (NULL);
227         }
228         DBG("configlist created 0x%p, ignore %i", (void *) conflist, ignore);
229         memset (conflist, '\0', sizeof (configlist_t));
231         if (ignore)
232                 conflist->ignore = ignore;
234         return (conflist);
235 } /* configlist_t *configlist_create (int ignore) */
237 /*
238  * create configlist_t and initialize the ignore state to 0
239  * return pointer to configlist_t
240  */
241 configlist_t *configlist_init (void)
243         return (configlist_create (0));
244 } /* configlist_t *configlist_init (void)  */
247 /*
248  * free memory used by configlist_t
249  */
250 void configlist_free (configlist_t *conflist)
252         configentry_t *this;
253         configentry_t *next;
255         DBG ("(conflist = 0x%p)", (void *) conflist);
257         if (conflist == NULL)
258                 return;
260         for (this = conflist->next; this != NULL; this = next)
261         {
262                 DBG ("free - confentry = 0x%p, numlist %i", (void *) this, conflist->num);
263                 next = this->next;
264                 conflist->num--;
265 #if HAVE_REGEX_H
266                 if (this->rmatch != NULL)
267                 {
268                         regfree (this->rmatch);
269                         this->rmatch = NULL;
270                 }
271 #endif
272                 if (this->smatch != NULL)
273                 {
274                         sfree (this->smatch);
275                         this->smatch = NULL;
276                 }
277                 sfree (this);
278         }
279 #if COLLECTD_DEBUG
280         if (conflist->num != 0)
281                 DBG ("after free numlist: %i", conflist->num);
282 #endif
283         conflist->num = 0;
284         sfree (conflist);
285         conflist = NULL;
286 } /* void configlist_destroy (configlist_t *conflist) */
288 /*
289  * set ignore state of the configlist_t
290  */
291 void configlist_ignore (configlist_t *conflist, int ignore)
293         if (conflist == NULL)
294         {
295                 DBG("ignore call with configlist_t == NULL");
296                 return;
297         }
299         conflist->ignore = ignore;
300 } /* void configlist_ignore (configlist_t *conflist, int ignore) */
302 /*
303  * get number of entries in the configlist_t
304  * return int number
305  */
306 int configlist_num (configlist_t *conflist)
308         if (conflist == NULL)
309         {
310                 DBG("get num called with configlist_t == NULL");
311                 return (0);
312         }
314         return (conflist->num);
315 } /* int configlist_num (configlist_t *conflist) */
317 /*
318  * append entry into configlist_t
319  * return 1 for success
320  */
321 int configlist_add (configlist_t *conflist, const char *entry)
323 #if HAVE_REGEX_H
324         char *entrytemp;
325 #endif
326         int restemp;
328         if (conflist == NULL)
329         {
330                 DBG("add called with configlist_t == NULL");
331                 return (0);
332         }
334         /* append nothing, report success */
335         if (strlen(entry) == 0)
336         {
337                 DBG("not appending: empty entry");
338                 return (1);
339         }
341 #if HAVE_REGEX_H
342         /* regex string is enclosed in "/.../" */
343         if (entry[0] == '/' && strlen(entry) > 2 && entry[strlen(entry) - 1] == '/')
344         {
345                 entrytemp = smalloc(strlen(entry) - 2);
346                 sstrncpy(entrytemp, &entry[1], strlen(entry) - 1);
347                 DBG("to add regex entry: %s", entrytemp);
348                 restemp = configlist_regappend(conflist, entrytemp);
349                 sfree (entrytemp);
350         }
351         else
352 #endif
353         {
354                 DBG("to add entry: %s", entry);
355                 restemp = configlist_strappend(conflist, entry);
356         }
357         return (restemp);
358 } /* int configlist_add (configlist_t *conflist, const char *entry) */
360 /*
361  * check list for entry
362  * return 1 for ignored entry
363  */
364 int configlist_ignored (configlist_t *conflist, const char *entry)
366         configentry_t *traverse;
368         /* if no entries, collect all */
369         if (configlist_num(conflist) == 0)
370                 return (0);
372         /* traverse list and check entries */
373         traverse = conflist->next;
374         while (traverse != NULL)
375         {
376 #if HAVE_REGEX_H
377                 if (traverse->rmatch != NULL)
378                 {
379                         if (configentry_rmatch (traverse, entry))
380                                 return (conflist->ignore);
381                 }
382                 else
383 #endif
384                 {
385                         if (configentry_smatch (traverse, entry))
386                                 return (conflist->ignore);
387                 }
388                 traverse = traverse->next;
389         }
391         return (1 - conflist->ignore);
392 } /* int configlist_ignored (configlist_t *conflist, const char *entry) */