1 /****************************************************************************
2 * RRDtool 1.2.6 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"
12 #include "unused.h"
14 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
15 #include <io.h>
16 #include <fcntl.h>
17 #endif
20 int rrd_xport(int, char **, int *,
21 time_t *, time_t *,
22 unsigned long *, unsigned long *,
23 char ***, rrd_value_t **);
25 int rrd_xport_fn(image_desc_t *,
26 time_t *, time_t *,
27 unsigned long *, unsigned long *,
28 char ***, rrd_value_t **);
33 int
34 rrd_xport(int argc, char **argv, int UNUSED(*xsize),
35 time_t *start,
36 time_t *end, /* which time frame do you want ?
37 * will be changed to represent reality */
38 unsigned long *step, /* which stepsize do you want?
39 * will be changed to represent reality */
40 unsigned long *col_cnt, /* number of data columns in the result */
41 char ***legend_v, /* legend entries */
42 rrd_value_t **data) /* two dimensional array containing the data */
44 {
46 image_desc_t im;
47 time_t start_tmp=0,end_tmp=0;
48 struct rrd_time_value start_tv, end_tv;
49 char *parsetime_error = NULL;
50 optind = 0; opterr = 0; /* initialize getopt */
52 rrd_graph_init(&im);
54 parsetime("end-24h", &start_tv);
55 parsetime("now", &end_tv);
57 while (1){
58 static struct option long_options[] =
59 {
60 {"start", required_argument, 0, 's'},
61 {"end", required_argument, 0, 'e'},
62 {"maxrows", required_argument, 0, 'm'},
63 {"step", required_argument, 0, 261},
64 {0,0,0,0}
65 };
66 int option_index = 0;
67 int opt;
69 opt = getopt_long(argc, argv, "s:e:m:",
70 long_options, &option_index);
72 if (opt == EOF)
73 break;
75 switch(opt) {
76 case 261:
77 im.step = atoi(optarg);
78 break;
79 case 's':
80 if ((parsetime_error = parsetime(optarg, &start_tv))) {
81 rrd_set_error( "start time: %s", parsetime_error );
82 return -1;
83 }
84 break;
85 case 'e':
86 if ((parsetime_error = parsetime(optarg, &end_tv))) {
87 rrd_set_error( "end time: %s", parsetime_error );
88 return -1;
89 }
90 break;
91 case 'm':
92 im.xsize = atol(optarg);
93 if (im.xsize < 10) {
94 rrd_set_error("maxrows below 10 rows");
95 return -1;
96 }
97 break;
98 case '?':
99 rrd_set_error("unknown option '%c'", optopt);
100 return -1;
101 }
102 }
104 if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
105 return -1;
106 }
108 if (start_tmp < 3600*24*365*10){
109 rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
110 return -1;
111 }
113 if (end_tmp < start_tmp) {
114 rrd_set_error("start (%ld) should be less than end (%ld)",
115 start_tmp, end_tmp);
116 return -1;
117 }
119 im.start = start_tmp;
120 im.end = end_tmp;
121 im.step = max((long)im.step, (im.end-im.start)/im.xsize);
123 rrd_graph_script(argc,argv,&im,0);
124 if (rrd_test_error()) {
125 im_free(&im);
126 return -1;
127 }
129 if (im.gdes_c == 0){
130 rrd_set_error("can't make a graph without contents");
131 im_free(&im);
132 return(-1);
133 }
135 if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
136 im_free(&im);
137 return -1;
138 }
140 im_free(&im);
141 return 0;
142 }
146 int
147 rrd_xport_fn(image_desc_t *im,
148 time_t *start,
149 time_t *end, /* which time frame do you want ?
150 * will be changed to represent reality */
151 unsigned long *step, /* which stepsize do you want?
152 * will be changed to represent reality */
153 unsigned long *col_cnt, /* number of data columns in the result */
154 char ***legend_v, /* legend entries */
155 rrd_value_t **data) /* two dimensional array containing the data */
156 {
158 int i = 0, j = 0;
159 unsigned long *ds_cnt; /* number of data sources in file */
160 unsigned long col, dst_row, row_cnt;
161 rrd_value_t *srcptr, *dstptr;
163 unsigned long nof_xports = 0;
164 unsigned long xport_counter = 0;
165 unsigned long *ref_list;
166 rrd_value_t **srcptr_list;
167 char **legend_list;
168 int ii = 0;
170 time_t start_tmp = 0;
171 time_t end_tmp = 0;
172 unsigned long step_tmp = 1;
174 /* pull the data from the rrd files ... */
175 if(data_fetch(im)==-1)
176 return -1;
178 /* evaluate CDEF operations ... */
179 if(data_calc(im)==-1)
180 return -1;
182 /* how many xports? */
183 for(i = 0; i < im->gdes_c; i++) {
184 switch(im->gdes[i].gf) {
185 case GF_XPORT:
186 nof_xports++;
187 break;
188 default:
189 break;
190 }
191 }
193 if(nof_xports == 0) {
194 rrd_set_error("no XPORT found, nothing to do");
195 return -1;
196 }
198 /* a list of referenced gdes */
199 ref_list = malloc(sizeof(int) * nof_xports);
200 if(ref_list == NULL)
201 return -1;
203 /* a list to save pointers into each gdes data */
204 srcptr_list = malloc(sizeof(srcptr) * nof_xports);
205 if(srcptr_list == NULL) {
206 free(ref_list);
207 return -1;
208 }
210 /* a list to save pointers to the column's legend entry */
211 /* this is a return value! */
212 legend_list = malloc(sizeof(char *) * nof_xports);
213 if(legend_list == NULL) {
214 free(srcptr_list);
215 free(ref_list);
216 return -1;
217 }
219 /* find referenced gdes and save their index and */
220 /* a pointer into their data */
221 for(i = 0; i < im->gdes_c; i++) {
222 switch(im->gdes[i].gf) {
223 case GF_XPORT:
224 ii = im->gdes[i].vidx;
225 if(xport_counter > nof_xports) {
226 rrd_set_error( "too many xports: should not happen. Hmmm");
227 free(srcptr_list);
228 free(ref_list);
229 free(legend_list);
230 return -1;
231 }
232 srcptr_list[xport_counter] = im->gdes[ii].data;
233 ref_list[xport_counter++] = i;
234 break;
235 default:
236 break;
237 }
238 }
240 start_tmp = im->gdes[0].start;
241 end_tmp = im->gdes[0].end;
242 step_tmp = im->gdes[0].step;
244 /* fill some return values */
245 *col_cnt = nof_xports;
246 *start = start_tmp;
247 *end = end_tmp;
248 *step = step_tmp;
250 row_cnt = ((*end)-(*start))/(*step);
252 /* room for rearranged data */
253 /* this is a return value! */
254 if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
255 free(srcptr_list);
256 free(ref_list);
257 free(legend_list);
258 rrd_set_error("malloc xport data area");
259 return(-1);
260 }
261 dstptr = (*data);
263 j = 0;
264 for(i = 0; i < im->gdes_c; i++) {
265 switch(im->gdes[i].gf) {
266 case GF_XPORT:
267 /* reserve room for one legend entry */
268 /* is FMT_LEG_LEN + 5 the correct size? */
269 if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
270 free(srcptr_list);
271 free(ref_list);
272 free(*data); *data = NULL;
273 while (--j > -1) free(legend_list[j]);
274 free(legend_list);
275 rrd_set_error("malloc xport legend entry");
276 return(-1);
277 }
279 if (im->gdes[i].legend)
280 /* omit bounds check, should have the same size */
281 strcpy (legend_list[j++], im->gdes[i].legend);
282 else
283 legend_list[j++][0] = '\0';
285 break;
286 default:
287 break;
288 }
289 }
291 /* fill data structure */
292 for(dst_row = 0; (int)dst_row < (int)row_cnt; dst_row++) {
293 for(i = 0; i < (int)nof_xports; i++) {
294 j = ref_list[i];
295 ii = im->gdes[j].vidx;
296 ds_cnt = &im->gdes[ii].ds_cnt;
298 srcptr = srcptr_list[i];
299 for(col = 0; col < (*ds_cnt); col++) {
300 rrd_value_t newval = DNAN;
301 newval = srcptr[col];
303 if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
304 if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
305 (*dstptr++) = newval;
306 } else {
307 (*dstptr++) = newval;
308 }
310 }
311 srcptr_list[i] += (*ds_cnt);
312 }
313 }
315 *legend_v = legend_list;
316 free(srcptr_list);
317 free(ref_list);
318 return 0;
320 }