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 **/
27 #include <Python.h>
28 #include <structmember.h>
30 #include <signal.h>
32 #include "collectd.h"
34 #include "common.h"
36 #include "cpython.h"
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;
45 static char log_doc[] = "This function sends a string to all logging plugins.";
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.";
60 static char flush_doc[] = "flush([plugin][, timeout][, identifier]) -> None\n"
61 "\n"
62 "Flushes the cache of another plugin.";
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.";
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.";
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.";
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.";
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.";
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.";
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.";
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.";
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.";
222 static pthread_t main_thread;
223 static PyOS_sighandler_t python_sigint_handler;
224 static _Bool do_interactive = 0;
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. */
231 static PyThreadState *state;
233 static PyObject *sys_path, *cpy_format_exception;
235 static cpy_callback_t *cpy_config_callbacks;
236 static cpy_callback_t *cpy_init_callbacks;
237 static cpy_callback_t *cpy_shutdown_callbacks;
239 /* Make sure to hold the GIL while modifying these. */
240 static int cpy_shutdown_triggered = 0;
241 static int cpy_num_callbacks = 0;
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 }
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. */
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;
265 if (name != NULL) {
266 snprintf(buf, size, "python.%s", name);
267 return;
268 }
270 mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */
271 if (mod != NULL)
272 module = cpy_unicode_or_bytes_to_string(&mod);
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);
282 snprintf(buf, size, "python.%p", callback);
283 PyErr_Clear();
284 }
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;
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);
320 for (int i = 0; i < l; ++i) {
321 PyObject *line;
322 char const *msg;
323 char *cpy;
325 line = PyList_GET_ITEM(list, i); /* Borrowed reference. */
326 Py_INCREF(line);
328 msg = cpy_unicode_or_bytes_to_string(&line);
329 Py_DECREF(line);
330 if (msg == NULL)
331 continue;
333 cpy = strdup(msg);
334 if (cpy == NULL)
335 continue;
337 if (cpy[strlen(cpy) - 1] == '\n')
338 cpy[strlen(cpy) - 1] = 0;
340 Py_BEGIN_ALLOW_THREADS
341 ERROR("%s", cpy);
342 Py_END_ALLOW_THREADS
344 free(cpy);
345 }
347 Py_XDECREF(list);
348 PyErr_Clear();
349 }
351 static int cpy_read_callback(user_data_t *data) {
352 cpy_callback_t *c = data->data;
353 PyObject *ret;
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 }
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;
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;
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;
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 }
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;
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 }
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;
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". */
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 }
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;
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. */
543 if (ret == NULL) {
544 cpy_log_exception("flush callback");
545 } else {
546 Py_DECREF(ret);
547 }
548 CPY_RELEASE_THREADS
549 }
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};
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);
566 Py_INCREF(callback);
567 Py_XINCREF(data);
569 c = calloc(1, sizeof(*c));
570 if (c == NULL)
571 return NULL;
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 }
584 static PyObject *float_or_none(float number) {
585 if (isnan(number)) {
586 Py_RETURN_NONE;
587 }
588 return PyFloat_FromDouble(number);
589 }
591 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
592 char *name;
593 const data_set_t *ds;
594 PyObject *list, *tuple;
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 }
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};
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 }
629 static PyObject *cpy_register_config(PyObject *self, PyObject *args, PyObject *kwds) {
630 return cpy_register_generic(&cpy_config_callbacks, args, kwds);
631 }
633 static PyObject *cpy_register_init(PyObject *self, PyObject *args, PyObject *kwds) {
634 return cpy_register_generic(&cpy_init_callbacks, args, kwds);
635 }
637 typedef int reg_function_t(const char *name, void *callback, void *data);
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};
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);
656 Py_INCREF(callback);
657 Py_XINCREF(data);
659 c = calloc(1, sizeof(*c));
660 if (c == NULL)
661 return NULL;
663 c->name = strdup(buf);
664 c->callback = callback;
665 c->data = data;
666 c->next = NULL;
668 register_function(buf, handler, &(user_data_t) {
669 .data = c,
670 .free_func = cpy_destroy_user_data,
671 });
673 ++cpy_num_callbacks;
674 return cpy_string_to_unicode_or_bytes(buf);
675 }
677 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
678 char buf[512];
679 cpy_callback_t *c = NULL;
680 double interval = 0;
681 char *name = NULL;
682 PyObject *callback = NULL, *data = NULL;
683 static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
685 if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
686 if (PyCallable_Check(callback) == 0) {
687 PyMem_Free(name);
688 PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object.");
689 return NULL;
690 }
691 cpy_build_name(buf, sizeof(buf), callback, name);
692 PyMem_Free(name);
694 Py_INCREF(callback);
695 Py_XINCREF(data);
697 c = calloc(1, sizeof(*c));
698 if (c == NULL)
699 return NULL;
701 c->name = strdup(buf);
702 c->callback = callback;
703 c->data = data;
704 c->next = NULL;
706 plugin_register_complex_read(/* group = */ "python", buf,
707 cpy_read_callback, DOUBLE_TO_CDTIME_T (interval),
708 &(user_data_t) {
709 .data = c,
710 .free_func = cpy_destroy_user_data,
711 });
712 ++cpy_num_callbacks;
713 return cpy_string_to_unicode_or_bytes(buf);
714 }
716 static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) {
717 return cpy_register_generic_userdata((void *) plugin_register_log,
718 (void *) cpy_log_callback, args, kwds);
719 }
721 static PyObject *cpy_register_write(PyObject *self, PyObject *args, PyObject *kwds) {
722 return cpy_register_generic_userdata((void *) plugin_register_write,
723 (void *) cpy_write_callback, args, kwds);
724 }
726 static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) {
727 return cpy_register_generic_userdata((void *) plugin_register_notification,
728 (void *) cpy_notification_callback, args, kwds);
729 }
731 static PyObject *cpy_register_flush(PyObject *self, PyObject *args, PyObject *kwds) {
732 return cpy_register_generic_userdata((void *) plugin_register_flush,
733 (void *) cpy_flush_callback, args, kwds);
734 }
736 static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject *kwds) {
737 return cpy_register_generic(&cpy_shutdown_callbacks, args, kwds);
738 }
740 static PyObject *cpy_error(PyObject *self, PyObject *args) {
741 char *text;
742 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
743 Py_BEGIN_ALLOW_THREADS
744 plugin_log(LOG_ERR, "%s", text);
745 Py_END_ALLOW_THREADS
746 PyMem_Free(text);
747 Py_RETURN_NONE;
748 }
750 static PyObject *cpy_warning(PyObject *self, PyObject *args) {
751 char *text;
752 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
753 Py_BEGIN_ALLOW_THREADS
754 plugin_log(LOG_WARNING, "%s", text);
755 Py_END_ALLOW_THREADS
756 PyMem_Free(text);
757 Py_RETURN_NONE;
758 }
760 static PyObject *cpy_notice(PyObject *self, PyObject *args) {
761 char *text;
762 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
763 Py_BEGIN_ALLOW_THREADS
764 plugin_log(LOG_NOTICE, "%s", text);
765 Py_END_ALLOW_THREADS
766 PyMem_Free(text);
767 Py_RETURN_NONE;
768 }
770 static PyObject *cpy_info(PyObject *self, PyObject *args) {
771 char *text;
772 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
773 Py_BEGIN_ALLOW_THREADS
774 plugin_log(LOG_INFO, "%s", text);
775 Py_END_ALLOW_THREADS
776 PyMem_Free(text);
777 Py_RETURN_NONE;
778 }
780 static PyObject *cpy_debug(PyObject *self, PyObject *args) {
781 #ifdef COLLECT_DEBUG
782 char *text;
783 if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL;
784 Py_BEGIN_ALLOW_THREADS
785 plugin_log(LOG_DEBUG, "%s", text);
786 Py_END_ALLOW_THREADS
787 PyMem_Free(text);
788 #endif
789 Py_RETURN_NONE;
790 }
792 static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *arg, const char *desc) {
793 char buf[512];
794 const char *name;
795 cpy_callback_t *prev = NULL, *tmp;
797 Py_INCREF(arg);
798 name = cpy_unicode_or_bytes_to_string(&arg);
799 if (name == NULL) {
800 PyErr_Clear();
801 if (!PyCallable_Check(arg)) {
802 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
803 Py_DECREF(arg);
804 return NULL;
805 }
806 cpy_build_name(buf, sizeof(buf), arg, NULL);
807 name = buf;
808 }
809 for (tmp = *list_head; tmp; prev = tmp, tmp = tmp->next)
810 if (strcmp(name, tmp->name) == 0)
811 break;
813 Py_DECREF(arg);
814 if (tmp == NULL) {
815 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
816 return NULL;
817 }
818 /* Yes, this is actually safe. To call this function the caller has to
819 * hold the GIL. Well, safe as long as there is only one GIL anyway ... */
820 if (prev == NULL)
821 *list_head = tmp->next;
822 else
823 prev->next = tmp->next;
824 cpy_destroy_user_data(tmp);
825 Py_RETURN_NONE;
826 }
828 static void cpy_unregister_list(cpy_callback_t **list_head) {
829 cpy_callback_t *cur, *next;
830 for (cur = *list_head; cur; cur = next) {
831 next = cur->next;
832 cpy_destroy_user_data(cur);
833 }
834 *list_head = NULL;
835 }
837 typedef int cpy_unregister_function_t(const char *name);
839 static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unreg, PyObject *arg, const char *desc) {
840 char buf[512];
841 const char *name;
843 Py_INCREF(arg);
844 name = cpy_unicode_or_bytes_to_string(&arg);
845 if (name == NULL) {
846 PyErr_Clear();
847 if (!PyCallable_Check(arg)) {
848 PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter.");
849 Py_DECREF(arg);
850 return NULL;
851 }
852 cpy_build_name(buf, sizeof(buf), arg, NULL);
853 name = buf;
854 }
855 if (unreg(name) == 0) {
856 Py_DECREF(arg);
857 Py_RETURN_NONE;
858 }
859 PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name);
860 Py_DECREF(arg);
861 return NULL;
862 }
864 static PyObject *cpy_unregister_log(PyObject *self, PyObject *arg) {
865 return cpy_unregister_generic_userdata(plugin_unregister_log, arg, "log");
866 }
868 static PyObject *cpy_unregister_init(PyObject *self, PyObject *arg) {
869 return cpy_unregister_generic(&cpy_init_callbacks, arg, "init");
870 }
872 static PyObject *cpy_unregister_config(PyObject *self, PyObject *arg) {
873 return cpy_unregister_generic(&cpy_config_callbacks, arg, "config");
874 }
876 static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) {
877 return cpy_unregister_generic_userdata(plugin_unregister_read, arg, "read");
878 }
880 static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) {
881 return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write");
882 }
884 static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) {
885 return cpy_unregister_generic_userdata(plugin_unregister_notification, arg, "notification");
886 }
888 static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) {
889 return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush");
890 }
892 static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) {
893 return cpy_unregister_generic(&cpy_shutdown_callbacks, arg, "shutdown");
894 }
896 static PyMethodDef cpy_methods[] = {
897 {"debug", cpy_debug, METH_VARARGS, log_doc},
898 {"info", cpy_info, METH_VARARGS, log_doc},
899 {"notice", cpy_notice, METH_VARARGS, log_doc},
900 {"warning", cpy_warning, METH_VARARGS, log_doc},
901 {"error", cpy_error, METH_VARARGS, log_doc},
902 {"get_dataset", (PyCFunction) cpy_get_dataset, METH_VARARGS, get_ds_doc},
903 {"flush", (PyCFunction) cpy_flush, METH_VARARGS | METH_KEYWORDS, flush_doc},
904 {"register_log", (PyCFunction) cpy_register_log, METH_VARARGS | METH_KEYWORDS, reg_log_doc},
905 {"register_init", (PyCFunction) cpy_register_init, METH_VARARGS | METH_KEYWORDS, reg_init_doc},
906 {"register_config", (PyCFunction) cpy_register_config, METH_VARARGS | METH_KEYWORDS, reg_config_doc},
907 {"register_read", (PyCFunction) cpy_register_read, METH_VARARGS | METH_KEYWORDS, reg_read_doc},
908 {"register_write", (PyCFunction) cpy_register_write, METH_VARARGS | METH_KEYWORDS, reg_write_doc},
909 {"register_notification", (PyCFunction) cpy_register_notification, METH_VARARGS | METH_KEYWORDS, reg_notification_doc},
910 {"register_flush", (PyCFunction) cpy_register_flush, METH_VARARGS | METH_KEYWORDS, reg_flush_doc},
911 {"register_shutdown", (PyCFunction) cpy_register_shutdown, METH_VARARGS | METH_KEYWORDS, reg_shutdown_doc},
912 {"unregister_log", cpy_unregister_log, METH_O, unregister_doc},
913 {"unregister_init", cpy_unregister_init, METH_O, unregister_doc},
914 {"unregister_config", cpy_unregister_config, METH_O, unregister_doc},
915 {"unregister_read", cpy_unregister_read, METH_O, unregister_doc},
916 {"unregister_write", cpy_unregister_write, METH_O, unregister_doc},
917 {"unregister_notification", cpy_unregister_notification, METH_O, unregister_doc},
918 {"unregister_flush", cpy_unregister_flush, METH_O, unregister_doc},
919 {"unregister_shutdown", cpy_unregister_shutdown, METH_O, unregister_doc},
920 {0, 0, 0, 0}
921 };
923 static int cpy_shutdown(void) {
924 PyObject *ret;
926 if (!state) {
927 printf("================================================================\n");
928 printf("collectd shutdown while running an interactive session. This will\n");
929 printf("probably leave your terminal in a mess.\n");
930 printf("Run the command \"reset\" to get it back into a usable state.\n");
931 printf("You can press Ctrl+D in the interactive session to\n");
932 printf("close collectd and avoid this problem in the future.\n");
933 printf("================================================================\n");
934 }
936 CPY_LOCK_THREADS
938 for (cpy_callback_t *c = cpy_shutdown_callbacks; c; c = c->next) {
939 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
940 if (ret == NULL)
941 cpy_log_exception("shutdown callback");
942 else
943 Py_DECREF(ret);
944 }
945 PyErr_Print();
947 Py_BEGIN_ALLOW_THREADS
948 cpy_unregister_list(&cpy_config_callbacks);
949 cpy_unregister_list(&cpy_init_callbacks);
950 cpy_unregister_list(&cpy_shutdown_callbacks);
951 cpy_shutdown_triggered = 1;
952 Py_END_ALLOW_THREADS
954 if (!cpy_num_callbacks) {
955 Py_Finalize();
956 return 0;
957 }
959 CPY_RELEASE_THREADS
960 return 0;
961 }
963 static void *cpy_interactive(void *pipefd) {
964 PyOS_sighandler_t cur_sig;
966 /* Signal handler in a plugin? Bad stuff, but the best way to
967 * handle it I guess. In an interactive session people will
968 * press Ctrl+C at some time, which will generate a SIGINT.
969 * This will cause collectd to shutdown, thus killing the
970 * interactive interpreter, and leaving the terminal in a
971 * mess. Chances are, this isn't what the user wanted to do.
972 *
973 * So this is the plan:
974 * 1. Restore Python's own signal handler
975 * 2. Tell Python we just forked so it will accept this thread
976 * as the main one. No version of Python will ever handle
977 * interrupts anywhere but in the main thread.
978 * 3. After the interactive loop is done, restore collectd's
979 * SIGINT handler.
980 * 4. Raise SIGINT for a clean shutdown. The signal is sent to
981 * the main thread to ensure it wakes up the main interval
982 * sleep so that collectd shuts down immediately not in 10
983 * seconds.
984 *
985 * This will make sure that SIGINT won't kill collectd but
986 * still interrupt syscalls like sleep and pause. */
988 if (PyImport_ImportModule("readline") == NULL) {
989 /* This interactive session will suck. */
990 cpy_log_exception("interactive session init");
991 }
992 cur_sig = PyOS_setsig(SIGINT, python_sigint_handler);
993 PyOS_AfterFork();
994 PyEval_InitThreads();
995 close(*(int *) pipefd);
996 PyRun_InteractiveLoop(stdin, "<stdin>");
997 PyOS_setsig(SIGINT, cur_sig);
998 PyErr_Print();
999 state = PyEval_SaveThread();
1000 NOTICE("python: Interactive interpreter exited, stopping collectd ...");
1001 pthread_kill(main_thread, SIGINT);
1002 return NULL;
1003 }
1005 static int cpy_init(void) {
1006 PyObject *ret;
1007 int pipefd[2];
1008 char buf;
1009 static pthread_t thread;
1011 if (!Py_IsInitialized()) {
1012 WARNING("python: Plugin loaded but not configured.");
1013 plugin_unregister_shutdown("python");
1014 Py_Finalize();
1015 return 0;
1016 }
1017 main_thread = pthread_self();
1018 if (do_interactive) {
1019 if (pipe(pipefd)) {
1020 ERROR("python: Unable to create pipe.");
1021 return 1;
1022 }
1023 if (plugin_thread_create(&thread, NULL, cpy_interactive, pipefd + 1)) {
1024 ERROR("python: Error creating thread for interactive interpreter.");
1025 }
1026 if(read(pipefd[0], &buf, 1))
1027 ;
1028 (void)close(pipefd[0]);
1029 } else {
1030 PyEval_InitThreads();
1031 state = PyEval_SaveThread();
1032 }
1033 CPY_LOCK_THREADS
1034 for (cpy_callback_t *c = cpy_init_callbacks; c; c = c->next) {
1035 ret = PyObject_CallFunctionObjArgs(c->callback, c->data, (void *) 0); /* New reference. */
1036 if (ret == NULL)
1037 cpy_log_exception("init callback");
1038 else
1039 Py_DECREF(ret);
1040 }
1041 CPY_RELEASE_THREADS
1043 return 0;
1044 }
1046 static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) {
1047 PyObject *item, *values, *children, *tmp;
1049 if (parent == NULL)
1050 parent = Py_None;
1052 values = PyTuple_New(ci->values_num); /* New reference. */
1053 for (int i = 0; i < ci->values_num; ++i) {
1054 if (ci->values[i].type == OCONFIG_TYPE_STRING) {
1055 PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
1056 } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
1057 PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number));
1058 } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) {
1059 PyTuple_SET_ITEM(values, i, PyBool_FromLong(ci->values[i].value.boolean));
1060 }
1061 }
1063 tmp = cpy_string_to_unicode_or_bytes(ci->key);
1064 item = PyObject_CallFunction((void *) &ConfigType, "NONO", tmp, parent, values, Py_None);
1065 if (item == NULL)
1066 return NULL;
1067 children = PyTuple_New(ci->children_num); /* New reference. */
1068 for (int i = 0; i < ci->children_num; ++i) {
1069 PyTuple_SET_ITEM(children, i, cpy_oconfig_to_pyconfig(ci->children + i, item));
1070 }
1071 tmp = ((Config *) item)->children;
1072 ((Config *) item)->children = children;
1073 Py_XDECREF(tmp);
1074 return item;
1075 }
1077 #ifdef IS_PY3K
1078 static struct PyModuleDef collectdmodule = {
1079 PyModuleDef_HEAD_INIT,
1080 "collectd", /* name of module */
1081 "The python interface to collectd", /* module documentation, may be NULL */
1082 -1,
1083 cpy_methods
1084 };
1086 PyMODINIT_FUNC PyInit_collectd(void) {
1087 return PyModule_Create(&collectdmodule);
1088 }
1089 #endif
1091 static int cpy_init_python(void) {
1092 PyOS_sighandler_t cur_sig;
1093 PyObject *sys;
1094 PyObject *module;
1096 #ifdef IS_PY3K
1097 wchar_t *argv = L"";
1098 /* Add a builtin module, before Py_Initialize */
1099 PyImport_AppendInittab("collectd", PyInit_collectd);
1100 #else
1101 char *argv = "";
1102 #endif
1104 /* Chances are the current signal handler is already SIG_DFL, but let's make sure. */
1105 cur_sig = PyOS_setsig(SIGINT, SIG_DFL);
1106 Py_Initialize();
1107 python_sigint_handler = PyOS_setsig(SIGINT, cur_sig);
1109 PyType_Ready(&ConfigType);
1110 PyType_Ready(&PluginDataType);
1111 ValuesType.tp_base = &PluginDataType;
1112 PyType_Ready(&ValuesType);
1113 NotificationType.tp_base = &PluginDataType;
1114 PyType_Ready(&NotificationType);
1115 SignedType.tp_base = &PyLong_Type;
1116 PyType_Ready(&SignedType);
1117 UnsignedType.tp_base = &PyLong_Type;
1118 PyType_Ready(&UnsignedType);
1119 sys = PyImport_ImportModule("sys"); /* New reference. */
1120 if (sys == NULL) {
1121 cpy_log_exception("python initialization");
1122 return 1;
1123 }
1124 sys_path = PyObject_GetAttrString(sys, "path"); /* New reference. */
1125 Py_DECREF(sys);
1126 if (sys_path == NULL) {
1127 cpy_log_exception("python initialization");
1128 return 1;
1129 }
1130 PySys_SetArgv(1, &argv);
1131 PyList_SetSlice(sys_path, 0, 1, NULL);
1133 #ifdef IS_PY3K
1134 module = PyImport_ImportModule("collectd");
1135 #else
1136 module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */
1137 #endif
1138 PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */
1139 PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */
1140 PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */
1141 PyModule_AddObject(module, "Signed", (void *) &SignedType); /* Steals a reference. */
1142 PyModule_AddObject(module, "Unsigned", (void *) &UnsignedType); /* Steals a reference. */
1143 PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
1144 PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
1145 PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
1146 PyModule_AddIntConstant(module, "LOG_WARNING", LOG_WARNING);
1147 PyModule_AddIntConstant(module, "LOG_ERROR", LOG_ERR);
1148 PyModule_AddIntConstant(module, "NOTIF_FAILURE", NOTIF_FAILURE);
1149 PyModule_AddIntConstant(module, "NOTIF_WARNING", NOTIF_WARNING);
1150 PyModule_AddIntConstant(module, "NOTIF_OKAY", NOTIF_OKAY);
1151 PyModule_AddStringConstant(module, "DS_TYPE_COUNTER", DS_TYPE_TO_STRING(DS_TYPE_COUNTER));
1152 PyModule_AddStringConstant(module, "DS_TYPE_GAUGE", DS_TYPE_TO_STRING(DS_TYPE_GAUGE));
1153 PyModule_AddStringConstant(module, "DS_TYPE_DERIVE", DS_TYPE_TO_STRING(DS_TYPE_DERIVE));
1154 PyModule_AddStringConstant(module, "DS_TYPE_ABSOLUTE", DS_TYPE_TO_STRING(DS_TYPE_ABSOLUTE));
1155 return 0;
1156 }
1158 static int cpy_config(oconfig_item_t *ci) {
1159 PyObject *tb;
1160 int status = 0;
1162 /* Ok in theory we shouldn't do initialization at this point
1163 * but we have to. In order to give python scripts a chance
1164 * to register a config callback we need to be able to execute
1165 * python code during the config callback so we have to start
1166 * the interpreter here. */
1167 /* Do *not* use the python "thread" module at this point! */
1169 if (!Py_IsInitialized() && cpy_init_python()) return 1;
1171 for (int i = 0; i < ci->children_num; ++i) {
1172 oconfig_item_t *item = ci->children + i;
1174 if (strcasecmp(item->key, "Interactive") == 0) {
1175 if (cf_util_get_boolean(item, &do_interactive) != 0) {
1176 status = 1;
1177 continue;
1178 }
1179 } else if (strcasecmp(item->key, "Encoding") == 0) {
1180 char *encoding = NULL;
1181 if (cf_util_get_string(item, &encoding) != 0) {
1182 status = 1;
1183 continue;
1184 }
1185 #ifdef IS_PY3K
1186 ERROR("python: \"Encoding\" was used in the config file but Python3 was used, which does not support changing encodings");
1187 status = 1;
1188 sfree(encoding);
1189 continue;
1190 #else
1191 /* Why is this even necessary? And undocumented? */
1192 if (PyUnicode_SetDefaultEncoding(encoding)) {
1193 cpy_log_exception("setting default encoding");
1194 status = 1;
1195 }
1196 #endif
1197 sfree(encoding);
1198 } else if (strcasecmp(item->key, "LogTraces") == 0) {
1199 _Bool log_traces;
1200 if (cf_util_get_boolean(item, &log_traces) != 0) {
1201 status = 1;
1202 continue;
1203 }
1204 if (!log_traces) {
1205 Py_XDECREF(cpy_format_exception);
1206 cpy_format_exception = NULL;
1207 continue;
1208 }
1209 if (cpy_format_exception)
1210 continue;
1211 tb = PyImport_ImportModule("traceback"); /* New reference. */
1212 if (tb == NULL) {
1213 cpy_log_exception("python initialization");
1214 status = 1;
1215 continue;
1216 }
1217 cpy_format_exception = PyObject_GetAttrString(tb, "format_exception"); /* New reference. */
1218 Py_DECREF(tb);
1219 if (cpy_format_exception == NULL) {
1220 cpy_log_exception("python initialization");
1221 status = 1;
1222 }
1223 } else if (strcasecmp(item->key, "ModulePath") == 0) {
1224 char *dir = NULL;
1225 PyObject *dir_object;
1227 if (cf_util_get_string(item, &dir) != 0) {
1228 status = 1;
1229 continue;
1230 }
1231 dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */
1232 if (dir_object == NULL) {
1233 ERROR("python plugin: Unable to convert \"%s\" to "
1234 "a python object.", dir);
1235 free(dir);
1236 cpy_log_exception("python initialization");
1237 status = 1;
1238 continue;
1239 }
1240 if (PyList_Insert(sys_path, 0, dir_object) != 0) {
1241 ERROR("python plugin: Unable to prepend \"%s\" to "
1242 "python module path.", dir);
1243 cpy_log_exception("python initialization");
1244 status = 1;
1245 }
1246 Py_DECREF(dir_object);
1247 free(dir);
1248 } else if (strcasecmp(item->key, "Import") == 0) {
1249 char *module_name = NULL;
1250 PyObject *module;
1252 if (cf_util_get_string(item, &module_name) != 0) {
1253 status = 1;
1254 continue;
1255 }
1256 module = PyImport_ImportModule(module_name); /* New reference. */
1257 if (module == NULL) {
1258 ERROR("python plugin: Error importing module \"%s\".", module_name);
1259 cpy_log_exception("importing module");
1260 status = 1;
1261 }
1262 free(module_name);
1263 Py_XDECREF(module);
1264 } else if (strcasecmp(item->key, "Module") == 0) {
1265 char *name = NULL;
1266 cpy_callback_t *c;
1267 PyObject *ret;
1269 if (cf_util_get_string(item, &name) != 0) {
1270 status = 1;
1271 continue;
1272 }
1273 for (c = cpy_config_callbacks; c; c = c->next) {
1274 if (strcasecmp(c->name + 7, name) == 0)
1275 break;
1276 }
1277 if (c == NULL) {
1278 WARNING("python plugin: Found a configuration for the \"%s\" plugin, "
1279 "but the plugin isn't loaded or didn't register "
1280 "a configuration callback.", name);
1281 free(name);
1282 continue;
1283 }
1284 free(name);
1285 if (c->data == NULL)
1286 ret = PyObject_CallFunction(c->callback, "N",
1287 cpy_oconfig_to_pyconfig(item, NULL)); /* New reference. */
1288 else
1289 ret = PyObject_CallFunction(c->callback, "NO",
1290 cpy_oconfig_to_pyconfig(item, NULL), c->data); /* New reference. */
1291 if (ret == NULL) {
1292 cpy_log_exception("loading module");
1293 status = 1;
1294 } else
1295 Py_DECREF(ret);
1296 } else {
1297 ERROR("python plugin: Unknown config key \"%s\".", item->key);
1298 status = 1;
1299 }
1300 }
1301 return (status);
1302 }
1304 void module_register(void) {
1305 plugin_register_complex_config("python", cpy_config);
1306 plugin_register_init("python", cpy_init);
1307 plugin_register_shutdown("python", cpy_shutdown);
1308 }