1 /****************************************************************************
2 * RRDtool 1.0.37 Copyright Tobias Oetiker, 1997 - 2000
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 #ifdef WIN32
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;
50 rrd_graph_init(&im);
52 parsetime("end-24h", &start_tv);
53 parsetime("now", &end_tv);
55 while (1){
56 static struct option long_options[] =
57 {
58 {"start", required_argument, 0, 's'},
59 {"end", required_argument, 0, 'e'},
60 {"maxrows", required_argument, 0, 'm'},
61 {"step", required_argument, 0, 261},
62 {0,0,0,0}
63 };
64 int option_index = 0;
65 int opt;
67 opt = getopt_long(argc, argv, "s:e:m:",
68 long_options, &option_index);
70 if (opt == EOF)
71 break;
73 switch(opt) {
74 case 261:
75 im.step = atoi(optarg);
76 break;
77 case 's':
78 if ((parsetime_error = parsetime(optarg, &start_tv))) {
79 rrd_set_error( "start time: %s", parsetime_error );
80 return -1;
81 }
82 break;
83 case 'e':
84 if ((parsetime_error = parsetime(optarg, &end_tv))) {
85 rrd_set_error( "end time: %s", parsetime_error );
86 return -1;
87 }
88 break;
89 case 'm':
90 im.xsize = atol(optarg);
91 if (im.xsize < 10) {
92 rrd_set_error("maxrows below 10 rows");
93 return -1;
94 }
95 break;
96 case '?':
97 rrd_set_error("unknown option '%c'", optopt);
98 return -1;
99 }
100 }
102 if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
103 return -1;
104 }
106 if (start_tmp < 3600*24*365*10){
107 rrd_set_error("the first entry to fetch should be after 1980 (%ld)",start_tmp);
108 return -1;
109 }
111 if (end_tmp < start_tmp) {
112 rrd_set_error("start (%ld) should be less than end (%ld)",
113 start_tmp, end_tmp);
114 return -1;
115 }
117 im.start = start_tmp;
118 im.end = end_tmp;
120 rrd_graph_script(argc,argv,&im,0);
121 if (rrd_test_error()) {
122 im_free(&im);
123 return -1;
124 }
126 if (im.gdes_c == 0){
127 rrd_set_error("can't make a graph without contents");
128 im_free(&im);
129 return(-1);
130 }
132 if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1){
133 im_free(&im);
134 return -1;
135 }
137 im_free(&im);
138 return 0;
139 }
143 int
144 rrd_xport_fn(image_desc_t *im,
145 time_t *start,
146 time_t *end, /* which time frame do you want ?
147 * will be changed to represent reality */
148 unsigned long *step, /* which stepsize do you want?
149 * will be changed to represent reality */
150 unsigned long *col_cnt, /* number of data columns in the result */
151 char ***legend_v, /* legend entries */
152 rrd_value_t **data) /* two dimensional array containing the data */
153 {
155 int i = 0, j = 0;
156 unsigned long *ds_cnt; /* number of data sources in file */
157 unsigned long col, dst_row, row_cnt;
158 rrd_value_t *srcptr, *dstptr;
160 unsigned long nof_xports = 0;
161 unsigned long xport_counter = 0;
162 unsigned long *ref_list;
163 rrd_value_t **srcptr_list;
164 char **legend_list;
165 int ii = 0;
167 time_t start_tmp = 0;
168 time_t end_tmp = 0;
169 unsigned long step_tmp = 1;
171 /* pull the data from the rrd files ... */
172 if(data_fetch(im)==-1)
173 return -1;
175 /* evaluate CDEF operations ... */
176 if(data_calc(im)==-1)
177 return -1;
179 /* how many xports? */
180 for(i = 0; i < im->gdes_c; i++) {
181 switch(im->gdes[i].gf) {
182 case GF_XPORT:
183 nof_xports++;
184 break;
185 default:
186 break;
187 }
188 }
190 if(nof_xports == 0) {
191 rrd_set_error("no XPORT found, nothing to do");
192 return -1;
193 }
195 /* a list of referenced gdes */
196 ref_list = malloc(sizeof(int) * nof_xports);
197 if(ref_list == NULL)
198 return -1;
200 /* a list to save pointers into each gdes data */
201 srcptr_list = malloc(sizeof(srcptr) * nof_xports);
202 if(srcptr_list == NULL) {
203 free(ref_list);
204 return -1;
205 }
207 /* a list to save pointers to the column's legend entry */
208 /* this is a return value! */
209 legend_list = malloc(sizeof(char *) * nof_xports);
210 if(legend_list == NULL) {
211 free(srcptr_list);
212 free(ref_list);
213 return -1;
214 }
216 /* find referenced gdes and save their index and */
217 /* a pointer into their data */
218 for(i = 0; i < im->gdes_c; i++) {
219 switch(im->gdes[i].gf) {
220 case GF_XPORT:
221 ii = im->gdes[i].vidx;
222 if(xport_counter > nof_xports) {
223 rrd_set_error( "too many xports: should not happen. Hmmm");
224 free(srcptr_list);
225 free(ref_list);
226 free(legend_list);
227 return -1;
228 }
229 srcptr_list[xport_counter] = im->gdes[ii].data;
230 ref_list[xport_counter++] = i;
231 break;
232 default:
233 break;
234 }
235 }
237 start_tmp = im->gdes[0].start;
238 end_tmp = im->gdes[0].end;
239 step_tmp = im->gdes[0].step;
241 /* fill some return values */
242 *col_cnt = nof_xports;
243 *start = start_tmp;
244 *end = end_tmp;
245 *step = step_tmp;
247 row_cnt = ((*end)-(*start))/(*step);
249 /* room for rearranged data */
250 /* this is a return value! */
251 if (((*data) = malloc((*col_cnt) * row_cnt * sizeof(rrd_value_t)))==NULL){
252 free(srcptr_list);
253 free(ref_list);
254 free(legend_list);
255 rrd_set_error("malloc xport data area");
256 return(-1);
257 }
258 dstptr = (*data);
260 j = 0;
261 for(i = 0; i < im->gdes_c; i++) {
262 switch(im->gdes[i].gf) {
263 case GF_XPORT:
264 /* reserve room for one legend entry */
265 /* is FMT_LEG_LEN + 5 the correct size? */
266 if ((legend_list[j] = malloc(sizeof(char) * (FMT_LEG_LEN+5)))==NULL) {
267 free(srcptr_list);
268 free(ref_list);
269 free(*data); *data = NULL;
270 while (--j > -1) free(legend_list[j]);
271 free(legend_list);
272 rrd_set_error("malloc xport legend entry");
273 return(-1);
274 }
276 if (im->gdes[i].legend)
277 /* omit bounds check, should have the same size */
278 strcpy (legend_list[j++], im->gdes[i].legend);
279 else
280 legend_list[j++][0] = '\0';
282 break;
283 default:
284 break;
285 }
286 }
288 /* fill data structure */
289 for(dst_row = 0; (int)dst_row < (int)row_cnt; dst_row++) {
290 for(i = 0; i < (int)nof_xports; i++) {
291 j = ref_list[i];
292 ii = im->gdes[j].vidx;
293 ds_cnt = &im->gdes[ii].ds_cnt;
295 srcptr = srcptr_list[i];
296 for(col = 0; col < (*ds_cnt); col++) {
297 rrd_value_t newval = DNAN;
298 newval = srcptr[col];
300 if (im->gdes[ii].ds_namv && im->gdes[ii].ds_nam) {
301 if(strcmp(im->gdes[ii].ds_namv[col],im->gdes[ii].ds_nam) == 0)
302 (*dstptr++) = newval;
303 } else {
304 (*dstptr++) = newval;
305 }
307 }
308 srcptr_list[i] += (*ds_cnt);
309 }
310 }
312 *legend_v = legend_list;
313 free(srcptr_list);
314 free(ref_list);
315 return 0;
317 }