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