Merge remote branch 'trenkel/st/python'
[collectd.git] / src / python.c
1 /**
2  * collectd - src/python.c
3  * Copyright (C) 2009  Sven Trenkel
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Sven Trenkel <collectd at semidefinite.de>  
25  **/
26
27 #include <Python.h>
28 #include <structmember.h>
29
30 #include <signal.h>
31 #if HAVE_PTHREAD_H
32 # include <pthread.h>
33 #endif
34
35 #include "collectd.h"
36 #include "common.h"
37
38 #include "cpython.h"
39
40 typedef struct cpy_callback_s {
41         char *name;
42         PyObject *callback;
43         PyObject *data;
44         struct cpy_callback_s *next;
45 } cpy_callback_t;
46
47 static char log_doc[] = "This function sends a string to all logging plugins.";
48
49 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
50                 "\n"
51                 "Flushes the cache of another plugin.";
52
53 static char unregister_doc[] = "Unregisters a callback. This function needs exactly one parameter either\n"
54                 "the function to unregister or the callback identifier to unregister.";
55
56 static char reg_log_doc[] = "register_log(callback[, data][, name]) -> identifier\n"
57                 "\n"
58                 "Register a callback function for log messages.\n"
59                 "\n"
60                 "'callback' is a callable object that will be called every time something\n"
61                 "    is logged.\n"
62                 "'data' is an optional object that will be passed back to the callback\n"
63                 "    function every time it is called.\n"
64                 "'name' is an optional identifier for this callback. The default name\n"
65                 "    is 'python.<module>'.\n"
66                 "    Every callback needs a unique identifier, so if you want to\n"
67                 "    register this callback multiple time from the same module you need\n"
68                 "    to specify a name here.\n"
69                 "'identifier' is the full identifier assigned to this callback.\n"
70                 "\n"
71                 "The callback function will be called with two or three parameters:\n"
72                 "severity: An integer that should be compared to the LOG_ constants.\n"
73                 "message: The text to be logged.\n"
74                 "data: The optional data parameter passed to the register function.\n"
75                 "    If the parameter was omitted it will be omitted here, too.";
76
77 static char reg_init_doc[] = "register_init(callback[, data][, name]) -> identifier\n"
78                 "\n"
79                 "Register a callback function that will be executed once after the config.\n"
80                 "file has been read, all plugins heve been loaded and the collectd has\n"
81                 "forked into the background.\n"
82                 "\n"
83                 "'callback' is a callable object that will be executed.\n"
84                 "'data' is an optional object that will be passed back to the callback\n"
85                 "    function when it is called.\n"
86                 "'name' is an optional identifier for this callback. The default name\n"
87                 "    is 'python.<module>'.\n"
88                 "    Every callback needs a unique identifier, so if you want to\n"
89                 "    register this callback multiple time from the same module you need\n"
90                 "    to specify a name here.\n"
91                 "'identifier' is the full identifier assigned to this callback.\n"
92                 "\n"
93                 "The callback function will be called without parameters, except for\n"
94                 "data if it was supplied.";
95
96 static char reg_config_doc[] = "register_config(callback[, data][, name]) -> identifier\n"
97                 "\n"
98                 "Register a callback function for config file entries.\n"
99                 "'callback' is a callable object that will be called for every config block.\n"
100                 "'data' is an optional object that will be passed back to the callback\n"
101                 "    function every time it is called.\n"
102                 "'name' is an optional identifier for this callback. The default name\n"
103                 "    is 'python.<module>'.\n"
104                 "    Every callback needs a unique identifier, so if you want to\n"
105                 "    register this callback multiple time from the same module you need\n"
106                 "    to specify a name here.\n"
107                 "'identifier' is the full identifier assigned to this callback.\n"
108                 "\n"
109                 "The callback function will be called with one or two parameters:\n"
110                 "config: A Config object.\n"
111                 "data: The optional data parameter passed to the register function.\n"
112                 "    If the parameter was omitted it will be omitted here, too.";
113
114 static char reg_read_doc[] = "register_read(callback[, interval][, data][, name]) -> identifier\n"
115                 "\n"
116                 "Register a callback function for reading data. It will just be called\n"
117                 "in a fixed interval to signal that it's time to dispatch new values.\n"
118                 "'callback' is a callable object that will be called every time something\n"
119                 "    is logged.\n"
120                 "'interval' is the number of seconds between between calls to the callback\n"
121                 "    function. Full float precision is supported here.\n"
122                 "'data' is an optional object that will be passed back to the callback\n"
123                 "    function every time it is called.\n"
124                 "'name' is an optional identifier for this callback. The default name\n"
125                 "    is 'python.<module>'.\n"
126                 "    Every callback needs a unique identifier, so if you want to\n"
127                 "    register this callback multiple time from the same module you need\n"
128                 "    to specify a name here.\n"
129                 "'identifier' is the full identifier assigned to this callback.\n"
130                 "\n"
131                 "The callback function will be called without parameters, except for\n"
132                 "data if it was supplied.";
133
134 static char reg_write_doc[] = "register_write(callback[, data][, name]) -> identifier\n"
135                 "\n"
136                 "Register a callback function to receive values dispatched by other plugins.\n"
137                 "'callback' is a callable object that will be called every time a value\n"
138                 "    is dispatched.\n"
139                 "'data' is an optional object that will be passed back to the callback\n"
140                 "    function every time it is called.\n"
141                 "'name' is an optional identifier for this callback. The default name\n"
142                 "    is 'python.<module>'.\n"
143                 "    Every callback needs a unique identifier, so if you want to\n"
144                 "    register this callback multiple time from the same module you need\n"
145                 "    to specify a name here.\n"
146                 "'identifier' is the full identifier assigned to this callback.\n"
147                 "\n"
148                 "The callback function will be called with one or two parameters:\n"
149                 "values: A Values object which is a copy of the dispatched values.\n"
150                 "data: The optional data parameter passed to the register function.\n"
151                 "    If the parameter was omitted it will be omitted here, too.";
152
153 static char reg_notification_doc[] = "register_notification(callback[, data][, name]) -> identifier\n"
154                 "\n"
155                 "Register a callback function for notifications.\n"
156                 "'callback' is a callable object that will be called every time a notification\n"
157                 "    is dispatched.\n"
158                 "'data' is an optional object that will be passed back to the callback\n"
159                 "    function every time it is called.\n"
160                 "'name' is an optional identifier for this callback. The default name\n"
161                 "    is 'python.<module>'.\n"
162                 "    Every callback needs a unique identifier, so if you want to\n"
163                 "    register this callback multiple time from the same module you need\n"
164                 "    to specify a name here.\n"
165                 "'identifier' is the full identifier assigned to this callback.\n"
166                 "\n"
167                 "The callback function will be called with one or two parameters:\n"
168                 "notification: A copy of the notification that was dispatched.\n"
169                 "data: The optional data parameter passed to the register function.\n"
170                 "    If the parameter was omitted it will be omitted here, too.";
171
172 static char reg_flush_doc[] = "register_flush(callback[, data][, name]) -> identifier\n"
173                 "\n"
174                 "Register a callback function for flush messages.\n"
175                 "'callback' is a callable object that will be called every time a plugin\n"
176                 "    requests a flush for either this or all plugins.\n"
177                 "'data' is an optional object that will be passed back to the callback\n"
178                 "    function every time it is called.\n"
179                 "'name' is an optional identifier for this callback. The default name\n"
180                 "    is 'python.<module>'.\n"
181                 "    Every callback needs a unique identifier, so if you want to\n"
182                 "    register this callback multiple time from the same module you need\n"
183                 "    to specify a name here.\n"
184                 "'identifier' is the full identifier assigned to this callback.\n"
185                 "\n"
186                 "The callback function will be called with two or three parameters:\n"
187                 "timeout: Indicates that only data older than 'timeout' seconds is to\n"
188                 "    be flushed.\n"
189                 "id: Specifies which values are to be flushed.\n"
190                 "data: The optional data parameter passed to the register function.\n"
191                 "    If the parameter was omitted it will be omitted here, too.";
192
193 static char reg_shutdown_doc[] = "register_shutdown(callback[, data][, name]) -> identifier\n"
194                 "\n"
195                 "Register a callback function for collectd shutdown.\n"
196                 "'callback' is a callable object that will be called once collectd is\n"
197                 "    shutting down.\n"
198                 "'data' is an optional object that will be passed back to the callback\n"
199                 "    function if it is called.\n"
200                 "'name' is an optional identifier for this callback. The default name\n"
201                 "    is 'python.<module>'.\n"
202                 "    Every callback needs a unique identifier, so if you want to\n"
203                 "    register this callback multiple time from the same module you need\n"
204                 "    to specify a name here.\n"
205                 "'identifier' is the full identifier assigned to this callback.\n"
206                 "\n"
207                 "The callback function will be called with no parameters except for\n"
208                 "    data if it was supplied.";
209
210
211 static int do_interactive = 0;
212
213 /* This is our global thread state. Python saves some stuff in thread-local
214  * storage. So if we allow the interpreter to run in the background
215  * (the scriptwriters might have created some threads from python), we have
216  * to save the state so we can resume it later after shutdown. */
217
218 static PyThreadState *state;
219
220 static PyObject *cpy_format_exception;
221
222 static cpy_callback_t *cpy_config_callbacks;
223 static cpy_callback_t *cpy_init_callbacks;
224 static cpy_callback_t *cpy_shutdown_callbacks;
225
226 static void cpy_destroy_user_data(void *data) {
227         cpy_callback_t *c = data;
228         free(c->name);
229         Py_DECREF(c->callback);
230         Py_XDECREF(c->data);
231         free(c);
232 }
233
234 /* You must hold the GIL to call this function!
235  * But if you managed to extract the callback parameter then you probably already do. */
236
237 static void cpy_build_name(char *buf, size_t size, PyObject *callback, const char *name) {
238         const char *module = NULL;
239         PyObject *mod = NULL;
240         
241         if (name != NULL) {
242                 snprintf(buf, size, "python.%s", name);
243                 return;
244         }
245         
246         mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
247         if (mod != NULL)
248                 module = cpy_unicode_or_bytes_to_string(&mod);
249         
250         if (module != NULL) {
251                 snprintf(buf, size, "python.%s", module);
252                 Py_XDECREF(mod);
253                 PyErr_Clear();
254                 return;
255         }
256         Py_XDECREF(mod);
257         
258         snprintf(buf, size, "python.%p", callback);
259         PyErr_Clear();
260 }
261
262 void cpy_log_exception(const char *context) {
263         int l = 0, i;
264         const char *typename = NULL, *message = NULL;
265         PyObject *type, *value, *traceback, *tn, *m, *list;
266         
267         PyErr_Fetch(&type, &value, &traceback);
268         PyErr_NormalizeException(&type, &value, &traceback);
269         if (type == NULL) return;
270         tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
271         m = PyObject_Str(value); /* New reference. */
272         if (tn != NULL)
273                 typename = cpy_unicode_or_bytes_to_string(&tn);
274         if (m != NULL)
275                 message = cpy_unicode_or_bytes_to_string(&m);
276         if (typename == NULL)
277                 typename = "NamelessException";
278         if (message == NULL)
279                 message = "N/A";
280         Py_BEGIN_ALLOW_THREADS
281         ERROR("Unhandled python exception in %s: %s: %s", context, typename, message);
282         Py_END_ALLOW_THREADS
283         Py_XDECREF(tn);
284         Py_XDECREF(m);
285         if (!cpy_format_exception) {
286                 PyErr_Clear();
287                 Py_XDECREF(type);
288                 Py_XDECREF(value);
289                 Py_XDECREF(traceback);
290                 return;
291         }
292         if (!traceback) {
293                 PyErr_Clear();
294                 return;
295         }
296         list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
297         if (list)
298                 l = PyObject_Length(list);
299         for (i = 0; i < l; ++i) {
300                 char *s;
301                 PyObject *line;
302                 
303                 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
304                 Py_INCREF(line);
305                 s = strdup(cpy_unicode_or_bytes_to_string(&line));
306                 Py_DECREF(line);
307                 if (s[strlen(s) - 1] == '\n')
308                         s[strlen(s) - 1] = 0;
309                 Py_BEGIN_ALLOW_THREADS
310                 ERROR("%s", s);
311                 Py_END_ALLOW_THREADS
312                 free(s);
313         }
314         Py_XDECREF(list);
315         PyErr_Clear();
316 }
317
318 static int cpy_read_callback(user_data_t *data) {
319         cpy_callback_t *c = data->data;
320         PyObject *ret;
321
322         CPY_LOCK_THREADS
323                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
324                 if (ret == NULL) {
325                         cpy_log_exception("read callback");
326                 } else {
327                         Py_DECREF(ret);
328                 }
329         CPY_RELEASE_THREADS
330         if (ret == NULL)
331                 return 1;
332         return 0;
333 }
334
335 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
336         int i;
337         cpy_callback_t *c = data->data;
338         PyObject *ret, *list, *temp, *dict = NULL;
339         Values *v;
340
341         CPY_LOCK_THREADS
342                 list = PyList_New(value_list->values_len); /* New reference. */
343                 if (list == NULL) {
344                         cpy_log_exception("write callback");
345                         CPY_RETURN_FROM_THREADS 0;
346                 }
347                 for (i = 0; i < value_list->values_len; ++i) {
348                         if (ds->ds->type == DS_TYPE_COUNTER) {
349                                 if ((long) value_list->values[i].counter == value_list->values[i].counter)
350                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
351                                 else
352                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
353                         } else if (ds->ds->type == DS_TYPE_GAUGE) {
354                                 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
355                         } else if (ds->ds->type == DS_TYPE_DERIVE) {
356                                 if ((long) value_list->values[i].derive == value_list->values[i].derive)
357                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
358                                 else
359                                         PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
360                         } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
361                                 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
362                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
363                                 else
364                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
365                         } else {
366                                 Py_BEGIN_ALLOW_THREADS
367                                 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
368                                 Py_END_ALLOW_THREADS
369                                 Py_DECREF(list);
370                                 CPY_RETURN_FROM_THREADS 0;
371                         }
372                         if (PyErr_Occurred() != NULL) {
373                                 cpy_log_exception("value building for write callback");
374                                 CPY_RETURN_FROM_THREADS 0;
375                         }
376                 }
377                 dict = PyDict_New();
378                 if (value_list->meta) {
379                         int i, num;
380                         char **table;
381                         meta_data_t *meta = value_list->meta;
382
383                         num = meta_data_toc(meta, &table);
384                         for (i = 0; i < num; ++i) {
385                                 int type;
386                                 char *string;
387                                 int64_t si;
388                                 uint64_t ui;
389                                 double d;
390                                 _Bool b;
391                                 
392                                 type = meta_data_type(meta, table[i]);
393                                 if (type == MD_TYPE_STRING) {
394                                         if (meta_data_get_string(meta, table[i], &string))
395                                                 continue;
396                                         temp = cpy_string_to_unicode_or_bytes(string);
397                                         free(string);
398                                         PyDict_SetItemString(dict, table[i], temp);
399                                         Py_XDECREF(temp);
400                                 } else if (type == MD_TYPE_SIGNED_INT) {
401                                         if (meta_data_get_signed_int(meta, table[i], &si))
402                                                 continue;
403                                         temp = PyObject_CallFunctionObjArgs((void *) &SignedType, PyLong_FromLongLong(si), (void *) 0);
404                                         PyDict_SetItemString(dict, table[i], temp);
405                                         Py_XDECREF(temp);
406                                 } else if (type == MD_TYPE_UNSIGNED_INT) {
407                                         if (meta_data_get_unsigned_int(meta, table[i], &ui))
408                                                 continue;
409                                         temp = PyObject_CallFunctionObjArgs((void *) &UnsignedType, PyLong_FromUnsignedLongLong(ui), (void *) 0);
410                                         PyDict_SetItemString(dict, table[i], temp);
411                                         Py_XDECREF(temp);
412                                 } else if (type == MD_TYPE_DOUBLE) {
413                                         if (meta_data_get_double(meta, table[i], &d))
414                                                 continue;
415                                         temp = PyFloat_FromDouble(d);
416                                         PyDict_SetItemString(dict, table[i], temp);
417                                         Py_XDECREF(temp);
418                                 } else if (type == MD_TYPE_BOOLEAN) {
419                                         if (meta_data_get_boolean(meta, table[i], &b))
420                                                 continue;
421                                         if (b)
422                                                 temp = Py_True;
423                                         else
424                                                 temp = Py_False;
425                                         PyDict_SetItemString(dict, table[i], temp);
426                                 }
427                                 free(table[i]);
428                         }
429                         free(table);
430                 }
431                 v = PyObject_New(Values, (void *) &ValuesType);
432                 sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
433                 sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
434                 sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance));
435                 sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
436                 sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance));
437                 v->data.time = value_list->time;
438                 v->interval = value_list->interval;
439                 v->values = list;
440                 v->meta = dict;
441                 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
442                 if (ret == NULL) {
443                         cpy_log_exception("write callback");
444                 } else {
445                         Py_DECREF(ret);
446                 }
447         CPY_RELEASE_THREADS
448         return 0;
449 }
450
451 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
452         cpy_callback_t *c = data->data;
453         PyObject *ret;
454         Notification *n;
455
456         CPY_LOCK_THREADS
457                 n = PyObject_New(Notification, (void *) &NotificationType);
458                 sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
459                 sstrncpy(n->data.type, notification->type, sizeof(n->data.type));
460                 sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance));
461                 sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
462                 sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance));
463                 n->data.time = notification->time;
464                 sstrncpy(n->message, notification->message, sizeof(n->message));
465                 n->severity = notification->severity;
466                 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
467                 if (ret == NULL) {
468                         cpy_log_exception("notification callback");
469                 } else {
470                         Py_DECREF(ret);
471                 }
472         CPY_RELEASE_THREADS
473         return 0;
474 }
475
476 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
477         cpy_callback_t * c = data->data;
478         PyObject *ret, *text;
479
480         CPY_LOCK_THREADS
481         text = cpy_string_to_unicode_or_bytes(message);
482         if (c->data == NULL)
483                 ret = PyObject_CallFunction(c->callback, "iN", severity, text); /* New reference. */
484         else
485                 ret = PyObject_CallFunction(c->callback, "iNO", severity, text, c->data); /* New reference. */
486
487         if (ret == NULL) {
488                 /* FIXME */
489                 /* Do we really want to trigger a log callback because a log callback failed?
490                  * Probably not. */
491                 PyErr_Print();
492                 /* In case someone wanted to be clever, replaced stderr and failed at that. */
493                 PyErr_Clear();
494         } else {
495                 Py_DECREF(ret);
496         }
497         CPY_RELEASE_THREADS
498 }
499
500 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
501         cpy_callback_t * c = data->data;
502         PyObject *ret, *text;
503
504         CPY_LOCK_THREADS
505         text = cpy_string_to_unicode_or_bytes(id);
506         if (c->data == NULL)
507                 ret = PyObject_CallFunction(c->callback, "iN", timeout, text); /* New reference. */
508         else
509                 ret = PyObject_CallFunction(c->callback, "iNO", timeout, text, c->data); /* New reference. */
510
511         if (ret == NULL) {
512                 cpy_log_exception("flush callback");
513         } else {
514                 Py_DECREF(ret);
515         }
516         CPY_RELEASE_THREADS
517 }
518
519 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
520         char buf[512];
521         cpy_callback_t *c;
522         const char *name = NULL;
523         PyObject *callback = NULL, *data = NULL, *mod = NULL;
524         static char *kwlist[] = {"callback", "data", "name", NULL};
525         
526         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
527         if (PyCallable_Check(callback) == 0) {
528                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
529                 return NULL;
530         }
531         cpy_build_name(buf, sizeof(buf), callback, name);
532
533         Py_INCREF(callback);
534         Py_XINCREF(data);
535         c = malloc(sizeof(*c));
536         c->name = strdup(buf);
537         c->callback = callback;
538         c->data = data;
539         c->next = *list_head;
540         *list_head = c;
541         Py_XDECREF(mod);
542         return cpy_string_to_unicode_or_bytes(buf);
543 }
544
545 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
546         int timeout = -1;
547         const char *plugin = NULL, *identifier = NULL;
548         static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
549         
550         if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin, &timeout, NULL, &identifier) == 0) return NULL;
551         Py_BEGIN_ALLOW_THREADS
552         plugin_flush(plugin, timeout, identifier);
553         Py_END_ALLOW_THREADS
554         Py_RETURN_NONE;
555 }
556
557 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
558         return cpy_register_generic(&cpy_config_callbacks, args, kwds);
559 }
560
561 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
562         return cpy_register_generic(&cpy_init_callbacks, args, kwds);
563 }
564
565 typedef int reg_function_t(const char *name, void *callback, void *data);
566
567 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
568         char buf[512];
569         reg_function_t *register_function = (reg_function_t *) reg;
570         cpy_callback_t *c = NULL;
571         user_data_t *user_data = NULL;
572         const char *name = NULL;
573         PyObject *callback = NULL, *data = NULL;
574         static char *kwlist[] = {"callback", "data", "name", NULL};
575         
576         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL;
577         if (PyCallable_Check(callback) == 0) {
578                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
579                 return NULL;
580         }
581         cpy_build_name(buf, sizeof(buf), callback, name);
582         
583         Py_INCREF(callback);
584         Py_XINCREF(data);
585         c = malloc(sizeof(*c));
586         c->name = strdup(buf);
587         c->callback = callback;
588         c->data = data;
589         c->next = NULL;
590         user_data = malloc(sizeof(*user_data));
591         user_data->free_func = cpy_destroy_user_data;
592         user_data->data = c;
593         register_function(buf, handler, user_data);
594         return cpy_string_to_unicode_or_bytes(buf);
595 }
596
597 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
598         char buf[512];
599         cpy_callback_t *c = NULL;
600         user_data_t *user_data = NULL;
601         double interval = 0;
602         const char *name = NULL;
603         PyObject *callback = NULL, *data = NULL;
604         struct timespec ts;
605         static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
606         
607         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
608         if (PyCallable_Check(callback) == 0) {
609                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
610                 return NULL;
611         }
612         cpy_build_name(buf, sizeof(buf), callback, name);
613         
614         Py_INCREF(callback);
615         Py_XINCREF(data);
616         c = malloc(sizeof(*c));
617         c->name = strdup(buf);
618         c->callback = callback;
619         c->data = data;
620         c->next = NULL;
621         user_data = malloc(sizeof(*user_data));
622         user_data->free_func = cpy_destroy_user_data;
623         user_data->data = c;
624         ts.tv_sec = interval;
625         ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
626         plugin_register_complex_read(/* group = */ NULL, buf,
627                         cpy_read_callback, &ts, user_data);
628         return cpy_string_to_unicode_or_bytes(buf);
629 }
630
631 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
632         return cpy_register_generic_userdata((void *) plugin_register_log,
633                         (void *) cpy_log_callback, args, kwds);
634 }
635
636 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
637         return cpy_register_generic_userdata((void *) plugin_register_write,
638                         (void *) cpy_write_callback, args, kwds);
639 }
640
641 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
642         return cpy_register_generic_userdata((void *) plugin_register_notification,
643                         (void *) cpy_notification_callback, args, kwds);
644 }
645
646 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
647         return cpy_register_generic_userdata((void *) plugin_register_flush,
648                         (void *) cpy_flush_callback, args, kwds);
649 }
650
651 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
652         return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
653 }
654
655 static PyObject *cpy_error(PyObject *self, PyObject *args) {
656         const char *text;
657         if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
658         Py_BEGIN_ALLOW_THREADS
659         plugin_log(LOG_ERR, "%s", text);
660         Py_END_ALLOW_THREADS
661         Py_RETURN_NONE;
662 }
663
664 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
665         const char *text;
666         if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
667         Py_BEGIN_ALLOW_THREADS
668         plugin_log(LOG_WARNING, "%s", text);
669         Py_END_ALLOW_THREADS
670         Py_RETURN_NONE;
671 }
672
673 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
674         const char *text;
675         if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
676         Py_BEGIN_ALLOW_THREADS
677         plugin_log(LOG_NOTICE, "%s", text);
678         Py_END_ALLOW_THREADS
679         Py_RETURN_NONE;
680 }
681
682 static PyObject *cpy_info(PyObject *self, PyObject *args) {
683         const char *text;
684         if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
685         Py_BEGIN_ALLOW_THREADS
686         plugin_log(LOG_INFO, "%s", text);
687         Py_END_ALLOW_THREADS
688         Py_RETURN_NONE;
689 }
690
691 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
692 #ifdef COLLECT_DEBUG
693         const char *text;
694         if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
695         Py_BEGIN_ALLOW_THREADS
696         plugin_log(LOG_DEBUG, "%s", text);
697         Py_END_ALLOW_THREADS
698 #endif
699         Py_RETURN_NONE;
700 }
701
702 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
703         char buf[512];
704         const char *name;
705         cpy_callback_t *prev = NULL, *tmp;
706
707         Py_INCREF(arg);
708         name = cpy_unicode_or_bytes_to_string(&arg);
709         if (name == NULL) {
710                 PyErr_Clear();
711                 if (!PyCallable_Check(arg)) {
712                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
713                         Py_DECREF(arg);
714                         return NULL;
715                 }
716                 cpy_build_name(buf, sizeof(buf), arg, NULL);
717                 name = buf;
718         }
719         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
720                 if (strcmp(name, tmp->name) == 0)
721                         break;
722         
723         Py_DECREF(arg);
724         if (tmp == NULL) {
725                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
726                 return NULL;
727         }
728         /* Yes, this is actually save. To call this function the caller has to
729          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
730         if (prev == NULL)
731                 *list_head = tmp->next;
732         else
733                 prev->next = tmp->next;
734         cpy_destroy_user_data(tmp);
735         Py_RETURN_NONE;
736 }
737
738 typedef int cpy_unregister_function_t(const char *name);
739
740 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
741         char buf[512];
742         const char *name;
743
744         Py_INCREF(arg);
745         name = cpy_unicode_or_bytes_to_string(&arg);
746         if (name == NULL) {
747                 PyErr_Clear();
748                 if (!PyCallable_Check(arg)) {
749                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
750                         Py_DECREF(arg);
751                         return NULL;
752                 }
753                 cpy_build_name(buf, sizeof(buf), arg, NULL);
754                 name = buf;
755         }
756         if (unreg(name) == 0) {
757                 Py_DECREF(arg);
758                 Py_RETURN_NONE;
759         }
760         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
761         Py_DECREF(arg);
762         return NULL;
763 }
764
765 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
766         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
767 }
768
769 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
770         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
771 }
772
773 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
774         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
775 }
776
777 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
778         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
779 }
780
781 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
782         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
783 }
784
785 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
786         return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
787 }
788
789 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
790         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
791 }
792
793 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
794         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
795 }
796
797 static PyMethodDef cpy_methods[] = {
798         {"debug", cpy_debug, METH_VARARGS, log_doc},
799         {"info", cpy_info, METH_VARARGS, log_doc},
800         {"notice", cpy_notice, METH_VARARGS, log_doc},
801         {"warning", cpy_warning, METH_VARARGS, log_doc},
802         {"error", cpy_error, METH_VARARGS, log_doc},
803         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
804         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
805         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
806         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
807         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
808         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
809         {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
810         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
811         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
812         {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
813         {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
814         {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
815         {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
816         {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
817         {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
818         {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
819         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
820         {0, 0, 0, 0}
821 };
822
823 static int cpy_shutdown(void) {
824         cpy_callback_t *c;
825         PyObject *ret;
826         
827         /* This can happen if the module was loaded but not configured. */
828         if (state != NULL)
829                 PyEval_RestoreThread(state);
830
831         for (c = cpy_shutdown_callbacks; c; c = c->next) {
832                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
833                 if (ret == NULL)
834                         cpy_log_exception("shutdown callback");
835                 else
836                         Py_DECREF(ret);
837         }
838         PyErr_Print();
839         Py_Finalize();
840         return 0;
841 }
842
843 static void cpy_int_handler(int sig) {
844         return;
845 }
846
847 static void *cpy_interactive(void *data) {
848         sigset_t sigset;
849         struct sigaction sig_int_action, old;
850         
851         /* Signal handler in a plugin? Bad stuff, but the best way to
852          * handle it I guess. In an interactive session people will
853          * press Ctrl+C at some time, which will generate a SIGINT.
854          * This will cause collectd to shutdown, thus killing the
855          * interactive interpreter, and leaving the terminal in a
856          * mess. Chances are, this isn't what the user wanted to do.
857          * 
858          * So this is the plan:
859          * 1. Block SIGINT in the main thread.
860          * 2. Install our own signal handler that does nothing.
861          * 3. Unblock SIGINT in the interactive thread.
862          *
863          * This will make sure that SIGINT won't kill collectd but
864          * still interrupt syscalls like sleep and pause.
865          * It does not raise a KeyboardInterrupt exception because so
866          * far nobody managed to figure out how to do that. */
867         memset (&sig_int_action, '\0', sizeof (sig_int_action));
868         sig_int_action.sa_handler = cpy_int_handler;
869         sigaction (SIGINT, &sig_int_action, &old);
870         
871         sigemptyset(&sigset);
872         sigaddset(&sigset, SIGINT);
873         pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
874         PyEval_AcquireThread(state);
875         if (PyImport_ImportModule("readline") == NULL) {
876                 /* This interactive session will suck. */
877                 cpy_log_exception("interactive session init");
878         }
879         PyRun_InteractiveLoop(stdin, "<stdin>");
880         PyErr_Print();
881         PyEval_ReleaseThread(state);
882         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
883         /* Restore the original collectd SIGINT handler and raise SIGINT.
884          * The main thread still has SIGINT blocked and there's nothing we
885          * can do about that so this thread will handle it. But that's not
886          * important, except that it won't interrupt the main loop and so
887          * it might take a few seconds before collectd really shuts down. */
888         sigaction (SIGINT, &old, NULL);
889         raise(SIGINT);
890         pause();
891         return NULL;
892 }
893
894 static int cpy_init(void) {
895         cpy_callback_t *c;
896         PyObject *ret;
897         static pthread_t thread;
898         sigset_t sigset;
899         
900         PyEval_InitThreads();
901         /* Now it's finally OK to use python threads. */
902         for (c = cpy_init_callbacks; c; c = c->next) {
903                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
904                 if (ret == NULL)
905                         cpy_log_exception("init callback");
906                 else
907                         Py_DECREF(ret);
908         }
909         sigemptyset(&sigset);
910         sigaddset(&sigset, SIGINT);
911         pthread_sigmask(SIG_BLOCK, &sigset, NULL);
912         state = PyEval_SaveThread();
913         if (do_interactive) {
914                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
915                         ERROR("python: Error creating thread for interactive interpreter.");
916                 }
917         }
918
919         return 0;
920 }
921
922 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
923         int i;
924         PyObject *item, *values, *children, *tmp;
925         
926         if (parent == NULL)
927                 parent = Py_None;
928         
929         values = PyTuple_New(ci->values_num); /* New reference. */
930         for (i = 0; i < ci->values_num; ++i) {
931                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
932                         PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
933                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
934                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
935                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
936                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
937                 }
938         }
939         
940         tmp = cpy_string_to_unicode_or_bytes(ci->key);
941         item = PyObject_CallFunction((void *) &ConfigType, "NONO", tmp, parent, values, Py_None);
942         if (item == NULL)
943                 return NULL;
944         children = PyTuple_New(ci->children_num); /* New reference. */
945         for (i = 0; i < ci->children_num; ++i) {
946                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
947         }
948         tmp = ((Config *) item)->children;
949         ((Config *) item)->children = children;
950         Py_XDECREF(tmp);
951         return item;
952 }
953
954 #ifdef IS_PY3K
955 static struct PyModuleDef collectdmodule = {
956         PyModuleDef_HEAD_INIT,
957         "collectd",   /* name of module */
958         "The python interface to collectd", /* module documentation, may be NULL */
959         -1,
960         cpy_methods
961 };
962
963 PyMODINIT_FUNC PyInit_collectd(void) {
964         return PyModule_Create(&collectdmodule);
965 }
966 #endif
967
968 static int cpy_config(oconfig_item_t *ci) {
969         int i;
970         PyObject *sys, *tb;
971         PyObject *sys_path;
972         PyObject *module;
973         
974         /* Ok in theory we shouldn't do initialization at this point
975          * but we have to. In order to give python scripts a chance
976          * to register a config callback we need to be able to execute
977          * python code during the config callback so we have to start
978          * the interpreter here. */
979         /* Do *not* use the python "thread" module at this point! */
980
981 #ifdef IS_PY3K
982         /* Add a builtin module, before Py_Initialize */
983         PyImport_AppendInittab("collectd", PyInit_collectd);
984 #endif
985         
986         Py_Initialize();
987         
988         PyType_Ready(&ConfigType);
989         PyType_Ready(&PluginDataType);
990         ValuesType.tp_base = &PluginDataType;
991         PyType_Ready(&ValuesType);
992         NotificationType.tp_base = &PluginDataType;
993         PyType_Ready(&NotificationType);
994         SignedType.tp_base = &PyLong_Type;
995         PyType_Ready(&SignedType);
996         UnsignedType.tp_base = &PyLong_Type;
997         PyType_Ready(&UnsignedType);
998         sys = PyImport_ImportModule("sys"); /* New reference. */
999         if (sys == NULL) {
1000                 cpy_log_exception("python initialization");
1001                 return 1;
1002         }
1003         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1004         Py_DECREF(sys);
1005         if (sys_path == NULL) {
1006                 cpy_log_exception("python initialization");
1007                 return 1;
1008         }
1009 #ifdef IS_PY3K
1010         module = PyImport_ImportModule("collectd");
1011 #else
1012         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1013 #endif
1014         PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
1015         PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
1016         PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
1017         PyModule_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */
1018         PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */
1019         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1020         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1021         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1022         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1023         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1024         PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1025         PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1026         PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1027         for (i = 0; i < ci->children_num; ++i) {
1028                 oconfig_item_t *item = ci->children + i;
1029                 
1030                 if (strcasecmp(item->key, "Interactive") == 0) {
1031                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1032                                 continue;
1033                         do_interactive = item->values[0].value.boolean;
1034                 } else if (strcasecmp(item->key, "Encoding") == 0) {
1035                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
1036                                 continue;
1037                         /* Why is this even necessary? And undocumented? */
1038                         if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
1039                                 cpy_log_exception("setting default encoding");
1040                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
1041                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
1042                                 continue;
1043                         if (!item->values[0].value.boolean) {
1044                                 Py_XDECREF(cpy_format_exception);
1045                                 cpy_format_exception = NULL;
1046                                 continue;
1047                         }
1048                         if (cpy_format_exception)
1049                                 continue;
1050                         tb = PyImport_ImportModule("traceback"); /* New reference. */
1051                         if (tb == NULL) {
1052                                 cpy_log_exception("python initialization");
1053                                 continue;
1054                         }
1055                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1056                         Py_DECREF(tb);
1057                         if (cpy_format_exception == NULL)
1058                                 cpy_log_exception("python initialization");
1059                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
1060                         char *dir = NULL;
1061                         PyObject *dir_object;
1062                         
1063                         if (cf_util_get_string(item, &dir) != 0) 
1064                                 continue;
1065                         dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1066                         if (dir_object == NULL) {
1067                                 ERROR("python plugin: Unable to convert \"%s\" to "
1068                                       "a python object.", dir);
1069                                 free(dir);
1070                                 cpy_log_exception("python initialization");
1071                                 continue;
1072                         }
1073                         if (PyList_Append(sys_path, dir_object) != 0) {
1074                                 ERROR("python plugin: Unable to append \"%s\" to "
1075                                       "python module path.", dir);
1076                                 cpy_log_exception("python initialization");
1077                         }
1078                         Py_DECREF(dir_object);
1079                         free(dir);
1080                 } else if (strcasecmp(item->key, "Import") == 0) {
1081                         char *module_name = NULL;
1082                         PyObject *module;
1083                         
1084                         if (cf_util_get_string(item, &module_name) != 0) 
1085                                 continue;
1086                         module = PyImport_ImportModule(module_name); /* New reference. */
1087                         if (module == NULL) {
1088                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
1089                                 cpy_log_exception("importing module");
1090                         }
1091                         free(module_name);
1092                         Py_XDECREF(module);
1093                 } else if (strcasecmp(item->key, "Module") == 0) {
1094                         char *name = NULL;
1095                         cpy_callback_t *c;
1096                         PyObject *ret;
1097                         
1098                         if (cf_util_get_string(item, &name) != 0)
1099                                 continue;
1100                         for (c = cpy_config_callbacks; c; c = c->next) {
1101                                 if (strcasecmp(c->name + 7, name) == 0)
1102                                         break;
1103                         }
1104                         if (c == NULL) {
1105                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1106                                         "but the plugin isn't loaded or didn't register "
1107                                         "a configuration callback.", name);
1108                                 free(name);
1109                                 continue;
1110                         }
1111                         free(name);
1112                         if (c->data == NULL)
1113                                 ret = PyObject_CallFunction(c->callback, "N",
1114                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1115                         else
1116                                 ret = PyObject_CallFunction(c->callback, "NO",
1117                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
1118                         if (ret == NULL)
1119                                 cpy_log_exception("loading module");
1120                         else
1121                                 Py_DECREF(ret);
1122                 } else {
1123                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
1124                 }
1125         }
1126         Py_DECREF(sys_path);
1127         return 0;
1128 }
1129
1130 void module_register(void) {
1131         plugin_register_complex_config("python", cpy_config);
1132         plugin_register_init("python", cpy_init);
1133         plugin_register_shutdown("python", cpy_shutdown);
1134 }