From: Florian Forster Date: Wed, 13 Jan 2010 11:11:28 +0000 (+0100) Subject: Merge branch 'collectd-4.9' X-Git-Tag: collectd-4.10.0~74 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=413c4dab34e5cbb227644dd3ead6e6e0a3cdb08c;hp=34f7eda9ad2cbd2cd5620c0a2d76d282e790b4de;p=collectd.git Merge branch 'collectd-4.9' --- diff --git a/configure.in b/configure.in index 8d0744ac..bb7b535a 100644 --- a/configure.in +++ b/configure.in @@ -2739,7 +2739,7 @@ fi if test "x$with_python" = "xyes" then AC_MSG_CHECKING([for Python CPPFLAGS]) - python_include_path=`echo "import distutils.sysconfig;print distutils.sysconfig.get_python_inc()" | "$with_python_prog" 2>&1` + python_include_path=`echo "import distutils.sysconfig;import sys;sys.stdout.write(distutils.sysconfig.get_python_inc())" | "$with_python_prog" 2>&1` python_config_status=$? if test "$python_config_status" -ne 0 || test "x$python_include_path" = "x" @@ -2762,7 +2762,7 @@ fi if test "x$with_python" = "xyes" then AC_MSG_CHECKING([for Python LDFLAGS]) - python_library_path=`echo "import distutils.sysconfig;print distutils.sysconfig.get_config_vars(\"LIBDIR\").__getitem__(0)" | "$with_python_prog" 2>&1` + python_library_path=`echo "import distutils.sysconfig;import sys;sys.stdout.write(distutils.sysconfig.get_config_vars(\"LIBDIR\").__getitem__(0))" | "$with_python_prog" 2>&1` python_config_status=$? if test "$python_config_status" -ne 0 || test "x$python_library_path" = "x" @@ -2777,7 +2777,7 @@ fi if test "x$with_python" = "xyes" then AC_MSG_CHECKING([for Python LIBS]) - python_library_flags=`echo "import distutils.sysconfig;print distutils.sysconfig.get_config_vars(\"BLDLIBRARY\").__getitem__(0)" | "$with_python_prog" 2>&1` + python_library_flags=`echo "import distutils.sysconfig;import sys;sys.stdout.write(distutils.sysconfig.get_config_vars(\"BLDLIBRARY\").__getitem__(0))" | "$with_python_prog" 2>&1` python_config_status=$? if test "$python_config_status" -ne 0 || test "x$python_library_flags" = "x" diff --git a/src/battery.c b/src/battery.c index b62ad81d..4178d8b5 100644 --- a/src/battery.c +++ b/src/battery.c @@ -514,7 +514,8 @@ static int battery_read (void) if (0 == access (battery_acpi_dir, R_OK)) walk_directory (battery_acpi_dir, battery_read_acpi, - /* user_data = */ NULL); + /* user_data = */ NULL, + /* include hidden */ 0); else { char errbuf[1024]; diff --git a/src/collectd-python.pod b/src/collectd-python.pod index 021a6c57..8742104c 100644 --- a/src/collectd-python.pod +++ b/src/collectd-python.pod @@ -27,8 +27,7 @@ for collectd in Python. This is a lot more efficient than executing a Python-script every time you want to read a value with the C (see L) and provides a lot more functionality, too. -Currently only I is supported and at least I is -required. +At least python I is required. =head1 CONFIGURATION @@ -119,6 +118,29 @@ The I identifies the callback. =back +=head1 STRINGS + +There are a lot of places where strings are send from collectd to python and +from python to collectd. How exactly this works depends on wheather byte or +unicode strings or python2 or python3 are used. + +Python2 has I, which is just bytes, and I. Python3 has I, +which is a unicode object, and I. + +When passing strings from python to collectd all of these object are supported +in all places, however I should be used if possible. These strings must +not contain a NUL byte. Ignoring this will result in a I exception. +If a byte string was used it will be used as is by collectd. If a unicode +object was used it will be encoded using the default encoding (see above). If +this is not possible python will raise a I exception. + +Wenn passing strings from collectd to python the behavior depends on the +python version used. Python2 will always receive a I object. Python3 will +usually receive a I object as well, however the original string will be +decoded to unicode using the default encoding. If this fails because the +string is not a valid sequence for this encoding a I object will be +returned instead. + =head1 WRITING YOUR OWN PLUGINS Writing your own plugins is quite simple. collectd manages plugins by means of diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index e2cb799e..9af1ff51 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -1104,6 +1104,12 @@ note that there are 1000 bytes in a kilobyte, not 1024. Controls whether or not to recurse into subdirectories. Enabled by default. +=item B I|I + +Controls whether or not to include "hidden" files and directories in the count. +"Hidden" files and directories are those, whose name begins with a dot. +Defaults to I, i.e. by default hidden files and directories are ignored. + =back =head2 Plugin C diff --git a/src/common.c b/src/common.c index c6a651dc..3695a9b7 100644 --- a/src/common.c +++ b/src/common.c @@ -1008,7 +1008,7 @@ int notification_init (notification_t *n, int severity, const char *message, } /* int notification_init */ int walk_directory (const char *dir, dirwalk_callback_f callback, - void *user_data) + void *user_data, int include_hidden) { struct dirent *ent; DIR *dh; @@ -1029,9 +1029,18 @@ int walk_directory (const char *dir, dirwalk_callback_f callback, while ((ent = readdir (dh)) != NULL) { int status; - - if (ent->d_name[0] == '.') - continue; + + if (include_hidden) + { + if ((strcmp (".", ent->d_name) == 0) + || (strcmp ("..", ent->d_name) == 0)) + continue; + } + else /* if (!include_hidden) */ + { + if (ent->d_name[0]=='.') + continue; + } status = (*callback) (dir, ent->d_name, user_data); if (status != 0) diff --git a/src/common.h b/src/common.h index 019e8b69..2d5c7945 100644 --- a/src/common.h +++ b/src/common.h @@ -280,7 +280,7 @@ int notification_init (notification_t *n, int severity, const char *message, typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename, void *user_data); int walk_directory (const char *dir, dirwalk_callback_f callback, - void *user_data); + void *user_data, int hidden); int read_file_contents (const char *filename, char *buf, int bufsize); counter_t counter_diff (counter_t old_value, counter_t new_value); diff --git a/src/cpython.h b/src/cpython.h index 661bf6a2..3e80cb0c 100644 --- a/src/cpython.h +++ b/src/cpython.h @@ -74,6 +74,89 @@ # define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif +/* This macro is a shortcut for calls like + * x = PyObject_Repr(x); + * This can't be done like this example because this would leak + * a reference the the original x and crash in case of x == NULL. + * This calling syntax is less than elegant but it works, saves + * a lot of lines and avoids potential refcount errors. */ + +#define CPY_SUBSTITUTE(func, a, ...) do {\ + if ((a) != NULL) {\ + PyObject *__tmp = (a);\ + (a) = func(__VA_ARGS__);\ + Py_DECREF(__tmp);\ + }\ +} while(0) + +/* Python3 compatibility layer. To keep the actual code as clean as possible + * do a lot of defines here. */ + +#if PY_MAJOR_VERSION >= 3 +#define IS_PY3K +#endif + +#ifdef IS_PY3K + +#define PyInt_FromLong PyLong_FromLong +#define CPY_INIT_TYPE PyVarObject_HEAD_INIT(NULL, 0) +#define IS_BYTES_OR_UNICODE(o) (PyUnicode_Check(o) || PyBytes_Check(o)) +#define CPY_STRCAT_AND_DEL(a, b) do {\ + CPY_STRCAT((a), (b));\ + Py_XDECREF((b));\ +} while (0) +static inline void CPY_STRCAT(PyObject **a, PyObject *b) { + PyObject *ret; + + if (!a || !*a) + return; + + ret = PyUnicode_Concat(*a, b); + Py_DECREF(*a); + *a = ret; +} + +#else + +#define CPY_INIT_TYPE PyObject_HEAD_INIT(NULL) 0, +#define IS_BYTES_OR_UNICODE(o) (PyUnicode_Check(o) || PyString_Check(o)) +#define CPY_STRCAT_AND_DEL PyString_ConcatAndDel +#define CPY_STRCAT PyString_Concat + +#endif + +static inline const char *cpy_unicode_or_bytes_to_string(PyObject **o) { + if (PyUnicode_Check(*o)) { + PyObject *tmp; + tmp = PyUnicode_AsEncodedString(*o, NULL, NULL); /* New reference. */ + if (tmp == NULL) + return NULL; + Py_DECREF(*o); + *o = tmp; + } +#ifdef IS_PY3K + return PyBytes_AsString(*o); +#else + return PyString_AsString(*o); +#endif +} + +static inline PyObject *cpy_string_to_unicode_or_bytes(const char *buf) { +#ifdef IS_PY3K +/* Python3 preferrs unicode */ + PyObject *ret; + ret = PyUnicode_Decode(buf, strlen(buf), NULL, NULL); + if (ret != NULL) + return ret; + PyErr_Clear(); + return PyBytes_FromString(buf); +#else + return PyString_FromString(buf); +#endif +} + + /* Python object declarations. */ + typedef struct { PyObject_HEAD /* No semicolon! */ PyObject *parent; /* Config */ diff --git a/src/filecount.c b/src/filecount.c index 05bb4b37..47f99e91 100644 --- a/src/filecount.c +++ b/src/filecount.c @@ -32,6 +32,7 @@ #include #define FC_RECURSIVE 1 +#define FC_HIDDEN 2 struct fc_directory_conf_s { @@ -310,8 +311,8 @@ static int fc_config_add_dir_size (fc_directory_conf_t *dir, return (0); } /* int fc_config_add_dir_size */ -static int fc_config_add_dir_recursive (fc_directory_conf_t *dir, - oconfig_item_t *ci) +static int fc_config_add_dir_option (fc_directory_conf_t *dir, + oconfig_item_t *ci, int bit) { if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) @@ -322,12 +323,12 @@ static int fc_config_add_dir_recursive (fc_directory_conf_t *dir, } if (ci->values[0].value.boolean) - dir->options |= FC_RECURSIVE; + dir->options |= bit; else - dir->options &= ~FC_RECURSIVE; + dir->options &= ~bit; return (0); -} /* int fc_config_add_dir_recursive */ +} /* int fc_config_add_dir_option */ static int fc_config_add_dir (oconfig_item_t *ci) { @@ -380,7 +381,9 @@ static int fc_config_add_dir (oconfig_item_t *ci) else if (strcasecmp ("Size", option->key) == 0) status = fc_config_add_dir_size (dir, option); else if (strcasecmp ("Recursive", option->key) == 0) - status = fc_config_add_dir_recursive (dir, option); + status = fc_config_add_dir_option (dir, option, FC_RECURSIVE); + else if (strcasecmp ("IncludeHidden", option->key) == 0) + status = fc_config_add_dir_option (dir, option, FC_HIDDEN); else { WARNING ("filecount plugin: fc_config_add_dir: " @@ -475,7 +478,8 @@ static int fc_read_dir_callback (const char *dirname, const char *filename, if (S_ISDIR (statbuf.st_mode) && (dir->options & FC_RECURSIVE)) { - status = walk_directory (abs_path, fc_read_dir_callback, dir); + status = walk_directory (abs_path, fc_read_dir_callback, dir, + /* include hidden = */ (dir->options & FC_HIDDEN) ? 1 : 0); return (status); } else if (!S_ISREG (statbuf.st_mode)) @@ -537,8 +541,9 @@ static int fc_read_dir (fc_directory_conf_t *dir) if (dir->mtime != 0) dir->now = time (NULL); - - status = walk_directory (dir->path, fc_read_dir_callback, dir); + + status = walk_directory (dir->path, fc_read_dir_callback, dir, + /* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0); if (status != 0) { WARNING ("filecount plugin: walk_directory (%s) failed.", dir->path); diff --git a/src/meta_data.c b/src/meta_data.c index 3a3f5e79..6a336c4b 100644 --- a/src/meta_data.c +++ b/src/meta_data.c @@ -26,15 +26,6 @@ #include /* - * Defines - */ -#define MD_TYPE_STRING 1 -#define MD_TYPE_SIGNED_INT 2 -#define MD_TYPE_UNSIGNED_INT 3 -#define MD_TYPE_DOUBLE 4 -#define MD_TYPE_BOOLEAN 5 - -/* * Data types */ union meta_value_u @@ -249,6 +240,49 @@ int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */ return (0); } /* }}} int meta_data_exists */ +int meta_data_type (meta_data_t *md, const char *key) /* {{{ */ +{ + meta_entry_t *e; + + if ((md == NULL) || (key == NULL)) + return -EINVAL; + + pthread_mutex_lock (&md->lock); + + for (e = md->head; e != NULL; e = e->next) + { + if (strcasecmp (key, e->key) == 0) + { + pthread_mutex_unlock (&md->lock); + return e->type; + } + } + + pthread_mutex_unlock (&md->lock); + return 0; +} /* }}} int meta_data_type */ + +int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */ +{ + int i = 0, count = 0; + meta_entry_t *e; + + if ((md == NULL) || (toc == NULL)) + return -EINVAL; + + pthread_mutex_lock (&md->lock); + + for (e = md->head; e != NULL; e = e->next) + ++count; + + *toc = malloc(count * sizeof(**toc)); + for (e = md->head; e != NULL; e = e->next) + (*toc)[i++] = strdup(e->key); + + pthread_mutex_unlock (&md->lock); + return count; +} /* }}} int meta_data_toc */ + int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */ { meta_entry_t *this; diff --git a/src/meta_data.h b/src/meta_data.h index 8e5a7852..9ef7b0a8 100644 --- a/src/meta_data.h +++ b/src/meta_data.h @@ -24,6 +24,15 @@ #include "collectd.h" +/* + * Defines + */ +#define MD_TYPE_STRING 1 +#define MD_TYPE_SIGNED_INT 2 +#define MD_TYPE_UNSIGNED_INT 3 +#define MD_TYPE_DOUBLE 4 +#define MD_TYPE_BOOLEAN 5 + struct meta_data_s; typedef struct meta_data_s meta_data_t; @@ -31,6 +40,8 @@ meta_data_t *meta_data_create (void); void meta_data_destroy (meta_data_t *md); int meta_data_exists (meta_data_t *md, const char *key); +int meta_data_type (meta_data_t *md, const char *key); +int meta_data_toc (meta_data_t *md, char ***toc); int meta_data_delete (meta_data_t *md, const char *key); int meta_data_add_string (meta_data_t *md, diff --git a/src/pyconfig.c b/src/pyconfig.c index bac39ae9..b5c01aaf 100644 --- a/src/pyconfig.c +++ b/src/pyconfig.c @@ -74,10 +74,17 @@ static int Config_init(PyObject *s, PyObject *args, PyObject *kwds) { Config *self = (Config *) s; static char *kwlist[] = {"key", "parent", "values", "children", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|OOO", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", kwlist, &key, &parent, &values, &children)) return -1; + if (!IS_BYTES_OR_UNICODE(key)) { + PyErr_SetString(PyExc_TypeError, "argument 1 must be str"); + Py_XDECREF(parent); + Py_XDECREF(values); + Py_XDECREF(children); + return -1; + } if (values == NULL) { values = PyTuple_New(0); PyErr_Clear(); @@ -113,8 +120,28 @@ static int Config_init(PyObject *s, PyObject *args, PyObject *kwds) { static PyObject *Config_repr(PyObject *s) { Config *self = (Config *) s; + PyObject *ret = NULL; + static PyObject *node_prefix = NULL, *root_prefix = NULL, *ending = NULL; + + /* This is ok because we have the GIL, so this is thread-save by default. */ + if (node_prefix == NULL) + node_prefix = cpy_string_to_unicode_or_bytes(""); + if (node_prefix == NULL || root_prefix == NULL || ending == NULL) + return NULL; - return PyString_FromFormat("", self->parent == Py_None ? "root " : "", PyString_AsString(PyObject_Str(self->key))); + ret = PyObject_Str(self->key); + CPY_SUBSTITUTE(PyObject_Repr, ret, ret); + if (self->parent == NULL || self->parent == Py_None) + CPY_STRCAT(&ret, root_prefix); + else + CPY_STRCAT(&ret, node_prefix); + CPY_STRCAT(&ret, ending); + + return ret; } static int Config_traverse(PyObject *self, visitproc visit, void *arg) { @@ -123,8 +150,7 @@ static int Config_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(c->key); Py_VISIT(c->values); Py_VISIT(c->children); - return 0; -} + return 0;} static int Config_clear(PyObject *self) { Config *c = (Config *) self; @@ -149,8 +175,7 @@ static PyMemberDef Config_members[] = { }; PyTypeObject ConfigType = { - PyObject_HEAD_INIT(NULL) - 0, /* Always 0 */ + CPY_INIT_TYPE "collectd.Config", /* tp_name */ sizeof(Config), /* tp_basicsize */ 0, /* Will be filled in later */ diff --git a/src/python.c b/src/python.c index d750d95b..5664b0c6 100644 --- a/src/python.c +++ b/src/python.c @@ -245,7 +245,7 @@ static void cpy_build_name(char *buf, size_t size, PyObject *callback, const cha mod = PyObject_GetAttrString(callback, "__module__"); /* New reference. */ if (mod != NULL) - module = PyString_AsString(mod); + module = cpy_unicode_or_bytes_to_string(&mod); if (module != NULL) { snprintf(buf, size, "python.%s", module); @@ -268,11 +268,11 @@ static void cpy_log_exception(const char *context) { PyErr_NormalizeException(&type, &value, &traceback); if (type == NULL) return; tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */ - m = PyObject_GetAttrString(value, "message"); /* New reference. */ + m = PyObject_Str(value); /* New reference. */ if (tn != NULL) - typename = PyString_AsString(tn); + typename = cpy_unicode_or_bytes_to_string(&tn); if (m != NULL) - message = PyString_AsString(m); + message = cpy_unicode_or_bytes_to_string(&m); if (typename == NULL) typename = "NamelessException"; if (message == NULL) @@ -301,7 +301,9 @@ static void cpy_log_exception(const char *context) { PyObject *line; line = PyList_GET_ITEM(list, i); /* Borrowed reference. */ - s = strdup(PyString_AsString(line)); + Py_INCREF(line); + s = strdup(cpy_unicode_or_bytes_to_string(&line)); + Py_DECREF(line); if (s[strlen(s) - 1] == '\n') s[strlen(s) - 1] = 0; Py_BEGIN_ALLOW_THREADS @@ -333,7 +335,8 @@ static int cpy_read_callback(user_data_t *data) { static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) { int i; cpy_callback_t *c = data->data; - PyObject *ret, *v, *list; + PyObject *ret, *list; + Values *v; CPY_LOCK_THREADS list = PyList_New(value_list->values_len); /* New reference. */ @@ -371,10 +374,15 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li CPY_RETURN_FROM_THREADS 0; } } - v = PyObject_CallFunction((void *) &ValuesType, "sOssssdi", value_list->type, list, - value_list->plugin_instance, value_list->type_instance, value_list->plugin, - value_list->host, (double) value_list->time, value_list->interval); - Py_DECREF(list); + v = PyObject_New(Values, (void *) &ValuesType); + sstrncpy(v->data.host, value_list->host, sizeof(v->data.host)); + sstrncpy(v->data.type, value_list->type, sizeof(v->data.type)); + sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance)); + sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin)); + sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance)); + v->data.time = value_list->time; + v->interval = value_list->interval; + v->values = list; ret = PyObject_CallFunctionObjArgs(c->callback, v, c->data, (void *) 0); /* New reference. */ if (ret == NULL) { cpy_log_exception("write callback"); @@ -387,12 +395,19 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li static int cpy_notification_callback(const notification_t *notification, user_data_t *data) { cpy_callback_t *c = data->data; - PyObject *ret, *n; + PyObject *ret; + Notification *n; CPY_LOCK_THREADS - n = PyObject_CallFunction((void *) &NotificationType, "ssssssdi", notification->type, notification->message, - notification->plugin_instance, notification->type_instance, notification->plugin, - notification->host, (double) notification->time, notification->severity); + n = PyObject_New(Notification, (void *) &NotificationType); + sstrncpy(n->data.host, notification->host, sizeof(n->data.host)); + sstrncpy(n->data.type, notification->type, sizeof(n->data.type)); + sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance)); + sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin)); + sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance)); + n->data.time = notification->time; + sstrncpy(n->message, notification->message, sizeof(n->message)); + n->severity = notification->severity; ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */ if (ret == NULL) { cpy_log_exception("notification callback"); @@ -405,13 +420,14 @@ static int cpy_notification_callback(const notification_t *notification, user_da static void cpy_log_callback(int severity, const char *message, user_data_t *data) { cpy_callback_t * c = data->data; - PyObject *ret; + PyObject *ret, *text; CPY_LOCK_THREADS + text = cpy_string_to_unicode_or_bytes(message); if (c->data == NULL) - ret = PyObject_CallFunction(c->callback, "is", severity, message); /* New reference. */ + ret = PyObject_CallFunction(c->callback, "iN", severity, text); /* New reference. */ else - ret = PyObject_CallFunction(c->callback, "isO", severity, message, c->data); /* New reference. */ + ret = PyObject_CallFunction(c->callback, "iNO", severity, text, c->data); /* New reference. */ if (ret == NULL) { /* FIXME */ @@ -428,13 +444,14 @@ static void cpy_log_callback(int severity, const char *message, user_data_t *dat static void cpy_flush_callback(int timeout, const char *id, user_data_t *data) { cpy_callback_t * c = data->data; - PyObject *ret; + PyObject *ret, *text; CPY_LOCK_THREADS + text = cpy_string_to_unicode_or_bytes(id); if (c->data == NULL) - ret = PyObject_CallFunction(c->callback, "is", timeout, id); /* New reference. */ + ret = PyObject_CallFunction(c->callback, "iN", timeout, text); /* New reference. */ else - ret = PyObject_CallFunction(c->callback, "isO", timeout, id, c->data); /* New reference. */ + ret = PyObject_CallFunction(c->callback, "iNO", timeout, text, c->data); /* New reference. */ if (ret == NULL) { cpy_log_exception("flush callback"); @@ -451,7 +468,7 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args PyObject *callback = NULL, *data = NULL, *mod = NULL; static char *kwlist[] = {"callback", "data", "name", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL; if (PyCallable_Check(callback) == 0) { PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object."); return NULL; @@ -467,7 +484,7 @@ static PyObject *cpy_register_generic(cpy_callback_t **list_head, PyObject *args c->next = *list_head; *list_head = c; Py_XDECREF(mod); - return PyString_FromString(buf); + return cpy_string_to_unicode_or_bytes(buf); } static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject *kwds) { @@ -475,7 +492,7 @@ static PyObject *cpy_flush(cpy_callback_t **list_head, PyObject *args, PyObject const char *plugin = NULL, *identifier = NULL; static char *kwlist[] = {"plugin", "timeout", "identifier", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kwds, "|ziz", kwlist, &plugin, &timeout, &identifier) == 0) return NULL; + if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin, &timeout, NULL, &identifier) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_flush(plugin, timeout, identifier); Py_END_ALLOW_THREADS @@ -501,7 +518,7 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec PyObject *callback = NULL, *data = NULL; static char *kwlist[] = {"callback", "data", "name", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oz", kwlist, &callback, &data, &name) == 0) return NULL; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O|Oet", kwlist, &callback, &data, NULL, &name) == 0) return NULL; if (PyCallable_Check(callback) == 0) { PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object."); return NULL; @@ -519,7 +536,7 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec user_data->free_func = cpy_destroy_user_data; user_data->data = c; register_function(buf, handler, user_data); - return PyString_FromString(buf); + return cpy_string_to_unicode_or_bytes(buf); } static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) { @@ -532,7 +549,7 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd struct timespec ts; static char *kwlist[] = {"callback", "interval", "data", "name", NULL}; - if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOz", kwlist, &callback, &interval, &data, &name) == 0) return NULL; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL; if (PyCallable_Check(callback) == 0) { PyErr_SetString(PyExc_TypeError, "callback needs a be a callable object."); return NULL; @@ -552,7 +569,7 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd ts.tv_sec = interval; ts.tv_nsec = (interval - ts.tv_sec) * 1000000000; plugin_register_complex_read(buf, cpy_read_callback, &ts, user_data); - return PyString_FromString(buf); + return cpy_string_to_unicode_or_bytes(buf); } static PyObject *cpy_register_log(PyObject *self, PyObject *args, PyObject *kwds) { @@ -581,7 +598,7 @@ static PyObject *cpy_register_shutdown(PyObject *self, PyObject *args, PyObject static PyObject *cpy_error(PyObject *self, PyObject *args) { const char *text; - if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL; + if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_log(LOG_ERR, "%s", text); Py_END_ALLOW_THREADS @@ -590,7 +607,7 @@ static PyObject *cpy_error(PyObject *self, PyObject *args) { static PyObject *cpy_warning(PyObject *self, PyObject *args) { const char *text; - if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL; + if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_log(LOG_WARNING, "%s", text); Py_END_ALLOW_THREADS @@ -599,7 +616,7 @@ static PyObject *cpy_warning(PyObject *self, PyObject *args) { static PyObject *cpy_notice(PyObject *self, PyObject *args) { const char *text; - if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL; + if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_log(LOG_NOTICE, "%s", text); Py_END_ALLOW_THREADS @@ -608,7 +625,7 @@ static PyObject *cpy_notice(PyObject *self, PyObject *args) { static PyObject *cpy_info(PyObject *self, PyObject *args) { const char *text; - if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL; + if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_log(LOG_INFO, "%s", text); Py_END_ALLOW_THREADS @@ -618,7 +635,7 @@ static PyObject *cpy_info(PyObject *self, PyObject *args) { static PyObject *cpy_debug(PyObject *self, PyObject *args) { #ifdef COLLECT_DEBUG const char *text; - if (PyArg_ParseTuple(args, "s", &text) == 0) return NULL; + if (PyArg_ParseTuple(args, "et", NULL, &text) == 0) return NULL; Py_BEGIN_ALLOW_THREADS plugin_log(LOG_DEBUG, "%s", text); Py_END_ALLOW_THREADS @@ -631,17 +648,13 @@ static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *ar const char *name; cpy_callback_t *prev = NULL, *tmp; - if (PyUnicode_Check(arg)) { - arg = PyUnicode_AsEncodedString(arg, NULL, NULL); - if (arg == NULL) - return NULL; - name = PyString_AsString(arg); - Py_DECREF(arg); - } else if (PyString_Check(arg)) { - name = PyString_AsString(arg); - } else { + Py_INCREF(arg); + name = cpy_unicode_or_bytes_to_string(&arg); + if (name == NULL) { + PyErr_Clear(); if (!PyCallable_Check(arg)) { PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter."); + Py_DECREF(arg); return NULL; } cpy_build_name(buf, sizeof(buf), arg, NULL); @@ -651,6 +664,7 @@ static PyObject *cpy_unregister_generic(cpy_callback_t **list_head, PyObject *ar if (strcmp(name, tmp->name) == 0) break; + Py_DECREF(arg); if (tmp == NULL) { PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name); return NULL; @@ -671,25 +685,24 @@ static PyObject *cpy_unregister_generic_userdata(cpy_unregister_function_t *unre char buf[512]; const char *name; - if (PyUnicode_Check(arg)) { - arg = PyUnicode_AsEncodedString(arg, NULL, NULL); - if (arg == NULL) - return NULL; - name = PyString_AsString(arg); - Py_DECREF(arg); - } else if (PyString_Check(arg)) { - name = PyString_AsString(arg); - } else { + Py_INCREF(arg); + name = cpy_unicode_or_bytes_to_string(&arg); + if (name == NULL) { + PyErr_Clear(); if (!PyCallable_Check(arg)) { PyErr_SetString(PyExc_TypeError, "This function needs a string or a callable object as its only parameter."); + Py_DECREF(arg); return NULL; } cpy_build_name(buf, sizeof(buf), arg, NULL); name = buf; } - if (unreg(name) == 0) + if (unreg(name) == 0) { + Py_DECREF(arg); Py_RETURN_NONE; + } PyErr_Format(PyExc_RuntimeError, "Unable to unregister %s callback '%s'.", desc, name); + Py_DECREF(arg); return NULL; } @@ -860,7 +873,7 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) { values = PyTuple_New(ci->values_num); /* New reference. */ for (i = 0; i < ci->values_num; ++i) { if (ci->values[i].type == OCONFIG_TYPE_STRING) { - PyTuple_SET_ITEM(values, i, PyString_FromString(ci->values[i].value.string)); + PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(ci->values[i].value.string)); } else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) { PyTuple_SET_ITEM(values, i, PyFloat_FromDouble(ci->values[i].value.number)); } else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) { @@ -868,7 +881,8 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) { } } - item = PyObject_CallFunction((void *) &ConfigType, "sONO", ci->key, parent, values, Py_None); + tmp = cpy_string_to_unicode_or_bytes(ci->key); + item = PyObject_CallFunction((void *) &ConfigType, "NONO", tmp, parent, values, Py_None); if (item == NULL) return NULL; children = PyTuple_New(ci->children_num); /* New reference. */ @@ -881,6 +895,20 @@ static PyObject *cpy_oconfig_to_pyconfig(oconfig_item_t *ci, PyObject *parent) { return item; } +#ifdef IS_PY3K +static struct PyModuleDef collectdmodule = { + PyModuleDef_HEAD_INIT, + "collectd", /* name of module */ + "The python interface to collectd", /* module documentation, may be NULL */ + -1, + cpy_methods +}; + +PyMODINIT_FUNC PyInit_collectd(void) { + return PyModule_Create(&collectdmodule); +} +#endif + static int cpy_config(oconfig_item_t *ci) { int i; PyObject *sys, *tb; @@ -893,6 +921,12 @@ static int cpy_config(oconfig_item_t *ci) { * python code during the config callback so we have to start * the interpreter here. */ /* Do *not* use the python "thread" module at this point! */ + +#ifdef IS_PY3K + /* Add a builtin module, before Py_Initialize */ + PyImport_AppendInittab("collectd", PyInit_collectd); +#endif + Py_Initialize(); PyType_Ready(&ConfigType); @@ -912,7 +946,11 @@ static int cpy_config(oconfig_item_t *ci) { cpy_log_exception("python initialization"); return 1; } +#ifdef IS_PY3K + module = PyImport_ImportModule("collectd"); +#else module = Py_InitModule("collectd", cpy_methods); /* Borrowed reference. */ +#endif PyModule_AddObject(module, "Config", (void *) &ConfigType); /* Steals a reference. */ PyModule_AddObject(module, "Values", (void *) &ValuesType); /* Steals a reference. */ PyModule_AddObject(module, "Notification", (void *) &NotificationType); /* Steals a reference. */ @@ -962,7 +1000,7 @@ static int cpy_config(oconfig_item_t *ci) { if (cf_util_get_string(item, &dir) != 0) continue; - dir_object = PyString_FromString(dir); /* New reference. */ + dir_object = cpy_string_to_unicode_or_bytes(dir); /* New reference. */ if (dir_object == NULL) { ERROR("python plugin: Unable to convert \"%s\" to " "a python object.", dir); @@ -987,7 +1025,6 @@ static int cpy_config(oconfig_item_t *ci) { if (module == NULL) { ERROR("python plugin: Error importing module \"%s\".", module_name); cpy_log_exception("importing module"); - PyErr_Print(); } free(module_name); Py_XDECREF(module); diff --git a/src/pyvalues.c b/src/pyvalues.c index d83f541b..a632dc16 100644 --- a/src/pyvalues.c +++ b/src/pyvalues.c @@ -32,6 +32,72 @@ #include "cpython.h" +static PyObject *cpy_common_repr(PyObject *s) { + PyObject *ret, *tmp; + static PyObject *l_type = NULL, *l_type_instance = NULL, *l_plugin = NULL, *l_plugin_instance = NULL; + static PyObject *l_host = NULL, *l_time = NULL; + PluginData *self = (PluginData *) s; + + if (l_type == NULL) + l_type = cpy_string_to_unicode_or_bytes("(type="); + if (l_type_instance == NULL) + l_type_instance = cpy_string_to_unicode_or_bytes(",type_instance="); + if (l_plugin == NULL) + l_plugin = cpy_string_to_unicode_or_bytes(",plugin="); + if (l_plugin_instance == NULL) + l_plugin_instance = cpy_string_to_unicode_or_bytes(",plugin_instance="); + if (l_host == NULL) + l_host = cpy_string_to_unicode_or_bytes(",host="); + if (l_time == NULL) + l_time = cpy_string_to_unicode_or_bytes(",time="); + + if (!l_type || !l_type_instance || !l_plugin || !l_plugin_instance || !l_host || !l_time) + return NULL; + + ret = cpy_string_to_unicode_or_bytes(s->ob_type->tp_name); + + CPY_STRCAT(&ret, l_type); + tmp = cpy_string_to_unicode_or_bytes(self->type); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + + if (self->type_instance[0] != 0) { + CPY_STRCAT(&ret, l_type_instance); + tmp = cpy_string_to_unicode_or_bytes(self->type_instance); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->plugin[0] != 0) { + CPY_STRCAT(&ret, l_plugin); + tmp = cpy_string_to_unicode_or_bytes(self->plugin); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->plugin_instance[0] != 0) { + CPY_STRCAT(&ret, l_plugin_instance); + tmp = cpy_string_to_unicode_or_bytes(self->plugin_instance); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->host[0] != 0) { + CPY_STRCAT(&ret, l_host); + tmp = cpy_string_to_unicode_or_bytes(self->host); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + + if (self->time != 0) { + CPY_STRCAT(&ret, l_time); + tmp = PyInt_FromLong(self->time); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + return ret; +} + static char time_doc[] = "This is the Unix timestap of the time this value was read.\n" "For dispatching values this can be set to 0 which means \"now\".\n" "This means the time the value is actually dispatched, not the time\n" @@ -81,8 +147,8 @@ static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"type", "plugin_instance", "type_instance", "plugin", "host", "time", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssd", kwlist, &type, - &plugin_instance, &type_instance, &plugin, &host, &time)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetd", kwlist, NULL, &type, + NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL, &host, &time)) return -1; if (type[0] != 0 && plugin_get_ds(type) == NULL) { @@ -101,14 +167,18 @@ static int PluginData_init(PyObject *s, PyObject *args, PyObject *kwds) { } static PyObject *PluginData_repr(PyObject *s) { - PluginData *self = (PluginData *) s; + PyObject *ret; + static PyObject *l_closing = NULL; + + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); - return PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu)", self->type, - *self->type_instance ? "',type_instance='" : "", self->type_instance, - *self->plugin ? "',plugin='" : "", self->plugin, - *self->plugin_instance ? "',plugin_instance='" : "", self->plugin_instance, - *self->host ? "',host='" : "", self->host, - (long unsigned) self->time); + if (l_closing == NULL) + return NULL; + + ret = cpy_common_repr(s); + CPY_STRCAT(&ret, l_closing); + return ret; } static PyMemberDef PluginData_members[] = { @@ -119,7 +189,7 @@ static PyMemberDef PluginData_members[] = { static PyObject *PluginData_getstring(PyObject *self, void *data) { const char *value = ((char *) self) + (intptr_t) data; - return PyString_FromString(value); + return cpy_string_to_unicode_or_bytes(value); } static int PluginData_setstring(PyObject *self, PyObject *value, void *data) { @@ -130,10 +200,15 @@ static int PluginData_setstring(PyObject *self, PyObject *value, void *data) { PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); return -1; } - new = PyString_AsString(value); - if (new == NULL) return -1; + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } old = ((char *) self) + (intptr_t) data; sstrncpy(old, new, DATA_MAX_NAME_LEN); + Py_DECREF(value); return 0; } @@ -145,16 +220,22 @@ static int PluginData_settype(PyObject *self, PyObject *value, void *data) { PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); return -1; } - new = PyString_AsString(value); - if (new == NULL) return -1; + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } if (plugin_get_ds(new) == NULL) { PyErr_Format(PyExc_TypeError, "Dataset %s not found", new); + Py_DECREF(value); return -1; } old = ((char *) self) + (intptr_t) data; sstrncpy(old, new, DATA_MAX_NAME_LEN); + Py_DECREF(value); return 0; } @@ -168,8 +249,7 @@ static PyGetSetDef PluginData_getseters[] = { }; PyTypeObject PluginDataType = { - PyObject_HEAD_INIT(NULL) - 0, /* Always 0 */ + CPY_INIT_TYPE "collectd.PluginData", /* tp_name */ sizeof(PluginData), /* tp_basicsize */ 0, /* Will be filled in later */ @@ -262,26 +342,30 @@ static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) { Values *self = (Values *) s; - int interval = 0, ret; + int interval = 0; double time = 0; PyObject *values = NULL, *tmp; const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = ""; static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance", "plugin", "host", "time", "interval", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist, - &type, &values, &plugin_instance, &type_instance, - &plugin, &host, &time, &interval)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist, + NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, + NULL, &plugin, NULL, &host, &time, &interval)) return -1; - tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time); - if (tmp == NULL) - return -1; - ret = PluginDataType.tp_init(s, tmp, NULL); - Py_DECREF(tmp); - if (ret != 0) + if (type[0] != 0 && plugin_get_ds(type) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); return -1; - + } + + sstrncpy(self->data.host, host, sizeof(self->data.host)); + sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin)); + sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance)); + sstrncpy(self->data.type, type, sizeof(self->data.type)); + sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance)); + self->data.time = time; + if (values == NULL) { values = PyList_New(0); PyErr_Clear(); @@ -314,9 +398,9 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance", "plugin", "host", "time", "interval", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist, - &type, &values, &plugin_instance, &type_instance, - &plugin, &host, &time, &interval)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist, + NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, + NULL, &plugin, NULL, &host, &time, &interval)) return NULL; if (type[0] == 0) { @@ -414,9 +498,9 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance", "plugin", "host", "time", "interval", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sOssssdi", kwlist, - &type, &values, &plugin_instance, &type_instance, - &plugin, &host, &time, &interval)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdi", kwlist, + NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance, + NULL, &plugin, NULL, &host, &time, &interval)) return NULL; if (type[0] == 0) { @@ -497,22 +581,33 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) { } static PyObject *Values_repr(PyObject *s) { - PyObject *ret, *valuestring = NULL; + PyObject *ret, *tmp; + static PyObject *l_interval = NULL, *l_values = NULL, *l_closing = NULL; Values *self = (Values *) s; - if (self->values != NULL) - valuestring = PyObject_Repr(self->values); - if (valuestring == NULL) + if (l_interval == NULL) + l_interval = cpy_string_to_unicode_or_bytes(",interval="); + if (l_values == NULL) + l_values = cpy_string_to_unicode_or_bytes(",values="); + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); + + if (l_interval == NULL || l_values == NULL || l_closing == NULL) return NULL; - ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i,values=%s)", self->data.type, - *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance, - *self->data.plugin ? "',plugin='" : "", self->data.plugin, - *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance, - *self->data.host ? "',host='" : "", self->data.host, - (long unsigned) self->data.time, self->interval, - valuestring ? PyString_AsString(valuestring) : "[]"); - Py_XDECREF(valuestring); + ret = cpy_common_repr(s); + if (self->interval != 0) { + CPY_STRCAT(&ret, l_interval); + tmp = PyInt_FromLong(self->interval); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->values != NULL && PySequence_Length(self->values) > 0) { + CPY_STRCAT(&ret, l_values); + tmp = PyObject_Repr(self->values); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + CPY_STRCAT(&ret, l_closing); return ret; } @@ -546,8 +641,7 @@ static PyMethodDef Values_methods[] = { }; PyTypeObject ValuesType = { - PyObject_HEAD_INIT(NULL) - 0, /* Always 0 */ + CPY_INIT_TYPE "collectd.Values", /* tp_name */ sizeof(Values), /* tp_basicsize */ 0, /* Will be filled in later */ @@ -600,27 +694,30 @@ static char Notification_doc[] = "The Notification class is a wrapper around the static int Notification_init(PyObject *s, PyObject *args, PyObject *kwds) { Notification *self = (Notification *) s; - PyObject *tmp; - int severity = 0, ret; + int severity = 0; double time = 0; const char *message = ""; const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = ""; static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance", "plugin", "host", "time", "severity", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist, - &type, &message, &plugin_instance, &type_instance, - &plugin, &host, &time, &severity)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, + NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance, + NULL, &plugin, NULL, &host, &time, &severity)) return -1; - tmp = Py_BuildValue("sssssd", type, plugin_instance, type_instance, plugin, host, time); - if (tmp == NULL) - return -1; - ret = PluginDataType.tp_init(s, tmp, NULL); - Py_DECREF(tmp); - if (ret != 0) + if (type[0] != 0 && plugin_get_ds(type) == NULL) { + PyErr_Format(PyExc_TypeError, "Dataset %s not found", type); return -1; - + } + + sstrncpy(self->data.host, host, sizeof(self->data.host)); + sstrncpy(self->data.plugin, plugin, sizeof(self->data.plugin)); + sstrncpy(self->data.plugin_instance, plugin_instance, sizeof(self->data.plugin_instance)); + sstrncpy(self->data.type, type, sizeof(self->data.type)); + sstrncpy(self->data.type_instance, type_instance, sizeof(self->data.type_instance)); + self->data.time = time; + sstrncpy(self->message, message, sizeof(self->message)); self->severity = severity; return 0; @@ -641,9 +738,9 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj static char *kwlist[] = {"type", "message", "plugin_instance", "type_instance", "plugin", "host", "time", "severity", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssdi", kwlist, - &type, &message, &plugin_instance, &type_instance, - &plugin, &host, &t, &severity)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, + NULL, &type, NULL, &message, NULL, &plugin_instance, NULL, &type_instance, + NULL, &plugin, NULL, &host, &t, &severity)) return NULL; if (type[0] == 0) { @@ -701,24 +798,47 @@ static int Notification_setstring(PyObject *self, PyObject *value, void *data) { PyErr_SetString(PyExc_TypeError, "Cannot delete this attribute"); return -1; } - new = PyString_AsString(value); - if (new == NULL) return -1; + Py_INCREF(value); + new = cpy_unicode_or_bytes_to_string(&value); + if (new == NULL) { + Py_DECREF(value); + return -1; + } old = ((char *) self) + (intptr_t) data; sstrncpy(old, new, NOTIF_MAX_MSG_LEN); + Py_DECREF(value); return 0; } static PyObject *Notification_repr(PyObject *s) { - PyObject *ret; + PyObject *ret, *tmp; + static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL; Notification *self = (Notification *) s; - ret = PyString_FromFormat("collectd.Values(type='%s%s%s%s%s%s%s%s%s%s%s',time=%lu,interval=%i)", self->data.type, - *self->data.type_instance ? "',type_instance='" : "", self->data.type_instance, - *self->data.plugin ? "',plugin='" : "", self->data.plugin, - *self->data.plugin_instance ? "',plugin_instance='" : "", self->data.plugin_instance, - *self->data.host ? "',host='" : "", self->data.host, - *self->message ? "',message='" : "", self->message, - (long unsigned) self->data.time, self->severity); + if (l_severity == NULL) + l_severity = cpy_string_to_unicode_or_bytes(",severity="); + if (l_message == NULL) + l_message = cpy_string_to_unicode_or_bytes(",message="); + if (l_closing == NULL) + l_closing = cpy_string_to_unicode_or_bytes(")"); + + if (l_severity == NULL || l_message == NULL || l_closing == NULL) + return NULL; + + ret = cpy_common_repr(s); + if (self->severity != 0) { + CPY_STRCAT(&ret, l_severity); + tmp = PyInt_FromLong(self->severity); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + if (self->message[0] != 0) { + CPY_STRCAT(&ret, l_message); + tmp = cpy_string_to_unicode_or_bytes(self->message); + CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp); + CPY_STRCAT_AND_DEL(&ret, tmp); + } + CPY_STRCAT(&ret, l_closing); return ret; } @@ -738,8 +858,7 @@ static PyGetSetDef Notification_getseters[] = { }; PyTypeObject NotificationType = { - PyObject_HEAD_INIT(NULL) - 0, /* Always 0 */ + CPY_INIT_TYPE "collectd.Notification", /* tp_name */ sizeof(Notification), /* tp_basicsize */ 0, /* Will be filled in later */ diff --git a/src/thermal.c b/src/thermal.c index 2b708052..b9d07bf5 100644 --- a/src/thermal.c +++ b/src/thermal.c @@ -218,13 +218,13 @@ static int thermal_config (const char *key, const char *value) static int thermal_sysfs_read (void) { return walk_directory (dirname_sysfs, thermal_sysfs_device_read, - /* user_data = */ NULL); + /* user_data = */ NULL, /* include hidden */ 0); } static int thermal_procfs_read (void) { return walk_directory (dirname_procfs, thermal_procfs_device_read, - /* user_data = */ NULL); + /* user_data = */ NULL, /* include hidden */ 0); } static int thermal_init (void)