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