Removed `#if HAVE_LIBRRD' around `plugin_write': The logmode works even without librrd.
[collectd.git] / src / plugin.c
1 /**
2  * collectd - src/plugin.c
3  * Copyright (C) 2005  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24
25 #include <ltdl.h>
26
27 #include "plugin.h"
28 #include "network.h"
29
30 typedef struct plugin
31 {
32         char *type;
33         void (*init) (void);
34         void (*read) (void);
35         void (*write) (char *host, char *inst, char *val);
36         struct plugin *next;
37 } plugin_t;
38
39 static plugin_t *first_plugin = NULL;
40
41 extern int operating_mode;
42
43 static char *plugindir = NULL;
44
45 char *plugin_get_dir (void)
46 {
47         if (plugindir == NULL)
48                 return (PLUGINDIR);
49         else
50                 return (plugindir);
51 }
52
53 void plugin_set_dir (const char *dir)
54 {
55         if (plugindir != NULL)
56                 free (plugindir);
57
58         if (dir == NULL)
59                 plugindir = NULL;
60         else if ((plugindir = strdup (dir)) == NULL)
61                 syslog (LOG_ERR, "strdup: %s", strerror (errno));
62 }
63
64 /*
65  * Returns the number of plugins registered
66  */
67 int plugin_count (void)
68 {
69         int i;
70         plugin_t *p;
71
72         for (i = 0, p = first_plugin; p != NULL; p = p->next)
73                 i++;
74
75         return (i);
76 }
77
78 /*
79  * Returns the plugins with the type `type' or NULL if it's not found.
80  */
81 plugin_t *plugin_search (const char *type)
82 {
83         plugin_t *ret;
84
85         if (type == NULL)
86                 return (NULL);
87
88         for (ret = first_plugin; ret != NULL; ret = ret->next)
89                 if (strcmp (ret->type, type) == 0)
90                         break;
91
92         return (ret);
93 }
94
95 /*
96  * Returns true if the plugin is loaded (i.e. `exists') and false otherwise.
97  * This is used in `configfile.c' to skip sections that are not needed..
98  */
99 int plugin_exists (char *type)
100 {
101         if (plugin_search (type) == NULL)
102                 return (0);
103         else
104                 return (1);
105 }
106
107 /*
108  * (Try to) load the shared object `file'. Won't complain if it isn't a shared
109  * object, but it will bitch about a shared object not having a
110  * ``module_register'' symbol..
111  */
112 int plugin_load_file (char *file)
113 {
114         lt_dlhandle dlh;
115         void (*reg_handle) (void);
116
117         lt_dlinit ();
118         lt_dlerror (); /* clear errors */
119
120         if ((dlh = lt_dlopen (file)) == NULL)
121                 return (1);
122
123         if ((reg_handle = lt_dlsym (dlh, "module_register")) == NULL)
124         {
125                 syslog (LOG_WARNING, "Couldn't find symbol ``module_register'' in ``%s'': %s\n",
126                                 file, lt_dlerror ());
127                 lt_dlclose (dlh);
128                 return (-1);
129         }
130
131         (*reg_handle) ();
132
133         return (0);
134 }
135
136 #define BUFSIZE 512
137 int plugin_load (const char *type)
138 {
139         DIR  *dh;
140         char *dir;
141         char  filename[BUFSIZE];
142         char  typename[BUFSIZE];
143         int   typename_len;
144         int   ret;
145         struct stat    statbuf;
146         struct dirent *de;
147
148         dir = plugin_get_dir ();
149         ret = 1;
150
151         /* don't load twice */
152         if (plugin_search (type) != NULL)
153                 return (0);
154
155         /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
156          * type when matching the filename */
157         if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
158         {
159                 syslog (LOG_WARNING, "snprintf: truncated: `%s.so'", type);
160                 return (-1);
161         }
162         typename_len = strlen (typename);
163
164         if ((dh = opendir (dir)) == NULL)
165         {
166                 syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
167                 return (-1);
168         }
169
170         while ((de = readdir (dh)) != NULL)
171         {
172                 if (strncasecmp (de->d_name, typename, typename_len))
173                         continue;
174
175                 if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
176                 {
177                         syslog (LOG_WARNING, "snprintf: truncated: `%s/%s'", dir, de->d_name);
178                         continue;
179                 }
180
181                 if (lstat (filename, &statbuf) == -1)
182                 {
183                         syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
184                         continue;
185                 }
186                 else if (!S_ISREG (statbuf.st_mode))
187                 {
188                         /* don't follow symlinks */
189                         continue;
190                 }
191
192                 if (plugin_load_file (filename) == 0)
193                 {
194                         /* success */
195                         ret = 0;
196                         break;
197                 }
198         }
199
200         closedir (dh);
201
202         return (ret);
203 }
204
205 /*
206  * (Try to) load all plugins in `dir'. Returns the number of loaded plugins..
207  */
208 int plugin_load_all (char *dir)
209 {
210         DIR *dh;
211         struct dirent *de;
212         char filename[BUFSIZE];
213         struct stat statbuf;
214
215         if (dir == NULL)
216                 dir = plugin_get_dir ();
217         else
218                 plugin_set_dir (dir);
219
220         if ((dh = opendir (dir)) == NULL)
221         {
222                 syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
223                 return (0);
224         }
225
226         while ((de = readdir (dh)) != NULL)
227         {
228                 if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
229                 {
230                         syslog (LOG_WARNING, "snprintf: truncated: %s/%s", dir, de->d_name);
231                         continue;
232                 }
233
234                 if (lstat (filename, &statbuf) == -1)
235                 {
236                         syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
237                         continue;
238                 }
239                 else if (!S_ISREG (statbuf.st_mode))
240                 {
241                         continue;
242                 }
243
244                 plugin_load_file (filename);
245         }
246
247         closedir (dh);
248
249         return (plugin_count ());
250 }
251 #undef BUFSIZE
252
253 /*
254  * Call `init' on all plugins (if given)
255  */
256 void plugin_init_all (void)
257 {
258         plugin_t *p;
259
260         for (p = first_plugin; p != NULL; p = p->next)
261                 if (p->init != NULL)
262                         (*p->init) ();
263 }
264
265 /*
266  * Call `read' on all plugins (if given)
267  */
268 void plugin_read_all (void)
269 {
270         plugin_t *p;
271
272         for (p = first_plugin; p != NULL; p = p->next)
273                 if (p->read != NULL)
274                         (*p->read) ();
275 }
276
277 /*
278  * Add plugin to the linked list of registered plugins.
279  */
280 void plugin_register (char *type,
281                 void (*init) (void),
282                 void (*read) (void),
283                 void (*write) (char *, char *, char *))
284 {
285         plugin_t *p;
286
287         if (plugin_search (type) != NULL)
288                 return;
289
290 #ifdef HAVE_LIBRRD
291         if (operating_mode != MODE_SERVER)
292 #endif
293                 if ((init != NULL) && (read == NULL))
294                         syslog (LOG_NOTICE, "Plugin `%s' doesn't provide a read function.", type);
295
296         if ((p = (plugin_t *) malloc (sizeof (plugin_t))) == NULL)
297                 return;
298
299         if ((p->type = strdup (type)) == NULL)
300         {
301                 free (p);
302                 return;
303         }
304
305         p->init  = init;
306         p->read  = read;
307         p->write = write;
308
309         p->next = first_plugin;
310         first_plugin = p;
311 }
312
313 /*
314  * Send received data back to the plugin/module which will append DS
315  * definitions and pass it on to ``rrd_update_file''.
316  */
317 void plugin_write (char *host, char *type, char *inst, char *val)
318 {
319         plugin_t *p;
320
321         if ((p = plugin_search (type)) == NULL)
322                 return;
323
324         if (p->write == NULL)
325                 return;
326
327         (*p->write) (host, inst, val);
328 }
329
330 /*
331  * Receive data from the plugin/module and get it somehow to ``plugin_write'':
332  * Either using ``network_send'' (when in network/client mode) or call it
333  * directly (in local mode).
334  */
335 void plugin_submit (char *type, char *inst, char *val)
336 {
337         if (operating_mode == MODE_CLIENT)
338                 network_send (type, inst, val);
339         else
340                 plugin_write (NULL, type, inst, val);
341 }