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