1 /*
2 * Lua bindings for RRDTool
3 *
4 * This software is licensed to the public under the Free Software
5 * Foundation's GNU GPL, version 2 or later. You may obtain a copy
6 * of the GPL by visiting the Free Software Foundations web site at
7 * www.fsf.org, and a copy is included in this distribution.
8 *
9 * Copyright 2008 Fidelis Assis, all rights reserved.
10 *
11 */
13 #include <ctype.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <math.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <inttypes.h>
24 #include "lua.h"
25 #include "lauxlib.h"
26 #include "lualib.h"
27 #include "../../src/rrd_tool.h"
29 #ifdef LUA50
30 #ifdef HAVE_COMPAT51
31 #include "compat-5.1.h"
32 #else
33 #include "compat-5.1r5/compat-5.1.h"
34 #endif
35 #endif
37 extern void rrd_freemem(void *mem);
39 extern int luaopen_rrd (lua_State * L);
40 typedef int (*RRD_FUNCTION)(int, char **);
41 typedef rrd_info_t *(RRD_FUNCTION_V)(int, char **);
43 /**********************************************************/
45 static void reset_rrd_state(void)
46 {
47 optind = 0;
48 opterr = 0;
49 rrd_clear_error();
50 }
52 static char **make_argv(const char *cmd, lua_State * L)
53 {
54 char **argv;
55 int i;
56 int argc = lua_gettop(L) + 1;
58 if (!(argv = calloc(argc, sizeof (char *))))
59 /* raise an error and never return */
60 luaL_error(L, "Can't allocate memory for arguments array", cmd);
62 /* fprintf(stderr, "Args:\n"); */
63 argv[0] = (char *) cmd; /* Dummy arg. Cast to (char *) because rrd */
64 /* functions don't expect (const * char) */
65 /* fprintf(stderr, "%s\n", argv[0]); */
66 for (i=1; i<argc; i++) {
67 /* accepts string or number */
68 if (lua_isstring(L, i) || lua_isnumber(L, i)) {
69 if (!(argv[i] = lua_tostring (L, i))) {
70 /* raise an error and never return */
71 luaL_error(L, "%s - error duplicating string area for arg #%d",
72 cmd, i);
73 }
74 } else {
75 /* raise an error and never return */
76 luaL_error(L, "Invalid arg #%d to %s: args must be strings or numbers",
77 i, cmd);
78 }
79 /* fprintf(stderr, "%s\n", argv[i]); */
80 }
81 return argv;
82 }
84 static int
85 rrd_common_call (lua_State *L, const char *cmd, RRD_FUNCTION rrd_function)
86 {
87 char **argv;
88 int argc = lua_gettop(L) + 1;
90 argv = make_argv(cmd, L);
91 reset_rrd_state();
92 rrd_function(argc, argv);
93 free(argv);
94 if (rrd_test_error()) luaL_error(L, rrd_get_error());
95 return 0;
96 }
98 #if defined(DINF)
99 static int
100 lua_rrd_infocall(lua_State *L, const char *cmd, RRD_FUNCTION_V rrd_function)
101 {
102 char **argv;
103 rrd_info_t *p, *data;
104 int argc = lua_gettop(L) + 1;
106 argv = make_argv(cmd, L);
107 reset_rrd_state();
108 data = rrd_function(argc, argv);
109 free(argv);
110 if (rrd_test_error()) luaL_error(L, rrd_get_error());
112 lua_newtable(L);
113 p = data;
114 while (data) {
115 lua_pushstring(L, data->key);
116 switch (data->type) {
117 case RD_I_CNT:
118 if (isnan(data->value.u_val)) {
119 lua_pushnil(L);
120 } else {
121 lua_pushnumber(L, (lua_Number) data->value.u_val);
122 }
123 lua_rawset(L, -3);
124 break;
125 case RD_I_VAL:
126 lua_pushnumber(L, (lua_Number) data->value.u_val);
127 lua_rawset(L, -3);
128 break;
129 case RD_I_STR:
130 lua_pushstring(L, data->value.u_str);
131 lua_rawset(L, -3);
132 break;
133 case RD_I_BLO:
134 lua_pushlstring(L, (const char *) data->value.u_blo.ptr,
135 data->value.u_blo.size);
136 lua_rawset(L, -3);
137 break;
138 default:
139 rrd_info_free(p);
140 return luaL_error(L, "Wrong data type to info call");
141 break;
142 }
143 data = data->next;
144 }
145 rrd_info_free(p);
146 return 1;
147 }
148 #endif
150 /**********************************************************/
152 static int
153 lua_rrd_create (lua_State * L)
154 {
155 rrd_common_call(L, "create", rrd_create);
156 return 0;
157 }
159 static int
160 lua_rrd_dump (lua_State * L)
161 {
162 rrd_common_call(L, "dump", rrd_dump);
163 return 0;
164 }
166 static int
167 lua_rrd_resize (lua_State * L)
168 {
169 rrd_common_call(L, "resize", rrd_resize);
170 return 0;
171 }
173 static int
174 lua_rrd_restore (lua_State * L)
175 {
176 rrd_common_call(L, "restore", rrd_restore);
177 return 0;
178 }
180 static int
181 lua_rrd_tune (lua_State * L)
182 {
183 rrd_common_call(L, "tune", rrd_tune);
184 return 0;
185 }
187 static int
188 lua_rrd_update (lua_State * L)
189 {
190 rrd_common_call(L, "update", rrd_update);
191 return 0;
192 }
194 static int
195 lua_rrd_fetch (lua_State * L)
196 {
197 int argc = lua_gettop(L) + 1;
198 char **argv = make_argv("fetch", L);
199 unsigned long i, j, step, ds_cnt;
200 rrd_value_t *data, *p;
201 char **names;
202 time_t t, start, end;
204 reset_rrd_state();
205 rrd_fetch(argc, argv, &start, &end, &step, &ds_cnt, &names, &data);
206 free(argv);
207 if (rrd_test_error()) luaL_error(L, rrd_get_error());
209 lua_pushnumber(L, (lua_Number) start);
210 lua_pushnumber(L, (lua_Number) step);
211 /* fprintf(stderr, "%lu, %lu, %lu, %lu\n", start, end, step, num_points); */
213 /* create the ds names array */
214 lua_newtable(L);
215 for (i=0; i<ds_cnt; i++) {
216 lua_pushstring(L, names[i]);
217 lua_rawseti(L, -2, i+1);
218 rrd_freemem(names[i]);
219 }
220 rrd_freemem(names);
222 /* create the data points array */
223 lua_newtable(L);
224 p = data;
225 for (t=start, i=0; t<end; t+=step, i++) {
226 lua_newtable(L);
227 for (j=0; j<ds_cnt; j++) {
228 /*fprintf(stderr, "Point #%lu\n", j+1); */
229 lua_pushnumber(L, (lua_Number) *p++);
230 lua_rawseti(L, -2, j+1);
231 }
232 lua_rawseti(L, -2, i+1);
233 }
234 rrd_freemem(data);
236 /* return the end as the last value */
237 lua_pushnumber(L, (lua_Number) end);
239 return 5;
240 }
242 static int
243 lua_rrd_first (lua_State * L)
244 {
245 time_t first;
246 int argc = lua_gettop(L) + 1;
247 char **argv = make_argv("first", L);
248 reset_rrd_state();
249 first = rrd_first(argc, argv);
250 free(argv);
251 if (rrd_test_error()) luaL_error(L, rrd_get_error());
252 lua_pushnumber(L, (lua_Number) first);
253 return 1;
254 }
256 static int
257 lua_rrd_last (lua_State * L)
258 {
259 time_t last;
260 int argc = lua_gettop(L) + 1;
261 char **argv = make_argv("last", L);
262 reset_rrd_state();
263 last = rrd_last(argc, argv);
264 free(argv);
265 if (rrd_test_error()) luaL_error(L, rrd_get_error());
266 lua_pushnumber(L, (lua_Number) last);
267 return 1;
268 }
270 static int
271 lua_rrd_graph (lua_State * L)
272 {
273 int argc = lua_gettop(L) + 1;
274 char **argv = make_argv("last", L);
275 char **calcpr;
276 int i, xsize, ysize;
277 double ymin, ymax;
279 reset_rrd_state();
280 rrd_graph(argc, argv, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
281 free(argv);
282 if (rrd_test_error()) luaL_error(L, rrd_get_error());
283 lua_pushnumber(L, (lua_Number) xsize);
284 lua_pushnumber(L, (lua_Number) ysize);
285 lua_newtable(L);
286 for (i = 0; calcpr && calcpr[i]; i++) {
287 lua_pushstring(L, calcpr[i]);
288 lua_rawseti(L, -2, i+1);
289 rrd_freemem(calcpr[i]);
290 }
291 rrd_freemem(calcpr);
292 return 3;
293 }
295 static int
296 lua_rrd_flushcached(lua_State *L)
297 {
298 return rrd_common_call(L, "flushcached", rrd_flushcached);
299 }
301 #if defined(DINF)
302 static int
303 lua_rrd_info (lua_State * L)
304 {
305 return lua_rrd_infocall(L, "info", rrd_info);
306 }
308 static int
309 lua_rrd_graphv (lua_State * L)
310 {
311 return lua_rrd_infocall(L, "graphv", rrd_graph_v);
312 }
314 static int
315 lua_rrd_updatev (lua_State * L)
316 {
317 return lua_rrd_infocall(L, "updatev", rrd_update_v);
318 }
319 #endif
321 /**********************************************************/
323 /*
324 ** Assumes the table is on top of the stack.
325 */
326 static void
327 set_info (lua_State * L)
328 {
329 lua_pushliteral (L, "_COPYRIGHT");
330 lua_pushliteral (L, "Copyright (C) 2008 Fidelis Assis");
331 lua_settable (L, -3);
332 lua_pushliteral (L, "_DESCRIPTION");
333 lua_pushliteral (L, "RRD-lua is a Lua binding for RRDTool.");
334 lua_settable (L, -3);
335 lua_pushliteral (L, "_NAME");
336 lua_pushliteral (L, "RRD-Lua");
337 lua_settable (L, -3);
338 lua_pushliteral (L, "_VERSION");
339 lua_pushliteral (L, LIB_VERSION);
340 lua_settable (L, -3);
341 }
343 /**********************************************************/
345 static const struct luaL_reg rrd[] = {
346 {"create", lua_rrd_create},
347 {"dump", lua_rrd_dump},
348 {"fetch", lua_rrd_fetch},
349 {"first", lua_rrd_first},
350 {"graph", lua_rrd_graph},
351 {"last", lua_rrd_last},
352 {"resize", lua_rrd_resize},
353 {"restore", lua_rrd_restore},
354 {"tune", lua_rrd_tune},
355 {"update", lua_rrd_update},
356 {"flushcached", lua_rrd_flushcached},
357 #if defined(DINF)
358 {"info", lua_rrd_info},
359 {"updatev", lua_rrd_updatev},
360 {"graphv", lua_rrd_graphv},
361 #endif
362 {NULL, NULL}
363 };
366 /*
367 ** Open RRD library
368 */
369 int
370 luaopen_rrd (lua_State * L)
371 {
372 #if defined LUA50
373 /* luaL_module is defined in compat-5.1.c */
374 luaL_module (L, "rrd", rrd, 0);
375 #else
376 luaL_register (L, "rrd", rrd);
377 #endif
378 set_info (L);
379 return 1;
380 }