Merge branch 'collectd-5.8'
[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
32 #include "collectd.h"
33
34 #include "common.h"
35
36 #include "cpython.h"
37
38 typedef struct cpy_callback_s {
39   char *name;
40   PyObject *callback;
41   PyObject *data;
42   struct cpy_callback_s *next;
43 } cpy_callback_t;
44
45 static char log_doc[] = "This function sends a string to all logging plugins.";
46
47 static char get_ds_doc[] =
48     "get_dataset(name) -> definition\n"
49     "\n"
50     "Returns the definition of a dataset specified by name.\n"
51     "\n"
52     "'name' is a string specifying the dataset to query.\n"
53     "'definition' is a list of 4-tuples. Every tuple represents a \n"
54     "    data source within the data set and its 4 values are the \n"
55     "    name, type, min and max value.\n"
56     "    'name' is a string.\n"
57     "    'type' is a string that is equal to either DS_TYPE_COUNTER,\n"
58     "        DS_TYPE_GAUGE, DS_TYPE_DERIVE or DS_TYPE_ABSOLUTE.\n"
59     "    'min' and 'max' are either a float or None.";
60
61 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
62                           "\n"
63                           "Flushes the cache of another plugin.";
64
65 static char unregister_doc[] =
66     "Unregisters a callback. This function needs exactly one parameter either\n"
67     "the function to unregister or the callback identifier to unregister.";
68
69 static char reg_log_doc[] =
70     "register_log(callback[, data][, name]) -> identifier\n"
71     "\n"
72     "Register a callback function for log messages.\n"
73     "\n"
74     "'callback' is a callable object that will be called every time something\n"
75     "    is logged.\n"
76     "'data' is an optional object that will be passed back to the callback\n"
77     "    function every time it is called.\n"
78     "'name' is an optional identifier for this callback. The default name\n"
79     "    is 'python.<module>'.\n"
80     "    Every callback needs a unique identifier, so if you want to\n"
81     "    register this callback multiple time from the same module you need\n"
82     "    to specify a name here.\n"
83     "'identifier' is the full identifier assigned to this callback.\n"
84     "\n"
85     "The callback function will be called with two or three parameters:\n"
86     "severity: An integer that should be compared to the LOG_ constants.\n"
87     "message: The text to be logged.\n"
88     "data: The optional data parameter passed to the register function.\n"
89     "    If the parameter was omitted it will be omitted here, too.";
90
91 static char reg_init_doc[] =
92     "register_init(callback[, data][, name]) -> identifier\n"
93     "\n"
94     "Register a callback function that will be executed once after the "
95     "config.\n"
96     "file has been read, all plugins heve been loaded and the collectd has\n"
97     "forked into the background.\n"
98     "\n"
99     "'callback' is a callable object that will be executed.\n"
100     "'data' is an optional object that will be passed back to the callback\n"
101     "    function when 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 without parameters, except for\n"
110     "data if it was supplied.";
111
112 static char reg_config_doc[] =
113     "register_config(callback[, data][, name]) -> identifier\n"
114     "\n"
115     "Register a callback function for config file entries.\n"
116     "'callback' is a callable object that will be called for every config "
117     "block.\n"
118     "'data' is an optional object that will be passed back to the callback\n"
119     "    function every time it is called.\n"
120     "'name' is an optional identifier for this callback. The default name\n"
121     "    is 'python.<module>'.\n"
122     "    Every callback needs a unique identifier, so if you want to\n"
123     "    register this callback multiple time from the same module you need\n"
124     "    to specify a name here.\n"
125     "'identifier' is the full identifier assigned to this callback.\n"
126     "\n"
127     "The callback function will be called with one or two parameters:\n"
128     "config: A Config object.\n"
129     "data: The optional data parameter passed to the register function.\n"
130     "    If the parameter was omitted it will be omitted here, too.";
131
132 static char reg_read_doc[] =
133     "register_read(callback[, interval][, data][, name]) -> identifier\n"
134     "\n"
135     "Register a callback function for reading data. It will just be called\n"
136     "in a fixed interval to signal that it's time to dispatch new values.\n"
137     "'callback' is a callable object that will be called every time something\n"
138     "    is logged.\n"
139     "'interval' is the number of seconds between between calls to the "
140     "callback\n"
141     "    function. Full float precision is supported here.\n"
142     "'data' is an optional object that will be passed back to the callback\n"
143     "    function every time it is called.\n"
144     "'name' is an optional identifier for this callback. The default name\n"
145     "    is 'python.<module>'.\n"
146     "    Every callback needs a unique identifier, so if you want to\n"
147     "    register this callback multiple time from the same module you need\n"
148     "    to specify a name here.\n"
149     "'identifier' is the full identifier assigned to this callback.\n"
150     "\n"
151     "The callback function will be called without parameters, except for\n"
152     "data if it was supplied.";
153
154 static char reg_write_doc[] =
155     "register_write(callback[, data][, name]) -> identifier\n"
156     "\n"
157     "Register a callback function to receive values dispatched by other "
158     "plugins.\n"
159     "'callback' is a callable object that will be called every time a value\n"
160     "    is dispatched.\n"
161     "'data' is an optional object that will be passed back to the callback\n"
162     "    function every time it is called.\n"
163     "'name' is an optional identifier for this callback. The default name\n"
164     "    is 'python.<module>'.\n"
165     "    Every callback needs a unique identifier, so if you want to\n"
166     "    register this callback multiple time from the same module you need\n"
167     "    to specify a name here.\n"
168     "'identifier' is the full identifier assigned to this callback.\n"
169     "\n"
170     "The callback function will be called with one or two parameters:\n"
171     "values: A Values object which is a copy of the dispatched values.\n"
172     "data: The optional data parameter passed to the register function.\n"
173     "    If the parameter was omitted it will be omitted here, too.";
174
175 static char reg_notification_doc[] =
176     "register_notification(callback[, data][, name]) -> identifier\n"
177     "\n"
178     "Register a callback function for notifications.\n"
179     "'callback' is a callable object that will be called every time a "
180     "notification\n"
181     "    is dispatched.\n"
182     "'data' is an optional object that will be passed back to the callback\n"
183     "    function every time it is called.\n"
184     "'name' is an optional identifier for this callback. The default name\n"
185     "    is 'python.<module>'.\n"
186     "    Every callback needs a unique identifier, so if you want to\n"
187     "    register this callback multiple time from the same module you need\n"
188     "    to specify a name here.\n"
189     "'identifier' is the full identifier assigned to this callback.\n"
190     "\n"
191     "The callback function will be called with one or two parameters:\n"
192     "notification: A copy of the notification that was dispatched.\n"
193     "data: The optional data parameter passed to the register function.\n"
194     "    If the parameter was omitted it will be omitted here, too.";
195
196 static char reg_flush_doc[] =
197     "register_flush(callback[, data][, name]) -> identifier\n"
198     "\n"
199     "Register a callback function for flush messages.\n"
200     "'callback' is a callable object that will be called every time a plugin\n"
201     "    requests a flush for either this or all plugins.\n"
202     "'data' is an optional object that will be passed back to the callback\n"
203     "    function every time it is called.\n"
204     "'name' is an optional identifier for this callback. The default name\n"
205     "    is 'python.<module>'.\n"
206     "    Every callback needs a unique identifier, so if you want to\n"
207     "    register this callback multiple time from the same module you need\n"
208     "    to specify a name here.\n"
209     "'identifier' is the full identifier assigned to this callback.\n"
210     "\n"
211     "The callback function will be called with two or three parameters:\n"
212     "timeout: Indicates that only data older than 'timeout' seconds is to\n"
213     "    be flushed.\n"
214     "id: Specifies which values are to be flushed. Might be None.\n"
215     "data: The optional data parameter passed to the register function.\n"
216     "    If the parameter was omitted it will be omitted here, too.";
217
218 static char reg_shutdown_doc[] =
219     "register_shutdown(callback[, data][, name]) -> identifier\n"
220     "\n"
221     "Register a callback function for collectd shutdown.\n"
222     "'callback' is a callable object that will be called once collectd is\n"
223     "    shutting down.\n"
224     "'data' is an optional object that will be passed back to the callback\n"
225     "    function if it is called.\n"
226     "'name' is an optional identifier for this callback. The default name\n"
227     "    is 'python.<module>'.\n"
228     "    Every callback needs a unique identifier, so if you want to\n"
229     "    register this callback multiple time from the same module you need\n"
230     "    to specify a name here.\n"
231     "'identifier' is the full identifier assigned to this callback.\n"
232     "\n"
233     "The callback function will be called with no parameters except for\n"
234     "    data if it was supplied.";
235
236 static char CollectdError_doc[] =
237     "Basic exception for collectd Python scripts.\n"
238     "\n"
239     "Throwing this exception will not cause a stacktrace to be logged, \n"
240     "even if LogTraces is enabled in the config.";
241
242 static pthread_t main_thread;
243 static PyOS_sighandler_t python_sigint_handler;
244 static bool do_interactive;
245
246 /* This is our global thread state. Python saves some stuff in thread-local
247  * storage. So if we allow the interpreter to run in the background
248  * (the scriptwriters might have created some threads from python), we have
249  * to save the state so we can resume it later after shutdown. */
250
251 static PyThreadState *state;
252
253 static PyObject *sys_path, *cpy_format_exception, *CollectdError;
254
255 static cpy_callback_t *cpy_config_callbacks;
256 static cpy_callback_t *cpy_init_callbacks;
257 static cpy_callback_t *cpy_shutdown_callbacks;
258
259 /* Make sure to hold the GIL while modifying these. */
260 static int cpy_shutdown_triggered;
261 static int cpy_num_callbacks;
262
263 static void cpy_destroy_user_data(void *data) {
264   cpy_callback_t *c = data;
265   free(c->name);
266   CPY_LOCK_THREADS
267   Py_DECREF(c->callback);
268   Py_XDECREF(c->data);
269   free(c);
270   --cpy_num_callbacks;
271   if (!cpy_num_callbacks && cpy_shutdown_triggered) {
272     Py_Finalize();
273     return;
274   }
275   CPY_RELEASE_THREADS
276 }
277
278 /* You must hold the GIL to call this function!
279  * But if you managed to extract the callback parameter then you probably
280  * already do. */
281
282 static void cpy_build_name(char *buf, size_t size, PyObject *callback,
283                            const char *name) {
284   const char *module = NULL;
285   PyObject *mod = NULL;
286
287   if (name != NULL) {
288     snprintf(buf, size, "python.%s", name);
289     return;
290   }
291
292   mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
293   if (mod != NULL)
294     module = cpy_unicode_or_bytes_to_string(&mod);
295
296   if (module != NULL) {
297     snprintf(buf, size, "python.%s", module);
298     Py_XDECREF(mod);
299     PyErr_Clear();
300     return;
301   }
302   Py_XDECREF(mod);
303
304   snprintf(buf, size, "python.%p", callback);
305   PyErr_Clear();
306 }
307
308 void cpy_log_exception(const char *context) {
309   int l = 0, collectd_error;
310   const char *typename = NULL, *message = NULL;
311   PyObject *type, *value, *traceback, *tn, *m, *list;
312
313   PyErr_Fetch(&type, &value, &traceback);
314   PyErr_NormalizeException(&type, &value, &traceback);
315   if (type == NULL)
316     return;
317   collectd_error = PyErr_GivenExceptionMatches(value, CollectdError);
318   tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
319   m = PyObject_Str(value);                       /* New reference. */
320   if (tn != NULL)
321     typename = cpy_unicode_or_bytes_to_string(&tn);
322   if (m != NULL)
323     message = cpy_unicode_or_bytes_to_string(&m);
324   if (typename == NULL)
325     typename = "NamelessException";
326   if (message == NULL)
327     message = "N/A";
328   Py_BEGIN_ALLOW_THREADS;
329   if (collectd_error) {
330     WARNING("%s in %s: %s", typename, context, message);
331   } else {
332     ERROR("Unhandled python exception in %s: %s: %s", context, typename,
333           message);
334   }
335   Py_END_ALLOW_THREADS;
336   Py_XDECREF(tn);
337   Py_XDECREF(m);
338   if (!cpy_format_exception || !traceback || collectd_error) {
339     PyErr_Clear();
340     Py_DECREF(type);
341     Py_XDECREF(value);
342     Py_XDECREF(traceback);
343     return;
344   }
345   list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value,
346                                traceback); /* New reference. Steals references
347                                               from "type", "value" and
348                                               "traceback". */
349   if (list)
350     l = PyObject_Length(list);
351
352   for (int i = 0; i < l; ++i) {
353     PyObject *line;
354     char const *msg;
355     char *cpy;
356
357     line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
358     Py_INCREF(line);
359
360     msg = cpy_unicode_or_bytes_to_string(&line);
361     Py_DECREF(line);
362     if (msg == NULL)
363       continue;
364
365     cpy = strdup(msg);
366     if (cpy == NULL)
367       continue;
368
369     if (cpy[strlen(cpy) - 1] == '\n')
370       cpy[strlen(cpy) - 1] = 0;
371
372     Py_BEGIN_ALLOW_THREADS;
373     ERROR("%s", cpy);
374     Py_END_ALLOW_THREADS;
375
376     free(cpy);
377   }
378
379   Py_XDECREF(list);
380   PyErr_Clear();
381 }
382
383 static int cpy_read_callback(user_data_t *data) {
384   cpy_callback_t *c = data->data;
385   PyObject *ret;
386
387   CPY_LOCK_THREADS
388   ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
389                                      (void *)0); /* New reference. */
390   if (ret == NULL) {
391     cpy_log_exception("read callback");
392   } else {
393     Py_DECREF(ret);
394   }
395   CPY_RELEASE_THREADS
396   if (ret == NULL)
397     return 1;
398   return 0;
399 }
400
401 static int cpy_write_callback(const data_set_t *ds,
402                               const value_list_t *value_list,
403                               user_data_t *data) {
404   cpy_callback_t *c = data->data;
405   PyObject *ret, *list, *temp, *dict = NULL;
406   Values *v;
407
408   CPY_LOCK_THREADS
409   list = PyList_New(value_list->values_len); /* New reference. */
410   if (list == NULL) {
411     cpy_log_exception("write callback");
412     CPY_RETURN_FROM_THREADS 0;
413   }
414   for (size_t i = 0; i < value_list->values_len; ++i) {
415     if (ds->ds[i].type == DS_TYPE_COUNTER) {
416       PyList_SetItem(
417           list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
418     } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
419       PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
420     } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
421       PyList_SetItem(list, i,
422                      PyLong_FromLongLong(value_list->values[i].derive));
423     } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
424       PyList_SetItem(
425           list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
426     } else {
427       Py_BEGIN_ALLOW_THREADS;
428       ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
429       Py_END_ALLOW_THREADS;
430       Py_DECREF(list);
431       CPY_RETURN_FROM_THREADS 0;
432     }
433     if (PyErr_Occurred() != NULL) {
434       cpy_log_exception("value building for write callback");
435       Py_DECREF(list);
436       CPY_RETURN_FROM_THREADS 0;
437     }
438   }
439   dict = PyDict_New(); /* New reference. */
440   if (value_list->meta) {
441     char **table = NULL;
442     meta_data_t *meta = value_list->meta;
443
444     int num = meta_data_toc(meta, &table);
445     for (int i = 0; i < num; ++i) {
446       int type;
447       char *string;
448       int64_t si;
449       uint64_t ui;
450       double d;
451       bool b;
452
453       type = meta_data_type(meta, table[i]);
454       if (type == MD_TYPE_STRING) {
455         if (meta_data_get_string(meta, table[i], &string))
456           continue;
457         temp = cpy_string_to_unicode_or_bytes(string); /* New reference. */
458         free(string);
459         PyDict_SetItemString(dict, table[i], temp);
460         Py_XDECREF(temp);
461       } else if (type == MD_TYPE_SIGNED_INT) {
462         if (meta_data_get_signed_int(meta, table[i], &si))
463           continue;
464         PyObject *sival = PyLong_FromLongLong(si); /* New reference */
465         temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
466                                             (void *)0); /* New reference. */
467         PyDict_SetItemString(dict, table[i], temp);
468         Py_XDECREF(temp);
469         Py_XDECREF(sival);
470       } else if (type == MD_TYPE_UNSIGNED_INT) {
471         if (meta_data_get_unsigned_int(meta, table[i], &ui))
472           continue;
473         PyObject *uval = PyLong_FromUnsignedLongLong(ui); /* New reference */
474         temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
475                                             (void *)0); /* New reference. */
476         PyDict_SetItemString(dict, table[i], temp);
477         Py_XDECREF(temp);
478         Py_XDECREF(uval);
479       } else if (type == MD_TYPE_DOUBLE) {
480         if (meta_data_get_double(meta, table[i], &d))
481           continue;
482         temp = PyFloat_FromDouble(d); /* New reference. */
483         PyDict_SetItemString(dict, table[i], temp);
484         Py_XDECREF(temp);
485       } else if (type == MD_TYPE_BOOLEAN) {
486         if (meta_data_get_boolean(meta, table[i], &b))
487           continue;
488         if (b)
489           PyDict_SetItemString(dict, table[i], Py_True);
490         else
491           PyDict_SetItemString(dict, table[i], Py_False);
492       }
493       free(table[i]);
494     }
495     free(table);
496   }
497   v = (Values *)Values_New(); /* New reference. */
498   sstrncpy(v->data.host, value_list->host, sizeof(v->data.host));
499   sstrncpy(v->data.type, value_list->type, sizeof(v->data.type));
500   sstrncpy(v->data.type_instance, value_list->type_instance,
501            sizeof(v->data.type_instance));
502   sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
503   sstrncpy(v->data.plugin_instance, value_list->plugin_instance,
504            sizeof(v->data.plugin_instance));
505   v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
506   v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
507   Py_CLEAR(v->values);
508   v->values = list;
509   Py_CLEAR(v->meta);
510   v->meta = dict; /* Steals a reference. */
511   ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data,
512                                      (void *)0); /* New reference. */
513   Py_XDECREF(v);
514   if (ret == NULL) {
515     cpy_log_exception("write callback");
516   } else {
517     Py_DECREF(ret);
518   }
519   CPY_RELEASE_THREADS
520   return 0;
521 }
522
523 static int cpy_notification_callback(const notification_t *notification,
524                                      user_data_t *data) {
525   cpy_callback_t *c = data->data;
526   PyObject *ret, *notify;
527   Notification *n;
528
529   CPY_LOCK_THREADS
530   PyObject *dict = PyDict_New(); /* New reference. */
531   for (notification_meta_t *meta = notification->meta; meta != NULL;
532        meta = meta->next) {
533     PyObject *temp = NULL;
534     if (meta->type == NM_TYPE_STRING) {
535       temp = cpy_string_to_unicode_or_bytes(
536           meta->nm_value.nm_string); /* New reference. */
537       PyDict_SetItemString(dict, meta->name, temp);
538       Py_XDECREF(temp);
539     } else if (meta->type == NM_TYPE_SIGNED_INT) {
540       PyObject *sival = PyLong_FromLongLong(meta->nm_value.nm_signed_int);
541       temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
542                                           (void *)0); /* New reference. */
543       PyDict_SetItemString(dict, meta->name, temp);
544       Py_XDECREF(temp);
545       Py_XDECREF(sival);
546     } else if (meta->type == NM_TYPE_UNSIGNED_INT) {
547       PyObject *uval =
548           PyLong_FromUnsignedLongLong(meta->nm_value.nm_unsigned_int);
549       temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
550                                           (void *)0); /* New reference. */
551       PyDict_SetItemString(dict, meta->name, temp);
552       Py_XDECREF(temp);
553       Py_XDECREF(uval);
554     } else if (meta->type == NM_TYPE_DOUBLE) {
555       temp = PyFloat_FromDouble(meta->nm_value.nm_double); /* New reference. */
556       PyDict_SetItemString(dict, meta->name, temp);
557       Py_XDECREF(temp);
558     } else if (meta->type == NM_TYPE_BOOLEAN) {
559       PyDict_SetItemString(dict, meta->name,
560                            meta->nm_value.nm_boolean ? Py_True : Py_False);
561     }
562   }
563   notify = Notification_New(); /* New reference. */
564   n = (Notification *)notify;
565   sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
566   sstrncpy(n->data.type, notification->type, sizeof(n->data.type));
567   sstrncpy(n->data.type_instance, notification->type_instance,
568            sizeof(n->data.type_instance));
569   sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
570   sstrncpy(n->data.plugin_instance, notification->plugin_instance,
571            sizeof(n->data.plugin_instance));
572   n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
573   sstrncpy(n->message, notification->message, sizeof(n->message));
574   n->severity = notification->severity;
575   Py_CLEAR(n->meta);
576   n->meta = dict; /* Steals a reference. */
577   ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data,
578                                      (void *)0); /* New reference. */
579   Py_XDECREF(notify);
580   if (ret == NULL) {
581     cpy_log_exception("notification callback");
582   } else {
583     Py_DECREF(ret);
584   }
585   CPY_RELEASE_THREADS
586   return 0;
587 }
588
589 static void cpy_log_callback(int severity, const char *message,
590                              user_data_t *data) {
591   cpy_callback_t *c = data->data;
592   PyObject *ret, *text;
593
594   CPY_LOCK_THREADS
595   text = cpy_string_to_unicode_or_bytes(message); /* New reference. */
596   if (c->data == NULL)
597     ret = PyObject_CallFunction(
598         c->callback, "iN", severity,
599         text); /* New reference. Steals a reference from "text". */
600   else
601     ret = PyObject_CallFunction(
602         c->callback, "iNO", severity, text,
603         c->data); /* New reference. Steals a reference from "text". */
604
605   if (ret == NULL) {
606     /* FIXME */
607     /* Do we really want to trigger a log callback because a log callback
608      * failed?
609      * Probably not. */
610     PyErr_Print();
611     /* In case someone wanted to be clever, replaced stderr and failed at that.
612      */
613     PyErr_Clear();
614   } else {
615     Py_DECREF(ret);
616   }
617   CPY_RELEASE_THREADS
618 }
619
620 static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) {
621   cpy_callback_t *c = data->data;
622   PyObject *ret, *text;
623
624   CPY_LOCK_THREADS
625   if (id) {
626     text = cpy_string_to_unicode_or_bytes(id);
627   } else {
628     text = Py_None;
629     Py_INCREF(text);
630   }
631   if (c->data == NULL)
632     ret = PyObject_CallFunction(c->callback, "iN", timeout,
633                                 text); /* New reference. */
634   else
635     ret = PyObject_CallFunction(c->callback, "iNO", timeout, text,
636                                 c->data); /* New reference. */
637
638   if (ret == NULL) {
639     cpy_log_exception("flush callback");
640   } else {
641     Py_DECREF(ret);
642   }
643   CPY_RELEASE_THREADS
644 }
645
646 static PyObject *cpy_register_generic(cpy_callback_t **list_head,
647                                       PyObject *args, PyObject *kwds) {
648   char buf[512];
649   cpy_callback_t *c;
650   char *name = NULL;
651   PyObject *callback = NULL, *data = NULL, *mod = NULL;
652   static char *kwlist[] = {"callback", "data", "name", NULL};
653
654   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data,
655                                   NULL, &name) == 0)
656     return NULL;
657   if (PyCallable_Check(callback) == 0) {
658     PyMem_Free(name);
659     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
660     return NULL;
661   }
662   cpy_build_name(buf, sizeof(buf), callback, name);
663
664   Py_INCREF(callback);
665   Py_XINCREF(data);
666
667   c = calloc(1, sizeof(*c));
668   if (c == NULL)
669     return NULL;
670
671   c->name = strdup(buf);
672   c->callback = callback;
673   c->data = data;
674   c->next = *list_head;
675   ++cpy_num_callbacks;
676   *list_head = c;
677   Py_XDECREF(mod);
678   PyMem_Free(name);
679   return cpy_string_to_unicode_or_bytes(buf);
680 }
681
682 static PyObject *float_or_none(float number) {
683   if (isnan(number)) {
684     Py_RETURN_NONE;
685   }
686   return PyFloat_FromDouble(number);
687 }
688
689 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
690   char *name;
691   const data_set_t *ds;
692   PyObject *list, *tuple;
693
694   if (PyArg_ParseTuple(args, "et", NULL, &name) == 0)
695     return NULL;
696   ds = plugin_get_ds(name);
697   PyMem_Free(name);
698   if (ds == NULL) {
699     PyErr_Format(PyExc_TypeError, "Dataset %s not found", name);
700     return NULL;
701   }
702   list = PyList_New(ds->ds_num); /* New reference. */
703   for (size_t i = 0; i < ds->ds_num; ++i) {
704     tuple = PyTuple_New(4);
705     PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name));
706     PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes(
707                                    DS_TYPE_TO_STRING(ds->ds[i].type)));
708     PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
709     PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
710     PyList_SET_ITEM(list, i, tuple);
711   }
712   return list;
713 }
714
715 static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
716   int timeout = -1;
717   char *plugin = NULL, *identifier = NULL;
718   static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
719
720   if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin,
721                                   &timeout, NULL, &identifier) == 0)
722     return NULL;
723   Py_BEGIN_ALLOW_THREADS;
724   plugin_flush(plugin, timeout, identifier);
725   Py_END_ALLOW_THREADS;
726   PyMem_Free(plugin);
727   PyMem_Free(identifier);
728   Py_RETURN_NONE;
729 }
730
731 static PyObject *cpy_register_config(PyObject *self, PyObject *args,
732                                      PyObject *kwds) {
733   return cpy_register_generic(&cpy_config_callbacks, args, kwds);
734 }
735
736 static PyObject *cpy_register_init(PyObject *self, PyObject *args,
737                                    PyObject *kwds) {
738   return cpy_register_generic(&cpy_init_callbacks, args, kwds);
739 }
740
741 typedef int reg_function_t(const char *name, void *callback, void *data);
742
743 static PyObject *cpy_register_generic_userdata(void *reg, void *handler,
744                                                PyObject *args, PyObject *kwds) {
745   char buf[512];
746   reg_function_t *register_function = (reg_function_t *)reg;
747   cpy_callback_t *c = NULL;
748   char *name = NULL;
749   PyObject *callback = NULL, *data = NULL;
750   static char *kwlist[] = {"callback", "data", "name", NULL};
751
752   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data,
753                                   NULL, &name) == 0)
754     return NULL;
755   if (PyCallable_Check(callback) == 0) {
756     PyMem_Free(name);
757     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
758     return NULL;
759   }
760   cpy_build_name(buf, sizeof(buf), callback, name);
761   PyMem_Free(name);
762
763   Py_INCREF(callback);
764   Py_XINCREF(data);
765
766   c = calloc(1, sizeof(*c));
767   if (c == NULL)
768     return NULL;
769
770   c->name = strdup(buf);
771   c->callback = callback;
772   c->data = data;
773   c->next = NULL;
774
775   register_function(buf, handler,
776                     &(user_data_t){
777                         .data = c, .free_func = cpy_destroy_user_data,
778                     });
779
780   ++cpy_num_callbacks;
781   return cpy_string_to_unicode_or_bytes(buf);
782 }
783
784 static PyObject *cpy_register_read(PyObject *self, PyObject *args,
785                                    PyObject *kwds) {
786   char buf[512];
787   cpy_callback_t *c = NULL;
788   double interval = 0;
789   char *name = NULL;
790   PyObject *callback = NULL, *data = NULL;
791   static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
792
793   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback,
794                                   &interval, &data, NULL, &name) == 0)
795     return NULL;
796   if (PyCallable_Check(callback) == 0) {
797     PyMem_Free(name);
798     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
799     return NULL;
800   }
801   cpy_build_name(buf, sizeof(buf), callback, name);
802   PyMem_Free(name);
803
804   Py_INCREF(callback);
805   Py_XINCREF(data);
806
807   c = calloc(1, sizeof(*c));
808   if (c == NULL)
809     return NULL;
810
811   c->name = strdup(buf);
812   c->callback = callback;
813   c->data = data;
814   c->next = NULL;
815
816   plugin_register_complex_read(
817       /* group = */ "python", buf, cpy_read_callback,
818       DOUBLE_TO_CDTIME_T(interval),
819       &(user_data_t){
820           .data = c, .free_func = cpy_destroy_user_data,
821       });
822   ++cpy_num_callbacks;
823   return cpy_string_to_unicode_or_bytes(buf);
824 }
825
826 static PyObject *cpy_register_log(PyObject *self, PyObject *args,
827                                   PyObject *kwds) {
828   return cpy_register_generic_userdata((void *)plugin_register_log,
829                                        (void *)cpy_log_callback, args, kwds);
830 }
831
832 static PyObject *cpy_register_write(PyObject *self, PyObject *args,
833                                     PyObject *kwds) {
834   return cpy_register_generic_userdata((void *)plugin_register_write,
835                                        (void *)cpy_write_callback, args, kwds);
836 }
837
838 static PyObject *cpy_register_notification(PyObject *self, PyObject *args,
839                                            PyObject *kwds) {
840   return cpy_register_generic_userdata((void *)plugin_register_notification,
841                                        (void *)cpy_notification_callback, args,
842                                        kwds);
843 }
844
845 static PyObject *cpy_register_flush(PyObject *self, PyObject *args,
846                                     PyObject *kwds) {
847   return cpy_register_generic_userdata((void *)plugin_register_flush,
848                                        (void *)cpy_flush_callback, args, kwds);
849 }
850
851 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args,
852                                        PyObject *kwds) {
853   return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
854 }
855
856 static PyObject *cpy_error(PyObject *self, PyObject *args) {
857   char *text;
858   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
859     return NULL;
860   Py_BEGIN_ALLOW_THREADS;
861   plugin_log(LOG_ERR, "%s", text);
862   Py_END_ALLOW_THREADS;
863   PyMem_Free(text);
864   Py_RETURN_NONE;
865 }
866
867 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
868   char *text;
869   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
870     return NULL;
871   Py_BEGIN_ALLOW_THREADS;
872   plugin_log(LOG_WARNING, "%s", text);
873   Py_END_ALLOW_THREADS;
874   PyMem_Free(text);
875   Py_RETURN_NONE;
876 }
877
878 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
879   char *text;
880   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
881     return NULL;
882   Py_BEGIN_ALLOW_THREADS;
883   plugin_log(LOG_NOTICE, "%s", text);
884   Py_END_ALLOW_THREADS;
885   PyMem_Free(text);
886   Py_RETURN_NONE;
887 }
888
889 static PyObject *cpy_info(PyObject *self, PyObject *args) {
890   char *text;
891   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
892     return NULL;
893   Py_BEGIN_ALLOW_THREADS;
894   plugin_log(LOG_INFO, "%s", text);
895   Py_END_ALLOW_THREADS;
896   PyMem_Free(text);
897   Py_RETURN_NONE;
898 }
899
900 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
901 #ifdef COLLECT_DEBUG
902   char *text;
903   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
904     return NULL;
905   Py_BEGIN_ALLOW_THREADS;
906   plugin_log(LOG_DEBUG, "%s", text);
907   Py_END_ALLOW_THREADS;
908   PyMem_Free(text);
909 #endif
910   Py_RETURN_NONE;
911 }
912
913 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head,
914                                         PyObject *arg, const char *desc) {
915   char buf[512];
916   const char *name;
917   cpy_callback_t *prev = NULL, *tmp;
918
919   Py_INCREF(arg);
920   name = cpy_unicode_or_bytes_to_string(&arg);
921   if (name == NULL) {
922     PyErr_Clear();
923     if (!PyCallable_Check(arg)) {
924       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
925                                        "callable object as its only "
926                                        "parameter.");
927       Py_DECREF(arg);
928       return NULL;
929     }
930     cpy_build_name(buf, sizeof(buf), arg, NULL);
931     name = buf;
932   }
933   for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
934     if (strcmp(name, tmp->name) == 0)
935       break;
936
937   Py_DECREF(arg);
938   if (tmp == NULL) {
939     PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
940                  desc, name);
941     return NULL;
942   }
943   /* Yes, this is actually safe. To call this function the caller has to
944    * hold the GIL. Well, safe as long as there is only one GIL anyway ... */
945   if (prev == NULL)
946     *list_head = tmp->next;
947   else
948     prev->next = tmp->next;
949   cpy_destroy_user_data(tmp);
950   Py_RETURN_NONE;
951 }
952
953 static void cpy_unregister_list(cpy_callback_t **list_head) {
954   cpy_callback_t *cur, *next;
955   for (cur = *list_head; cur; cur = next) {
956     next = cur->next;
957     cpy_destroy_user_data(cur);
958   }
959   *list_head = NULL;
960 }
961
962 typedef int cpy_unregister_function_t(const char *name);
963
964 static PyObject *
965 cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg,
966                                 const char *desc) {
967   char buf[512];
968   const char *name;
969
970   Py_INCREF(arg);
971   name = cpy_unicode_or_bytes_to_string(&arg);
972   if (name == NULL) {
973     PyErr_Clear();
974     if (!PyCallable_Check(arg)) {
975       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
976                                        "callable object as its only "
977                                        "parameter.");
978       Py_DECREF(arg);
979       return NULL;
980     }
981     cpy_build_name(buf, sizeof(buf), arg, NULL);
982     name = buf;
983   }
984   if (unreg(name) == 0) {
985     Py_DECREF(arg);
986     Py_RETURN_NONE;
987   }
988   PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
989                desc, name);
990   Py_DECREF(arg);
991   return NULL;
992 }
993
994 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
995   return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
996 }
997
998 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
999   return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
1000 }
1001
1002 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
1003   return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
1004 }
1005
1006 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
1007   return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
1008 }
1009
1010 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
1011   return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
1012 }
1013
1014 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
1015   return cpy_unregister_generic_userdata(plugin_unregister_notification, arg,
1016                                          "notification");
1017 }
1018
1019 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
1020   return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
1021 }
1022
1023 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
1024   return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
1025 }
1026
1027 static PyMethodDef cpy_methods[] = {
1028     {"debug", cpy_debug, METH_VARARGS, log_doc},
1029     {"info", cpy_info, METH_VARARGS, log_doc},
1030     {"notice", cpy_notice, METH_VARARGS, log_doc},
1031     {"warning", cpy_warning, METH_VARARGS, log_doc},
1032     {"error", cpy_error, METH_VARARGS, log_doc},
1033     {"get_dataset", (PyCFunction)cpy_get_dataset, METH_VARARGS, get_ds_doc},
1034     {"flush", (PyCFunction)cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
1035     {"register_log", (PyCFunction)cpy_register_log,
1036      METH_VARARGS | METH_KEYWORDS, reg_log_doc},
1037     {"register_init", (PyCFunction)cpy_register_init,
1038      METH_VARARGS | METH_KEYWORDS, reg_init_doc},
1039     {"register_config", (PyCFunction)cpy_register_config,
1040      METH_VARARGS | METH_KEYWORDS, reg_config_doc},
1041     {"register_read", (PyCFunction)cpy_register_read,
1042      METH_VARARGS | METH_KEYWORDS, reg_read_doc},
1043     {"register_write", (PyCFunction)cpy_register_write,
1044      METH_VARARGS | METH_KEYWORDS, reg_write_doc},
1045     {"register_notification", (PyCFunction)cpy_register_notification,
1046      METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
1047     {"register_flush", (PyCFunction)cpy_register_flush,
1048      METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
1049     {"register_shutdown", (PyCFunction)cpy_register_shutdown,
1050      METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
1051     {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
1052     {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
1053     {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
1054     {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
1055     {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
1056     {"unregister_notification", cpy_unregister_notification, METH_O,
1057      unregister_doc},
1058     {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
1059     {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
1060     {0, 0, 0, 0}};
1061
1062 static int cpy_shutdown(void) {
1063   PyObject *ret;
1064
1065   if (!state) {
1066     printf(
1067         "================================================================\n");
1068     printf(
1069         "collectd shutdown while running an interactive session. This will\n");
1070     printf("probably leave your terminal in a mess.\n");
1071     printf("Run the command \"reset\" to get it back into a usable state.\n");
1072     printf("You can press Ctrl+D in the interactive session to\n");
1073     printf("close collectd and avoid this problem in the future.\n");
1074     printf(
1075         "================================================================\n");
1076   }
1077
1078   CPY_LOCK_THREADS
1079
1080   for (cpy_callback_t *c = cpy_shutdown_callbacks; c; c = c->next) {
1081     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1082                                        (void *)0); /* New reference. */
1083     if (ret == NULL)
1084       cpy_log_exception("shutdown callback");
1085     else
1086       Py_DECREF(ret);
1087   }
1088   PyErr_Print();
1089
1090   Py_BEGIN_ALLOW_THREADS;
1091   cpy_unregister_list(&cpy_config_callbacks);
1092   cpy_unregister_list(&cpy_init_callbacks);
1093   cpy_unregister_list(&cpy_shutdown_callbacks);
1094   cpy_shutdown_triggered = 1;
1095   Py_END_ALLOW_THREADS;
1096
1097   if (!cpy_num_callbacks) {
1098     Py_Finalize();
1099     return 0;
1100   }
1101
1102   CPY_RELEASE_THREADS
1103   return 0;
1104 }
1105
1106 static void *cpy_interactive(void *pipefd) {
1107   PyOS_sighandler_t cur_sig;
1108
1109   /* Signal handler in a plugin? Bad stuff, but the best way to
1110    * handle it I guess. In an interactive session people will
1111    * press Ctrl+C at some time, which will generate a SIGINT.
1112    * This will cause collectd to shutdown, thus killing the
1113    * interactive interpreter, and leaving the terminal in a
1114    * mess. Chances are, this isn't what the user wanted to do.
1115    *
1116    * So this is the plan:
1117    * 1. Restore Python's own signal handler
1118    * 2. Tell Python we just forked so it will accept this thread
1119    *    as the main one. No version of Python will ever handle
1120    *    interrupts anywhere but in the main thread.
1121    * 3. After the interactive loop is done, restore collectd's
1122    *    SIGINT handler.
1123    * 4. Raise SIGINT for a clean shutdown. The signal is sent to
1124    *    the main thread to ensure it wakes up the main interval
1125    *    sleep so that collectd shuts down immediately not in 10
1126    *    seconds.
1127    *
1128    * This will make sure that SIGINT won't kill collectd but
1129    * still interrupt syscalls like sleep and pause. */
1130
1131   if (PyImport_ImportModule("readline") == NULL) {
1132     /* This interactive session will suck. */
1133     cpy_log_exception("interactive session init");
1134   }
1135   cur_sig = PyOS_setsig(SIGINT, python_sigint_handler);
1136   PyOS_AfterFork();
1137   PyEval_InitThreads();
1138   close(*(int *)pipefd);
1139   PyRun_InteractiveLoop(stdin, "<stdin>");
1140   PyOS_setsig(SIGINT, cur_sig);
1141   PyErr_Print();
1142   state = PyEval_SaveThread();
1143   NOTICE("python: Interactive interpreter exited, stopping collectd ...");
1144   pthread_kill(main_thread, SIGINT);
1145   return NULL;
1146 }
1147
1148 static int cpy_init(void) {
1149   PyObject *ret;
1150   int pipefd[2];
1151   char buf;
1152   static pthread_t thread;
1153
1154   if (!Py_IsInitialized()) {
1155     WARNING("python: Plugin loaded but not configured.");
1156     plugin_unregister_shutdown("python");
1157     Py_Finalize();
1158     return 0;
1159   }
1160   main_thread = pthread_self();
1161   if (do_interactive) {
1162     if (pipe(pipefd)) {
1163       ERROR("python: Unable to create pipe.");
1164       return 1;
1165     }
1166     if (plugin_thread_create(&thread, NULL, cpy_interactive, pipefd + 1,
1167                              "python interpreter")) {
1168       ERROR("python: Error creating thread for interactive interpreter.");
1169     }
1170     if (read(pipefd[0], &buf, 1))
1171       ;
1172     (void)close(pipefd[0]);
1173   } else {
1174     PyEval_InitThreads();
1175     state = PyEval_SaveThread();
1176   }
1177   CPY_LOCK_THREADS
1178   for (cpy_callback_t *c = cpy_init_callbacks; c; c = c->next) {
1179     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1180                                        (void *)0); /* New reference. */
1181     if (ret == NULL)
1182       cpy_log_exception("init callback");
1183     else
1184       Py_DECREF(ret);
1185   }
1186   CPY_RELEASE_THREADS
1187
1188   return 0;
1189 }
1190
1191 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
1192   PyObject *item, *values, *children, *tmp;
1193
1194   if (parent == NULL)
1195     parent = Py_None;
1196
1197   values = PyTuple_New(ci->values_num); /* New reference. */
1198   for (int i = 0; i < ci->values_num; ++i) {
1199     if (ci->values[i].type == OCONFIG_TYPE_STRING) {
1200       PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(
1201                                       ci->values[i].value.string));
1202     } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
1203       PyTuple_SET_ITEM(values, i,
1204                        PyFloat_FromDouble(ci->values[i].value.number));
1205     } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
1206       PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
1207     }
1208   }
1209
1210   tmp = cpy_string_to_unicode_or_bytes(ci->key);
1211   item = PyObject_CallFunction((void *)&ConfigType, "NONO", tmp, parent, values,
1212                                Py_None);
1213   if (item == NULL)
1214     return NULL;
1215   children = PyTuple_New(ci->children_num); /* New reference. */
1216   for (int i = 0; i < ci->children_num; ++i) {
1217     PyTuple_SET_ITEM(children, i,
1218                      cpy_oconfig_to_pyconfig(ci->children + i, item));
1219   }
1220   tmp = ((Config *)item)->children;
1221   ((Config *)item)->children = children;
1222   Py_XDECREF(tmp);
1223   return item;
1224 }
1225
1226 #ifdef IS_PY3K
1227 static struct PyModuleDef collectdmodule = {
1228     PyModuleDef_HEAD_INIT, "collectd",  /* name of module */
1229     "The python interface to collectd", /* module documentation, may be NULL */
1230     -1, cpy_methods};
1231
1232 PyMODINIT_FUNC PyInit_collectd(void) {
1233   return PyModule_Create(&collectdmodule);
1234 }
1235 #endif
1236
1237 static int cpy_init_python(void) {
1238   PyOS_sighandler_t cur_sig;
1239   PyObject *sys, *errordict;
1240   PyObject *module;
1241
1242 #ifdef IS_PY3K
1243   wchar_t *argv = L"";
1244   /* Add a builtin module, before Py_Initialize */
1245   PyImport_AppendInittab("collectd", PyInit_collectd);
1246 #else
1247   char *argv = "";
1248 #endif
1249
1250   /* Chances are the current signal handler is already SIG_DFL, but let's make
1251    * sure. */
1252   cur_sig = PyOS_setsig(SIGINT, SIG_DFL);
1253   Py_Initialize();
1254   python_sigint_handler = PyOS_setsig(SIGINT, cur_sig);
1255
1256   PyType_Ready(&ConfigType);
1257   PyType_Ready(&PluginDataType);
1258   ValuesType.tp_base = &PluginDataType;
1259   PyType_Ready(&ValuesType);
1260   NotificationType.tp_base = &PluginDataType;
1261   PyType_Ready(&NotificationType);
1262   SignedType.tp_base = &PyLong_Type;
1263   PyType_Ready(&SignedType);
1264   UnsignedType.tp_base = &PyLong_Type;
1265   PyType_Ready(&UnsignedType);
1266   errordict = PyDict_New();
1267   PyDict_SetItemString(
1268       errordict, "__doc__",
1269       cpy_string_to_unicode_or_bytes(CollectdError_doc)); /* New reference. */
1270   CollectdError = PyErr_NewException("collectd.CollectdError", NULL, errordict);
1271   sys = PyImport_ImportModule("sys"); /* New reference. */
1272   if (sys == NULL) {
1273     cpy_log_exception("python initialization");
1274     return 1;
1275   }
1276   sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1277   Py_DECREF(sys);
1278   if (sys_path == NULL) {
1279     cpy_log_exception("python initialization");
1280     return 1;
1281   }
1282   PySys_SetArgv(1, &argv);
1283   PyList_SetSlice(sys_path, 0, 1, NULL);
1284
1285 #ifdef IS_PY3K
1286   module = PyImport_ImportModule("collectd");
1287 #else
1288   module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1289 #endif
1290   PyModule_AddObject(module, "Config",
1291                      (void *)&ConfigType); /* Steals a reference. */
1292   PyModule_AddObject(module, "Values",
1293                      (void *)&ValuesType); /* Steals a reference. */
1294   PyModule_AddObject(module, "Notification",
1295                      (void *)&NotificationType); /* Steals a reference. */
1296   PyModule_AddObject(module, "Signed",
1297                      (void *)&SignedType); /* Steals a reference. */
1298   PyModule_AddObject(module, "Unsigned",
1299                      (void *)&UnsignedType); /* Steals a reference. */
1300   Py_XINCREF(CollectdError);
1301   PyModule_AddObject(module, "CollectdError",
1302                      CollectdError); /* Steals a reference. */
1303   PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1304   PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1305   PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1306   PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1307   PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1308   PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1309   PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1310   PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1311   PyModule_AddStringConstant(module, "DS_TYPE_COUNTER",
1312                              DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1313   PyModule_AddStringConstant(module, "DS_TYPE_GAUGE",
1314                              DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1315   PyModule_AddStringConstant(module, "DS_TYPE_DERIVE",
1316                              DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1317   PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE",
1318                              DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1319   return 0;
1320 }
1321
1322 static int cpy_config(oconfig_item_t *ci) {
1323   PyObject *tb;
1324   int status = 0;
1325
1326   /* Ok in theory we shouldn't do initialization at this point
1327    * but we have to. In order to give python scripts a chance
1328    * to register a config callback we need to be able to execute
1329    * python code during the config callback so we have to start
1330    * the interpreter here. */
1331   /* Do *not* use the python "thread" module at this point! */
1332
1333   if (!Py_IsInitialized() && cpy_init_python())
1334     return 1;
1335
1336   for (int i = 0; i < ci->children_num; ++i) {
1337     oconfig_item_t *item = ci->children + i;
1338
1339     if (strcasecmp(item->key, "Interactive") == 0) {
1340       if (cf_util_get_boolean(item, &do_interactive) != 0) {
1341         status = 1;
1342         continue;
1343       }
1344     } else if (strcasecmp(item->key, "Encoding") == 0) {
1345       char *encoding = NULL;
1346       if (cf_util_get_string(item, &encoding) != 0) {
1347         status = 1;
1348         continue;
1349       }
1350 #ifdef IS_PY3K
1351       ERROR("python: \"Encoding\" was used in the config file but Python3 was "
1352             "used, which does not support changing encodings");
1353       status = 1;
1354       sfree(encoding);
1355       continue;
1356 #else
1357       /* Why is this even necessary? And undocumented? */
1358       if (PyUnicode_SetDefaultEncoding(encoding)) {
1359         cpy_log_exception("setting default encoding");
1360         status = 1;
1361       }
1362 #endif
1363       sfree(encoding);
1364     } else if (strcasecmp(item->key, "LogTraces") == 0) {
1365       bool log_traces;
1366       if (cf_util_get_boolean(item, &log_traces) != 0) {
1367         status = 1;
1368         continue;
1369       }
1370       if (!log_traces) {
1371         Py_XDECREF(cpy_format_exception);
1372         cpy_format_exception = NULL;
1373         continue;
1374       }
1375       if (cpy_format_exception)
1376         continue;
1377       tb = PyImport_ImportModule("traceback"); /* New reference. */
1378       if (tb == NULL) {
1379         cpy_log_exception("python initialization");
1380         status = 1;
1381         continue;
1382       }
1383       cpy_format_exception =
1384           PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1385       Py_DECREF(tb);
1386       if (cpy_format_exception == NULL) {
1387         cpy_log_exception("python initialization");
1388         status = 1;
1389       }
1390     } else if (strcasecmp(item->key, "ModulePath") == 0) {
1391       char *dir = NULL;
1392       PyObject *dir_object;
1393
1394       if (cf_util_get_string(item, &dir) != 0) {
1395         status = 1;
1396         continue;
1397       }
1398       dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1399       if (dir_object == NULL) {
1400         ERROR("python plugin: Unable to convert \"%s\" to "
1401               "a python object.",
1402               dir);
1403         free(dir);
1404         cpy_log_exception("python initialization");
1405         status = 1;
1406         continue;
1407       }
1408       if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1409         ERROR("python plugin: Unable to prepend \"%s\" to "
1410               "python module path.",
1411               dir);
1412         cpy_log_exception("python initialization");
1413         status = 1;
1414       }
1415       Py_DECREF(dir_object);
1416       free(dir);
1417     } else if (strcasecmp(item->key, "Import") == 0) {
1418       char *module_name = NULL;
1419       PyObject *module;
1420
1421       if (cf_util_get_string(item, &module_name) != 0) {
1422         status = 1;
1423         continue;
1424       }
1425       module = PyImport_ImportModule(module_name); /* New reference. */
1426       if (module == NULL) {
1427         ERROR("python plugin: Error importing module \"%s\".", module_name);
1428         cpy_log_exception("importing module");
1429         status = 1;
1430       }
1431       free(module_name);
1432       Py_XDECREF(module);
1433     } else if (strcasecmp(item->key, "Module") == 0) {
1434       char *name = NULL;
1435       cpy_callback_t *c;
1436       PyObject *ret;
1437
1438       if (cf_util_get_string(item, &name) != 0) {
1439         status = 1;
1440         continue;
1441       }
1442       for (c = cpy_config_callbacks; c; c = c->next) {
1443         if (strcasecmp(c->name + 7, name) == 0)
1444           break;
1445       }
1446       if (c == NULL) {
1447         WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1448                 "but the plugin isn't loaded or didn't register "
1449                 "a configuration callback.",
1450                 name);
1451         free(name);
1452         continue;
1453       }
1454       free(name);
1455       if (c->data == NULL)
1456         ret = PyObject_CallFunction(
1457             c->callback, "N",
1458             cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1459       else
1460         ret = PyObject_CallFunction(c->callback, "NO",
1461                                     cpy_oconfig_to_pyconfig(item, NULL),
1462                                     c->data); /* New reference. */
1463       if (ret == NULL) {
1464         cpy_log_exception("loading module");
1465         status = 1;
1466       } else
1467         Py_DECREF(ret);
1468     } else {
1469       ERROR("python plugin: Unknown config key \"%s\".", item->key);
1470       status = 1;
1471     }
1472   }
1473   return status;
1474 }
1475
1476 void module_register(void) {
1477   plugin_register_complex_config("python", cpy_config);
1478   plugin_register_init("python", cpy_init);
1479   plugin_register_shutdown("python", cpy_shutdown);
1480 }