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