1 /****************************************************************************
2 * RRDtool 1.2rc5 Copyright by Tobi Oetiker, 1997-2005
3 ****************************************************************************
4 * rrd_xport.c export RRD data
5 ****************************************************************************/
10 #include "rrd_graph.h"
11 #include "rrd_xport.h"
13 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
19 int rrd_xport(int, char **, int *,
21 unsigned long *, unsigned long *,
22 char ***, rrd_value_t **);
24 int rrd_xport_fn(image_desc_t *,
26 unsigned long *, unsigned long *,
27 char ***, rrd_value_t **);
33 rrd_xport(int argc, char **argv, int *xsize,
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 */
46 time_t start_tmp=0,end_tmp=0;
47 struct rrd_time_value start_tv, end_tv;
48 char *parsetime_error = NULL;
52 parsetime("end-24h", &start_tv);
53 parsetime("now", &end_tv);
56 static struct option long_options[] =
58 {"start", required_argument, 0, 's'},
59 {"end", required_argument, 0, 'e'},
60 {"maxrows", required_argument, 0, 'm'},
61 {"step", required_argument, 0, 261},
67 opt = getopt_long(argc, argv, "s:e:m:",
68 long_options, &option_index);
75 im.step = atoi(optarg);
78 if ((parsetime_error = parsetime(optarg, &start_tv))) {
79 rrd_set_error( "start time: %s", parsetime_error );
84 if ((parsetime_error = parsetime(optarg, &end_tv))) {
85 rrd_set_error( "end time: %s", parsetime_error );
90 im.xsize = atol(optarg);
92 rrd_set_error("maxrows below 10 rows");
97 rrd_set_error("unknown option '%c'", optopt);
102 if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
106 if (start_tmp < 3600*24*365*10){
107 rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
111 if (end_tmp < start_tmp) {
112 rrd_set_error("start (%ld) should be less than end (%ld)",
117 im.start = start_tmp;
119 im.step = max((long)im.step, (im.end-im.start)/im.xsize);
121 rrd_graph_script(argc,argv,&im,0);
122 if (rrd_test_error()) {
128 rrd_set_error("can't make a graph without contents");
133 if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
145 rrd_xport_fn(image_desc_t *im,
147 time_t *end, /* which time frame do you want ?
148 * will be changed to represent reality */
149 unsigned long *step, /* which stepsize do you want?
150 * will be changed to represent reality */
151 unsigned long *col_cnt, /* number of data columns in the result */
152 char ***legend_v, /* legend entries */
153 rrd_value_t **data) /* two dimensional array containing the data */
157 unsigned long *ds_cnt; /* number of data sources in file */
158 unsigned long col, dst_row, row_cnt;
159 rrd_value_t *srcptr, *dstptr;
161 unsigned long nof_xports = 0;
162 unsigned long xport_counter = 0;
163 unsigned long *ref_list;
164 rrd_value_t **srcptr_list;
168 time_t start_tmp = 0;
170 unsigned long step_tmp = 1;
172 /* pull the data from the rrd files ... */
173 if(data_fetch(im)==-1)
176 /* evaluate CDEF operations ... */
177 if(data_calc(im)==-1)
180 /* how many xports? */
181 for(i = 0; i < im->gdes_c; i++) {
182 switch(im->gdes[i].gf) {
191 if(nof_xports == 0) {
192 rrd_set_error("no XPORT found, nothing to do");
196 /* a list of referenced gdes */
197 ref_list = malloc(sizeof(int) * nof_xports);
201 /* a list to save pointers into each gdes data */
202 srcptr_list = malloc(sizeof(srcptr) * nof_xports);
203 if(srcptr_list == NULL) {
208 /* a list to save pointers to the column's legend entry */
209 /* this is a return value! */
210 legend_list = malloc(sizeof(char *) * nof_xports);
211 if(legend_list == NULL) {
217 /* find referenced gdes and save their index and */
218 /* a pointer into their data */
219 for(i = 0; i < im->gdes_c; i++) {
220 switch(im->gdes[i].gf) {
222 ii = im->gdes[i].vidx;
223 if(xport_counter > nof_xports) {
224 rrd_set_error( "too many xports: should not happen. Hmmm");
230 srcptr_list[xport_counter] = im->gdes[ii].data;
231 ref_list[xport_counter++] = i;
238 start_tmp = im->gdes[0].start;
239 end_tmp = im->gdes[0].end;
240 step_tmp = im->gdes[0].step;
242 /* fill some return values */
243 *col_cnt = nof_xports;
248 row_cnt = ((*end)-(*start))/(*step);
250 /* room for rearranged data */
251 /* this is a return value! */
252 if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
256 rrd_set_error("malloc xport data area");
262 for(i = 0; i < im->gdes_c; i++) {
263 switch(im->gdes[i].gf) {
265 /* reserve room for one legend entry */
266 /* is FMT_LEG_LEN + 5 the correct size? */
267 if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
270 free(*data); *data = NULL;
271 while (--j > -1) free(legend_list[j]);
273 rrd_set_error("malloc xport legend entry");
277 if (im->gdes[i].legend)
278 /* omit bounds check, should have the same size */
279 strcpy (legend_list[j++], im->gdes[i].legend);
281 legend_list[j++][0] = '\0';
289 /* fill data structure */
290 for(dst_row = 0; (int)dst_row < (int)row_cnt; dst_row++) {
291 for(i = 0; i < (int)nof_xports; i++) {
293 ii = im->gdes[j].vidx;
294 ds_cnt = &im->gdes[ii].ds_cnt;
296 srcptr = srcptr_list[i];
297 for(col = 0; col < (*ds_cnt); col++) {
298 rrd_value_t newval = DNAN;
299 newval = srcptr[col];
301 if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
302 if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
303 (*dstptr++) = newval;
305 (*dstptr++) = newval;
309 srcptr_list[i] += (*ds_cnt);
313 *legend_v = legend_list;