src/graph.[ch]: Implement "graph_inst_find_all_matching".
[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>
9
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"
19
20 #include <fcgiapp.h>
21 #include <fcgi_stdio.h>
22
23 /*
24  * Data types
25  */
26 struct graph_config_s /* {{{ */
27 {
28   graph_ident_t *select;
29
30   char *title;
31   char *vertical_label;
32   _Bool show_zero;
33
34   graph_def_t *defs;
35
36   graph_instance_t **instances;
37   size_t instances_num;
38 }; /* }}} struct graph_config_s */
39
40 /*
41  * Private functions
42  */
43
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;
56
57   for (i = 0; i < ci->children_num; i++)
58   {
59     oconfig_item_t *child;
60
61     child = ci->children + i;
62
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 */
75
76   ret = ident_create (host, plugin, plugin_instance, type, type_instance);
77
78   free (host);
79   free (plugin);
80   free (plugin_instance);
81   free (type);
82   free (type_instance);
83
84   return (ret);
85 } /* }}} int graph_config_get_selector */
86
87 /*
88  * Global functions
89  */
90 graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
91 {
92   graph_config_t *cfg;
93
94   cfg = malloc (sizeof (*cfg));
95   if (cfg == NULL)
96     return (NULL);
97   memset (cfg, 0, sizeof (*cfg));
98
99   if (selector != NULL)
100     cfg->select = ident_clone (selector);
101   else
102     cfg->select = NULL;
103
104   cfg->title = NULL;
105   cfg->vertical_label = NULL;
106   cfg->defs = NULL;
107   cfg->instances = NULL;
108
109   return (cfg);
110 } /* }}} int graph_create */
111
112 void graph_destroy (graph_config_t *cfg) /* {{{ */
113 {
114   size_t i;
115
116   if (cfg == NULL)
117     return;
118
119   ident_destroy (cfg->select);
120
121   free (cfg->title);
122   free (cfg->vertical_label);
123
124   def_destroy (cfg->defs);
125
126   for (i = 0; i < cfg->instances_num; i++)
127     inst_destroy (cfg->instances[i]);
128   free (cfg->instances);
129 } /* }}} void graph_destroy */
130
131 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
132 {
133   graph_ident_t *select;
134   graph_config_t *cfg = NULL;
135   int i;
136
137   select = graph_config_get_selector (ci);
138   if (select == NULL)
139     return (EINVAL);
140
141   cfg = graph_create (/* selector = */ NULL);
142   if (cfg == NULL)
143     return (ENOMEM);
144
145   cfg->select = select;
146
147   for (i = 0; i < ci->children_num; i++)
148   {
149     oconfig_item_t *child;
150
151     child = ci->children + i;
152
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 */
162
163   gl_add_graph (cfg);
164
165   return (0);
166 } /* }}} graph_config_add */
167
168 int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
169 {
170   graph_instance_t *inst;
171
172   inst = graph_inst_find_matching (cfg, file);
173   if (inst == NULL)
174   {
175     graph_instance_t **tmp;
176
177     tmp = realloc (cfg->instances,
178         sizeof (*cfg->instances) * (cfg->instances_num + 1));
179     if (tmp == NULL)
180       return (ENOMEM);
181     cfg->instances = tmp;
182
183     inst = inst_create (cfg, file);
184     if (inst == NULL)
185       return (ENOMEM);
186
187     cfg->instances[cfg->instances_num] = inst;
188     cfg->instances_num++;
189   }
190
191   return (inst_add_file (inst, file));
192 } /* }}} int graph_add_file */
193
194 int graph_get_title (graph_config_t *cfg, /* {{{ */
195     char *buffer, size_t buffer_size)
196 {
197   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
198     return (EINVAL);
199
200   if (cfg->title == NULL)
201     cfg->title = ident_to_string (cfg->select);
202
203   if (cfg->title == NULL)
204     return (ENOMEM);
205
206   strncpy (buffer, cfg->title, buffer_size);
207   buffer[buffer_size - 1] = 0;
208
209   return (0);
210 } /* }}} int graph_get_title */
211
212 int graph_get_params (graph_config_t *cfg, /* {{{ */
213     char *buffer, size_t buffer_size)
214 {
215   buffer[0] = 0;
216
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)
225
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);
235
236 #undef COPY_FIELD
237
238   return (0);
239 } /* }}} int graph_get_params */
240
241 graph_ident_t *graph_get_selector (graph_config_t *cfg) /* {{{ */
242 {
243   if (cfg == NULL)
244     return (NULL);
245
246   return (ident_clone (cfg->select));
247 } /* }}} graph_ident_t *graph_get_selector */
248
249 graph_def_t *graph_get_defs (graph_config_t *cfg) /* {{{ */
250 {
251   if (cfg == NULL)
252     return (NULL);
253
254   return (cfg->defs);
255 } /* }}} graph_def_t *graph_get_defs */
256
257 int graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
258 {
259   if ((cfg == NULL) || (def == NULL))
260     return (EINVAL);
261
262   if (cfg->defs == NULL)
263   {
264     cfg->defs = def;
265     return (0);
266   }
267
268   return (def_append (cfg->defs, def));
269 } /* }}} int graph_add_def */
270
271 _Bool graph_matches_ident (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
272 {
273   if ((cfg == NULL) || (ident == NULL))
274     return (0);
275
276   return (ident_matches (cfg->select, ident));
277 } /* }}} _Bool graph_matches_ident */
278
279 _Bool graph_matches_field (graph_config_t *cfg, /* {{{ */
280     graph_ident_field_t field, const char *field_value)
281 {
282   const char *selector_value;
283
284   if ((cfg == NULL) || (field_value == NULL))
285     return (0);
286
287   selector_value = ident_get_field (cfg->select, field);
288   if (selector_value == NULL)
289     return (0);
290
291   if (IS_ALL (selector_value) || IS_ANY (selector_value))
292     return (1);
293   else if (strcasecmp (selector_value, field_value) == 0)
294     return (1);
295
296   return (0);
297 } /* }}} _Bool graph_matches_field */
298
299 int graph_inst_foreach (graph_config_t *cfg, /* {{{ */
300                 inst_callback_t cb, void *user_data)
301 {
302   size_t i;
303   int status;
304
305   for (i = 0; i < cfg->instances_num; i++)
306   {
307     status = (*cb) (cfg->instances[i], user_data);
308     if (status != 0)
309       return (status);
310   }
311
312   return (0);
313 } /* }}} int graph_inst_foreach */
314
315 graph_instance_t *graph_inst_find_exact (graph_config_t *cfg, /* {{{ */
316     graph_ident_t *ident)
317 {
318   size_t i;
319
320   if ((cfg == NULL) || (ident == NULL))
321     return (NULL);
322
323   for (i = 0; i < cfg->instances_num; i++)
324     if (inst_compare_ident (cfg->instances[i], ident) == 0)
325       return (cfg->instances[i]);
326
327   return (NULL);
328 } /* }}} graph_instance_t *graph_inst_find_exact */
329
330 graph_instance_t *graph_inst_find_matching (graph_config_t *cfg, /* {{{ */
331     const graph_ident_t *ident)
332 {
333   size_t i;
334
335   if ((cfg == NULL) || (ident == NULL))
336     return (NULL);
337
338   for (i = 0; i < cfg->instances_num; i++)
339     if (inst_matches_ident (cfg->instances[i], ident))
340       return (cfg->instances[i]);
341
342   return (NULL);
343 } /* }}} graph_instance_t *graph_inst_find_matching */
344
345 int graph_inst_find_all_matching (graph_config_t *cfg, /* {{{ */
346     const graph_ident_t *ident,
347     graph_inst_callback_t callback, void *user_data)
348 {
349   size_t i;
350
351   if ((cfg == NULL) || (ident == NULL) || (callback == NULL))
352     return (EINVAL);
353
354   for (i = 0; i < cfg->instances_num; i++)
355   {
356     int status;
357
358     if (!inst_matches_ident (cfg->instances[i], ident))
359       continue;
360
361     status = (*callback) (cfg, cfg->instances[i], user_data);
362     if (status != 0)
363       return (status);
364   }
365
366   return (0);
367 } /* }}} int graph_inst_find_all_matching */
368
369 int graph_inst_search (graph_config_t *cfg, const char *term, /* {{{ */
370     graph_inst_callback_t cb,
371     void *user_data)
372 {
373   char buffer[1024];
374   int status;
375   size_t i;
376
377   status = graph_get_title (cfg, buffer, sizeof (buffer));
378   if (status != 0)
379   {
380     fprintf (stderr, "graph_inst_search: graph_get_title failed\n");
381     return (status);
382   }
383
384   strtolower (buffer);
385
386   if (strstr (buffer, term) != NULL)
387   {
388     for (i = 0; i < cfg->instances_num; i++)
389     {
390       status = (*cb) (cfg, cfg->instances[i], user_data);
391       if (status != 0)
392         return (status);
393     }
394   }
395   else
396   {
397     for (i = 0; i < cfg->instances_num; i++)
398     {
399       if (inst_matches_string (cfg, cfg->instances[i], term))
400       {
401         status = (*cb) (cfg, cfg->instances[i], user_data);
402         if (status != 0)
403           return (status);
404       }
405     }
406   }
407
408   return (0);
409 } /* }}} int graph_inst_search */
410
411 int graph_inst_search_field (graph_config_t *cfg, /* {{{ */
412     graph_ident_field_t field, const char *field_value,
413     graph_inst_callback_t callback, void *user_data)
414 {
415   size_t i;
416   const char *selector_field;
417   _Bool need_check_instances = 0;
418
419   if ((cfg == NULL) || (field_value == NULL) || (callback == NULL))
420     return (EINVAL);
421
422   if (!graph_matches_field (cfg, field, field_value))
423     return (0);
424
425   selector_field = ident_get_field (cfg->select, field);
426   if (selector_field == NULL)
427     return (-1);
428
429   if (IS_ALL (selector_field) || IS_ANY (selector_field))
430     need_check_instances = 1;
431
432   for (i = 0; i < cfg->instances_num; i++)
433   {
434     int status;
435
436     if (need_check_instances
437         && !inst_matches_field (cfg->instances[i], field, field_value))
438       continue;
439
440     status = (*callback) (cfg, cfg->instances[i], user_data);
441     if (status != 0)
442       return (status);
443   }
444
445   return (0);
446 } /* }}} int graph_inst_search_field */
447
448 int graph_compare (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
449 {
450   if ((cfg == NULL) || (ident == NULL))
451     return (0);
452
453   return (ident_compare (cfg->select, ident));
454 } /* }}} int graph_compare */
455
456 int graph_clear_instances (graph_config_t *cfg) /* {{{ */
457 {
458   size_t i;
459
460   if (cfg == NULL)
461     return (EINVAL);
462
463   for (i = 0; i < cfg->instances_num; i++)
464     inst_destroy (cfg->instances[i]);
465   free (cfg->instances);
466   cfg->instances = NULL;
467   cfg->instances_num = 0;
468
469   return (0);
470 } /* }}} int graph_clear_instances */
471
472 int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
473     str_array_t *args)
474 {
475   if ((cfg == NULL) || (inst == NULL) || (args == NULL))
476     return (EINVAL);
477
478   if (cfg->title != NULL)
479   {
480     array_append (args, "-t");
481     array_append (args, cfg->title);
482   }
483
484   if (cfg->vertical_label != NULL)
485   {
486     array_append (args, "-v");
487     array_append (args, cfg->vertical_label);
488   }
489
490   if (cfg->show_zero)
491   {
492     array_append (args, "-l");
493     array_append (args, "0");
494   }
495
496   return (0);
497 } /* }}} int graph_get_rrdargs */
498
499 /* vim: set sw=2 sts=2 et fdm=marker : */