1 /****************************************************************************
2 * RRDtool 1.2.0 Copyright by Tobi Oetiker, 1997-2005
3 ****************************************************************************
4 * rrd_xport.c export RRD data
5 ****************************************************************************/
7 #include <sys/stat.h>
9 #include "rrd_tool.h"
10 #include "rrd_graph.h"
11 #include "rrd_xport.h"
13 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
14 #include <io.h>
15 #include <fcntl.h>
16 #endif
19 int rrd_xport(int, char **, int *,
20 time_t *, time_t *,
21 unsigned long *, unsigned long *,
22 char ***, rrd_value_t **);
24 int rrd_xport_fn(image_desc_t *,
25 time_t *, time_t *,
26 unsigned long *, unsigned long *,
27 char ***, rrd_value_t **);
32 int
33 rrd_xport(int argc, char **argv, int *xsize,
34 time_t *start,
35 time_t *end, /* which time frame do you want ?
36 * will be changed to represent reality */
37 unsigned long *step, /* which stepsize do you want?
38 * will be changed to represent reality */
39 unsigned long *col_cnt, /* number of data columns in the result */
40 char ***legend_v, /* legend entries */
41 rrd_value_t **data) /* two dimensional array containing the data */
43 {
45 image_desc_t im;
46 time_t start_tmp=0,end_tmp=0;
47 struct rrd_time_value start_tv, end_tv;
48 char *parsetime_error = NULL;
49 optind = 0; opterr = 0; /* initialize getopt */
51 rrd_graph_init(&im);
53 parsetime("end-24h", &start_tv);
54 parsetime("now", &end_tv);
56 while (1){
57 static struct option long_options[] =
58 {
59 {"start", required_argument, 0, 's'},
60 {"end", required_argument, 0, 'e'},
61 {"maxrows", required_argument, 0, 'm'},
62 {"step", required_argument, 0, 261},
63 {0,0,0,0}
64 };
65 int option_index = 0;
66 int opt;
68 opt = getopt_long(argc, argv, "s:e:m:",
69 long_options, &option_index);
71 if (opt == EOF)
72 break;
74 switch(opt) {
75 case 261:
76 im.step = atoi(optarg);
77 break;
78 case 's':
79 if ((parsetime_error = parsetime(optarg, &start_tv))) {
80 rrd_set_error( "start time: %s", parsetime_error );
81 return -1;
82 }
83 break;
84 case 'e':
85 if ((parsetime_error = parsetime(optarg, &end_tv))) {
86 rrd_set_error( "end time: %s", parsetime_error );
87 return -1;
88 }
89 break;
90 case 'm':
91 im.xsize = atol(optarg);
92 if (im.xsize < 10) {
93 rrd_set_error("maxrows below 10 rows");
94 return -1;
95 }
96 break;
97 case '?':
98 rrd_set_error("unknown option '%c'", optopt);
99 return -1;
100 }
101 }
103 if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
104 return -1;
105 }
107 if (start_tmp < 3600*24*365*10){
108 rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
109 return -1;
110 }
112 if (end_tmp < start_tmp) {
113 rrd_set_error("start (%ld) should be less than end (%ld)",
114 start_tmp, end_tmp);
115 return -1;
116 }
118 im.start = start_tmp;
119 im.end = end_tmp;
120 im.step = max((long)im.step, (im.end-im.start)/im.xsize);
122 rrd_graph_script(argc,argv,&im,0);
123 if (rrd_test_error()) {
124 im_free(&im);
125 return -1;
126 }
128 if (im.gdes_c == 0){
129 rrd_set_error("can't make a graph without contents");
130 im_free(&im);
131 return(-1);
132 }
134 if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
135 im_free(&im);
136 return -1;
137 }
139 im_free(&im);
140 return 0;
141 }
145 int
146 rrd_xport_fn(image_desc_t *im,
147 time_t *start,
148 time_t *end, /* which time frame do you want ?
149 * will be changed to represent reality */
150 unsigned long *step, /* which stepsize do you want?
151 * will be changed to represent reality */
152 unsigned long *col_cnt, /* number of data columns in the result */
153 char ***legend_v, /* legend entries */
154 rrd_value_t **data) /* two dimensional array containing the data */
155 {
157 int i = 0, j = 0;
158 unsigned long *ds_cnt; /* number of data sources in file */
159 unsigned long col, dst_row, row_cnt;
160 rrd_value_t *srcptr, *dstptr;
162 unsigned long nof_xports = 0;
163 unsigned long xport_counter = 0;
164 unsigned long *ref_list;
165 rrd_value_t **srcptr_list;
166 char **legend_list;
167 int ii = 0;
169 time_t start_tmp = 0;
170 time_t end_tmp = 0;
171 unsigned long step_tmp = 1;
173 /* pull the data from the rrd files ... */
174 if(data_fetch(im)==-1)
175 return -1;
177 /* evaluate CDEF operations ... */
178 if(data_calc(im)==-1)
179 return -1;
181 /* how many xports? */
182 for(i = 0; i < im->gdes_c; i++) {
183 switch(im->gdes[i].gf) {
184 case GF_XPORT:
185 nof_xports++;
186 break;
187 default:
188 break;
189 }
190 }
192 if(nof_xports == 0) {
193 rrd_set_error("no XPORT found, nothing to do");
194 return -1;
195 }
197 /* a list of referenced gdes */
198 ref_list = malloc(sizeof(int) * nof_xports);
199 if(ref_list == NULL)
200 return -1;
202 /* a list to save pointers into each gdes data */
203 srcptr_list = malloc(sizeof(srcptr) * nof_xports);
204 if(srcptr_list == NULL) {
205 free(ref_list);
206 return -1;
207 }
209 /* a list to save pointers to the column's legend entry */
210 /* this is a return value! */
211 legend_list = malloc(sizeof(char *) * nof_xports);
212 if(legend_list == NULL) {
213 free(srcptr_list);
214 free(ref_list);
215 return -1;
216 }
218 /* find referenced gdes and save their index and */
219 /* a pointer into their data */
220 for(i = 0; i < im->gdes_c; i++) {
221 switch(im->gdes[i].gf) {
222 case GF_XPORT:
223 ii = im->gdes[i].vidx;
224 if(xport_counter > nof_xports) {
225 rrd_set_error( "too many xports: should not happen. Hmmm");
226 free(srcptr_list);
227 free(ref_list);
228 free(legend_list);
229 return -1;
230 }
231 srcptr_list[xport_counter] = im->gdes[ii].data;
232 ref_list[xport_counter++] = i;
233 break;
234 default:
235 break;
236 }
237 }
239 start_tmp = im->gdes[0].start;
240 end_tmp = im->gdes[0].end;
241 step_tmp = im->gdes[0].step;
243 /* fill some return values */
244 *col_cnt = nof_xports;
245 *start = start_tmp;
246 *end = end_tmp;
247 *step = step_tmp;
249 row_cnt = ((*end)-(*start))/(*step);
251 /* room for rearranged data */
252 /* this is a return value! */
253 if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
254 free(srcptr_list);
255 free(ref_list);
256 free(legend_list);
257 rrd_set_error("malloc xport data area");
258 return(-1);
259 }
260 dstptr = (*data);
262 j = 0;
263 for(i = 0; i < im->gdes_c; i++) {
264 switch(im->gdes[i].gf) {
265 case GF_XPORT:
266 /* reserve room for one legend entry */
267 /* is FMT_LEG_LEN + 5 the correct size? */
268 if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
269 free(srcptr_list);
270 free(ref_list);
271 free(*data); *data = NULL;
272 while (--j > -1) free(legend_list[j]);
273 free(legend_list);
274 rrd_set_error("malloc xport legend entry");
275 return(-1);
276 }
278 if (im->gdes[i].legend)
279 /* omit bounds check, should have the same size */
280 strcpy (legend_list[j++], im->gdes[i].legend);
281 else
282 legend_list[j++][0] = '\0';
284 break;
285 default:
286 break;
287 }
288 }
290 /* fill data structure */
291 for(dst_row = 0; (int)dst_row < (int)row_cnt; dst_row++) {
292 for(i = 0; i < (int)nof_xports; i++) {
293 j = ref_list[i];
294 ii = im->gdes[j].vidx;
295 ds_cnt = &im->gdes[ii].ds_cnt;
297 srcptr = srcptr_list[i];
298 for(col = 0; col < (*ds_cnt); col++) {
299 rrd_value_t newval = DNAN;
300 newval = srcptr[col];
302 if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
303 if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
304 (*dstptr++) = newval;
305 } else {
306 (*dstptr++) = newval;
307 }
309 }
310 srcptr_list[i] += (*ds_cnt);
311 }
312 }
314 *legend_v = legend_list;
315 free(srcptr_list);
316 free(ref_list);
317 return 0;
319 }