Merge branch 'search'
[collection4.git] / src / graph_def.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4
5 #include "graph_def.h"
6 #include "graph.h"
7 #include "graph_config.h"
8 #include "graph_ident.h"
9 #include "common.h"
10 #include "oconfig.h"
11
12 #include <fcgiapp.h>
13 #include <fcgi_stdio.h>
14
15 /*
16  * Data structures
17  */
18 struct graph_def_s
19 {
20   graph_ident_t *select;
21
22   char *ds_name;
23   char *legend;
24   uint32_t color;
25   _Bool stack;
26   _Bool area;
27   char *format;
28
29   graph_def_t *next;
30 };
31
32 /*
33  * Private functions
34  */
35 #define DEF_CONFIG_FIELD(field) \
36 static int def_config_##field (const oconfig_item_t *ci, graph_ident_t *ident) \
37 {                                                                              \
38   char *tmp = NULL;                                                            \
39   int status = graph_config_get_string (ci, &tmp);                             \
40   if (status != 0)                                                             \
41     return (status);                                                           \
42   ident_set_##field (ident, tmp);                                              \
43   free (tmp);                                                                  \
44   return (0);                                                                  \
45 } /* }}} int def_config_field */
46
47 DEF_CONFIG_FIELD (host);
48 DEF_CONFIG_FIELD (plugin);
49 DEF_CONFIG_FIELD (plugin_instance);
50 DEF_CONFIG_FIELD (type);
51 DEF_CONFIG_FIELD (type_instance);
52
53 #undef DEF_CONFIG_FIELD
54
55 static int def_config_color (const oconfig_item_t *ci, uint32_t *ret_color) /* {{{ */
56 {
57   char *tmp;
58   char *endptr;
59   uint32_t color;
60
61   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
62     return (EINVAL);
63
64   tmp = ci->values[0].value.string;
65
66   endptr = NULL;
67   errno = 0;
68   color = (uint32_t) strtoul (tmp, &endptr, /* base = */ 16);
69   if ((errno != 0) || (endptr == tmp) || (color > 0x00ffffff))
70     return (EINVAL);
71
72   *ret_color = color;
73
74   return (0);
75 } /* }}} int def_config_color */
76
77 static graph_def_t *def_config_get_obj (graph_config_t *cfg, /* {{{ */
78     const oconfig_item_t *ci)
79 {
80   graph_ident_t *ident;
81   char *ds_name = NULL;
82   graph_def_t *def;
83   int i;
84
85   ident = graph_get_selector (cfg);
86   if (ident == NULL)
87   {
88     fprintf (stderr, "def_config_get_obj: graph_get_selector failed");
89     return (NULL);
90   }
91
92   for (i = 0; i < ci->children_num; i++)
93   {
94     oconfig_item_t *child;
95
96 #define HANDLE_FIELD(name,field) \
97     else if (strcasecmp (name, child->key) == 0) \
98       def_config_##field (child, ident)
99
100     child = ci->children + i;
101     if (strcasecmp ("DSName", child->key) == 0)
102       graph_config_get_string (child, &ds_name);
103
104     HANDLE_FIELD ("Host", host);
105     HANDLE_FIELD ("Plugin", plugin);
106     HANDLE_FIELD ("PluginInstance", plugin_instance);
107     HANDLE_FIELD ("Type", type);
108     HANDLE_FIELD ("TypeInstance", type_instance);
109
110 #undef HANDLE_FIELD
111   }
112
113   def = def_create (cfg, ident, ds_name);
114   if (def == NULL)
115   {
116     fprintf (stderr, "def_config_get_obj: def_create failed\n");
117     ident_destroy (ident);
118     free (ds_name);
119     return (NULL);
120   }
121
122   ident_destroy (ident);
123   free (ds_name);
124
125   return (def);
126 } /* }}} graph_def_t *def_config_get_obj */
127
128 /*
129  * Public functions
130  */
131 graph_def_t *def_create (graph_config_t *cfg, graph_ident_t *ident, /* {{{ */
132     const char *ds_name)
133 {
134   graph_ident_t *selector;
135   graph_def_t *ret;
136
137   if ((cfg == NULL) || (ident == NULL) || (ds_name == NULL))
138     return (NULL);
139
140   selector = graph_get_selector (cfg);
141   if (selector == NULL)
142     return (NULL);
143
144   ret = malloc (sizeof (*ret));
145   if (ret == NULL)
146   {
147     ident_destroy (selector);
148     return (NULL);
149   }
150   memset (ret, 0, sizeof (*ret));
151   ret->legend = NULL;
152   ret->format = NULL;
153
154   ret->ds_name = strdup (ds_name);
155   if (ret->ds_name == NULL)
156   {
157     ident_destroy (selector);
158     free (ret);
159     return (NULL);
160   }
161
162   ret->color = get_random_color ();
163   ret->next = NULL;
164
165   ret->select = ident_copy_with_selector (selector, ident,
166       IDENT_FLAG_REPLACE_ALL);
167   if (ret->select == NULL)
168   {
169     ident_destroy (selector);
170     free (ret->ds_name);
171     free (ret);
172     return (NULL);
173   }
174
175   ident_destroy (selector);
176   return (ret);
177 } /* }}} graph_def_t *def_create */
178
179 void def_destroy (graph_def_t *def) /* {{{ */
180 {
181   graph_def_t *next;
182
183   if (def == NULL)
184     return;
185
186   next = def->next;
187
188   ident_destroy (def->select);
189
190   free (def->ds_name);
191   free (def->legend);
192   free (def->format);
193
194   free (def);
195
196   def_destroy (next);
197 } /* }}} void def_destroy */
198
199 int def_config (graph_config_t *cfg, const oconfig_item_t *ci) /* {{{ */
200 {
201   graph_def_t *def;
202   int i;
203
204   def = def_config_get_obj (cfg, ci);
205   if (def == NULL)
206     return (EINVAL);
207
208   for (i = 0; i < ci->children_num; i++)
209   {
210     oconfig_item_t *child;
211
212     child = ci->children + i;
213     if (strcasecmp ("Legend", child->key) == 0)
214       graph_config_get_string (child, &def->legend);
215     else if (strcasecmp ("Color", child->key) == 0)
216       def_config_color (child, &def->color);
217     else if (strcasecmp ("Stack", child->key) == 0)
218       graph_config_get_bool (child, &def->stack);
219     else if (strcasecmp ("Area", child->key) == 0)
220       graph_config_get_bool (child, &def->area);
221     else if (strcasecmp ("Format", child->key) == 0)
222       graph_config_get_string (child, &def->format);
223   }
224
225   return (graph_add_def (cfg, def));
226 } /* }}} int def_config */
227
228 int def_append (graph_def_t *head, graph_def_t *def) /* {{{ */
229 {
230   graph_def_t *ptr;
231
232   if ((head == NULL) || (def == NULL))
233     return (EINVAL);
234
235   ptr = head;
236   while (ptr->next != NULL)
237     ptr = ptr->next;
238
239   ptr->next = def;
240
241   return (0);
242 } /* }}} int def_append */
243
244 graph_def_t *def_search (graph_def_t *head, graph_ident_t *ident, /* {{{ */
245     const char *ds_name)
246 {
247   graph_def_t *ptr;
248
249   if ((head == NULL) || (ident == NULL) || (ds_name == NULL))
250     return (NULL);
251
252   for (ptr = head; ptr != NULL; ptr = ptr->next)
253   {
254     if (!ident_matches (ptr->select, ident))
255       continue;
256
257     if (strcmp (ptr->ds_name, ds_name) == 0)
258       return (ptr);
259   }
260
261   return (NULL);
262 } /* }}} graph_def_t *def_search */
263
264 _Bool def_matches (graph_def_t *def, graph_ident_t *ident) /* {{{ */
265 {
266   return (ident_matches (def->select, ident));
267 } /* }}} _Bool def_matches */
268
269 int def_foreach (graph_def_t *def, def_callback_t callback, /* {{{ */
270     void *user_data)
271 {
272   graph_def_t *ptr;
273
274   if ((def == NULL) || (callback == NULL))
275     return (EINVAL);
276
277   for (ptr = def; ptr != NULL; ptr = ptr->next)
278   {
279     int status;
280
281     status = (*callback) (ptr, user_data);
282     if (status != 0)
283       return (status);
284   }
285
286   return (0);
287 } /* }}} int def_foreach */
288
289 int def_get_rrdargs (graph_def_t *def, graph_ident_t *ident, /* {{{ */
290     str_array_t *args)
291 {
292   char *file;
293   int index;
294
295   if ((def == NULL) || (ident == NULL) || (args == NULL))
296     return (EINVAL);
297
298   file = ident_to_file (ident);
299   if (file == NULL)
300   {
301     DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
302     return (-1);
303   }
304
305   DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
306
307   index = array_argc (args);
308
309   /* CDEFs */
310   array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
311       index, file, def->ds_name);
312   array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
313       index, file, def->ds_name);
314   array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
315       index, file, def->ds_name);
316   /* VDEFs */
317   array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
318       index, index);
319   array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
320       index, index);
321   array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
322       index, index);
323   array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
324       index, index);
325
326   /* Graph part */
327   array_append_format (args, "%s:def_%04i_avg#%06"PRIx32":%s%s",
328       def->area ? "AREA" : "LINE1",
329       index, def->color,
330       (def->legend != NULL) ? def->legend : def->ds_name,
331       def->stack ? ":STACK" : "");
332   array_append_format (args, "GPRINT:vdef_%04i_min:%s min,",
333       index, (def->format != NULL) ? def->format : "%6.2lf");
334   array_append_format (args, "GPRINT:vdef_%04i_avg:%s avg,",
335       index, (def->format != NULL) ? def->format : "%6.2lf");
336   array_append_format (args, "GPRINT:vdef_%04i_max:%s max,",
337       index, (def->format != NULL) ? def->format : "%6.2lf");
338   array_append_format (args, "GPRINT:vdef_%04i_lst:%s last\\l",
339       index, (def->format != NULL) ? def->format : "%6.2lf");
340
341   free (file);
342
343   return (0);
344 } /* }}} int def_get_rrdargs */
345
346 /* vim: set sw=2 sts=2 et fdm=marker : */