Code

src/graph.c: graph_add_def: Add graphs in reverse order.
[collection4.git] / src / graph.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <inttypes.h>
5 #include <string.h>
6 #include <time.h>
7 #include <errno.h>
8 #include <assert.h>
10 #include "graph.h"
11 #include "graph_ident.h"
12 #include "graph_instance.h"
13 #include "graph_list.h"
14 #include "graph_def.h"
15 #include "graph_config.h"
16 #include "common.h"
17 #include "filesystem.h"
18 #include "utils_cgi.h"
20 #include <fcgiapp.h>
21 #include <fcgi_stdio.h>
23 /*
24  * Data types
25  */
26 struct graph_config_s /* {{{ */
27 {
28   graph_ident_t *select;
30   char *title;
31   char *vertical_label;
32   _Bool show_zero;
34   graph_def_t *defs;
36   graph_instance_t **instances;
37   size_t instances_num;
38 }; /* }}} struct graph_config_s */
40 /*
41  * Private functions
42  */
44 /*
45  * Config functions
46  */
47 static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
48 {
49   char *host = NULL;
50   char *plugin = NULL;
51   char *plugin_instance = NULL;
52   char *type = NULL;
53   char *type_instance = NULL;
54   graph_ident_t *ret;
55   int i;
57   for (i = 0; i < ci->children_num; i++)
58   {
59     oconfig_item_t *child;
61     child = ci->children + i;
63     if (strcasecmp ("Host", child->key) == 0)
64       graph_config_get_string (child, &host);
65     else if (strcasecmp ("Plugin", child->key) == 0)
66       graph_config_get_string (child, &plugin);
67     else if (strcasecmp ("PluginInstance", child->key) == 0)
68       graph_config_get_string (child, &plugin_instance);
69     else if (strcasecmp ("Type", child->key) == 0)
70       graph_config_get_string (child, &type);
71     else if (strcasecmp ("TypeInstance", child->key) == 0)
72       graph_config_get_string (child, &type_instance);
73     /* else: ignore all other directives here. */
74   } /* for */
76   ret = ident_create (host, plugin, plugin_instance, type, type_instance);
78   free (host);
79   free (plugin);
80   free (plugin_instance);
81   free (type);
82   free (type_instance);
84   return (ret);
85 } /* }}} int graph_config_get_selector */
87 /*
88  * Global functions
89  */
90 graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
91 {
92   graph_config_t *cfg;
94   cfg = malloc (sizeof (*cfg));
95   if (cfg == NULL)
96     return (NULL);
97   memset (cfg, 0, sizeof (*cfg));
99   if (selector != NULL)
100     cfg->select = ident_clone (selector);
101   else
102     cfg->select = NULL;
104   cfg->title = NULL;
105   cfg->vertical_label = NULL;
106   cfg->defs = NULL;
107   cfg->instances = NULL;
109   return (cfg);
110 } /* }}} int graph_create */
112 void graph_destroy (graph_config_t *cfg) /* {{{ */
114   size_t i;
116   if (cfg == NULL)
117     return;
119   ident_destroy (cfg->select);
121   free (cfg->title);
122   free (cfg->vertical_label);
124   def_destroy (cfg->defs);
126   for (i = 0; i < cfg->instances_num; i++)
127     inst_destroy (cfg->instances[i]);
128   free (cfg->instances);
129 } /* }}} void graph_destroy */
131 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
133   graph_ident_t *select;
134   graph_config_t *cfg = NULL;
135   int i;
137   select = graph_config_get_selector (ci);
138   if (select == NULL)
139     return (EINVAL);
141   cfg = graph_create (/* selector = */ NULL);
142   if (cfg == NULL)
143     return (ENOMEM);
145   cfg->select = select;
147   for (i = 0; i < ci->children_num; i++)
148   {
149     oconfig_item_t *child;
151     child = ci->children + i;
153     if (strcasecmp ("Title", child->key) == 0)
154       graph_config_get_string (child, &cfg->title);
155     else if (strcasecmp ("VerticalLabel", child->key) == 0)
156       graph_config_get_string (child, &cfg->vertical_label);
157     else if (strcasecmp ("ShowZero", child->key) == 0)
158       graph_config_get_bool (child, &cfg->show_zero);
159     else if (strcasecmp ("DEF", child->key) == 0)
160       def_config (cfg, child);
161   } /* for */
163   gl_add_graph (cfg);
165   return (0);
166 } /* }}} graph_config_add */
168 int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
170   graph_instance_t *inst;
172   inst = graph_inst_find_matching (cfg, file);
173   if (inst == NULL)
174   {
175     graph_instance_t **tmp;
177     tmp = realloc (cfg->instances,
178         sizeof (*cfg->instances) * (cfg->instances_num + 1));
179     if (tmp == NULL)
180       return (ENOMEM);
181     cfg->instances = tmp;
183     inst = inst_create (cfg, file);
184     if (inst == NULL)
185       return (ENOMEM);
187     cfg->instances[cfg->instances_num] = inst;
188     cfg->instances_num++;
189   }
191   return (inst_add_file (inst, file));
192 } /* }}} int graph_add_file */
194 int graph_get_title (graph_config_t *cfg, /* {{{ */
195     char *buffer, size_t buffer_size)
197   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
198     return (EINVAL);
200   if (cfg->title == NULL)
201     cfg->title = ident_to_string (cfg->select);
203   if (cfg->title == NULL)
204     return (ENOMEM);
206   strncpy (buffer, cfg->title, buffer_size);
207   buffer[buffer_size - 1] = 0;
209   return (0);
210 } /* }}} int graph_get_title */
212 int graph_get_params (graph_config_t *cfg, /* {{{ */
213     char *buffer, size_t buffer_size)
215   buffer[0] = 0;
217 #define COPY_FIELD(field) do {                                       \
218   const char *str = ident_get_##field (cfg->select);                 \
219   char uri_str[1024];                                                \
220   uri_escape_copy (uri_str, str, sizeof (uri_str));                  \
221   strlcat (buffer, #field, buffer_size);                             \
222   strlcat (buffer, "=", buffer_size);                                \
223   strlcat (buffer, uri_str, buffer_size);                            \
224 } while (0)
226   COPY_FIELD(host);
227   strlcat (buffer, ";", buffer_size);
228   COPY_FIELD(plugin);
229   strlcat (buffer, ";", buffer_size);
230   COPY_FIELD(plugin_instance);
231   strlcat (buffer, ";", buffer_size);
232   COPY_FIELD(type);
233   strlcat (buffer, ";", buffer_size);
234   COPY_FIELD(type_instance);
236 #undef COPY_FIELD
238   return (0);
239 } /* }}} int graph_get_params */
241 graph_ident_t *graph_get_selector (graph_config_t *cfg) /* {{{ */
243   if (cfg == NULL)
244     return (NULL);
246   return (ident_clone (cfg->select));
247 } /* }}} graph_ident_t *graph_get_selector */
249 graph_def_t *graph_get_defs (graph_config_t *cfg) /* {{{ */
251   if (cfg == NULL)
252     return (NULL);
254   return (cfg->defs);
255 } /* }}} graph_def_t *graph_get_defs */
257 int graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
259   graph_def_t *tmp;
261   if ((cfg == NULL) || (def == NULL))
262     return (EINVAL);
264   if (cfg->defs == NULL)
265   {
266     cfg->defs = def;
267     return (0);
268   }
270   /* Insert in reverse order. This makes the order in the config file and the
271    * order of the DEFs in the graph more natural. Really. */
272   tmp = cfg->defs;
273   cfg->defs = def;
274   return (def_append (cfg->defs, tmp));
275 } /* }}} int graph_add_def */
277 _Bool graph_matches_ident (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
279   if ((cfg == NULL) || (ident == NULL))
280     return (0);
282   return (ident_matches (cfg->select, ident));
283 } /* }}} _Bool graph_matches_ident */
285 _Bool graph_matches_field (graph_config_t *cfg, /* {{{ */
286     graph_ident_field_t field, const char *field_value)
288   const char *selector_value;
290   if ((cfg == NULL) || (field_value == NULL))
291     return (0);
293   selector_value = ident_get_field (cfg->select, field);
294   if (selector_value == NULL)
295     return (0);
297   if (IS_ALL (selector_value) || IS_ANY (selector_value))
298     return (1);
299   else if (strcasecmp (selector_value, field_value) == 0)
300     return (1);
302   return (0);
303 } /* }}} _Bool graph_matches_field */
305 int graph_inst_foreach (graph_config_t *cfg, /* {{{ */
306                 inst_callback_t cb, void *user_data)
308   size_t i;
309   int status;
311   for (i = 0; i < cfg->instances_num; i++)
312   {
313     status = (*cb) (cfg->instances[i], user_data);
314     if (status != 0)
315       return (status);
316   }
318   return (0);
319 } /* }}} int graph_inst_foreach */
321 graph_instance_t *graph_inst_find_exact (graph_config_t *cfg, /* {{{ */
322     graph_ident_t *ident)
324   size_t i;
326   if ((cfg == NULL) || (ident == NULL))
327     return (NULL);
329   for (i = 0; i < cfg->instances_num; i++)
330     if (inst_compare_ident (cfg->instances[i], ident) == 0)
331       return (cfg->instances[i]);
333   return (NULL);
334 } /* }}} graph_instance_t *graph_inst_find_exact */
336 graph_instance_t *graph_inst_find_matching (graph_config_t *cfg, /* {{{ */
337     const graph_ident_t *ident)
339   size_t i;
341   if ((cfg == NULL) || (ident == NULL))
342     return (NULL);
344   for (i = 0; i < cfg->instances_num; i++)
345     if (inst_ident_matches (cfg->instances[i], ident))
346       return (cfg->instances[i]);
348   return (NULL);
349 } /* }}} graph_instance_t *graph_inst_find_matching */
351 int graph_inst_find_all_matching (graph_config_t *cfg, /* {{{ */
352     const graph_ident_t *ident,
353     graph_inst_callback_t callback, void *user_data)
355   size_t i;
357   if ((cfg == NULL) || (ident == NULL) || (callback == NULL))
358     return (EINVAL);
360   for (i = 0; i < cfg->instances_num; i++)
361   {
362     int status;
364     if (!inst_matches_ident (cfg->instances[i], ident))
365       continue;
367     status = (*callback) (cfg, cfg->instances[i], user_data);
368     if (status != 0)
369       return (status);
370   }
372   return (0);
373 } /* }}} int graph_inst_find_all_matching */
375 int graph_inst_search (graph_config_t *cfg, const char *term, /* {{{ */
376     graph_inst_callback_t cb,
377     void *user_data)
379   char buffer[1024];
380   int status;
381   size_t i;
383   status = graph_get_title (cfg, buffer, sizeof (buffer));
384   if (status != 0)
385   {
386     fprintf (stderr, "graph_inst_search: graph_get_title failed\n");
387     return (status);
388   }
390   strtolower (buffer);
392   if (strstr (buffer, term) != NULL)
393   {
394     for (i = 0; i < cfg->instances_num; i++)
395     {
396       status = (*cb) (cfg, cfg->instances[i], user_data);
397       if (status != 0)
398         return (status);
399     }
400   }
401   else
402   {
403     for (i = 0; i < cfg->instances_num; i++)
404     {
405       if (inst_matches_string (cfg, cfg->instances[i], term))
406       {
407         status = (*cb) (cfg, cfg->instances[i], user_data);
408         if (status != 0)
409           return (status);
410       }
411     }
412   }
414   return (0);
415 } /* }}} int graph_inst_search */
417 int graph_inst_search_field (graph_config_t *cfg, /* {{{ */
418     graph_ident_field_t field, const char *field_value,
419     graph_inst_callback_t callback, void *user_data)
421   size_t i;
422   const char *selector_field;
423   _Bool need_check_instances = 0;
425   if ((cfg == NULL) || (field_value == NULL) || (callback == NULL))
426     return (EINVAL);
428   if (!graph_matches_field (cfg, field, field_value))
429     return (0);
431   selector_field = ident_get_field (cfg->select, field);
432   if (selector_field == NULL)
433     return (-1);
435   if (IS_ALL (selector_field) || IS_ANY (selector_field))
436     need_check_instances = 1;
438   for (i = 0; i < cfg->instances_num; i++)
439   {
440     int status;
442     if (need_check_instances
443         && !inst_matches_field (cfg->instances[i], field, field_value))
444       continue;
446     status = (*callback) (cfg, cfg->instances[i], user_data);
447     if (status != 0)
448       return (status);
449   }
451   return (0);
452 } /* }}} int graph_inst_search_field */
454 int graph_compare (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
456   if ((cfg == NULL) || (ident == NULL))
457     return (0);
459   return (ident_compare (cfg->select, ident));
460 } /* }}} int graph_compare */
462 int graph_clear_instances (graph_config_t *cfg) /* {{{ */
464   size_t i;
466   if (cfg == NULL)
467     return (EINVAL);
469   for (i = 0; i < cfg->instances_num; i++)
470     inst_destroy (cfg->instances[i]);
471   free (cfg->instances);
472   cfg->instances = NULL;
473   cfg->instances_num = 0;
475   return (0);
476 } /* }}} int graph_clear_instances */
478 int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
479     rrd_args_t *args)
481   if ((cfg == NULL) || (inst == NULL) || (args == NULL))
482     return (EINVAL);
484   if (cfg->title != NULL)
485   {
486     array_append (args->options, "-t");
487     array_append (args->options, cfg->title);
488   }
490   if (cfg->vertical_label != NULL)
491   {
492     array_append (args->options, "-v");
493     array_append (args->options, cfg->vertical_label);
494   }
496   if (cfg->show_zero)
497   {
498     array_append (args->options, "-l");
499     array_append (args->options, "0");
500   }
502   return (0);
503 } /* }}} int graph_get_rrdargs */
505 /* vim: set sw=2 sts=2 et fdm=marker : */