python: Fixed some memory leaks in the write and notification callbacks.
[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 = PyString_AsString(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 static 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_GetAttrString(value, "message"); /* New reference. */
272         if (tn != NULL)
273                 typename = PyString_AsString(tn);
274         if (m != NULL)
275                 message = PyString_AsString(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                 s = strdup(PyString_AsString(line));
305                 if (s[strlen(s) - 1] == '\n')
306                         s[strlen(s) - 1] = 0;
307                 Py_BEGIN_ALLOW_THREADS
308                 ERROR("%s", s);
309                 Py_END_ALLOW_THREADS
310                 free(s);
311         }
312         Py_XDECREF(list);
313         PyErr_Clear();
314 }
315
316 static int cpy_read_callback(user_data_t *data) {
317         cpy_callback_t *c = data->data;
318         PyObject *ret;
319
320         CPY_LOCK_THREADS
321                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
322                 if (ret == NULL) {
323                         cpy_log_exception("read callback");
324                 } else {
325                         Py_DECREF(ret);
326                 }
327         CPY_RELEASE_THREADS
328         if (ret == NULL)
329                 return 1;
330         return 0;
331 }
332
333 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
334         int i;
335         cpy_callback_t *c = data->data;
336         PyObject *ret, *v, *list;
337
338         CPY_LOCK_THREADS
339                 list = PyList_New(value_list->values_len); /* New reference. */
340                 if (list == NULL) {
341                         cpy_log_exception("write callback");
342                         CPY_RETURN_FROM_THREADS 0;
343                 }
344                 for (i = 0; i < value_list->values_len; ++i) {
345                         if (ds->ds->type == DS_TYPE_COUNTER) {
346                                 if ((long) value_list->values[i].counter == value_list->values[i].counter)
347                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
348                                 else
349                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
350                         } else if (ds->ds->type == DS_TYPE_GAUGE) {
351                                 PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
352                         } else if (ds->ds->type == DS_TYPE_DERIVE) {
353                                 if ((long) value_list->values[i].derive == value_list->values[i].derive)
354                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
355                                 else
356                                         PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
357                         } else if (ds->ds->type == DS_TYPE_ABSOLUTE) {
358                                 if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
359                                         PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
360                                 else
361                                         PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
362                         } else {
363                                 Py_BEGIN_ALLOW_THREADS
364                                 ERROR("cpy_write_callback: Unknown value type %d.", ds->ds->type);
365                                 Py_END_ALLOW_THREADS
366                                 Py_DECREF(list);
367                                 CPY_RETURN_FROM_THREADS 0;
368                         }
369                         if (PyErr_Occurred() != NULL) {
370                                 cpy_log_exception("value building for write callback");
371                                 Py_DECREF(list);
372                                 CPY_RETURN_FROM_THREADS 0;
373                         }
374                 }
375                 v = PyObject_CallFunction((void *) &ValuesType, "sOssssdi", value_list->type,
376                                 list, value_list->plugin_instance, value_list->type_instance,
377                                 value_list->plugin, value_list->host, (double) value_list->time,
378                                 value_list->interval); /* New reference. */
379                 Py_DECREF(list);
380                 ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */
381                 Py_XDECREF(v);
382                 if (ret == NULL) {
383                         cpy_log_exception("write callback");
384                 } else {
385                         Py_DECREF(ret);
386                 }
387         CPY_RELEASE_THREADS
388         return 0;
389 }
390
391 static int cpy_notification_callback(const notification_t *notification, user_data_t *data) {
392         cpy_callback_t *c = data->data;
393         PyObject *ret, *n;
394
395         CPY_LOCK_THREADS
396                 n = PyObject_CallFunction((void *) &NotificationType, "ssssssdi", notification->type, notification->message,
397                                 notification->plugin_instance, notification->type_instance, notification->plugin,
398                                 notification->host, (double) notification->time, notification->severity); /* New reference. */
399                 ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
400                 Py_XDECREF(n);
401                 if (ret == NULL) {
402                         cpy_log_exception("notification callback");
403                 } else {
404                         Py_DECREF(ret);
405                 }
406         CPY_RELEASE_THREADS
407         return 0;
408 }
409
410 static void cpy_log_callback(int severity, const char *message, user_data_t *data) {
411         cpy_callback_t * c = data->data;
412         PyObject *ret;
413
414         CPY_LOCK_THREADS
415         if (c->data == NULL)
416                 ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */
417         else
418                 ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */
419
420         if (ret == NULL) {
421                 /* FIXME */
422                 /* Do we really want to trigger a log callback because a log callback failed?
423                  * Probably not. */
424                 PyErr_Print();
425                 /* In case someone wanted to be clever, replaced stderr and failed at that. */
426                 PyErr_Clear();
427         } else {
428                 Py_DECREF(ret);
429         }
430         CPY_RELEASE_THREADS
431 }
432
433 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
434         cpy_callback_t * c = data->data;
435         PyObject *ret;
436
437         CPY_LOCK_THREADS
438         if (c->data == NULL)
439                 ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */
440         else
441                 ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */
442
443         if (ret == NULL) {
444                 cpy_log_exception("flush callback");
445         } else {
446                 Py_DECREF(ret);
447         }
448         CPY_RELEASE_THREADS
449 }
450
451 static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
452         char buf[512];
453         cpy_callback_t *c;
454         const char *name = NULL;
455         PyObject *callback = NULL, *data = NULL, *mod = NULL;
456         static char *kwlist[] = {"callback", "data", "name", NULL};
457         
458         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
459         if (PyCallable_Check(callback) == 0) {
460                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
461                 return NULL;
462         }
463         cpy_build_name(buf, sizeof(buf), callback, name);
464
465         Py_INCREF(callback);
466         Py_XINCREF(data);
467         c = malloc(sizeof(*c));
468         c->name = strdup(buf);
469         c->callback = callback;
470         c->data = data;
471         c->next = *list_head;
472         *list_head = c;
473         Py_XDECREF(mod);
474         return PyString_FromString(buf);
475 }
476
477 static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) {
478         int timeout = -1;
479         const char *plugin = NULL, *identifier = NULL;
480         static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
481         
482         if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL;
483         Py_BEGIN_ALLOW_THREADS
484         plugin_flush(plugin, timeout, identifier);
485         Py_END_ALLOW_THREADS
486         Py_RETURN_NONE;
487 }
488
489 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
490         return cpy_register_generic(&cpy_config_callbacks, args, kwds);
491 }
492
493 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
494         return cpy_register_generic(&cpy_init_callbacks, args, kwds);
495 }
496
497 typedef int reg_function_t(const char *name, void *callback, void *data);
498
499 static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObject *args, PyObject *kwds) {
500         char buf[512];
501         reg_function_t *register_function = (reg_function_t *) reg;
502         cpy_callback_t *c = NULL;
503         user_data_t *user_data = NULL;
504         const char *name = NULL;
505         PyObject *callback = NULL, *data = NULL;
506         static char *kwlist[] = {"callback", "data", "name", NULL};
507         
508         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL;
509         if (PyCallable_Check(callback) == 0) {
510                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
511                 return NULL;
512         }
513         cpy_build_name(buf, sizeof(buf), callback, name);
514         
515         Py_INCREF(callback);
516         Py_XINCREF(data);
517         c = malloc(sizeof(*c));
518         c->name = strdup(buf);
519         c->callback = callback;
520         c->data = data;
521         c->next = NULL;
522         user_data = malloc(sizeof(*user_data));
523         user_data->free_func = cpy_destroy_user_data;
524         user_data->data = c;
525         register_function(buf, handler, user_data);
526         return PyString_FromString(buf);
527 }
528
529 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
530         char buf[512];
531         cpy_callback_t *c = NULL;
532         user_data_t *user_data = NULL;
533         double interval = 0;
534         const char *name = NULL;
535         PyObject *callback = NULL, *data = NULL;
536         struct timespec ts;
537         static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
538         
539         if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL;
540         if (PyCallable_Check(callback) == 0) {
541                 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
542                 return NULL;
543         }
544         cpy_build_name(buf, sizeof(buf), callback, name);
545         
546         Py_INCREF(callback);
547         Py_XINCREF(data);
548         c = malloc(sizeof(*c));
549         c->name = strdup(buf);
550         c->callback = callback;
551         c->data = data;
552         c->next = NULL;
553         user_data = malloc(sizeof(*user_data));
554         user_data->free_func = cpy_destroy_user_data;
555         user_data->data = c;
556         ts.tv_sec = interval;
557         ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
558         plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data);
559         return PyString_FromString(buf);
560 }
561
562 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
563         return cpy_register_generic_userdata((void *) plugin_register_log,
564                         (void *) cpy_log_callback, args, kwds);
565 }
566
567 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
568         return cpy_register_generic_userdata((void *) plugin_register_write,
569                         (void *) cpy_write_callback, args, kwds);
570 }
571
572 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
573         return cpy_register_generic_userdata((void *) plugin_register_notification,
574                         (void *) cpy_notification_callback, args, kwds);
575 }
576
577 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
578         return cpy_register_generic_userdata((void *) plugin_register_flush,
579                         (void *) cpy_flush_callback, args, kwds);
580 }
581
582 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
583         return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
584 }
585
586 static PyObject *cpy_error(PyObject *self, PyObject *args) {
587         const char *text;
588         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
589         Py_BEGIN_ALLOW_THREADS
590         plugin_log(LOG_ERR, "%s", text);
591         Py_END_ALLOW_THREADS
592         Py_RETURN_NONE;
593 }
594
595 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
596         const char *text;
597         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
598         Py_BEGIN_ALLOW_THREADS
599         plugin_log(LOG_WARNING, "%s", text);
600         Py_END_ALLOW_THREADS
601         Py_RETURN_NONE;
602 }
603
604 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
605         const char *text;
606         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
607         Py_BEGIN_ALLOW_THREADS
608         plugin_log(LOG_NOTICE, "%s", text);
609         Py_END_ALLOW_THREADS
610         Py_RETURN_NONE;
611 }
612
613 static PyObject *cpy_info(PyObject *self, PyObject *args) {
614         const char *text;
615         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
616         Py_BEGIN_ALLOW_THREADS
617         plugin_log(LOG_INFO, "%s", text);
618         Py_END_ALLOW_THREADS
619         Py_RETURN_NONE;
620 }
621
622 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
623 #ifdef COLLECT_DEBUG
624         const char *text;
625         if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL;
626         Py_BEGIN_ALLOW_THREADS
627         plugin_log(LOG_DEBUG, "%s", text);
628         Py_END_ALLOW_THREADS
629 #endif
630         Py_RETURN_NONE;
631 }
632
633 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
634         char buf[512];
635         const char *name;
636         cpy_callback_t *prev = NULL, *tmp;
637
638         if (PyUnicode_Check(arg)) {
639                 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
640                 if (arg == NULL)
641                         return NULL;
642                 name = PyString_AsString(arg);
643                 Py_DECREF(arg);
644         } else if (PyString_Check(arg)) {
645                 name = PyString_AsString(arg);
646         } else {
647                 if (!PyCallable_Check(arg)) {
648                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
649                         return NULL;
650                 }
651                 cpy_build_name(buf, sizeof(buf), arg, NULL);
652                 name = buf;
653         }
654         for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
655                 if (strcmp(name, tmp->name) == 0)
656                         break;
657         
658         if (tmp == NULL) {
659                 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
660                 return NULL;
661         }
662         /* Yes, this is actually save. To call this function the caller has to
663          * hold the GIL. Well, save as long as there is only one GIL anyway ... */
664         if (prev == NULL)
665                 *list_head = tmp->next;
666         else
667                 prev->next = tmp->next;
668         cpy_destroy_user_data(tmp);
669         Py_RETURN_NONE;
670 }
671
672 typedef int cpy_unregister_function_t(const char *name);
673
674 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
675         char buf[512];
676         const char *name;
677
678         if (PyUnicode_Check(arg)) {
679                 arg = PyUnicode_AsEncodedString(arg, NULL, NULL);
680                 if (arg == NULL)
681                         return NULL;
682                 name = PyString_AsString(arg);
683                 Py_DECREF(arg);
684         } else if (PyString_Check(arg)) {
685                 name = PyString_AsString(arg);
686         } else {
687                 if (!PyCallable_Check(arg)) {
688                         PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
689                         return NULL;
690                 }
691                 cpy_build_name(buf, sizeof(buf), arg, NULL);
692                 name = buf;
693         }
694         if (unreg(name) == 0)
695                 Py_RETURN_NONE;
696         PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
697         return NULL;
698 }
699
700 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
701         return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
702 }
703
704 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
705         return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
706 }
707
708 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
709         return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
710 }
711
712 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
713         return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
714 }
715
716 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
717         return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
718 }
719
720 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
721         return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
722 }
723
724 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
725         return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
726 }
727
728 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
729         return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
730 }
731
732 static PyMethodDef cpy_methods[] = {
733         {"debug", cpy_debug, METH_VARARGS, log_doc},
734         {"info", cpy_info, METH_VARARGS, log_doc},
735         {"notice", cpy_notice, METH_VARARGS, log_doc},
736         {"warning", cpy_warning, METH_VARARGS, log_doc},
737         {"error", cpy_error, METH_VARARGS, log_doc},
738         {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
739         {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
740         {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
741         {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
742         {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
743         {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
744         {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
745         {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
746         {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
747         {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
748         {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
749         {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
750         {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
751         {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
752         {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
753         {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
754         {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
755         {0, 0, 0, 0}
756 };
757
758 static int cpy_shutdown(void) {
759         cpy_callback_t *c;
760         PyObject *ret;
761         
762         /* This can happen if the module was loaded but not configured. */
763         if (state != NULL)
764                 PyEval_RestoreThread(state);
765
766         for (c = cpy_shutdown_callbacks; c; c = c->next) {
767                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
768                 if (ret == NULL)
769                         cpy_log_exception("shutdown callback");
770                 else
771                         Py_DECREF(ret);
772         }
773         PyErr_Print();
774         Py_Finalize();
775         return 0;
776 }
777
778 static void cpy_int_handler(int sig) {
779         return;
780 }
781
782 static void *cpy_interactive(void *data) {
783         sigset_t sigset;
784         struct sigaction sig_int_action, old;
785         
786         /* Signal handler in a plugin? Bad stuff, but the best way to
787          * handle it I guess. In an interactive session people will
788          * press Ctrl+C at some time, which will generate a SIGINT.
789          * This will cause collectd to shutdown, thus killing the
790          * interactive interpreter, and leaving the terminal in a
791          * mess. Chances are, this isn't what the user wanted to do.
792          * 
793          * So this is the plan:
794          * 1. Block SIGINT in the main thread.
795          * 2. Install our own signal handler that does nothing.
796          * 3. Unblock SIGINT in the interactive thread.
797          *
798          * This will make sure that SIGINT won't kill collectd but
799          * still interrupt syscalls like sleep and pause.
800          * It does not raise a KeyboardInterrupt exception because so
801          * far nobody managed to figure out how to do that. */
802         memset (&sig_int_action, '\0', sizeof (sig_int_action));
803         sig_int_action.sa_handler = cpy_int_handler;
804         sigaction (SIGINT, &sig_int_action, &old);
805         
806         sigemptyset(&sigset);
807         sigaddset(&sigset, SIGINT);
808         pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
809         PyEval_AcquireThread(state);
810         if (PyImport_ImportModule("readline") == NULL) {
811                 /* This interactive session will suck. */
812                 cpy_log_exception("interactive session init");
813         }
814         PyRun_InteractiveLoop(stdin, "<stdin>");
815         PyErr_Print();
816         PyEval_ReleaseThread(state);
817         NOTICE("python: Interactive interpreter exited, stopping collectd ...");
818         /* Restore the original collectd SIGINT handler and raise SIGINT.
819          * The main thread still has SIGINT blocked and there's nothing we
820          * can do about that so this thread will handle it. But that's not
821          * important, except that it won't interrupt the main loop and so
822          * it might take a few seconds before collectd really shuts down. */
823         sigaction (SIGINT, &old, NULL);
824         raise(SIGINT);
825         pause();
826         return NULL;
827 }
828
829 static int cpy_init(void) {
830         cpy_callback_t *c;
831         PyObject *ret;
832         static pthread_t thread;
833         sigset_t sigset;
834         
835         if (!Py_IsInitialized()) {
836                 WARNING("python: Plugin loaded but not configured.");
837                 plugin_unregister_shutdown("python");
838                 return 0;
839         }
840         PyEval_InitThreads();
841         /* Now it's finally OK to use python threads. */
842         for (c = cpy_init_callbacks; c; c = c->next) {
843                 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
844                 if (ret == NULL)
845                         cpy_log_exception("init callback");
846                 else
847                         Py_DECREF(ret);
848         }
849         sigemptyset(&sigset);
850         sigaddset(&sigset, SIGINT);
851         pthread_sigmask(SIG_BLOCK, &sigset, NULL);
852         state = PyEval_SaveThread();
853         if (do_interactive) {
854                 if (pthread_create(&thread, NULL, cpy_interactive, NULL)) {
855                         ERROR("python: Error creating thread for interactive interpreter.");
856                 }
857         }
858
859         return 0;
860 }
861
862 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
863         int i;
864         PyObject *item, *values, *children, *tmp;
865         
866         if (parent == NULL)
867                 parent = Py_None;
868         
869         values = PyTuple_New(ci->values_num); /* New reference. */
870         for (i = 0; i < ci->values_num; ++i) {
871                 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
872                         PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string));
873                 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
874                         PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
875                 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
876                         PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
877                 }
878         }
879         
880         item = PyObject_CallFunction((void *) &ConfigType, "sONO", ci->key, parent, values, Py_None);
881         if (item == NULL)
882                 return NULL;
883         children = PyTuple_New(ci->children_num); /* New reference. */
884         for (i = 0; i < ci->children_num; ++i) {
885                 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
886         }
887         tmp = ((Config *) item)->children;
888         ((Config *) item)->children = children;
889         Py_XDECREF(tmp);
890         return item;
891 }
892
893 static int cpy_config(oconfig_item_t *ci) {
894         int i;
895         PyObject *sys, *tb;
896         PyObject *sys_path;
897         PyObject *module;
898         
899         /* Ok in theory we shouldn't do initialization at this point
900          * but we have to. In order to give python scripts a chance
901          * to register a config callback we need to be able to execute
902          * python code during the config callback so we have to start
903          * the interpreter here. */
904         /* Do *not* use the python "thread" module at this point! */
905         Py_Initialize();
906         
907         PyType_Ready(&ConfigType);
908         PyType_Ready(&PluginDataType);
909         ValuesType.tp_base = &PluginDataType;
910         PyType_Ready(&ValuesType);
911         NotificationType.tp_base = &PluginDataType;
912         PyType_Ready(&NotificationType);
913         sys = PyImport_ImportModule("sys"); /* New reference. */
914         if (sys == NULL) {
915                 cpy_log_exception("python initialization");
916                 return 1;
917         }
918         sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
919         Py_DECREF(sys);
920         if (sys_path == NULL) {
921                 cpy_log_exception("python initialization");
922                 return 1;
923         }
924         module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
925         PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
926         PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
927         PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
928         PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
929         PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
930         PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
931         PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
932         PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
933         PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
934         PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
935         PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
936         for (i = 0; i < ci->children_num; ++i) {
937                 oconfig_item_t *item = ci->children + i;
938                 
939                 if (strcasecmp(item->key, "Interactive") == 0) {
940                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
941                                 continue;
942                         do_interactive = item->values[0].value.boolean;
943                 } else if (strcasecmp(item->key, "Encoding") == 0) {
944                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_STRING)
945                                 continue;
946                         /* Why is this even necessary? And undocumented? */
947                         if (PyUnicode_SetDefaultEncoding(item->values[0].value.string))
948                                 cpy_log_exception("setting default encoding");
949                 } else if (strcasecmp(item->key, "LogTraces") == 0) {
950                         if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_BOOLEAN)
951                                 continue;
952                         if (!item->values[0].value.boolean) {
953                                 Py_XDECREF(cpy_format_exception);
954                                 cpy_format_exception = NULL;
955                                 continue;
956                         }
957                         if (cpy_format_exception)
958                                 continue;
959                         tb = PyImport_ImportModule("traceback"); /* New reference. */
960                         if (tb == NULL) {
961                                 cpy_log_exception("python initialization");
962                                 continue;
963                         }
964                         cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
965                         Py_DECREF(tb);
966                         if (cpy_format_exception == NULL)
967                                 cpy_log_exception("python initialization");
968                 } else if (strcasecmp(item->key, "ModulePath") == 0) {
969                         char *dir = NULL;
970                         PyObject *dir_object;
971                         
972                         if (cf_util_get_string(item, &dir) != 0) 
973                                 continue;
974                         dir_object = PyString_FromString(dir); /* New reference. */
975                         if (dir_object == NULL) {
976                                 ERROR("python plugin: Unable to convert \"%s\" to "
977                                       "a python object.", dir);
978                                 free(dir);
979                                 cpy_log_exception("python initialization");
980                                 continue;
981                         }
982                         if (PyList_Append(sys_path, dir_object) != 0) {
983                                 ERROR("python plugin: Unable to append \"%s\" to "
984                                       "python module path.", dir);
985                                 cpy_log_exception("python initialization");
986                         }
987                         Py_DECREF(dir_object);
988                         free(dir);
989                 } else if (strcasecmp(item->key, "Import") == 0) {
990                         char *module_name = NULL;
991                         PyObject *module;
992                         
993                         if (cf_util_get_string(item, &module_name) != 0) 
994                                 continue;
995                         module = PyImport_ImportModule(module_name); /* New reference. */
996                         if (module == NULL) {
997                                 ERROR("python plugin: Error importing module \"%s\".", module_name);
998                                 cpy_log_exception("importing module");
999                                 PyErr_Print();
1000                         }
1001                         free(module_name);
1002                         Py_XDECREF(module);
1003                 } else if (strcasecmp(item->key, "Module") == 0) {
1004                         char *name = NULL;
1005                         cpy_callback_t *c;
1006                         PyObject *ret;
1007                         
1008                         if (cf_util_get_string(item, &name) != 0)
1009                                 continue;
1010                         for (c = cpy_config_callbacks; c; c = c->next) {
1011                                 if (strcasecmp(c->name + 7, name) == 0)
1012                                         break;
1013                         }
1014                         if (c == NULL) {
1015                                 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1016                                         "but the plugin isn't loaded or didn't register "
1017                                         "a configuration callback.", name);
1018                                 free(name);
1019                                 continue;
1020                         }
1021                         free(name);
1022                         if (c->data == NULL)
1023                                 ret = PyObject_CallFunction(c->callback, "N",
1024                                         cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1025                         else
1026                                 ret = PyObject_CallFunction(c->callback, "NO",
1027                                         cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
1028                         if (ret == NULL)
1029                                 cpy_log_exception("loading module");
1030                         else
1031                                 Py_DECREF(ret);
1032                 } else {
1033                         WARNING("python plugin: Ignoring unknown config key \"%s\".", item->key);
1034                 }
1035         }
1036         Py_DECREF(sys_path);
1037         return 0;
1038 }
1039
1040 void module_register(void) {
1041         plugin_register_complex_config("python", cpy_config);
1042         plugin_register_init("python", cpy_init);
1043         plugin_register_shutdown("python", cpy_shutdown);
1044 }