Fix compile time issues
[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 "utils/common/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     ssnprintf(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     ssnprintf(buf, size, "python.%s", module);
298     Py_XDECREF(mod);
299     PyErr_Clear();
300     return;
301   }
302   Py_XDECREF(mod);
303
304   ssnprintf(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(
707         tuple, 1,
708         cpy_string_to_unicode_or_bytes(DS_TYPE_TO_STRING(ds->ds[i].type)));
709     PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
710     PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
711     PyList_SET_ITEM(list, i, tuple);
712   }
713   return list;
714 }
715
716 static PyObject *cpy_flush(PyObject *self, PyObject *args, PyObject *kwds) {
717   int timeout = -1;
718   char *plugin = NULL, *identifier = NULL;
719   static char *kwlist[] = {"plugin", "timeout", "identifier", NULL};
720
721   if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin,
722                                   &timeout, NULL, &identifier) == 0)
723     return NULL;
724   Py_BEGIN_ALLOW_THREADS;
725   plugin_flush(plugin, timeout, identifier);
726   Py_END_ALLOW_THREADS;
727   PyMem_Free(plugin);
728   PyMem_Free(identifier);
729   Py_RETURN_NONE;
730 }
731
732 static PyObject *cpy_register_config(PyObject *self, PyObject *args,
733                                      PyObject *kwds) {
734   return cpy_register_generic(&cpy_config_callbacks, args, kwds);
735 }
736
737 static PyObject *cpy_register_init(PyObject *self, PyObject *args,
738                                    PyObject *kwds) {
739   return cpy_register_generic(&cpy_init_callbacks, args, kwds);
740 }
741
742 typedef int reg_function_t(const char *name, void *callback, void *data);
743
744 static PyObject *cpy_register_generic_userdata(void *reg, void *handler,
745                                                PyObject *args, PyObject *kwds) {
746   char buf[512];
747   reg_function_t *register_function = (reg_function_t *)reg;
748   cpy_callback_t *c = NULL;
749   char *name = NULL;
750   PyObject *callback = NULL, *data = NULL;
751   static char *kwlist[] = {"callback", "data", "name", NULL};
752
753   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data,
754                                   NULL, &name) == 0)
755     return NULL;
756   if (PyCallable_Check(callback) == 0) {
757     PyMem_Free(name);
758     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
759     return NULL;
760   }
761   cpy_build_name(buf, sizeof(buf), callback, name);
762   PyMem_Free(name);
763
764   Py_INCREF(callback);
765   Py_XINCREF(data);
766
767   c = calloc(1, sizeof(*c));
768   if (c == NULL)
769     return NULL;
770
771   c->name = strdup(buf);
772   c->callback = callback;
773   c->data = data;
774   c->next = NULL;
775
776   register_function(buf, handler,
777                     &(user_data_t){
778                         .data = c,
779                         .free_func = cpy_destroy_user_data,
780                     });
781
782   ++cpy_num_callbacks;
783   return cpy_string_to_unicode_or_bytes(buf);
784 }
785
786 static PyObject *cpy_register_read(PyObject *self, PyObject *args,
787                                    PyObject *kwds) {
788   char buf[512];
789   cpy_callback_t *c = NULL;
790   double interval = 0;
791   char *name = NULL;
792   PyObject *callback = NULL, *data = NULL;
793   static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
794
795   if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback,
796                                   &interval, &data, NULL, &name) == 0)
797     return NULL;
798   if (PyCallable_Check(callback) == 0) {
799     PyMem_Free(name);
800     PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
801     return NULL;
802   }
803   cpy_build_name(buf, sizeof(buf), callback, name);
804   PyMem_Free(name);
805
806   Py_INCREF(callback);
807   Py_XINCREF(data);
808
809   c = calloc(1, sizeof(*c));
810   if (c == NULL)
811     return NULL;
812
813   c->name = strdup(buf);
814   c->callback = callback;
815   c->data = data;
816   c->next = NULL;
817
818   plugin_register_complex_read(
819       /* group = */ "python", buf, cpy_read_callback,
820       DOUBLE_TO_CDTIME_T(interval),
821       &(user_data_t){
822           .data = c,
823           .free_func = cpy_destroy_user_data,
824       });
825   ++cpy_num_callbacks;
826   return cpy_string_to_unicode_or_bytes(buf);
827 }
828
829 static PyObject *cpy_register_log(PyObject *self, PyObject *args,
830                                   PyObject *kwds) {
831   return cpy_register_generic_userdata((void *)plugin_register_log,
832                                        (void *)cpy_log_callback, args, kwds);
833 }
834
835 static PyObject *cpy_register_write(PyObject *self, PyObject *args,
836                                     PyObject *kwds) {
837   return cpy_register_generic_userdata((void *)plugin_register_write,
838                                        (void *)cpy_write_callback, args, kwds);
839 }
840
841 static PyObject *cpy_register_notification(PyObject *self, PyObject *args,
842                                            PyObject *kwds) {
843   return cpy_register_generic_userdata((void *)plugin_register_notification,
844                                        (void *)cpy_notification_callback, args,
845                                        kwds);
846 }
847
848 static PyObject *cpy_register_flush(PyObject *self, PyObject *args,
849                                     PyObject *kwds) {
850   return cpy_register_generic_userdata((void *)plugin_register_flush,
851                                        (void *)cpy_flush_callback, args, kwds);
852 }
853
854 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args,
855                                        PyObject *kwds) {
856   return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
857 }
858
859 static PyObject *cpy_error(PyObject *self, PyObject *args) {
860   char *text;
861   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
862     return NULL;
863   Py_BEGIN_ALLOW_THREADS;
864   plugin_log(LOG_ERR, "%s", text);
865   Py_END_ALLOW_THREADS;
866   PyMem_Free(text);
867   Py_RETURN_NONE;
868 }
869
870 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
871   char *text;
872   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
873     return NULL;
874   Py_BEGIN_ALLOW_THREADS;
875   plugin_log(LOG_WARNING, "%s", text);
876   Py_END_ALLOW_THREADS;
877   PyMem_Free(text);
878   Py_RETURN_NONE;
879 }
880
881 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
882   char *text;
883   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
884     return NULL;
885   Py_BEGIN_ALLOW_THREADS;
886   plugin_log(LOG_NOTICE, "%s", text);
887   Py_END_ALLOW_THREADS;
888   PyMem_Free(text);
889   Py_RETURN_NONE;
890 }
891
892 static PyObject *cpy_info(PyObject *self, PyObject *args) {
893   char *text;
894   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
895     return NULL;
896   Py_BEGIN_ALLOW_THREADS;
897   plugin_log(LOG_INFO, "%s", text);
898   Py_END_ALLOW_THREADS;
899   PyMem_Free(text);
900   Py_RETURN_NONE;
901 }
902
903 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
904 #ifdef COLLECT_DEBUG
905   char *text;
906   if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
907     return NULL;
908   Py_BEGIN_ALLOW_THREADS;
909   plugin_log(LOG_DEBUG, "%s", text);
910   Py_END_ALLOW_THREADS;
911   PyMem_Free(text);
912 #endif
913   Py_RETURN_NONE;
914 }
915
916 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head,
917                                         PyObject *arg, const char *desc) {
918   char buf[512];
919   const char *name;
920   cpy_callback_t *prev = NULL, *tmp;
921
922   Py_INCREF(arg);
923   name = cpy_unicode_or_bytes_to_string(&arg);
924   if (name == NULL) {
925     PyErr_Clear();
926     if (!PyCallable_Check(arg)) {
927       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
928                                        "callable object as its only "
929                                        "parameter.");
930       Py_DECREF(arg);
931       return NULL;
932     }
933     cpy_build_name(buf, sizeof(buf), arg, NULL);
934     name = buf;
935   }
936   for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
937     if (strcmp(name, tmp->name) == 0)
938       break;
939
940   Py_DECREF(arg);
941   if (tmp == NULL) {
942     PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
943                  desc, name);
944     return NULL;
945   }
946   /* Yes, this is actually safe. To call this function the caller has to
947    * hold the GIL. Well, safe as long as there is only one GIL anyway ... */
948   if (prev == NULL)
949     *list_head = tmp->next;
950   else
951     prev->next = tmp->next;
952   cpy_destroy_user_data(tmp);
953   Py_RETURN_NONE;
954 }
955
956 static void cpy_unregister_list(cpy_callback_t **list_head) {
957   cpy_callback_t *cur, *next;
958   for (cur = *list_head; cur; cur = next) {
959     next = cur->next;
960     cpy_destroy_user_data(cur);
961   }
962   *list_head = NULL;
963 }
964
965 typedef int cpy_unregister_function_t(const char *name);
966
967 static PyObject *
968 cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg,
969                                 const char *desc) {
970   char buf[512];
971   const char *name;
972
973   Py_INCREF(arg);
974   name = cpy_unicode_or_bytes_to_string(&arg);
975   if (name == NULL) {
976     PyErr_Clear();
977     if (!PyCallable_Check(arg)) {
978       PyErr_SetString(PyExc_TypeError, "This function needs a string or a "
979                                        "callable object as its only "
980                                        "parameter.");
981       Py_DECREF(arg);
982       return NULL;
983     }
984     cpy_build_name(buf, sizeof(buf), arg, NULL);
985     name = buf;
986   }
987   if (unreg(name) == 0) {
988     Py_DECREF(arg);
989     Py_RETURN_NONE;
990   }
991   PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.",
992                desc, name);
993   Py_DECREF(arg);
994   return NULL;
995 }
996
997 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
998   return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
999 }
1000
1001 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
1002   return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
1003 }
1004
1005 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
1006   return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
1007 }
1008
1009 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
1010   return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
1011 }
1012
1013 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
1014   return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
1015 }
1016
1017 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
1018   return cpy_unregister_generic_userdata(plugin_unregister_notification, arg,
1019                                          "notification");
1020 }
1021
1022 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
1023   return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
1024 }
1025
1026 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
1027   return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
1028 }
1029
1030 static PyMethodDef cpy_methods[] = {
1031     {"debug", cpy_debug, METH_VARARGS, log_doc},
1032     {"info", cpy_info, METH_VARARGS, log_doc},
1033     {"notice", cpy_notice, METH_VARARGS, log_doc},
1034     {"warning", cpy_warning, METH_VARARGS, log_doc},
1035     {"error", cpy_error, METH_VARARGS, log_doc},
1036     {"get_dataset", (PyCFunction)cpy_get_dataset, METH_VARARGS, get_ds_doc},
1037     {"flush", (PyCFunction)cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
1038     {"register_log", (PyCFunction)cpy_register_log,
1039      METH_VARARGS | METH_KEYWORDS, reg_log_doc},
1040     {"register_init", (PyCFunction)cpy_register_init,
1041      METH_VARARGS | METH_KEYWORDS, reg_init_doc},
1042     {"register_config", (PyCFunction)cpy_register_config,
1043      METH_VARARGS | METH_KEYWORDS, reg_config_doc},
1044     {"register_read", (PyCFunction)cpy_register_read,
1045      METH_VARARGS | METH_KEYWORDS, reg_read_doc},
1046     {"register_write", (PyCFunction)cpy_register_write,
1047      METH_VARARGS | METH_KEYWORDS, reg_write_doc},
1048     {"register_notification", (PyCFunction)cpy_register_notification,
1049      METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
1050     {"register_flush", (PyCFunction)cpy_register_flush,
1051      METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
1052     {"register_shutdown", (PyCFunction)cpy_register_shutdown,
1053      METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
1054     {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
1055     {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
1056     {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
1057     {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
1058     {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
1059     {"unregister_notification", cpy_unregister_notification, METH_O,
1060      unregister_doc},
1061     {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
1062     {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
1063     {0, 0, 0, 0}};
1064
1065 static int cpy_shutdown(void) {
1066   PyObject *ret;
1067
1068   if (!state) {
1069     printf(
1070         "================================================================\n");
1071     printf(
1072         "collectd shutdown while running an interactive session. This will\n");
1073     printf("probably leave your terminal in a mess.\n");
1074     printf("Run the command \"reset\" to get it back into a usable state.\n");
1075     printf("You can press Ctrl+D in the interactive session to\n");
1076     printf("close collectd and avoid this problem in the future.\n");
1077     printf(
1078         "================================================================\n");
1079   }
1080
1081   CPY_LOCK_THREADS
1082
1083   for (cpy_callback_t *c = cpy_shutdown_callbacks; c; c = c->next) {
1084     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1085                                        (void *)0); /* New reference. */
1086     if (ret == NULL)
1087       cpy_log_exception("shutdown callback");
1088     else
1089       Py_DECREF(ret);
1090   }
1091   PyErr_Print();
1092
1093   Py_BEGIN_ALLOW_THREADS;
1094   cpy_unregister_list(&cpy_config_callbacks);
1095   cpy_unregister_list(&cpy_init_callbacks);
1096   cpy_unregister_list(&cpy_shutdown_callbacks);
1097   cpy_shutdown_triggered = 1;
1098   Py_END_ALLOW_THREADS;
1099
1100   if (!cpy_num_callbacks) {
1101     Py_Finalize();
1102     return 0;
1103   }
1104
1105   CPY_RELEASE_THREADS
1106   return 0;
1107 }
1108
1109 static void *cpy_interactive(void *pipefd) {
1110   PyOS_sighandler_t cur_sig;
1111
1112   /* Signal handler in a plugin? Bad stuff, but the best way to
1113    * handle it I guess. In an interactive session people will
1114    * press Ctrl+C at some time, which will generate a SIGINT.
1115    * This will cause collectd to shutdown, thus killing the
1116    * interactive interpreter, and leaving the terminal in a
1117    * mess. Chances are, this isn't what the user wanted to do.
1118    *
1119    * So this is the plan:
1120    * 1. Restore Python's own signal handler
1121    * 2. Tell Python we just forked so it will accept this thread
1122    *    as the main one. No version of Python will ever handle
1123    *    interrupts anywhere but in the main thread.
1124    * 3. After the interactive loop is done, restore collectd's
1125    *    SIGINT handler.
1126    * 4. Raise SIGINT for a clean shutdown. The signal is sent to
1127    *    the main thread to ensure it wakes up the main interval
1128    *    sleep so that collectd shuts down immediately not in 10
1129    *    seconds.
1130    *
1131    * This will make sure that SIGINT won't kill collectd but
1132    * still interrupt syscalls like sleep and pause. */
1133
1134   if (PyImport_ImportModule("readline") == NULL) {
1135     /* This interactive session will suck. */
1136     cpy_log_exception("interactive session init");
1137   }
1138   cur_sig = PyOS_setsig(SIGINT, python_sigint_handler);
1139 #if PY_VERSION_HEX < 0x03070000
1140   PyOS_AfterFork();
1141 #else
1142   PyOS_AfterFork_Child();
1143 #endif
1144   PyEval_InitThreads();
1145   close(*(int *)pipefd);
1146   PyRun_InteractiveLoop(stdin, "<stdin>");
1147   PyOS_setsig(SIGINT, cur_sig);
1148   PyErr_Print();
1149   state = PyEval_SaveThread();
1150   NOTICE("python: Interactive interpreter exited, stopping collectd ...");
1151   pthread_kill(main_thread, SIGINT);
1152   return NULL;
1153 }
1154
1155 static int cpy_init(void) {
1156   PyObject *ret;
1157   int pipefd[2];
1158   char buf;
1159   static pthread_t thread;
1160
1161   if (!Py_IsInitialized()) {
1162     WARNING("python: Plugin loaded but not configured.");
1163     plugin_unregister_shutdown("python");
1164     Py_Finalize();
1165     return 0;
1166   }
1167   main_thread = pthread_self();
1168   if (do_interactive) {
1169     if (pipe(pipefd)) {
1170       ERROR("python: Unable to create pipe.");
1171       return 1;
1172     }
1173     if (plugin_thread_create(&thread, NULL, cpy_interactive, pipefd + 1,
1174                              "python interpreter")) {
1175       ERROR("python: Error creating thread for interactive interpreter.");
1176     }
1177     if (read(pipefd[0], &buf, 1))
1178       ;
1179     (void)close(pipefd[0]);
1180   } else {
1181     PyEval_InitThreads();
1182     state = PyEval_SaveThread();
1183   }
1184   CPY_LOCK_THREADS
1185   for (cpy_callback_t *c = cpy_init_callbacks; c; c = c->next) {
1186     ret = PyObject_CallFunctionObjArgs(c->callback, c->data,
1187                                        (void *)0); /* New reference. */
1188     if (ret == NULL)
1189       cpy_log_exception("init callback");
1190     else
1191       Py_DECREF(ret);
1192   }
1193   CPY_RELEASE_THREADS
1194
1195   return 0;
1196 }
1197
1198 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
1199   PyObject *item, *values, *children, *tmp;
1200
1201   if (parent == NULL)
1202     parent = Py_None;
1203
1204   values = PyTuple_New(ci->values_num); /* New reference. */
1205   for (int i = 0; i < ci->values_num; ++i) {
1206     if (ci->values[i].type == OCONFIG_TYPE_STRING) {
1207       PyTuple_SET_ITEM(
1208           values, i,
1209           cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
1210     } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
1211       PyTuple_SET_ITEM(values, i,
1212                        PyFloat_FromDouble(ci->values[i].value.number));
1213     } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
1214       PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
1215     }
1216   }
1217
1218   tmp = cpy_string_to_unicode_or_bytes(ci->key);
1219   item = PyObject_CallFunction((void *)&ConfigType, "NONO", tmp, parent, values,
1220                                Py_None);
1221   if (item == NULL)
1222     return NULL;
1223   children = PyTuple_New(ci->children_num); /* New reference. */
1224   for (int i = 0; i < ci->children_num; ++i) {
1225     PyTuple_SET_ITEM(children, i,
1226                      cpy_oconfig_to_pyconfig(ci->children + i, item));
1227   }
1228   tmp = ((Config *)item)->children;
1229   ((Config *)item)->children = children;
1230   Py_XDECREF(tmp);
1231   return item;
1232 }
1233
1234 #ifdef IS_PY3K
1235 static struct PyModuleDef collectdmodule = {
1236     PyModuleDef_HEAD_INIT, "collectd",  /* name of module */
1237     "The python interface to collectd", /* module documentation, may be NULL */
1238     -1, cpy_methods};
1239
1240 PyMODINIT_FUNC PyInit_collectd(void) {
1241   return PyModule_Create(&collectdmodule);
1242 }
1243 #endif
1244
1245 static int cpy_init_python(void) {
1246   PyOS_sighandler_t cur_sig;
1247   PyObject *sys, *errordict;
1248   PyObject *module;
1249
1250 #ifdef IS_PY3K
1251   wchar_t *argv = L"";
1252   /* Add a builtin module, before Py_Initialize */
1253   PyImport_AppendInittab("collectd", PyInit_collectd);
1254 #else
1255   char *argv = "";
1256 #endif
1257
1258   /* Chances are the current signal handler is already SIG_DFL, but let's make
1259    * sure. */
1260   cur_sig = PyOS_setsig(SIGINT, SIG_DFL);
1261   Py_Initialize();
1262   python_sigint_handler = PyOS_setsig(SIGINT, cur_sig);
1263
1264   PyType_Ready(&ConfigType);
1265   PyType_Ready(&PluginDataType);
1266   ValuesType.tp_base = &PluginDataType;
1267   PyType_Ready(&ValuesType);
1268   NotificationType.tp_base = &PluginDataType;
1269   PyType_Ready(&NotificationType);
1270   SignedType.tp_base = &PyLong_Type;
1271   PyType_Ready(&SignedType);
1272   UnsignedType.tp_base = &PyLong_Type;
1273   PyType_Ready(&UnsignedType);
1274   errordict = PyDict_New();
1275   PyDict_SetItemString(
1276       errordict, "__doc__",
1277       cpy_string_to_unicode_or_bytes(CollectdError_doc)); /* New reference. */
1278   CollectdError = PyErr_NewException("collectd.CollectdError", NULL, errordict);
1279   sys = PyImport_ImportModule("sys"); /* New reference. */
1280   if (sys == NULL) {
1281     cpy_log_exception("python initialization");
1282     return 1;
1283   }
1284   sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1285   Py_DECREF(sys);
1286   if (sys_path == NULL) {
1287     cpy_log_exception("python initialization");
1288     return 1;
1289   }
1290   PySys_SetArgv(1, &argv);
1291   PyList_SetSlice(sys_path, 0, 1, NULL);
1292
1293 #ifdef IS_PY3K
1294   module = PyImport_ImportModule("collectd");
1295 #else
1296   module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1297 #endif
1298   PyModule_AddObject(module, "Config",
1299                      (void *)&ConfigType); /* Steals a reference. */
1300   PyModule_AddObject(module, "Values",
1301                      (void *)&ValuesType); /* Steals a reference. */
1302   PyModule_AddObject(module, "Notification",
1303                      (void *)&NotificationType); /* Steals a reference. */
1304   PyModule_AddObject(module, "Signed",
1305                      (void *)&SignedType); /* Steals a reference. */
1306   PyModule_AddObject(module, "Unsigned",
1307                      (void *)&UnsignedType); /* Steals a reference. */
1308   Py_XINCREF(CollectdError);
1309   PyModule_AddObject(module, "CollectdError",
1310                      CollectdError); /* Steals a reference. */
1311   PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1312   PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1313   PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1314   PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1315   PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1316   PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1317   PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1318   PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1319   PyModule_AddStringConstant(module, "DS_TYPE_COUNTER",
1320                              DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1321   PyModule_AddStringConstant(module, "DS_TYPE_GAUGE",
1322                              DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1323   PyModule_AddStringConstant(module, "DS_TYPE_DERIVE",
1324                              DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1325   PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE",
1326                              DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1327   return 0;
1328 }
1329
1330 static int cpy_config(oconfig_item_t *ci) {
1331   PyObject *tb;
1332   int status = 0;
1333
1334   /* Ok in theory we shouldn't do initialization at this point
1335    * but we have to. In order to give python scripts a chance
1336    * to register a config callback we need to be able to execute
1337    * python code during the config callback so we have to start
1338    * the interpreter here. */
1339   /* Do *not* use the python "thread" module at this point! */
1340
1341   if (!Py_IsInitialized() && cpy_init_python())
1342     return 1;
1343
1344   for (int i = 0; i < ci->children_num; ++i) {
1345     oconfig_item_t *item = ci->children + i;
1346
1347     if (strcasecmp(item->key, "Interactive") == 0) {
1348       if (cf_util_get_boolean(item, &do_interactive) != 0) {
1349         status = 1;
1350         continue;
1351       }
1352     } else if (strcasecmp(item->key, "Encoding") == 0) {
1353       char *encoding = NULL;
1354       if (cf_util_get_string(item, &encoding) != 0) {
1355         status = 1;
1356         continue;
1357       }
1358 #ifdef IS_PY3K
1359       ERROR("python: \"Encoding\" was used in the config file but Python3 was "
1360             "used, which does not support changing encodings");
1361       status = 1;
1362       sfree(encoding);
1363       continue;
1364 #else
1365       /* Why is this even necessary? And undocumented? */
1366       if (PyUnicode_SetDefaultEncoding(encoding)) {
1367         cpy_log_exception("setting default encoding");
1368         status = 1;
1369       }
1370 #endif
1371       sfree(encoding);
1372     } else if (strcasecmp(item->key, "LogTraces") == 0) {
1373       bool log_traces;
1374       if (cf_util_get_boolean(item, &log_traces) != 0) {
1375         status = 1;
1376         continue;
1377       }
1378       if (!log_traces) {
1379         Py_XDECREF(cpy_format_exception);
1380         cpy_format_exception = NULL;
1381         continue;
1382       }
1383       if (cpy_format_exception)
1384         continue;
1385       tb = PyImport_ImportModule("traceback"); /* New reference. */
1386       if (tb == NULL) {
1387         cpy_log_exception("python initialization");
1388         status = 1;
1389         continue;
1390       }
1391       cpy_format_exception =
1392           PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1393       Py_DECREF(tb);
1394       if (cpy_format_exception == NULL) {
1395         cpy_log_exception("python initialization");
1396         status = 1;
1397       }
1398     } else if (strcasecmp(item->key, "ModulePath") == 0) {
1399       char *dir = NULL;
1400       PyObject *dir_object;
1401
1402       if (cf_util_get_string(item, &dir) != 0) {
1403         status = 1;
1404         continue;
1405       }
1406       dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1407       if (dir_object == NULL) {
1408         ERROR("python plugin: Unable to convert \"%s\" to "
1409               "a python object.",
1410               dir);
1411         free(dir);
1412         cpy_log_exception("python initialization");
1413         status = 1;
1414         continue;
1415       }
1416       if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1417         ERROR("python plugin: Unable to prepend \"%s\" to "
1418               "python module path.",
1419               dir);
1420         cpy_log_exception("python initialization");
1421         status = 1;
1422       }
1423       Py_DECREF(dir_object);
1424       free(dir);
1425     } else if (strcasecmp(item->key, "Import") == 0) {
1426       char *module_name = NULL;
1427       PyObject *module;
1428
1429       if (cf_util_get_string(item, &module_name) != 0) {
1430         status = 1;
1431         continue;
1432       }
1433       module = PyImport_ImportModule(module_name); /* New reference. */
1434       if (module == NULL) {
1435         ERROR("python plugin: Error importing module \"%s\".", module_name);
1436         cpy_log_exception("importing module");
1437         status = 1;
1438       }
1439       free(module_name);
1440       Py_XDECREF(module);
1441     } else if (strcasecmp(item->key, "Module") == 0) {
1442       char *name = NULL;
1443       cpy_callback_t *c;
1444       PyObject *ret;
1445
1446       if (cf_util_get_string(item, &name) != 0) {
1447         status = 1;
1448         continue;
1449       }
1450       for (c = cpy_config_callbacks; c; c = c->next) {
1451         if (strcasecmp(c->name + 7, name) == 0)
1452           break;
1453       }
1454       if (c == NULL) {
1455         WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1456                 "but the plugin isn't loaded or didn't register "
1457                 "a configuration callback.",
1458                 name);
1459         free(name);
1460         continue;
1461       }
1462       free(name);
1463       if (c->data == NULL)
1464         ret = PyObject_CallFunction(
1465             c->callback, "N",
1466             cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1467       else
1468         ret = PyObject_CallFunction(c->callback, "NO",
1469                                     cpy_oconfig_to_pyconfig(item, NULL),
1470                                     c->data); /* New reference. */
1471       if (ret == NULL) {
1472         cpy_log_exception("loading module");
1473         status = 1;
1474       } else
1475         Py_DECREF(ret);
1476     } else {
1477       ERROR("python plugin: Unknown config key \"%s\".", item->key);
1478       status = 1;
1479     }
1480   }
1481   return status;
1482 }
1483
1484 void module_register(void) {
1485   plugin_register_complex_config("python", cpy_config);
1486   plugin_register_init("python", cpy_init);
1487   plugin_register_shutdown("python", cpy_shutdown);
1488 }