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) /* {{{ */
113 {
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) /* {{{ */
132 {
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) /* {{{ */
169 {
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)
196 {
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)
214 {
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) /* {{{ */
242 {
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) /* {{{ */
250 {
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) /* {{{ */
258 {
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) /* {{{ */
278 {
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)
287 {
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)
307 {
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)
323 {
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)
338 {
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)
354 {
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)
378 {
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)
420 {
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) /* {{{ */
455 {
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) /* {{{ */
463 {
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)
480 {
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 : */