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