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