Stop RRDs for segfaulting on invalid graph input -- Ian Holsman <Ian.Holsman@cnet...
[rrdtool.git] / bindings / perl-shared / RRDs.xs
1 #ifdef __cplusplus
2 extern "C" {
3 #endif
4
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #ifdef __cplusplus
10 }
11 #endif
12
13 #include "../../src/rrd_tool.h"
14
15 /* perl 5.004 compatibility */
16 #if PERLPATCHLEVEL < 5 
17 #define PL_sv_undef sv_undef
18 #endif
19
20
21 #define rrdcode(name) \
22                 argv = (char **) malloc((items+1)*sizeof(char *));\
23                 argv[0] = "dummy";\
24                 for (i = 0; i < items; i++) { \
25                     STRLEN len; \
26                     char *handle= SvPV(ST(i),len);\
27                     /* actually copy the data to make sure possible modifications \
28                        on the argv data does not backfire into perl */ \
29                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
30                     strcpy(argv[i+1],handle); \
31                 } \
32                 optind=0; opterr=0; \
33                 rrd_clear_error();\
34                 RETVAL=name(items+1,argv); \
35                 for (i=0; i < items; i++) {\
36                     free(argv[i+1]);\
37                 } \
38                 free(argv);\
39                 \
40                 if (rrd_test_error()) XSRETURN_UNDEF;
41
42 #define hvs(VAL) hv_store_ent(hash, sv_2mortal(newSVpv(data->key,0)),VAL,0)                 
43
44 #define rrdinfocode(name) \
45                 /* prepare argument list */ \
46                 argv = (char **) malloc((items+1)*sizeof(char *)); \
47                 argv[0] = "dummy"; \
48                 for (i = 0; i < items; i++) { \
49                     STRLEN len; \
50                     char *handle= SvPV(ST(i),len); \
51                     /* actually copy the data to make sure possible modifications \
52                        on the argv data does not backfire into perl */ \
53                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char)); \
54                     strcpy(argv[i+1],handle); \
55                 } \
56                 optind=0; opterr=0; \
57                 rrd_clear_error(); \
58                 data=name(items+1, argv); \
59                 for (i=0; i < items; i++) { \
60                     free(argv[i+1]); \
61                 } \
62                 free(argv); \
63                 if (rrd_test_error()) XSRETURN_UNDEF; \
64                 hash = newHV(); \
65                 while (data) { \
66                     save=data; \
67                 /* the newSV will get copied by hv so we create it as a mortal \
68            to make sure it does not keep hanging round after the fact */ \
69                     switch (data->type) { \
70                     case RD_I_VAL: \
71                         if (isnan(data->value.u_val)) \
72                             hvs(&PL_sv_undef); \
73                         else \
74                             hvs(newSVnv(data->value.u_val)); \
75                         break; \
76                         case RD_I_INT: \
77                         hvs(newSViv(data->value.u_int)); \
78                         break; \
79                     case RD_I_CNT: \
80                         hvs(newSViv(data->value.u_cnt)); \
81                         break; \
82                     case RD_I_STR: \
83                         hvs(newSVpv(data->value.u_str,0)); \
84                         rrd_freemem(data->value.u_str); \
85                         break; \
86                     } \
87                     rrd_freemem(data->key); \
88                     data = data->next; \
89                     rrd_freemem(save); \
90                     } \
91             rrd_freemem(data); \
92             RETVAL = newRV_noinc((SV*)hash);
93
94 /*
95  * should not be needed if libc is linked (see ntmake.pl)
96 #ifdef WIN32
97  #define free free
98  #define malloc malloc
99  #define realloc realloc
100 #endif
101 */
102
103
104 MODULE = RRDs   PACKAGE = RRDs  PREFIX = rrd_
105
106 BOOT:
107 #ifdef MUST_DISABLE_SIGFPE
108         signal(SIGFPE,SIG_IGN);
109 #endif
110 #ifdef MUST_DISABLE_FPMASK
111         fpsetmask(0);
112 #endif 
113         
114
115 SV*
116 rrd_error()
117         CODE:
118                 if (! rrd_test_error()) XSRETURN_UNDEF;
119                 RETVAL = newSVpv(rrd_get_error(),0);
120         OUTPUT:
121                 RETVAL
122
123         
124 int
125 rrd_last(...)
126       PROTOTYPE: @
127       PREINIT:
128       int i;
129       char **argv;
130       CODE:
131               rrdcode(rrd_last);
132       OUTPUT:
133             RETVAL
134
135
136 int
137 rrd_create(...)
138         PROTOTYPE: @    
139         PREINIT:
140         int i;
141         char **argv;
142         CODE:
143                 rrdcode(rrd_create);
144                 RETVAL = 1;
145         OUTPUT:
146                 RETVAL
147
148
149 int
150 rrd_update(...)
151         PROTOTYPE: @    
152         PREINIT:
153         int i;
154         char **argv;
155         CODE:
156                 rrdcode(rrd_update);
157                 RETVAL = 1;
158         OUTPUT:
159                 RETVAL
160
161
162 int
163 rrd_tune(...)
164         PROTOTYPE: @    
165         PREINIT:
166         int i;
167         char **argv;
168         CODE:
169                 rrdcode(rrd_tune);
170                 RETVAL = 1;
171         OUTPUT:
172                 RETVAL
173
174
175 void
176 rrd_graph(...)
177         PROTOTYPE: @    
178         PREINIT:
179         char **calcpr=NULL;
180         int i,xsize,ysize;
181         char **argv;
182         AV *retar;
183         PPCODE:
184                 argv = (char **) malloc((items+1)*sizeof(char *));
185                 argv[0] = "dummy";
186                 for (i = 0; i < items; i++) { 
187                     STRLEN len;
188                     char *handle = SvPV(ST(i),len);
189                     /* actually copy the data to make sure possible modifications
190                        on the argv data does not backfire into perl */ 
191                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
192                     strcpy(argv[i+1],handle);
193                 }
194                 optind=0; opterr=0; 
195                 rrd_clear_error();
196                 rrd_graph(items+1,argv,&calcpr,&xsize,&ysize,NULL); 
197                 for (i=0; i < items; i++) {
198                     free(argv[i+1]);
199                 }
200                 free(argv);
201
202                 if (rrd_test_error()) {
203                         if(calcpr)
204                            for(i=0;calcpr[i];i++)
205                                 rrd_freemem(calcpr[i]);
206                         XSRETURN_UNDEF;
207                 }
208                 retar=newAV();
209                 if(calcpr){
210                         for(i=0;calcpr[i];i++){
211                                  av_push(retar,newSVpv(calcpr[i],0));
212                                  rrd_freemem(calcpr[i]);
213                         }
214                         rrd_freemem(calcpr);
215                 }
216                 EXTEND(sp,4);
217                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
218                 PUSHs(sv_2mortal(newSViv(xsize)));
219                 PUSHs(sv_2mortal(newSViv(ysize)));
220
221 void
222 rrd_fetch(...)
223         PROTOTYPE: @    
224         PREINIT:
225                 time_t        start,end;                
226                 unsigned long step, ds_cnt,i,ii;
227                 rrd_value_t   *data,*datai;
228                 char **argv;
229                 char **ds_namv;
230                 AV *retar,*line,*names;
231         PPCODE:
232                 argv = (char **) malloc((items+1)*sizeof(char *));
233                 argv[0] = "dummy";
234                 for (i = 0; i < items; i++) { 
235                     STRLEN len;
236                     char *handle= SvPV(ST(i),len);
237                     /* actually copy the data to make sure possible modifications
238                        on the argv data does not backfire into perl */ 
239                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
240                     strcpy(argv[i+1],handle);
241                 }
242                 optind=0; opterr=0; 
243                 rrd_clear_error();
244                 rrd_fetch(items+1,argv,&start,&end,&step,&ds_cnt,&ds_namv,&data); 
245                 for (i=0; i < items; i++) {
246                     free(argv[i+1]);
247                 }
248                 free(argv);
249                 if (rrd_test_error()) XSRETURN_UNDEF;
250                 /* convert the ds_namv into perl format */
251                 names=newAV();
252                 for (ii = 0; ii < ds_cnt; ii++){
253                     av_push(names,newSVpv(ds_namv[ii],0));
254                     rrd_freemem(ds_namv[ii]);
255                 }
256                 rrd_freemem(ds_namv);                   
257                 /* convert the data array into perl format */
258                 datai=data;
259                 retar=newAV();
260                 for (i = start+step; i <= end; i += step){
261                         line = newAV();
262                         for (ii = 0; ii < ds_cnt; ii++){
263                           av_push(line,(isnan(*datai) ? &PL_sv_undef : newSVnv(*datai)));
264                           datai++;
265                         }
266                         av_push(retar,newRV_noinc((SV*)line));
267                 }
268                 rrd_freemem(data);
269                 EXTEND(sp,5);
270                 PUSHs(sv_2mortal(newSViv(start+step)));
271                 PUSHs(sv_2mortal(newSViv(step)));
272                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
273                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
274
275
276 int
277 rrd_xport(...)
278         PROTOTYPE: @    
279         PREINIT:
280                 time_t start,end;               
281                 int xsize;
282                 unsigned long step, col_cnt,row_cnt,i,ii;
283                 rrd_value_t *data,*ptr;
284                 char **argv,**legend_v;
285                 AV *retar,*line,*names;
286         PPCODE:
287                 argv = (char **) malloc((items+1)*sizeof(char *));
288                 argv[0] = "dummy";
289                 for (i = 0; i < items; i++) { 
290                     STRLEN len;
291                     char *handle = SvPV(ST(i),len);
292                     /* actually copy the data to make sure possible modifications
293                        on the argv data does not backfire into perl */ 
294                     argv[i+1] = (char *) malloc((strlen(handle)+1)*sizeof(char));
295                     strcpy(argv[i+1],handle);
296                 }
297                 optind=0; opterr=0; 
298                 rrd_clear_error();
299                 rrd_xport(items+1,argv,&xsize,&start,&end,&step,&col_cnt,&legend_v,&data); 
300                 for (i=0; i < items; i++) {
301                     free(argv[i+1]);
302                 }
303                 free(argv);
304                 if (rrd_test_error()) XSRETURN_UNDEF;
305
306                 /* convert the legend_v into perl format */
307                 names=newAV();
308                 for (ii = 0; ii < col_cnt; ii++){
309                     av_push(names,newSVpv(legend_v[ii],0));
310                     rrd_freemem(legend_v[ii]);
311                 }
312                 rrd_freemem(legend_v);                  
313
314                 /* convert the data array into perl format */
315                 ptr=data;
316                 retar=newAV();
317                 for (i = start+step; i <= end; i += step){
318                         line = newAV();
319                         for (ii = 0; ii < col_cnt; ii++){
320                           av_push(line,(isnan(*ptr) ? &PL_sv_undef : newSVnv(*ptr)));
321                           ptr++;
322                         }
323                         av_push(retar,newRV_noinc((SV*)line));
324                 }
325                 rrd_freemem(data);
326
327                 EXTEND(sp,7);
328                 PUSHs(sv_2mortal(newSViv(start+step)));
329                 PUSHs(sv_2mortal(newSViv(end)));
330                 PUSHs(sv_2mortal(newSViv(step)));
331                 PUSHs(sv_2mortal(newSViv(col_cnt)));
332                 PUSHs(sv_2mortal(newRV_noinc((SV*)names)));
333                 PUSHs(sv_2mortal(newRV_noinc((SV*)retar)));
334
335 SV*
336 rrd_info(...)
337         PROTOTYPE: @    
338         PREINIT:
339                 info_t *data,*save;
340                 int i;
341                 char **argv;
342                 HV *hash;
343         CODE:
344                 rrdinfocode(rrd_info);  
345     OUTPUT:
346            RETVAL
347
348 SV*
349 rrd_updatev(...)
350         PROTOTYPE: @    
351         PREINIT:
352                 info_t *data,*save;
353                 int i;
354                 char **argv;
355                 HV *hash;
356         CODE:
357                 rrdinfocode(rrd_update_v);      
358     OUTPUT:
359            RETVAL
360