| File: | rrdtoolmodule.c |
| Warning: | line 741, column 13 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * python-rrdtool, Python bindings for rrdtool. | |||
| 3 | * Based on the rrdtool Python bindings for Python 2 from | |||
| 4 | * Hye-Shik Chang <perky@fallin.lv>. | |||
| 5 | * | |||
| 6 | * Copyright 2012 Christian Kroeger <commx@commx.ws> | |||
| 7 | * | |||
| 8 | * This program is free software; you can redistribute it and/or modify | |||
| 9 | * it under the terms of the GNU Lesser General Public License as | |||
| 10 | * published by the Free Software Foundation; either version 2.1 of the | |||
| 11 | * License, or (at your option) any later version. | |||
| 12 | * | |||
| 13 | * This program is distributed in the hope that it will be useful, | |||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 16 | * GNU General Public License for more details. | |||
| 17 | * | |||
| 18 | * You should have received a copy of the GNU Lesser General Public License | |||
| 19 | * along with this program; if not, write to the Free Software | |||
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |||
| 21 | * MA 02110-1301, USA. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include <Python.h> | |||
| 26 | #include <datetime.h> | |||
| 27 | #include "rrdtoolmodule.h" | |||
| 28 | ||||
| 29 | /* Some macros to maintain compatibility between Python 2.x and 3.x */ | |||
| 30 | #if PY_MAJOR_VERSION3 >= 3 | |||
| 31 | #define HAVE_PY3K | |||
| 32 | #define PyRRD_String_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) PyUnicode_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) | |||
| 33 | #define PyRRD_String_FromString(x)PyUnicode_FromString(x) PyUnicode_FromString(x) | |||
| 34 | #define PyRRD_String_AS_STRING(x)PyUnicode_AsUTF8(x) PyUnicode_AsUTF8(x) | |||
| 35 | #define PyRRD_String_FromStringAndSize(x, y)PyBytes_FromStringAndSize(x, y) PyBytes_FromStringAndSize(x, y) | |||
| 36 | #define PyRRD_String_Size(x)PyUnicode_Size(x) PyUnicode_Size(x) | |||
| 37 | #define PyRRD_Int_FromLong(x)PyLong_FromLong(x) PyLong_FromLong(x) | |||
| 38 | #define PyRRD_Int_FromString(x, y, z)PyLong_FromString(x,y,z) PyLong_FromString(x,y,z) | |||
| 39 | #define PyRRD_Long_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) PyLong_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) | |||
| 40 | #else | |||
| 41 | #define PyRRD_String_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 28))) != 0) PyString_Check(x) | |||
| 42 | #define PyRRD_String_FromString(x)PyUnicode_FromString(x) PyString_FromString(x) | |||
| 43 | #define PyRRD_String_AS_STRING(x)PyUnicode_AsUTF8(x) PyString_AS_STRING(x) | |||
| 44 | #define PyRRD_String_FromStringAndSize(x, y)PyBytes_FromStringAndSize(x, y) PyString_FromStringAndSize(x, y) | |||
| 45 | #define PyRRD_String_Size(x)PyUnicode_Size(x) PyString_Size(x) | |||
| 46 | #define PyRRD_Int_FromLong(x)PyLong_FromLong(x) PyInt_FromLong(x) | |||
| 47 | #define PyRRD_Int_FromString(x, y, z)PyLong_FromString(x,y,z) PyInt_FromString(x,y,z) | |||
| 48 | #define PyRRD_Long_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0) (PyInt_Check(x) || PyLong_Check(x)((((((PyObject*)(x))->ob_type))->tp_flags & ((1UL << 24))) != 0)) | |||
| 49 | #endif | |||
| 50 | ||||
| 51 | #ifndef Py_UNUSED | |||
| 52 | #ifdef __GNUC__4 | |||
| 53 | #define Py_UNUSED(name)_unused_name __attribute__((unused)) _unused_ ## name __attribute__((unused)) | |||
| 54 | #else | |||
| 55 | #define Py_UNUSED(name)_unused_name __attribute__((unused)) _unused_ ## -name | |||
| 56 | #endif | |||
| 57 | #endif | |||
| 58 | ||||
| 59 | #ifndef DS_NAM_SIZE20 | |||
| 60 | #define DS_NAM_SIZE20 20 | |||
| 61 | #endif | |||
| 62 | ||||
| 63 | /** Binding version. */ | |||
| 64 | static const char *_version = PACKAGE_VERSION"0.1.15"; | |||
| 65 | ||||
| 66 | /** Exception types. */ | |||
| 67 | static PyObject *rrdtool_OperationalError; | |||
| 68 | static PyObject *rrdtool_ProgrammingError; | |||
| 69 | ||||
| 70 | /** | |||
| 71 | * PyRRD_DateTime_FromTS: convert UNIX timestamp (time_t) | |||
| 72 | * to Python datetime object. | |||
| 73 | * | |||
| 74 | * @param ts UNIX timestamp (time_t) | |||
| 75 | * @return Pointer to new PyObject (New Reference) | |||
| 76 | */ | |||
| 77 | static PyObject * | |||
| 78 | PyRRD_DateTime_FromTS(time_t ts) | |||
| 79 | { | |||
| 80 | PyObject *ret; | |||
| 81 | struct tm lt; | |||
| 82 | ||||
| 83 | localtime_r(&ts, <); | |||
| 84 | ||||
| 85 | ret = PyDateTime_FromDateAndTime(PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 86 | lt.tm_year + 1900,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 87 | lt.tm_mon + 1,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 88 | lt.tm_mday,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 89 | lt.tm_hour,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 90 | lt.tm_min,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 91 | lt.tm_sec,PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType) | |||
| 92 | 0)PyDateTimeAPI->DateTime_FromDateAndTime(lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday, lt.tm_hour, lt.tm_min, lt.tm_sec, 0, (&_Py_NoneStruct), PyDateTimeAPI->DateTimeType); | |||
| 93 | ||||
| 94 | return ret; | |||
| 95 | } | |||
| 96 | ||||
| 97 | /** | |||
| 98 | * PyRRD_String_FromCF: get string representation of CF enum index | |||
| 99 | * | |||
| 100 | * @param cf enum cf_en | |||
| 101 | * @return Null-terminated string | |||
| 102 | */ | |||
| 103 | const char * | |||
| 104 | PyRRD_String_FromCF(enum cf_en cf) | |||
| 105 | { | |||
| 106 | switch (cf) { | |||
| 107 | case CF_AVERAGE: | |||
| 108 | return "AVERAGE"; | |||
| 109 | case CF_MINIMUM: | |||
| 110 | return "MIN"; | |||
| 111 | case CF_MAXIMUM: | |||
| 112 | return "MAX"; | |||
| 113 | case CF_LAST: | |||
| 114 | return "LAST"; | |||
| 115 | default: | |||
| 116 | return "INVALID"; | |||
| 117 | } | |||
| 118 | } | |||
| 119 | ||||
| 120 | /** | |||
| 121 | * Helper function to convert Python objects into a representation that the | |||
| 122 | * rrdtool functions can work with. | |||
| 123 | * | |||
| 124 | * @param command RRDtool command name | |||
| 125 | * @param args Command arguments | |||
| 126 | * @return Zero if the function succeeds, otherwise -1 | |||
| 127 | */ | |||
| 128 | static int | |||
| 129 | convert_args(char *command, PyObject *args, char ***rrdtool_argv, int *rrdtool_argc) | |||
| 130 | { | |||
| 131 | PyObject *o, *lo; | |||
| 132 | int i, j, args_count, argv_count, element_count; | |||
| 133 | ||||
| 134 | argv_count = element_count = 0; | |||
| 135 | args_count = PyTuple_Size(args); | |||
| 136 | ||||
| 137 | for (i = 0; i < args_count; i++) { | |||
| 138 | o = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]); | |||
| 139 | ||||
| 140 | if (PyRRD_String_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
| 141 | element_count++; | |||
| 142 | else if (PyList_CheckExact(o)((((PyObject*)(o))->ob_type) == &PyList_Type)) | |||
| 143 | element_count += PyList_Size(o); | |||
| 144 | else { | |||
| 145 | PyErr_Format(PyExc_TypeError, | |||
| 146 | "Argument %d must be str or a list of str", i); | |||
| 147 | return -1; | |||
| 148 | } | |||
| 149 | } | |||
| 150 | ||||
| 151 | *rrdtool_argv = PyMem_New(char *, element_count + 1)( ((size_t)(element_count + 1) > ((Py_ssize_t)(((size_t)-1 )>>1)) / sizeof(char *)) ? ((void*)0) : ( (char * *) PyMem_Malloc ((element_count + 1) * sizeof(char *)) ) ); | |||
| 152 | ||||
| 153 | if (*rrdtool_argv == NULL((void*)0)) | |||
| 154 | return -1; | |||
| 155 | ||||
| 156 | for (i = 0; i < args_count; i++) { | |||
| 157 | o = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]); | |||
| 158 | ||||
| 159 | if (PyRRD_String_Check(o)((((((PyObject*)(o))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
| 160 | (*rrdtool_argv)[++argv_count] = (char *)PyRRD_String_AS_STRING(o)PyUnicode_AsUTF8(o); | |||
| 161 | else if (PyList_CheckExact(o)((((PyObject*)(o))->ob_type) == &PyList_Type)) { | |||
| 162 | for (j = 0; j < PyList_Size(o); j++) { | |||
| 163 | lo = PyList_GetItem(o, j); | |||
| 164 | ||||
| 165 | if (PyRRD_String_Check(lo)((((((PyObject*)(lo))->ob_type))->tp_flags & ((1UL << 28))) != 0)) | |||
| 166 | (*rrdtool_argv)[++argv_count] = (char *)PyRRD_String_AS_STRING(lo)PyUnicode_AsUTF8(lo); | |||
| 167 | else { | |||
| 168 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
| 169 | PyErr_Format(PyExc_TypeError, | |||
| 170 | "Element %d in argument %d must be str", j, i); | |||
| 171 | return -1; | |||
| 172 | } | |||
| 173 | } | |||
| 174 | } else { | |||
| 175 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
| 176 | PyErr_Format(rrdtool_ProgrammingError, | |||
| 177 | "Argument %d must be str or list of str", i); | |||
| 178 | return -1; | |||
| 179 | } | |||
| 180 | } | |||
| 181 | ||||
| 182 | (*rrdtool_argv)[0] = command; | |||
| 183 | *rrdtool_argc = element_count + 1; | |||
| 184 | ||||
| 185 | return 0; | |||
| 186 | } | |||
| 187 | ||||
| 188 | /** | |||
| 189 | * Destroy argument vector. | |||
| 190 | */ | |||
| 191 | static void | |||
| 192 | destroy_args(char ***rrdtool_argv) | |||
| 193 | { | |||
| 194 | PyMem_DelPyMem_Free(*rrdtool_argv); | |||
| 195 | *rrdtool_argv = NULL((void*)0); | |||
| 196 | } | |||
| 197 | ||||
| 198 | /** | |||
| 199 | * Convert RRDtool info to dict. | |||
| 200 | * | |||
| 201 | * @param data RRDtool info object | |||
| 202 | * @return Python dict object | |||
| 203 | */ | |||
| 204 | static PyObject * | |||
| 205 | _rrdtool_util_info2dict(const rrd_info_t *data) | |||
| 206 | { | |||
| 207 | PyObject *dict, *val; | |||
| 208 | ||||
| 209 | dict = PyDict_New(); | |||
| 210 | ||||
| 211 | while (data) { | |||
| 212 | val = NULL((void*)0); | |||
| 213 | ||||
| 214 | switch (data->type) { | |||
| 215 | case RD_I_VAL: | |||
| 216 | if (isnan(data->value.u_val)__builtin_isnan (data->value.u_val)) { | |||
| 217 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 218 | val = Py_None(&_Py_NoneStruct); | |||
| 219 | } else | |||
| 220 | val = PyFloat_FromDouble(data->value.u_val); | |||
| 221 | break; | |||
| 222 | ||||
| 223 | case RD_I_CNT: | |||
| 224 | val = PyLong_FromUnsignedLong(data->value.u_cnt); | |||
| 225 | break; | |||
| 226 | ||||
| 227 | case RD_I_INT: | |||
| 228 | val = PyLong_FromLong(data->value.u_int); | |||
| 229 | break; | |||
| 230 | ||||
| 231 | case RD_I_STR: | |||
| 232 | val = PyRRD_String_FromString(data->value.u_str)PyUnicode_FromString(data->value.u_str); | |||
| 233 | break; | |||
| 234 | ||||
| 235 | case RD_I_BLO: | |||
| 236 | val = PyRRD_String_FromStringAndSize(PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size) | |||
| 237 | (char *)data->value.u_blo.ptr,PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size) | |||
| 238 | data->value.u_blo.size)PyBytes_FromStringAndSize((char *)data->value.u_blo.ptr, data ->value.u_blo.size); | |||
| 239 | break; | |||
| 240 | default: | |||
| 241 | break; | |||
| 242 | } | |||
| 243 | ||||
| 244 | if (val != NULL((void*)0)) { | |||
| 245 | PyDict_SetItemString(dict, data->key, val); | |||
| 246 | Py_DECREF(val)_Py_DECREF(((PyObject*)(val))); | |||
| 247 | } | |||
| 248 | ||||
| 249 | data = data->next; | |||
| 250 | } | |||
| 251 | ||||
| 252 | return dict; | |||
| 253 | } | |||
| 254 | ||||
| 255 | static char _rrdtool_create__doc__[] = "Create a new Round Robin Database.\n\n\ | |||
| 256 | Usage: create(args...)\n\ | |||
| 257 | Arguments:\n\n\ | |||
| 258 | filename\n\ | |||
| 259 | [-b|--start start time]\n\ | |||
| 260 | [-s|--step step]\n\ | |||
| 261 | [-t|--template template-file]\n\ | |||
| 262 | [-r|--source source-file]\n\ | |||
| 263 | [-O|--no-overwrite]\n\ | |||
| 264 | [-d|--daemon address]\n\ | |||
| 265 | [DS:ds-name[=mapped-ds-name[source-index]]:DST:heartbeat:min:max]\n\ | |||
| 266 | [RRA:CF:xff:steps:rows]\n\n\ | |||
| 267 | Full documentation can be found at:\n\ | |||
| 268 | https://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html"; | |||
| 269 | ||||
| 270 | static PyObject * | |||
| 271 | _rrdtool_create(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 272 | { | |||
| 273 | char **rrdtool_argv = NULL((void*)0); | |||
| 274 | int rrdtool_argc = 0; | |||
| 275 | PyObject *ret; | |||
| 276 | int status; | |||
| 277 | ||||
| 278 | if (convert_args("create", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 279 | return NULL((void*)0); | |||
| 280 | ||||
| 281 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 282 | status = rrd_create(rrdtool_argc, rrdtool_argv); | |||
| 283 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 284 | ||||
| 285 | if (status == -1) { | |||
| 286 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 287 | rrd_clear_error(); | |||
| 288 | ret = NULL((void*)0); | |||
| 289 | } else { | |||
| 290 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 291 | ret = Py_None(&_Py_NoneStruct); | |||
| 292 | } | |||
| 293 | ||||
| 294 | destroy_args(&rrdtool_argv); | |||
| 295 | return ret; | |||
| 296 | } | |||
| 297 | ||||
| 298 | static char _rrdtool_dump__doc__[] = "Dump an RRD to XML.\n\n\ | |||
| 299 | Usage: dump(args..)\n\ | |||
| 300 | Arguments:\n\n\ | |||
| 301 | [-h|--header {none,xsd,dtd}\n\ | |||
| 302 | [-n|--no-header]\n\ | |||
| 303 | [-d|--daemon address]\n\ | |||
| 304 | file.rrd\n\ | |||
| 305 | [file.xml]\n\n\ | |||
| 306 | Full documentation can be found at:\n\ | |||
| 307 | https://oss.oetiker.ch/rrdtool/doc/rrddump.en.html"; | |||
| 308 | ||||
| 309 | static PyObject * | |||
| 310 | _rrdtool_dump(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 311 | { | |||
| 312 | char **rrdtool_argv = NULL((void*)0); | |||
| 313 | int rrdtool_argc = 0; | |||
| 314 | PyObject *ret; | |||
| 315 | int status; | |||
| 316 | ||||
| 317 | if (convert_args("dump", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 318 | return NULL((void*)0); | |||
| 319 | ||||
| 320 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 321 | status = rrd_dump(rrdtool_argc, rrdtool_argv); | |||
| 322 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 323 | ||||
| 324 | if (status != 0) { | |||
| 325 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 326 | rrd_clear_error(); | |||
| 327 | ret = NULL((void*)0); | |||
| 328 | } else { | |||
| 329 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 330 | ret = Py_None(&_Py_NoneStruct); | |||
| 331 | } | |||
| 332 | ||||
| 333 | destroy_args(&rrdtool_argv); | |||
| 334 | return ret; | |||
| 335 | } | |||
| 336 | ||||
| 337 | static char _rrdtool_update__doc__[] = "Store a new set of values into\ | |||
| 338 | the RRD.\n\n\ | |||
| 339 | Usage: update(args..)\n\ | |||
| 340 | Arguments:\n\n\ | |||
| 341 | filename\n\ | |||
| 342 | [--template|-t ds-name[:ds-name]...]\n\ | |||
| 343 | N|timestamp:value[:value...]\n\ | |||
| 344 | [timestamp:value[:value...] ...]\n\n\ | |||
| 345 | Full documentation can be found at:\n\ | |||
| 346 | https://oss.oetiker.ch/rrdtool/doc/rrdupdate.en.html"; | |||
| 347 | ||||
| 348 | static PyObject * | |||
| 349 | _rrdtool_update(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 350 | { | |||
| 351 | char **rrdtool_argv = NULL((void*)0); | |||
| 352 | int rrdtool_argc = 0; | |||
| 353 | PyObject *ret; | |||
| 354 | int status; | |||
| 355 | ||||
| 356 | if (convert_args("update", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 357 | return NULL((void*)0); | |||
| 358 | ||||
| 359 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 360 | status = rrd_update(rrdtool_argc, rrdtool_argv); | |||
| 361 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 362 | ||||
| 363 | if (status == -1) { | |||
| 364 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 365 | rrd_clear_error(); | |||
| 366 | ret = NULL((void*)0); | |||
| 367 | } else { | |||
| 368 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 369 | ret = Py_None(&_Py_NoneStruct); | |||
| 370 | } | |||
| 371 | ||||
| 372 | destroy_args(&rrdtool_argv); | |||
| 373 | return ret; | |||
| 374 | } | |||
| 375 | ||||
| 376 | static char _rrdtool_updatev__doc__[] = "Store a new set of values into "\ | |||
| 377 | "the Round Robin Database and return an info dictionary.\n\n\ | |||
| 378 | This function works in the same manner as 'update', but will return an\n\ | |||
| 379 | info dictionary instead of None."; | |||
| 380 | ||||
| 381 | static PyObject * | |||
| 382 | _rrdtool_updatev(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 383 | { | |||
| 384 | char **rrdtool_argv = NULL((void*)0); | |||
| 385 | int rrdtool_argc = 0; | |||
| 386 | PyObject *ret; | |||
| 387 | rrd_info_t *data; | |||
| 388 | ||||
| 389 | if (convert_args("updatev", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 390 | return NULL((void*)0); | |||
| 391 | ||||
| 392 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 393 | data = rrd_update_v(rrdtool_argc, rrdtool_argv); | |||
| 394 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 395 | ||||
| 396 | if (data == NULL((void*)0)) { | |||
| 397 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 398 | rrd_clear_error(); | |||
| 399 | ret = NULL((void*)0); | |||
| 400 | } else { | |||
| 401 | ret = _rrdtool_util_info2dict(data); | |||
| 402 | rrd_info_free(data); | |||
| 403 | } | |||
| 404 | ||||
| 405 | destroy_args(&rrdtool_argv); | |||
| 406 | return ret; | |||
| 407 | } | |||
| 408 | ||||
| 409 | static char _rrdtool_fetch__doc__[] = "Fetch data from an RRD.\n\n\ | |||
| 410 | Usage: fetch(args..)\n\ | |||
| 411 | Arguments:\n\n\ | |||
| 412 | filename\n\ | |||
| 413 | CF\n\ | |||
| 414 | [-r|--resolution resolution]\n\ | |||
| 415 | [-s|--start start]\n\ | |||
| 416 | [-e|--end end]\n\ | |||
| 417 | [-a|--align-start]\n\ | |||
| 418 | [-d|--daemon address]\n\n\ | |||
| 419 | Full documentation can be found at:\n\ | |||
| 420 | https://oss.oetiker.ch/rrdtool/doc/rrdfetch.en.html"; | |||
| 421 | ||||
| 422 | static PyObject * | |||
| 423 | _rrdtool_fetch(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 424 | { | |||
| 425 | char **rrdtool_argv = NULL((void*)0); | |||
| 426 | int rrdtool_argc = 0; | |||
| 427 | PyObject *ret, *range_tup, *dsnam_tup, *data_list, *t; | |||
| 428 | rrd_value_t *data, *datai, dv; | |||
| 429 | unsigned long step, ds_cnt, i, j, row; | |||
| 430 | time_t start, end; | |||
| 431 | char **ds_namv; | |||
| 432 | int status; | |||
| 433 | ||||
| 434 | if (convert_args("fetch", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 435 | return NULL((void*)0); | |||
| 436 | ||||
| 437 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 438 | status = rrd_fetch(rrdtool_argc, rrdtool_argv, &start, &end, &step, | |||
| 439 | &ds_cnt, &ds_namv, &data); | |||
| 440 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 441 | ||||
| 442 | if (status == -1) { | |||
| 443 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 444 | rrd_clear_error(); | |||
| 445 | ret = NULL((void*)0); | |||
| 446 | } else { | |||
| 447 | row = (end - start) / step; | |||
| 448 | ret = PyTuple_New(3); | |||
| 449 | range_tup = PyTuple_New(3); | |||
| 450 | dsnam_tup = PyTuple_New(ds_cnt); | |||
| 451 | data_list = PyList_New(row); | |||
| 452 | ||||
| 453 | PyTuple_SET_ITEM(ret, 0, range_tup)PyTuple_SetItem(ret, 0, range_tup); | |||
| 454 | PyTuple_SET_ITEM(ret, 1, dsnam_tup)PyTuple_SetItem(ret, 1, dsnam_tup); | |||
| 455 | PyTuple_SET_ITEM(ret, 2, data_list)PyTuple_SetItem(ret, 2, data_list); | |||
| 456 | ||||
| 457 | datai = data; | |||
| 458 | ||||
| 459 | PyTuple_SET_ITEM(range_tup, 0, PyRRD_Int_FromLong((long) start))PyTuple_SetItem(range_tup, 0, PyLong_FromLong((long) start)); | |||
| 460 | PyTuple_SET_ITEM(range_tup, 1, PyRRD_Int_FromLong((long) end))PyTuple_SetItem(range_tup, 1, PyLong_FromLong((long) end)); | |||
| 461 | PyTuple_SET_ITEM(range_tup, 2, PyRRD_Int_FromLong((long) step))PyTuple_SetItem(range_tup, 2, PyLong_FromLong((long) step)); | |||
| 462 | ||||
| 463 | for (i = 0; i < ds_cnt; i++) | |||
| 464 | PyTuple_SET_ITEM(dsnam_tup, i, PyRRD_String_FromString(ds_namv[i]))PyTuple_SetItem(dsnam_tup, i, PyUnicode_FromString(ds_namv[i] )); | |||
| 465 | ||||
| 466 | for (i = 0; i < row; i++) { | |||
| 467 | t = PyTuple_New(ds_cnt); | |||
| 468 | PyList_SET_ITEM(data_list, i, t)PyList_SetItem(data_list, i, t); | |||
| 469 | ||||
| 470 | for (j = 0; j < ds_cnt; j++) { | |||
| 471 | dv = *(datai++); | |||
| 472 | if (isnan(dv)__builtin_isnan (dv)) { | |||
| 473 | PyTuple_SET_ITEM(t, j, Py_None)PyTuple_SetItem(t, j, (&_Py_NoneStruct)); | |||
| 474 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 475 | } else | |||
| 476 | PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv))PyTuple_SetItem(t, j, PyFloat_FromDouble((double) dv)); | |||
| 477 | } | |||
| 478 | } | |||
| 479 | ||||
| 480 | for (i = 0; i < ds_cnt; i++) | |||
| 481 | rrd_freemem(ds_namv[i]); | |||
| 482 | ||||
| 483 | rrd_freemem(ds_namv); | |||
| 484 | rrd_freemem(data); | |||
| 485 | } | |||
| 486 | ||||
| 487 | destroy_args(&rrdtool_argv); | |||
| 488 | return ret; | |||
| 489 | } | |||
| 490 | ||||
| 491 | static char _rrdtool_flushcached__doc__[] = "Flush RRD files from memory.\n\n\ | |||
| 492 | Usage: flushcached(args..)\n\ | |||
| 493 | Arguments:\n\n\ | |||
| 494 | [-d|--daemon address]\n\ | |||
| 495 | filename\n\ | |||
| 496 | [filename ...]\n\n\ | |||
| 497 | Full documentation can be found at:\n\ | |||
| 498 | https://oss.oetiker.ch/rrdtool/doc/rrdflushcached.en.html"; | |||
| 499 | ||||
| 500 | static PyObject * | |||
| 501 | _rrdtool_flushcached(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 502 | { | |||
| 503 | char **rrdtool_argv = NULL((void*)0); | |||
| 504 | int rrdtool_argc = 0; | |||
| 505 | PyObject *ret; | |||
| 506 | int status; | |||
| 507 | ||||
| 508 | if (convert_args("flushcached", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 509 | return NULL((void*)0); | |||
| 510 | ||||
| 511 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 512 | status = rrd_flushcached(rrdtool_argc, rrdtool_argv); | |||
| 513 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 514 | ||||
| 515 | if (status != 0) { | |||
| 516 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 517 | rrd_clear_error(); | |||
| 518 | ret = NULL((void*)0); | |||
| 519 | } else { | |||
| 520 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 521 | ret = Py_None(&_Py_NoneStruct); | |||
| 522 | } | |||
| 523 | ||||
| 524 | destroy_args(&rrdtool_argv); | |||
| 525 | return ret; | |||
| 526 | } | |||
| 527 | ||||
| 528 | static char _rrdtool_graph__doc__[] = "Create a graph based on one or more " \ | |||
| 529 | "RRDs.\n\n\ | |||
| 530 | Usage: graph(args..)\n\ | |||
| 531 | Arguments:\n\n\ | |||
| 532 | filename | -\n\ | |||
| 533 | [-s|--start start]\n\ | |||
| 534 | [-e|--end end]\n\ | |||
| 535 | [-S|--step step]\n\ | |||
| 536 | [-t|--title string]\n\ | |||
| 537 | [-v|--vertical-label string]\n\ | |||
| 538 | [-w|--width pixels]\n\ | |||
| 539 | [-h|--height pixels]\n\ | |||
| 540 | [-j|--only-graph]\n\ | |||
| 541 | [-D|--full-size-mode]\n\ | |||
| 542 | [-u|--upper-limit value]\n\ | |||
| 543 | [-l|--lower-limit value]\n\ | |||
| 544 | [-r|--rigid]\n\ | |||
| 545 | [-A|--alt-autoscale]\n\ | |||
| 546 | [-J|--alt-autoscale-min]\n\ | |||
| 547 | [-M|--alt-autoscale-max]\n\ | |||
| 548 | [-N|--no-gridfit]\n\ | |||
| 549 | [-x|--x-grid (GTM:GST:MTM:MST:LTM:LST:LPR:LFM|none)]\n\ | |||
| 550 | [-y|--y-grid (grid step:label factor|none)]\n\ | |||
| 551 | [--week-fmt strftime format string]\n\ | |||
| 552 | [--left-axis-formatter formatter-name]\n\ | |||
| 553 | [--left-axis-format format-string]\n\ | |||
| 554 | [-Y|--alt-y-grid]\n\ | |||
| 555 | [-o|--logarithmic]\n\ | |||
| 556 | [-X|--units-exponent value]\n\ | |||
| 557 | [-L|--units-length value]\n\ | |||
| 558 | [--units=si]\n\ | |||
| 559 | [--right-axis scale:shift]\n\ | |||
| 560 | [--right-axis-label label]\n\ | |||
| 561 | [--right-axis-format format-string]\n\ | |||
| 562 | [-g|--no-legend]\n\ | |||
| 563 | [-F|--force-rules-legend]\n\ | |||
| 564 | [--legend-position=(north|south|west|east)]\n\ | |||
| 565 | [--legend-direction=(topdown|bottomup)]\n\ | |||
| 566 | [-z|--lazy]\n\ | |||
| 567 | [-d|--daemon address]\n\ | |||
| 568 | [-f|--imginfo printfstr]\n\ | |||
| 569 | [-c|--color COLORTAG#rrggbb[aa]]\n\ | |||
| 570 | [--grid-dash on:off]\n\ | |||
| 571 | [--border width]\n\ | |||
| 572 | [--dynamic-labels]\n\ | |||
| 573 | [-m|--zoom factor]\n\ | |||
| 574 | [-n|--font FONTTAG:size:[font]]\n\ | |||
| 575 | [-R|--font-render-mode {normal,light,mono}]\n\ | |||
| 576 | [-B|--font-smoothing-threshold size]\n\ | |||
| 577 | [-P|--pango-markup]\n\ | |||
| 578 | [-G|--graph-render-mode {normal,mono}]\n\ | |||
| 579 | [-E|--slope-mode]\n\ | |||
| 580 | [-a|--imgformat {PNG,SVG,EPS,PDF,XML,XMLENUM,JSON,JSONTIME,CSV,TSV,SSV}]\n\ | |||
| 581 | [-i|--interlaced]\n\ | |||
| 582 | [-T|--tabwidth value]\n\ | |||
| 583 | [-b|--base value]\n\ | |||
| 584 | [-W|--watermark string]\n\ | |||
| 585 | [-Z|--use-nan-for-all-missing-data]\n\ | |||
| 586 | DEF:vname=rrdfile:ds-name:CF[:step=step][:start=time][:end=time]\n\ | |||
| 587 | CDEF:vname=RPN expression\n\ | |||
| 588 | VDEF=vname:RPN expression\n\n\ | |||
| 589 | Full documentation can be found at:\n\ | |||
| 590 | https://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html"; | |||
| 591 | ||||
| 592 | static PyObject * | |||
| 593 | _rrdtool_graph(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 594 | { | |||
| 595 | char **rrdtool_argv = NULL((void*)0); | |||
| 596 | int rrdtool_argc = 0; | |||
| 597 | PyObject *ret; | |||
| 598 | int xsize, ysize, i, status; | |||
| 599 | double ymin, ymax; | |||
| 600 | char **calcpr = NULL((void*)0); | |||
| 601 | ||||
| 602 | if (convert_args("graph", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 603 | return NULL((void*)0); | |||
| 604 | ||||
| 605 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 606 | status = rrd_graph(rrdtool_argc, rrdtool_argv, &calcpr, &xsize, &ysize, | |||
| 607 | NULL((void*)0), &ymin, &ymax); | |||
| 608 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 609 | ||||
| 610 | if (status == -1) { | |||
| 611 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 612 | rrd_clear_error(); | |||
| 613 | ret = NULL((void*)0); | |||
| 614 | } else { | |||
| 615 | ret = PyTuple_New(3); | |||
| 616 | ||||
| 617 | PyTuple_SET_ITEM(ret, 0, PyRRD_Int_FromLong((long) xsize))PyTuple_SetItem(ret, 0, PyLong_FromLong((long) xsize)); | |||
| 618 | PyTuple_SET_ITEM(ret, 1, PyRRD_Int_FromLong((long) ysize))PyTuple_SetItem(ret, 1, PyLong_FromLong((long) ysize)); | |||
| 619 | ||||
| 620 | if (calcpr) { | |||
| 621 | PyObject *e, *t; | |||
| 622 | ||||
| 623 | e = PyList_New(0); | |||
| 624 | PyTuple_SET_ITEM(ret, 2, e)PyTuple_SetItem(ret, 2, e); | |||
| 625 | ||||
| 626 | for (i = 0; calcpr[i]; i++) { | |||
| 627 | t = PyRRD_String_FromString(calcpr[i])PyUnicode_FromString(calcpr[i]); | |||
| 628 | PyList_Append(e, t); | |||
| 629 | Py_DECREF(t)_Py_DECREF(((PyObject*)(t))); | |||
| 630 | rrd_freemem(calcpr[i]); | |||
| 631 | } | |||
| 632 | } else { | |||
| 633 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 634 | PyTuple_SET_ITEM(ret, 2, Py_None)PyTuple_SetItem(ret, 2, (&_Py_NoneStruct)); | |||
| 635 | } | |||
| 636 | } | |||
| 637 | ||||
| 638 | destroy_args(&rrdtool_argv); | |||
| 639 | return ret; | |||
| 640 | } | |||
| 641 | ||||
| 642 | static char _rrdtool_graphv__doc__[] = "Create a graph based on one or more " \ | |||
| 643 | "RRDs and return data in RRDtool info format.\n\n\ | |||
| 644 | This function works the same way as 'graph', but will return a info\n\ | |||
| 645 | dictionary instead of None.\n\n\ | |||
| 646 | Full documentation can be found at (graphv section):\n\ | |||
| 647 | https://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html"; | |||
| 648 | ||||
| 649 | static PyObject * | |||
| 650 | _rrdtool_graphv(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 651 | { | |||
| 652 | char **rrdtool_argv = NULL((void*)0); | |||
| 653 | int rrdtool_argc = 0; | |||
| 654 | PyObject *ret; | |||
| 655 | rrd_info_t *data; | |||
| 656 | ||||
| 657 | if (convert_args("graphv", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 658 | return NULL((void*)0); | |||
| 659 | ||||
| 660 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 661 | data = rrd_graph_v(rrdtool_argc, rrdtool_argv); | |||
| 662 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 663 | ||||
| 664 | if (data == NULL((void*)0)) { | |||
| 665 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 666 | rrd_clear_error(); | |||
| 667 | ret = NULL((void*)0); | |||
| 668 | } else { | |||
| 669 | ret = _rrdtool_util_info2dict(data); | |||
| 670 | rrd_info_free(data); | |||
| 671 | } | |||
| 672 | ||||
| 673 | destroy_args(&rrdtool_argv); | |||
| 674 | return ret; | |||
| 675 | } | |||
| 676 | ||||
| 677 | static char _rrdtool_xport__doc__[] = "Dictionary representation of data " \ | |||
| 678 | "stored in RRDs.\n\n\ | |||
| 679 | Usage: xport(args..)\n\ | |||
| 680 | Arguments:\n\n\ | |||
| 681 | [-s[--start seconds]\n\ | |||
| 682 | [-e|--end seconds]\n\ | |||
| 683 | [-m|--maxrows rows]\n\ | |||
| 684 | [--step value]\n\ | |||
| 685 | [--json]\n\ | |||
| 686 | [--enumds]\n\ | |||
| 687 | [--daemon address]\n\ | |||
| 688 | [DEF:vname=rrd:ds-name:CF]\n\ | |||
| 689 | [CDEF:vname=rpn-expression]\n\ | |||
| 690 | [XPORT:vname[:legend]]\n\n\ | |||
| 691 | Full documentation can be found at:\n\ | |||
| 692 | https://oss.oetiker.ch/rrdtool/doc/rrdxport.en.html"; | |||
| 693 | ||||
| 694 | static PyObject * | |||
| 695 | _rrdtool_xport(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 696 | { | |||
| 697 | char **rrdtool_argv = NULL((void*)0); | |||
| 698 | int rrdtool_argc = 0; | |||
| 699 | PyObject *ret; | |||
| 700 | int xsize, status; | |||
| 701 | char **legend_v; | |||
| 702 | time_t start, end; | |||
| 703 | unsigned long step, col_cnt; | |||
| 704 | rrd_value_t *data, *datai; | |||
| 705 | ||||
| 706 | if (convert_args("xport", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| ||||
| 707 | return NULL((void*)0); | |||
| 708 | ||||
| 709 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 710 | status = rrd_xport(rrdtool_argc, rrdtool_argv, &xsize, &start, &end, &step, | |||
| 711 | &col_cnt, &legend_v, &data); | |||
| 712 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 713 | ||||
| 714 | if (status == -1) { | |||
| 715 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 716 | rrd_clear_error(); | |||
| 717 | ret = NULL((void*)0); | |||
| 718 | } else { | |||
| 719 | PyObject *meta_dict, *data_list, *legend_list, *t; | |||
| 720 | rrd_value_t dv; | |||
| 721 | unsigned long i, j, row_cnt = (end - start) / step; | |||
| 722 | ||||
| 723 | ret = PyDict_New(); | |||
| 724 | meta_dict = PyDict_New(); | |||
| 725 | legend_list = PyList_New(col_cnt); | |||
| 726 | data_list = PyList_New(row_cnt); | |||
| 727 | ||||
| 728 | PyDict_SetItem(ret, PyRRD_String_FromString("meta")PyUnicode_FromString("meta"), meta_dict); | |||
| 729 | PyDict_SetItem(ret, PyRRD_String_FromString("data")PyUnicode_FromString("data"), data_list); | |||
| 730 | ||||
| 731 | datai = data; | |||
| 732 | ||||
| 733 | PyDict_SetItem(meta_dict, | |||
| 734 | PyRRD_String_FromString("start")PyUnicode_FromString("start"), | |||
| 735 | PyRRD_Int_FromLong((long) start)PyLong_FromLong((long) start)); | |||
| 736 | PyDict_SetItem(meta_dict, | |||
| 737 | PyRRD_String_FromString("end")PyUnicode_FromString("end"), | |||
| 738 | PyRRD_Int_FromLong((long) end)PyLong_FromLong((long) end)); | |||
| 739 | PyDict_SetItem(meta_dict, | |||
| 740 | PyRRD_String_FromString("step")PyUnicode_FromString("step"), | |||
| 741 | PyRRD_Int_FromLong((long) step)PyLong_FromLong((long) step)); | |||
| ||||
| 742 | PyDict_SetItem(meta_dict, | |||
| 743 | PyRRD_String_FromString("rows")PyUnicode_FromString("rows"), | |||
| 744 | PyRRD_Int_FromLong((long) row_cnt)PyLong_FromLong((long) row_cnt)); | |||
| 745 | PyDict_SetItem(meta_dict, | |||
| 746 | PyRRD_String_FromString("columns")PyUnicode_FromString("columns"), | |||
| 747 | PyRRD_Int_FromLong((long) col_cnt)PyLong_FromLong((long) col_cnt)); | |||
| 748 | PyDict_SetItem(meta_dict, | |||
| 749 | PyRRD_String_FromString("legend")PyUnicode_FromString("legend"), | |||
| 750 | legend_list); | |||
| 751 | ||||
| 752 | for (i = 0; i < col_cnt; i++) | |||
| 753 | PyList_SET_ITEM(legend_list, i, PyRRD_String_FromString(legend_v[i]))PyList_SetItem(legend_list, i, PyUnicode_FromString(legend_v[ i])); | |||
| 754 | ||||
| 755 | for (i = 0; i < row_cnt; i++) { | |||
| 756 | t = PyTuple_New(col_cnt); | |||
| 757 | PyList_SET_ITEM(data_list, i, t)PyList_SetItem(data_list, i, t); | |||
| 758 | ||||
| 759 | for (j = 0; j < col_cnt; j++) { | |||
| 760 | dv = *(datai++); | |||
| 761 | ||||
| 762 | if (isnan(dv)__builtin_isnan (dv)) { | |||
| 763 | PyTuple_SET_ITEM(t, j, Py_None)PyTuple_SetItem(t, j, (&_Py_NoneStruct)); | |||
| 764 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 765 | } else { | |||
| 766 | PyTuple_SET_ITEM(t, j, PyFloat_FromDouble((double) dv))PyTuple_SetItem(t, j, PyFloat_FromDouble((double) dv)); | |||
| 767 | } | |||
| 768 | } | |||
| 769 | } | |||
| 770 | ||||
| 771 | for (i = 0; i < col_cnt; i++) | |||
| 772 | rrd_freemem(legend_v[i]); | |||
| 773 | ||||
| 774 | rrd_freemem(legend_v); | |||
| 775 | rrd_freemem(data); | |||
| 776 | } | |||
| 777 | ||||
| 778 | destroy_args(&rrdtool_argv); | |||
| 779 | ||||
| 780 | return ret; | |||
| 781 | } | |||
| 782 | ||||
| 783 | static char _rrdtool_tune__doc__[] = "Modify some basic properties of a " \ | |||
| 784 | "Round Robin Database.\n\n\ | |||
| 785 | Usage: tune(args..)\n\ | |||
| 786 | Arguments:\n\n\ | |||
| 787 | filename\n\ | |||
| 788 | [-h|--heartbeat ds-name:heartbeat]\n\ | |||
| 789 | [-i|--minimum ds-name:min]\n\ | |||
| 790 | [-a|--maximum ds-name:max]\n\ | |||
| 791 | [-d|--data-source-type ds-name:DST]\n\ | |||
| 792 | [-r|--data-source-rename old-name:new-name]\n\n\ | |||
| 793 | Full documentation can be found at:\n\ | |||
| 794 | https://oss.oetiker.ch/rrdtool/doc/rrdtune.en.html"; | |||
| 795 | ||||
| 796 | static PyObject * | |||
| 797 | _rrdtool_tune(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 798 | { | |||
| 799 | char **rrdtool_argv = NULL((void*)0); | |||
| 800 | int rrdtool_argc = 0; | |||
| 801 | PyObject *ret; | |||
| 802 | int status; | |||
| 803 | ||||
| 804 | if (convert_args("tune", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 805 | return NULL((void*)0); | |||
| 806 | ||||
| 807 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 808 | status = rrd_tune(rrdtool_argc, rrdtool_argv); | |||
| 809 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 810 | ||||
| 811 | if (status == -1) { | |||
| 812 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 813 | rrd_clear_error(); | |||
| 814 | ret = NULL((void*)0); | |||
| 815 | } else { | |||
| 816 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 817 | ret = Py_None(&_Py_NoneStruct); | |||
| 818 | } | |||
| 819 | ||||
| 820 | destroy_args(&rrdtool_argv); | |||
| 821 | return ret; | |||
| 822 | } | |||
| 823 | ||||
| 824 | static char _rrdtool_first__doc__[] = "Get the first UNIX timestamp of the "\ | |||
| 825 | "first data sample in an Round Robin Database.\n\n\ | |||
| 826 | Usage: first(args..)\n\ | |||
| 827 | Arguments:\n\n\ | |||
| 828 | filename\n\ | |||
| 829 | [--rraindex number]\n\ | |||
| 830 | [-d|--daemon address]\n\n\ | |||
| 831 | Full documentation can be found at:\n\ | |||
| 832 | https://oss.oetiker.ch/rrdtool/doc/rrdfirst.en.html"; | |||
| 833 | ||||
| 834 | static PyObject * | |||
| 835 | _rrdtool_first(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 836 | { | |||
| 837 | char **rrdtool_argv = NULL((void*)0); | |||
| 838 | int rrdtool_argc = 0; | |||
| 839 | PyObject *ret; | |||
| 840 | int ts; | |||
| 841 | ||||
| 842 | if (convert_args("first", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 843 | return NULL((void*)0); | |||
| 844 | ||||
| 845 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 846 | ts = rrd_first(rrdtool_argc, rrdtool_argv); | |||
| 847 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 848 | ||||
| 849 | if (ts == -1) { | |||
| 850 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 851 | rrd_clear_error(); | |||
| 852 | ret = NULL((void*)0); | |||
| 853 | } else | |||
| 854 | ret = PyRRD_Int_FromLong((long) ts)PyLong_FromLong((long) ts); | |||
| 855 | ||||
| 856 | destroy_args(&rrdtool_argv); | |||
| 857 | return ret; | |||
| 858 | } | |||
| 859 | ||||
| 860 | static char _rrdtool_last__doc__[] = "Get the UNIX timestamp of the most "\ | |||
| 861 | "recent data sample in an Round Robin Database.\n\n\ | |||
| 862 | Usage: last(args..)\n\ | |||
| 863 | Arguments:\n\n\ | |||
| 864 | filename\n\ | |||
| 865 | [-d|--daemon address]\n\n\ | |||
| 866 | Full documentation can be found at:\n\ | |||
| 867 | https://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |||
| 868 | ||||
| 869 | static PyObject * | |||
| 870 | _rrdtool_last(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 871 | { | |||
| 872 | char **rrdtool_argv = NULL((void*)0); | |||
| 873 | int rrdtool_argc = 0; | |||
| 874 | PyObject *ret; | |||
| 875 | int ts; | |||
| 876 | ||||
| 877 | if (convert_args("last", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 878 | return NULL((void*)0); | |||
| 879 | ||||
| 880 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 881 | ts = rrd_last(rrdtool_argc, rrdtool_argv); | |||
| 882 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 883 | ||||
| 884 | if (ts == -1) { | |||
| 885 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 886 | rrd_clear_error(); | |||
| 887 | ret = NULL((void*)0); | |||
| 888 | } else | |||
| 889 | ret = PyRRD_Int_FromLong((long) ts)PyLong_FromLong((long) ts); | |||
| 890 | ||||
| 891 | destroy_args(&rrdtool_argv); | |||
| 892 | return ret; | |||
| 893 | } | |||
| 894 | ||||
| 895 | static char _rrdtool_resize__doc__[] = "Modify the number of rows in a "\ | |||
| 896 | "Round Robin Database.\n\n\ | |||
| 897 | Usage: resize(args..)\n\ | |||
| 898 | Arguments:\n\n\ | |||
| 899 | filename\n\ | |||
| 900 | rra-num\n\ | |||
| 901 | GROW|SHRINK\n\ | |||
| 902 | rows\n\n\ | |||
| 903 | Full documentation can be found at:\n\ | |||
| 904 | https://oss.oetiker.ch/rrdtool/doc/rrdlast.en.html"; | |||
| 905 | ||||
| 906 | static PyObject * | |||
| 907 | _rrdtool_resize(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 908 | { | |||
| 909 | char **rrdtool_argv = NULL((void*)0); | |||
| 910 | int rrdtool_argc = 0; | |||
| 911 | PyObject *ret; | |||
| 912 | int status; | |||
| 913 | ||||
| 914 | if (convert_args("resize", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 915 | return NULL((void*)0); | |||
| 916 | ||||
| 917 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 918 | status = rrd_resize(rrdtool_argc, rrdtool_argv); | |||
| 919 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 920 | ||||
| 921 | if (status == -1) { | |||
| 922 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 923 | rrd_clear_error(); | |||
| 924 | ret = NULL((void*)0); | |||
| 925 | } else { | |||
| 926 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | |||
| 927 | ret = Py_None(&_Py_NoneStruct); | |||
| 928 | } | |||
| 929 | ||||
| 930 | destroy_args(&rrdtool_argv); | |||
| 931 | return ret; | |||
| 932 | } | |||
| 933 | ||||
| 934 | static char _rrdtool_info__doc__[] = "Extract header information from an "\ | |||
| 935 | "Round Robin Database.\n\n\ | |||
| 936 | Usage: info(filename, ...)\n\ | |||
| 937 | Arguments:\n\n\ | |||
| 938 | filename\n\ | |||
| 939 | [-d|--daemon address]\n\ | |||
| 940 | [-F|--noflush]\n\n\ | |||
| 941 | Full documentation can be found at:\n\ | |||
| 942 | https://oss.oetiker.ch/rrdtool/doc/rrdinfo.en.html"; | |||
| 943 | ||||
| 944 | static PyObject * | |||
| 945 | _rrdtool_info(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 946 | { | |||
| 947 | char **rrdtool_argv = NULL((void*)0); | |||
| 948 | int rrdtool_argc = 0; | |||
| 949 | PyObject *ret; | |||
| 950 | rrd_info_t *data; | |||
| 951 | ||||
| 952 | if (convert_args("info", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 953 | return NULL((void*)0); | |||
| 954 | ||||
| 955 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 956 | data = rrd_info(rrdtool_argc, rrdtool_argv); | |||
| 957 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 958 | ||||
| 959 | if (data == NULL((void*)0)) { | |||
| 960 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 961 | rrd_clear_error(); | |||
| 962 | ret = NULL((void*)0); | |||
| 963 | } else { | |||
| 964 | ret = _rrdtool_util_info2dict(data); | |||
| 965 | rrd_info_free(data); | |||
| 966 | } | |||
| 967 | ||||
| 968 | destroy_args(&rrdtool_argv); | |||
| 969 | return ret; | |||
| 970 | } | |||
| 971 | ||||
| 972 | static char _rrdtool_lastupdate__doc__[] = "Returns datetime and value stored "\ | |||
| 973 | "for each datum in the most recent update of an RRD.\n\n\ | |||
| 974 | Usage: lastupdate(filename, ...)\n\ | |||
| 975 | Arguments:\n\n\ | |||
| 976 | filename\n\ | |||
| 977 | [-d|--daemon address]\n\n\ | |||
| 978 | Full documentation can be found at:\n\ | |||
| 979 | https://oss.oetiker.ch/rrdtool/doc/rrdlastupdate.en.html"; | |||
| 980 | ||||
| 981 | static PyObject * | |||
| 982 | _rrdtool_lastupdate(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 983 | { | |||
| 984 | char **rrdtool_argv = NULL((void*)0); | |||
| 985 | int rrdtool_argc = 0; | |||
| 986 | PyObject *ret, *ds_dict, *lastupd; | |||
| 987 | int status; | |||
| 988 | time_t last_update; | |||
| 989 | char **ds_names, **last_ds; | |||
| 990 | unsigned long ds_cnt, i; | |||
| 991 | ||||
| 992 | if (convert_args("lastupdate", args, &rrdtool_argv, &rrdtool_argc) == -1) | |||
| 993 | return NULL((void*)0); | |||
| 994 | else if (rrdtool_argc < 2) { | |||
| 995 | PyErr_SetString(rrdtool_ProgrammingError, "Missing filename argument"); | |||
| 996 | return NULL((void*)0); | |||
| 997 | } | |||
| 998 | ||||
| 999 | Py_BEGIN_ALLOW_THREADS{ PyThreadState *_save; _save = PyEval_SaveThread(); | |||
| 1000 | status = rrd_lastupdate_r(rrdtool_argv[1], | |||
| 1001 | &last_update, | |||
| 1002 | &ds_cnt, | |||
| 1003 | &ds_names, | |||
| 1004 | &last_ds); | |||
| 1005 | Py_END_ALLOW_THREADSPyEval_RestoreThread(_save); } | |||
| 1006 | ||||
| 1007 | if (status != 0) { | |||
| 1008 | PyErr_SetString(rrdtool_OperationalError, rrd_get_error()); | |||
| 1009 | rrd_clear_error(); | |||
| 1010 | ret = NULL((void*)0); | |||
| 1011 | } else { | |||
| 1012 | /* convert last_update to Python datetime object */ | |||
| 1013 | ret = PyDict_New(); | |||
| 1014 | ds_dict = PyDict_New(); | |||
| 1015 | lastupd = PyRRD_DateTime_FromTS(last_update); | |||
| 1016 | ||||
| 1017 | PyDict_SetItemString(ret, "date", lastupd); | |||
| 1018 | PyDict_SetItemString(ret, "ds", ds_dict); | |||
| 1019 | ||||
| 1020 | Py_DECREF(lastupd)_Py_DECREF(((PyObject*)(lastupd))); | |||
| 1021 | Py_DECREF(ds_dict)_Py_DECREF(((PyObject*)(ds_dict))); | |||
| 1022 | ||||
| 1023 | for (i = 0; i < ds_cnt; i++) { | |||
| 1024 | PyObject* val = Py_None(&_Py_NoneStruct); | |||
| 1025 | ||||
| 1026 | double num; | |||
| 1027 | if (sscanf(last_ds[i], "%lf", &num) == 1) { | |||
| 1028 | val = PyFloat_FromDouble(num); | |||
| 1029 | } | |||
| 1030 | ||||
| 1031 | if (!val) | |||
| 1032 | return NULL((void*)0); | |||
| 1033 | ||||
| 1034 | PyDict_SetItemString(ds_dict, ds_names[i], val); | |||
| 1035 | ||||
| 1036 | if (val != Py_None(&_Py_NoneStruct)) | |||
| 1037 | Py_DECREF(val)_Py_DECREF(((PyObject*)(val))); | |||
| 1038 | ||||
| 1039 | free(last_ds[i]); | |||
| 1040 | free(ds_names[i]); | |||
| 1041 | } | |||
| 1042 | ||||
| 1043 | free(last_ds); | |||
| 1044 | free(ds_names); | |||
| 1045 | ||||
| 1046 | } | |||
| 1047 | ||||
| 1048 | destroy_args(&rrdtool_argv); | |||
| 1049 | ||||
| 1050 | return ret; | |||
| 1051 | } | |||
| 1052 | ||||
| 1053 | #ifdef WITH_FETCH_CB1 | |||
| 1054 | ||||
| 1055 | /** A Python object which will hold a callable for fetch callbacks */ | |||
| 1056 | static PyObject *_rrdtool_fetch_callable = NULL((void*)0); | |||
| 1057 | ||||
| 1058 | static int | |||
| 1059 | _rrdtool_fetch_cb_wrapper( | |||
| 1060 | const char *filename, | |||
| 1061 | enum cf_en cf_idx, | |||
| 1062 | time_t *start, | |||
| 1063 | time_t *end, | |||
| 1064 | unsigned long *step, | |||
| 1065 | unsigned long *ds_cnt, | |||
| 1066 | char ***ds_namv, | |||
| 1067 | rrd_value_t **data) | |||
| 1068 | { | |||
| 1069 | PyObject *args; | |||
| 1070 | PyObject *kwargs; | |||
| 1071 | PyObject *ret = NULL((void*)0); | |||
| 1072 | PyObject *tmp; | |||
| 1073 | PyObject *tmp_min_ts; | |||
| 1074 | PyGILState_STATE gstate; | |||
| 1075 | Py_ssize_t rowcount = 0; | |||
| 1076 | int rc = -1; | |||
| 1077 | unsigned int i, ii; | |||
| 1078 | ||||
| 1079 | gstate = PyGILState_Ensure(); | |||
| 1080 | ||||
| 1081 | if (_rrdtool_fetch_callable == NULL((void*)0)) { | |||
| 1082 | rrd_set_error("use rrdtool.register_fetch_cb to register a fetch callback"); | |||
| 1083 | goto gil_release_err; | |||
| 1084 | } | |||
| 1085 | ||||
| 1086 | args = PyTuple_New(0); | |||
| 1087 | kwargs = PyDict_New(); | |||
| 1088 | ||||
| 1089 | /* minimum possible UNIX datetime */ | |||
| 1090 | tmp_min_ts = PyLong_FromLong(0); | |||
| 1091 | ||||
| 1092 | PyObject *po_filename = PyRRD_String_FromString(filename)PyUnicode_FromString(filename); | |||
| 1093 | PyDict_SetItemString(kwargs, "filename", po_filename); | |||
| 1094 | Py_DECREF(po_filename)_Py_DECREF(((PyObject*)(po_filename))); | |||
| 1095 | ||||
| 1096 | PyObject *po_cfstr = PyRRD_String_FromString(PyRRD_String_FromCF(cf_idx))PyUnicode_FromString(PyRRD_String_FromCF(cf_idx)); | |||
| 1097 | PyDict_SetItemString(kwargs, "cf", po_cfstr); | |||
| 1098 | Py_DECREF(po_cfstr)_Py_DECREF(((PyObject*)(po_cfstr))); | |||
| 1099 | ||||
| 1100 | PyObject *po_start = PyLong_FromLong(*start); | |||
| 1101 | PyDict_SetItemString(kwargs, "start", po_start); | |||
| 1102 | Py_DECREF(po_start)_Py_DECREF(((PyObject*)(po_start))); | |||
| 1103 | ||||
| 1104 | PyObject *po_end = PyLong_FromLong(*end); | |||
| 1105 | PyDict_SetItemString(kwargs, "end", po_end); | |||
| 1106 | Py_DECREF(po_end)_Py_DECREF(((PyObject*)(po_end))); | |||
| 1107 | ||||
| 1108 | PyObject *po_step = PyLong_FromUnsignedLong(*step); | |||
| 1109 | PyDict_SetItemString(kwargs, "step", po_step); | |||
| 1110 | Py_DECREF(po_step)_Py_DECREF(((PyObject*)(po_step))); | |||
| 1111 | ||||
| 1112 | /* execute Python callback method */ | |||
| 1113 | ret = PyObject_Call(_rrdtool_fetch_callable, args, kwargs); | |||
| 1114 | Py_DECREF(args)_Py_DECREF(((PyObject*)(args))); | |||
| 1115 | Py_DECREF(kwargs)_Py_DECREF(((PyObject*)(kwargs))); | |||
| 1116 | ||||
| 1117 | if (ret == NULL((void*)0)) { | |||
| 1118 | rrd_set_error("calling python callback failed"); | |||
| 1119 | goto gil_release_err; | |||
| 1120 | } | |||
| 1121 | ||||
| 1122 | /* handle return value of callback */ | |||
| 1123 | if (!PyDict_Check(ret)((((((PyObject*)(ret))->ob_type))->tp_flags & ((1UL << 29))) != 0)) { | |||
| 1124 | rrd_set_error("expected callback method to be a dict"); | |||
| 1125 | goto gil_release_err; | |||
| 1126 | } | |||
| 1127 | ||||
| 1128 | tmp = PyDict_GetItemString(ret, "step"); | |||
| 1129 | if (tmp == NULL((void*)0)) { | |||
| 1130 | rrd_set_error("expected 'step' key in callback return value"); | |||
| 1131 | goto gil_release_err; | |||
| 1132 | } else if (!PyRRD_Long_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 24))) != 0)) { | |||
| 1133 | rrd_set_error("the 'step' key in callback return value must be int"); | |||
| 1134 | goto gil_release_err; | |||
| 1135 | } else | |||
| 1136 | *step = PyLong_AsLong(tmp); | |||
| 1137 | ||||
| 1138 | tmp = PyDict_GetItemString(ret, "start"); | |||
| 1139 | if (tmp == NULL((void*)0)) { | |||
| 1140 | rrd_set_error("expected 'start' key in callback return value"); | |||
| 1141 | goto gil_release_err; | |||
| 1142 | } else if (!PyRRD_Long_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 24))) != 0)) { | |||
| 1143 | rrd_set_error("expected 'start' key in callback return value to be " | |||
| 1144 | "of type int"); | |||
| 1145 | goto gil_release_err; | |||
| 1146 | } else if (PyObject_RichCompareBool(tmp, tmp_min_ts, Py_EQ2) || | |||
| 1147 | PyObject_RichCompareBool(tmp, po_start, Py_LT0)) { | |||
| 1148 | rrd_set_error("expected 'start' value in callback return dict to be " | |||
| 1149 | "equal or earlier than passed start timestamp"); | |||
| 1150 | goto gil_release_err; | |||
| 1151 | } else { | |||
| 1152 | *start = PyLong_AsLong(po_start); | |||
| 1153 | ||||
| 1154 | if (*start == -1) { | |||
| 1155 | rrd_set_error("expected 'start' value in callback return value to" | |||
| 1156 | " not exceed LONG_MAX"); | |||
| 1157 | goto gil_release_err; | |||
| 1158 | } | |||
| 1159 | } | |||
| 1160 | ||||
| 1161 | tmp = PyDict_GetItemString(ret, "data"); | |||
| 1162 | if (tmp == NULL((void*)0)) { | |||
| 1163 | rrd_set_error("expected 'data' key in callback return value"); | |||
| 1164 | goto gil_release_err; | |||
| 1165 | } else if (!PyDict_Check(tmp)((((((PyObject*)(tmp))->ob_type))->tp_flags & ((1UL << 29))) != 0)) { | |||
| 1166 | rrd_set_error("expected 'data' key in callback return value of type " | |||
| 1167 | "dict"); | |||
| 1168 | goto gil_release_err; | |||
| 1169 | } else { | |||
| 1170 | *ds_cnt = (unsigned long)PyDict_Size(tmp); | |||
| 1171 | *ds_namv = (char **)calloc(*ds_cnt, sizeof(char *)); | |||
| 1172 | ||||
| 1173 | if (*ds_namv == NULL((void*)0)) { | |||
| 1174 | rrd_set_error("an error occurred while allocating memory for " | |||
| 1175 | "ds_namv when allocating memory for python callback"); | |||
| 1176 | goto gil_release_err; | |||
| 1177 | } | |||
| 1178 | ||||
| 1179 | PyObject *key, *value; | |||
| 1180 | Py_ssize_t pos = 0; /* don't use pos for indexing */ | |||
| 1181 | unsigned int x = 0; | |||
| 1182 | ||||
| 1183 | while (PyDict_Next(tmp, &pos, &key, &value)) { | |||
| 1184 | const char *key_str = PyRRD_String_AS_STRING(key)PyUnicode_AsUTF8(key); | |||
| 1185 | ||||
| 1186 | if (key_str == NULL((void*)0)) { | |||
| 1187 | rrd_set_error("key of 'data' element from callback return " | |||
| 1188 | "value is not a string"); | |||
| 1189 | goto gil_release_free_dsnamv_err; | |||
| 1190 | } else if (strlen(key_str) > DS_NAM_SIZE20) { | |||
| 1191 | rrd_set_error("key '%s' longer than the allowed maximum of %d " | |||
| 1192 | "byte", key_str, DS_NAM_SIZE20 - 1); | |||
| 1193 | goto gil_release_free_dsnamv_err; | |||
| 1194 | } | |||
| 1195 | ||||
| 1196 | if ((((*ds_namv)[x]) = (char *)malloc(sizeof(char) * DS_NAM_SIZE20)) == NULL((void*)0)) { | |||
| 1197 | rrd_set_error("malloc fetch ds_namv entry"); | |||
| 1198 | goto gil_release_free_dsnamv_err; | |||
| 1199 | } | |||
| 1200 | ||||
| 1201 | strncpy((*ds_namv)[x], key_str, DS_NAM_SIZE20 - 1); | |||
| 1202 | (*ds_namv)[x][DS_NAM_SIZE20 - 1] = '\0'; | |||
| 1203 | ||||
| 1204 | if (!PyList_Check(value)((((((PyObject*)(value))->ob_type))->tp_flags & ((1UL << 25))) != 0)) { | |||
| 1205 | rrd_set_error("expected 'data' dict values in callback return " | |||
| 1206 | "value of type list"); | |||
| 1207 | goto gil_release_free_dsnamv_err; | |||
| 1208 | } else if (PyList_Size(value) > rowcount) | |||
| 1209 | rowcount = PyList_Size(value); | |||
| 1210 | ||||
| 1211 | ++x; | |||
| 1212 | } | |||
| 1213 | ||||
| 1214 | *end = *start + *step * rowcount; | |||
| 1215 | ||||
| 1216 | if (((*data) = (rrd_value_t *)malloc(*ds_cnt * rowcount * sizeof(rrd_value_t))) == NULL((void*)0)) { | |||
| 1217 | rrd_set_error("malloc fetch data area"); | |||
| 1218 | goto gil_release_free_dsnamv_err; | |||
| 1219 | } | |||
| 1220 | ||||
| 1221 | for (i = 0; i < *ds_cnt; i++) { | |||
| 1222 | for (ii = 0; ii < (unsigned int)rowcount; ii++) { | |||
| 1223 | char *ds_namv_i = (*ds_namv)[i]; | |||
| 1224 | double va; | |||
| 1225 | PyObject *lstv = PyList_GetItem(PyDict_GetItemString(tmp, ds_namv_i), ii); | |||
| 1226 | ||||
| 1227 | /* lstv may be NULL here in case an IndexError has been raised; | |||
| 1228 | in such case the rowcount is higher than the number of elements for | |||
| 1229 | the list of that ds. use DNAN as value for these then */ | |||
| 1230 | if (lstv == NULL((void*)0) || lstv == Py_None(&_Py_NoneStruct)) { | |||
| 1231 | if (lstv == NULL((void*)0)) | |||
| 1232 | PyErr_Clear(); | |||
| 1233 | va = DNANrrd_set_to_DNAN(); | |||
| 1234 | } | |||
| 1235 | else { | |||
| 1236 | va = PyFloat_AsDouble(lstv); | |||
| 1237 | if (va == -1.0 && PyErr_Occurred()) { | |||
| 1238 | PyObject *exc_type, *exc_value, *exc_value_str = NULL((void*)0), *exc_tb; | |||
| 1239 | PyErr_Fetch(&exc_type, &exc_value, &exc_tb); | |||
| 1240 | ||||
| 1241 | if (exc_value != NULL((void*)0)) { | |||
| 1242 | exc_value_str = PyObject_Str(exc_value); | |||
| 1243 | rrd_set_error((char *)PyRRD_String_AS_STRING(exc_value_str)PyUnicode_AsUTF8(exc_value_str)); | |||
| 1244 | Py_DECREF(exc_value)_Py_DECREF(((PyObject*)(exc_value))); | |||
| 1245 | } | |||
| 1246 | ||||
| 1247 | Py_DECREF(exc_type)_Py_DECREF(((PyObject*)(exc_type))); | |||
| 1248 | Py_DECREF(exc_value_str)_Py_DECREF(((PyObject*)(exc_value_str))); | |||
| 1249 | if (exc_tb != NULL((void*)0)) | |||
| 1250 | Py_DECREF(exc_tb)_Py_DECREF(((PyObject*)(exc_tb))); | |||
| 1251 | goto gil_release_free_dsnamv_err; | |||
| 1252 | } | |||
| 1253 | } | |||
| 1254 | ||||
| 1255 | (*data)[i + ii * (*ds_cnt)] = va; | |||
| 1256 | } | |||
| 1257 | } | |||
| 1258 | } | |||
| 1259 | ||||
| 1260 | /* success */ | |||
| 1261 | rc = 1; | |||
| 1262 | goto gil_release; | |||
| 1263 | ||||
| 1264 | gil_release_free_dsnamv_err: | |||
| 1265 | for (i = 0; i < *ds_cnt; i++) { | |||
| 1266 | if ((*ds_namv)[i]) { | |||
| 1267 | free((*ds_namv)[i]); | |||
| 1268 | } | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | free(*ds_namv); | |||
| 1272 | ||||
| 1273 | gil_release_err: | |||
| 1274 | rc = -1; | |||
| 1275 | ||||
| 1276 | gil_release: | |||
| 1277 | if (ret != NULL((void*)0)) | |||
| 1278 | Py_DECREF(ret)_Py_DECREF(((PyObject*)(ret))); | |||
| 1279 | PyGILState_Release(gstate); | |||
| 1280 | return rc; | |||
| 1281 | } | |||
| 1282 | ||||
| 1283 | static char _rrdtool_register_fetch_cb__doc__[] = "Register callback for " | |||
| 1284 | "fetching data"; | |||
| 1285 | ||||
| 1286 | static PyObject * | |||
| 1287 | _rrdtool_register_fetch_cb(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *args) | |||
| 1288 | { | |||
| 1289 | PyObject *callable; | |||
| 1290 | ||||
| 1291 | if (!PyArg_ParseTuple(args, "O", &callable)) | |||
| 1292 | return NULL((void*)0); | |||
| 1293 | else if (!PyCallable_Check(callable)) { | |||
| 1294 | PyErr_SetString(rrdtool_ProgrammingError, "first argument must be callable"); | |||
| 1295 | return NULL((void*)0); | |||
| 1296 | } else { | |||
| 1297 | _rrdtool_fetch_callable = callable; | |||
| 1298 | rrd_fetch_cb_register(_rrdtool_fetch_cb_wrapper); | |||
| 1299 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | |||
| 1300 | } | |||
| 1301 | } | |||
| 1302 | ||||
| 1303 | static char _rrdtool_clear_fetch_cb__doc__[] = "Clear callback for " | |||
| 1304 | "fetching data"; | |||
| 1305 | ||||
| 1306 | static PyObject * | |||
| 1307 | _rrdtool_clear_fetch_cb(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *Py_UNUSED(args)_unused_args __attribute__((unused))) | |||
| 1308 | { | |||
| 1309 | if (_rrdtool_fetch_callable == NULL((void*)0)) { | |||
| 1310 | PyErr_SetString(rrdtool_ProgrammingError, "no callback has been set previously"); | |||
| 1311 | return NULL((void*)0); | |||
| 1312 | } | |||
| 1313 | ||||
| 1314 | _rrdtool_fetch_callable = NULL((void*)0); | |||
| 1315 | rrd_fetch_cb_register(NULL((void*)0)); | |||
| 1316 | Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (& _Py_NoneStruct); | |||
| 1317 | } | |||
| 1318 | ||||
| 1319 | #endif /* WITH_FETCH_CB */ | |||
| 1320 | ||||
| 1321 | static char _rrdtool_lib_version__doc__[] = "Get the version this binding "\ | |||
| 1322 | "was compiled against."; | |||
| 1323 | ||||
| 1324 | /** | |||
| 1325 | * Returns a str object that contains the librrd version. | |||
| 1326 | * | |||
| 1327 | * @return librrd version (Python str object) | |||
| 1328 | */ | |||
| 1329 | static PyObject * | |||
| 1330 | _rrdtool_lib_version(PyObject *Py_UNUSED(self)_unused_self __attribute__((unused)), PyObject *Py_UNUSED(args)_unused_args __attribute__((unused))) | |||
| 1331 | { | |||
| 1332 | return PyRRD_String_FromString(rrd_strversion())PyUnicode_FromString(rrd_strversion()); | |||
| 1333 | } | |||
| 1334 | ||||
| 1335 | /** Method table. */ | |||
| 1336 | static PyMethodDef rrdtool_methods[] = { | |||
| 1337 | {"create", (PyCFunction)_rrdtool_create, | |||
| 1338 | METH_VARARGS0x0001, _rrdtool_create__doc__}, | |||
| 1339 | {"dump", (PyCFunction)_rrdtool_dump, | |||
| 1340 | METH_VARARGS0x0001, _rrdtool_dump__doc__}, | |||
| 1341 | {"update", (PyCFunction)_rrdtool_update, | |||
| 1342 | METH_VARARGS0x0001, _rrdtool_update__doc__}, | |||
| 1343 | {"updatev", (PyCFunction)_rrdtool_updatev, | |||
| 1344 | METH_VARARGS0x0001, _rrdtool_updatev__doc__}, | |||
| 1345 | {"fetch", (PyCFunction)_rrdtool_fetch, | |||
| 1346 | METH_VARARGS0x0001, _rrdtool_fetch__doc__}, | |||
| 1347 | {"flushcached", (PyCFunction)_rrdtool_flushcached, | |||
| 1348 | METH_VARARGS0x0001, _rrdtool_flushcached__doc__}, | |||
| 1349 | {"graph", (PyCFunction)_rrdtool_graph, | |||
| 1350 | METH_VARARGS0x0001, _rrdtool_graph__doc__}, | |||
| 1351 | {"graphv", (PyCFunction)_rrdtool_graphv, | |||
| 1352 | METH_VARARGS0x0001, _rrdtool_graphv__doc__}, | |||
| 1353 | {"xport", (PyCFunction)_rrdtool_xport, | |||
| 1354 | METH_VARARGS0x0001, _rrdtool_xport__doc__}, | |||
| 1355 | {"tune", (PyCFunction)_rrdtool_tune, | |||
| 1356 | METH_VARARGS0x0001, _rrdtool_tune__doc__}, | |||
| 1357 | {"first", (PyCFunction)_rrdtool_first, | |||
| 1358 | METH_VARARGS0x0001, _rrdtool_first__doc__}, | |||
| 1359 | {"last", (PyCFunction)_rrdtool_last, | |||
| 1360 | METH_VARARGS0x0001, _rrdtool_last__doc__}, | |||
| 1361 | {"resize", (PyCFunction)_rrdtool_resize, | |||
| 1362 | METH_VARARGS0x0001, _rrdtool_resize__doc__}, | |||
| 1363 | {"info", (PyCFunction)_rrdtool_info, | |||
| 1364 | METH_VARARGS0x0001, _rrdtool_info__doc__}, | |||
| 1365 | {"lastupdate", (PyCFunction)_rrdtool_lastupdate, | |||
| 1366 | METH_VARARGS0x0001, _rrdtool_lastupdate__doc__}, | |||
| 1367 | #ifdef WITH_FETCH_CB1 | |||
| 1368 | {"register_fetch_cb", (PyCFunction)_rrdtool_register_fetch_cb, | |||
| 1369 | METH_VARARGS0x0001, _rrdtool_register_fetch_cb__doc__}, | |||
| 1370 | {"clear_fetch_cb", (PyCFunction)_rrdtool_clear_fetch_cb, | |||
| 1371 | METH_NOARGS0x0004, _rrdtool_clear_fetch_cb__doc__}, | |||
| 1372 | #endif /* WITH_FETCH_CB */ | |||
| 1373 | {"lib_version", (PyCFunction)_rrdtool_lib_version, | |||
| 1374 | METH_NOARGS0x0004, _rrdtool_lib_version__doc__}, | |||
| 1375 | {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)} | |||
| 1376 | }; | |||
| 1377 | ||||
| 1378 | /** Library init function. */ | |||
| 1379 | #ifdef HAVE_PY3K | |||
| 1380 | static struct PyModuleDef rrdtoolmodule = { | |||
| 1381 | .m_base = PyModuleDef_HEAD_INIT{ { 1, ((void*)0) }, ((void*)0), 0, ((void*)0), }, | |||
| 1382 | .m_name = "rrdtool", | |||
| 1383 | .m_doc = "Python bindings for rrdtool", | |||
| 1384 | .m_size = -1, | |||
| 1385 | .m_methods = rrdtool_methods | |||
| 1386 | }; | |||
| 1387 | ||||
| 1388 | #endif | |||
| 1389 | ||||
| 1390 | #ifdef HAVE_PY3K | |||
| 1391 | PyMODINIT_FUNCPyObject* | |||
| 1392 | PyInit_rrdtool(void) | |||
| 1393 | #else | |||
| 1394 | void | |||
| 1395 | initrrdtool(void) | |||
| 1396 | #endif | |||
| 1397 | { | |||
| 1398 | PyObject *m; | |||
| 1399 | ||||
| 1400 | PyDateTime_IMPORTPyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import("datetime.datetime_CAPI" , 0); /* initialize PyDateTime_ functions */ | |||
| 1401 | ||||
| 1402 | /* make sure that the GIL has been created as we need to aquire it */ | |||
| 1403 | if (!PyEval_ThreadsInitialized()) | |||
| 1404 | PyEval_InitThreads(); | |||
| 1405 | ||||
| 1406 | #ifdef HAVE_PY3K | |||
| 1407 | m = PyModule_Create(&rrdtoolmodule)PyModule_Create2(&rrdtoolmodule, 1013); | |||
| 1408 | #else | |||
| 1409 | m = Py_InitModule3("rrdtool", | |||
| 1410 | rrdtool_methods, | |||
| 1411 | "Python bindings for rrdtool"); | |||
| 1412 | #endif | |||
| 1413 | ||||
| 1414 | if (m == NULL((void*)0)) | |||
| 1415 | #ifdef HAVE_PY3K | |||
| 1416 | return NULL((void*)0); | |||
| 1417 | #else | |||
| 1418 | return; | |||
| 1419 | #endif | |||
| 1420 | ||||
| 1421 | rrdtool_ProgrammingError = PyErr_NewException("rrdtool.ProgrammingError", | |||
| 1422 | NULL((void*)0), NULL((void*)0)); | |||
| 1423 | Py_INCREF(rrdtool_ProgrammingError)_Py_INCREF(((PyObject*)(rrdtool_ProgrammingError))); | |||
| 1424 | PyModule_AddObject(m, "ProgrammingError", rrdtool_ProgrammingError); | |||
| 1425 | ||||
| 1426 | rrdtool_OperationalError = PyErr_NewException("rrdtool.OperationalError", | |||
| 1427 | NULL((void*)0), NULL((void*)0)); | |||
| 1428 | Py_INCREF(rrdtool_OperationalError)_Py_INCREF(((PyObject*)(rrdtool_OperationalError))); | |||
| 1429 | PyModule_AddObject(m, "OperationalError", rrdtool_OperationalError); | |||
| 1430 | PyModule_AddStringConstant(m, "__version__", _version); | |||
| 1431 | ||||
| 1432 | #ifdef HAVE_PY3K | |||
| 1433 | return m; | |||
| 1434 | #endif | |||
| 1435 | } |
| 1 | #ifndef PyLong_FromLong |
| 2 | struct _object; |
| 3 | typedef struct _object PyObject; |
| 4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
| 5 | PyObject* PyLong_FromLong(long v) { |
| 6 | return clang_analyzer_PyObject_New_Reference(); |
| 7 | } |
| 8 | #else |
| 9 | #warning "API PyLong_FromLong is defined as a macro." |
| 10 | #endif |