File: | rrdtoolmodule.c |
Warning: | line 1034, column 13 Calling function 'PyDict_SetItemString' with a PyObject argument whose ownership has been released |
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 PyDict_New |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyDict_New() { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyDict_New is defined as a macro." |
10 | #endif |
1 | void _Py_DECREF(PyObject *op) { --op->ob_refcnt; } |