1 /*****************************************************************************
2 * RRDtool 1.3.9 Copyright by Tobi Oetiker, 1997-2009
3 *****************************************************************************
4 * rrd_info Get Information about the configuration of an RRD
5 *****************************************************************************/
7 #include "rrd_tool.h"
8 #include "rrd_rpncalc.h"
9 #include <stdarg.h>
11 #ifdef WIN32
12 #include <stdlib.h>
13 #endif
15 /* proto */
16 rrd_info_t *rrd_info(
17 int,
18 char **);
19 rrd_info_t *rrd_info_r(
20 char *filename);
22 /* allocate memory for string */
23 char *sprintf_alloc(
24 char *fmt,
25 ...)
26 {
27 char *str = NULL;
28 va_list argp;
29 #ifdef HAVE_VASPRINTF
30 va_start( argp, fmt );
31 vasprintf( &str, fmt, argp );
32 #else
33 int maxlen = 1024 + strlen(fmt);
34 str = (char*)(malloc(sizeof(char) * (maxlen + 1)));
35 if (str != NULL) {
36 va_start(argp, fmt);
37 #ifdef HAVE_VSNPRINTF
38 vsnprintf(str, maxlen, fmt, argp);
39 #else
40 vsprintf(str, fmt, argp);
41 #endif
42 }
43 #endif // HAVE_VASPRINTF
44 va_end(argp);
45 return str;
46 }
48 /* the function formerly known as push was renamed to info_push and later
49 * rrd_info_push because it is now used outside the scope of this file */
50 rrd_info_t
51 * rrd_info_push(rrd_info_t * info,
52 char *key, rrd_info_type_t type, rrd_infoval_t value)
53 {
54 rrd_info_t *next;
56 next = (rrd_info_t*)(malloc(sizeof(*next)));
57 next->next = (rrd_info_t *) 0;
58 if (info)
59 info->next = next;
60 next->type = type;
61 next->key = key;
62 switch (type) {
63 case RD_I_VAL:
64 next->value.u_val = value.u_val;
65 break;
66 case RD_I_CNT:
67 next->value.u_cnt = value.u_cnt;
68 break;
69 case RD_I_INT:
70 next->value.u_int = value.u_int;
71 break;
72 case RD_I_STR:
73 next->value.u_str = (char*)(malloc(sizeof(char) * (strlen(value.u_str) + 1)));
74 strcpy(next->value.u_str, value.u_str);
75 break;
76 case RD_I_BLO:
77 next->value.u_blo.size = value.u_blo.size;
78 next->value.u_blo.ptr =
79 (unsigned char*)malloc(sizeof(unsigned char) * value.u_blo.size);
80 memcpy(next->value.u_blo.ptr, value.u_blo.ptr, value.u_blo.size);
81 break;
82 }
83 return (next);
84 }
87 rrd_info_t *rrd_info(
88 int argc,
89 char **argv)
90 {
91 rrd_info_t *info;
93 if (argc < 2) {
94 rrd_set_error("please specify an rrd");
95 return NULL;
96 }
98 info = rrd_info_r(argv[1]);
100 return (info);
101 }
105 rrd_info_t *rrd_info_r(
106 char *filename)
107 {
108 unsigned int i, ii = 0;
109 rrd_t rrd;
110 rrd_info_t *data = NULL, *cd;
111 rrd_infoval_t info;
112 rrd_file_t *rrd_file;
113 enum cf_en current_cf;
114 enum dst_en current_ds;
116 rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
117 if (rrd_file == NULL)
118 goto err_free;
120 info.u_str = filename;
121 cd = rrd_info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
122 data = cd;
124 info.u_str = rrd.stat_head->version;
125 cd = rrd_info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);
127 info.u_cnt = rrd.stat_head->pdp_step;
128 cd = rrd_info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);
130 info.u_cnt = rrd.live_head->last_up;
131 cd = rrd_info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);
133 for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
135 info.u_cnt=i;
136 cd= rrd_info_push(cd,sprintf_alloc("ds[%s].index",
137 rrd.ds_def[i].ds_nam),
138 RD_I_CNT, info);
140 info.u_str = rrd.ds_def[i].dst;
141 cd = rrd_info_push(cd, sprintf_alloc("ds[%s].type",
142 rrd.ds_def[i].ds_nam),
143 RD_I_STR, info);
145 current_ds = dst_conv(rrd.ds_def[i].dst);
146 switch (current_ds) {
147 case DST_CDEF:
148 {
149 char *buffer = NULL;
151 rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
152 rrd.ds_def, &buffer);
153 info.u_str = buffer;
154 cd = rrd_info_push(cd,
155 sprintf_alloc("ds[%s].cdef",
156 rrd.ds_def[i].ds_nam), RD_I_STR,
157 info);
158 free(buffer);
159 }
160 break;
161 default:
162 info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt;
163 cd = rrd_info_push(cd,
164 sprintf_alloc("ds[%s].minimal_heartbeat",
165 rrd.ds_def[i].ds_nam), RD_I_CNT,
166 info);
168 info.u_val = rrd.ds_def[i].par[DS_min_val].u_val;
169 cd = rrd_info_push(cd,
170 sprintf_alloc("ds[%s].min",
171 rrd.ds_def[i].ds_nam), RD_I_VAL,
172 info);
174 info.u_val = rrd.ds_def[i].par[DS_max_val].u_val;
175 cd = rrd_info_push(cd,
176 sprintf_alloc("ds[%s].max",
177 rrd.ds_def[i].ds_nam), RD_I_VAL,
178 info);
179 break;
180 }
182 info.u_str = rrd.pdp_prep[i].last_ds;
183 cd = rrd_info_push(cd,
184 sprintf_alloc("ds[%s].last_ds",
185 rrd.ds_def[i].ds_nam), RD_I_STR,
186 info);
188 info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val;
189 cd = rrd_info_push(cd,
190 sprintf_alloc("ds[%s].value",
191 rrd.ds_def[i].ds_nam), RD_I_VAL,
192 info);
194 info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt;
195 cd = rrd_info_push(cd,
196 sprintf_alloc("ds[%s].unknown_sec",
197 rrd.ds_def[i].ds_nam), RD_I_CNT,
198 info);
199 }
201 for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
202 info.u_str = rrd.rra_def[i].cf_nam;
203 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR,
204 info);
205 current_cf = cf_conv(rrd.rra_def[i].cf_nam);
207 info.u_cnt = rrd.rra_def[i].row_cnt;
208 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT,
209 info);
211 info.u_cnt = rrd.rra_ptr[i].cur_row;
212 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].cur_row", i), RD_I_CNT,
213 info);
215 info.u_cnt = rrd.rra_def[i].pdp_cnt;
216 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i),
217 RD_I_CNT, info);
219 switch (current_cf) {
220 case CF_HWPREDICT:
221 case CF_MHWPREDICT:
222 info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val;
223 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].alpha", i),
224 RD_I_VAL, info);
225 info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val;
226 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
227 info);
228 break;
229 case CF_SEASONAL:
230 case CF_DEVSEASONAL:
231 info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val;
232 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].gamma", i),
233 RD_I_VAL, info);
234 if (atoi(rrd.stat_head->version) >= 4) {
235 info.u_val =
236 rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val;
237 cd = rrd_info_push(cd,
238 sprintf_alloc("rra[%d].smoothing_window",
239 i), RD_I_VAL, info);
240 }
241 break;
242 case CF_FAILURES:
243 info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val;
244 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
245 RD_I_VAL, info);
246 info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val;
247 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
248 RD_I_VAL, info);
249 info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt;
250 cd = rrd_info_push(cd,
251 sprintf_alloc("rra[%d].failure_threshold", i),
252 RD_I_CNT, info);
253 info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt;
254 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].window_length", i),
255 RD_I_CNT, info);
256 break;
257 case CF_DEVPREDICT:
258 break;
259 default:
260 info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val;
261 cd = rrd_info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
262 info);
263 break;
264 }
266 for (ii = 0; ii < rrd.stat_head->ds_cnt; ii++) {
267 switch (current_cf) {
268 case CF_HWPREDICT:
269 case CF_MHWPREDICT:
270 info.u_val =
271 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
272 ii].scratch[CDP_hw_intercept].u_val;
273 cd = rrd_info_push(cd,
274 sprintf_alloc
275 ("rra[%d].cdp_prep[%d].intercept", i, ii),
276 RD_I_VAL, info);
277 info.u_val =
278 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
279 ii].scratch[CDP_hw_slope].u_val;
280 cd = rrd_info_push(cd,
281 sprintf_alloc("rra[%d].cdp_prep[%d].slope",
282 i, ii), RD_I_VAL, info);
283 info.u_cnt =
284 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
285 ii].scratch[CDP_null_count].u_cnt;
286 cd = rrd_info_push(cd,
287 sprintf_alloc
288 ("rra[%d].cdp_prep[%d].NaN_count", i, ii),
289 RD_I_CNT, info);
290 break;
291 case CF_SEASONAL:
292 info.u_val =
293 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
294 ii].scratch[CDP_hw_seasonal].u_val;
295 cd = rrd_info_push(cd,
296 sprintf_alloc
297 ("rra[%d].cdp_prep[%d].seasonal", i, ii),
298 RD_I_VAL, info);
299 break;
300 case CF_DEVSEASONAL:
301 info.u_val =
302 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
303 ii].scratch[CDP_seasonal_deviation].u_val;
304 cd = rrd_info_push(cd,
305 sprintf_alloc
306 ("rra[%d].cdp_prep[%d].deviation", i, ii),
307 RD_I_VAL, info);
308 break;
309 case CF_DEVPREDICT:
310 break;
311 case CF_FAILURES:
312 {
313 unsigned short j;
314 char *violations_array;
315 char history[MAX_FAILURES_WINDOW_LEN + 1];
317 violations_array =
318 (char *) rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
319 ii].scratch;
320 for (j = 0; j < rrd.rra_def[i].par[RRA_window_len].u_cnt; ++j)
321 history[j] = (violations_array[j] == 1) ? '1' : '0';
322 history[j] = '\0';
323 info.u_str = history;
324 cd = rrd_info_push(cd,
325 sprintf_alloc
326 ("rra[%d].cdp_prep[%d].history", i, ii),
327 RD_I_STR, info);
328 }
329 break;
330 default:
331 info.u_val =
332 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
333 ii].scratch[CDP_val].u_val;
334 cd = rrd_info_push(cd,
335 sprintf_alloc("rra[%d].cdp_prep[%d].value",
336 i, ii), RD_I_VAL, info);
337 info.u_cnt =
338 rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
339 ii].scratch[CDP_unkn_pdp_cnt].u_cnt;
340 cd = rrd_info_push(cd,
341 sprintf_alloc
342 ("rra[%d].cdp_prep[%d].unknown_datapoints",
343 i, ii), RD_I_CNT, info);
344 break;
345 }
346 }
347 }
349 rrd_close(rrd_file);
350 err_free:
351 rrd_free(&rrd);
352 return (data);
353 }
356 void rrd_info_print(
357 rrd_info_t * data)
358 {
359 while (data) {
360 printf("%s = ", data->key);
362 switch (data->type) {
363 case RD_I_VAL:
364 if (isnan(data->value.u_val))
365 printf("NaN\n");
366 else
367 printf("%0.10e\n", data->value.u_val);
368 break;
369 case RD_I_CNT:
370 printf("%lu\n", data->value.u_cnt);
371 break;
372 case RD_I_INT:
373 printf("%d\n", data->value.u_int);
374 break;
375 case RD_I_STR:
376 printf("\"%s\"\n", data->value.u_str);
377 break;
378 case RD_I_BLO:
379 printf("BLOB_SIZE:%lu\n", data->value.u_blo.size);
380 fwrite(data->value.u_blo.ptr, data->value.u_blo.size, 1, stdout);
381 break;
382 }
383 data = data->next;
384 }
385 }
387 void rrd_info_free(
388 rrd_info_t * data)
389 {
390 rrd_info_t *save;
392 while (data) {
393 save = data;
394 if (data->key) {
395 if (data->type == RD_I_STR) {
396 free(data->value.u_str);
397 }
398 if (data->type == RD_I_BLO) {
399 free(data->value.u_blo.ptr);
400 }
401 free(data->key);
402 }
403 data = data->next;
404 free(save);
405 }
406 }