2 * collection4 - graph.c
3 * Copyright (C) 2010 Florian octo Forster
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 * Florian octo Forster <ff at octo.it>
34 #include "graph_ident.h"
35 #include "graph_instance.h"
36 #include "graph_list.h"
37 #include "graph_def.h"
38 #include "graph_config.h"
40 #include "filesystem.h"
41 #include "utils_cgi.h"
44 #include <fcgi_stdio.h>
49 struct graph_config_s /* {{{ */
51 graph_ident_t *select;
59 graph_instance_t **instances;
61 }; /* }}} struct graph_config_s */
70 static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
74 char *plugin_instance = NULL;
76 char *type_instance = NULL;
80 for (i = 0; i < ci->children_num; i++)
82 oconfig_item_t *child;
84 child = ci->children + i;
86 if (strcasecmp ("Host", child->key) == 0)
87 graph_config_get_string (child, &host);
88 else if (strcasecmp ("Plugin", child->key) == 0)
89 graph_config_get_string (child, &plugin);
90 else if (strcasecmp ("PluginInstance", child->key) == 0)
91 graph_config_get_string (child, &plugin_instance);
92 else if (strcasecmp ("Type", child->key) == 0)
93 graph_config_get_string (child, &type);
94 else if (strcasecmp ("TypeInstance", child->key) == 0)
95 graph_config_get_string (child, &type_instance);
96 /* else: ignore all other directives here. */
99 ret = ident_create (host, plugin, plugin_instance, type, type_instance);
103 free (plugin_instance);
105 free (type_instance);
108 } /* }}} int graph_config_get_selector */
113 graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
117 cfg = malloc (sizeof (*cfg));
120 memset (cfg, 0, sizeof (*cfg));
122 if (selector != NULL)
123 cfg->select = ident_clone (selector);
128 cfg->vertical_label = NULL;
130 cfg->instances = NULL;
133 } /* }}} int graph_create */
135 void graph_destroy (graph_config_t *cfg) /* {{{ */
142 ident_destroy (cfg->select);
145 free (cfg->vertical_label);
147 def_destroy (cfg->defs);
149 for (i = 0; i < cfg->instances_num; i++)
150 inst_destroy (cfg->instances[i]);
151 free (cfg->instances);
152 } /* }}} void graph_destroy */
154 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
156 graph_ident_t *select;
157 graph_config_t *cfg = NULL;
160 select = graph_config_get_selector (ci);
164 cfg = graph_create (/* selector = */ NULL);
168 cfg->select = select;
170 for (i = 0; i < ci->children_num; i++)
172 oconfig_item_t *child;
174 child = ci->children + i;
176 if (strcasecmp ("Title", child->key) == 0)
177 graph_config_get_string (child, &cfg->title);
178 else if (strcasecmp ("VerticalLabel", child->key) == 0)
179 graph_config_get_string (child, &cfg->vertical_label);
180 else if (strcasecmp ("ShowZero", child->key) == 0)
181 graph_config_get_bool (child, &cfg->show_zero);
182 else if (strcasecmp ("DEF", child->key) == 0)
183 def_config (cfg, child);
189 } /* }}} graph_config_add */
191 int graph_add_inst (graph_config_t *graph, graph_instance_t *inst) /* {{{ */
193 graph_instance_t **tmp;
195 if ((graph == NULL) || (inst == NULL))
198 tmp = realloc (graph->instances,
199 sizeof (*graph->instances) * (graph->instances_num + 1));
202 graph->instances = tmp;
204 graph->instances[graph->instances_num] = inst;
205 graph->instances_num++;
208 } /* }}} int graph_add_inst */
210 int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
212 graph_instance_t *inst;
214 inst = graph_inst_find_matching (cfg, file);
217 inst = inst_create (cfg, file);
221 graph_add_inst (cfg, inst);
224 return (inst_add_file (inst, file));
225 } /* }}} int graph_add_file */
227 int graph_get_title (graph_config_t *cfg, /* {{{ */
228 char *buffer, size_t buffer_size)
230 if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
233 if (cfg->title == NULL)
234 cfg->title = ident_to_string (cfg->select);
236 if (cfg->title == NULL)
239 strncpy (buffer, cfg->title, buffer_size);
240 buffer[buffer_size - 1] = 0;
243 } /* }}} int graph_get_title */
245 int graph_get_params (graph_config_t *cfg, /* {{{ */
246 char *buffer, size_t buffer_size)
250 #define COPY_FIELD(field) do { \
251 const char *str = ident_get_##field (cfg->select); \
252 char uri_str[1024]; \
253 uri_escape_copy (uri_str, str, sizeof (uri_str)); \
254 strlcat (buffer, #field, buffer_size); \
255 strlcat (buffer, "=", buffer_size); \
256 strlcat (buffer, uri_str, buffer_size); \
260 strlcat (buffer, ";", buffer_size);
262 strlcat (buffer, ";", buffer_size);
263 COPY_FIELD(plugin_instance);
264 strlcat (buffer, ";", buffer_size);
266 strlcat (buffer, ";", buffer_size);
267 COPY_FIELD(type_instance);
272 } /* }}} int graph_get_params */
274 graph_ident_t *graph_get_selector (graph_config_t *cfg) /* {{{ */
279 return (ident_clone (cfg->select));
280 } /* }}} graph_ident_t *graph_get_selector */
282 graph_def_t *graph_get_defs (graph_config_t *cfg) /* {{{ */
288 } /* }}} graph_def_t *graph_get_defs */
290 int graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
294 if ((cfg == NULL) || (def == NULL))
297 if (cfg->defs == NULL)
303 /* Insert in reverse order. This makes the order in the config file and the
304 * order of the DEFs in the graph more natural. Really. */
307 return (def_append (cfg->defs, tmp));
308 } /* }}} int graph_add_def */
310 _Bool graph_ident_matches (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
313 if ((cfg == NULL) || (ident == NULL))
317 return (ident_matches (cfg->select, ident));
318 } /* }}} _Bool graph_ident_matches */
320 _Bool graph_matches_ident (graph_config_t *cfg, /* {{{ */
321 const graph_ident_t *selector)
324 if ((cfg == NULL) || (selector == NULL))
328 return (ident_matches (selector, cfg->select));
329 } /* }}} _Bool graph_matches_ident */
331 _Bool graph_ident_intersect (graph_config_t *cfg, /* {{{ */
332 const graph_ident_t *selector)
335 if ((cfg == NULL) || (selector == NULL))
339 return (ident_intersect (cfg->select, selector));
340 } /* }}} _Bool graph_ident_intersect */
342 _Bool graph_matches_field (graph_config_t *cfg, /* {{{ */
343 graph_ident_field_t field, const char *field_value)
345 const char *selector_value;
347 if ((cfg == NULL) || (field_value == NULL))
350 selector_value = ident_get_field (cfg->select, field);
351 if (selector_value == NULL)
354 if (IS_ALL (selector_value) || IS_ANY (selector_value))
356 else if (strcasecmp (selector_value, field_value) == 0)
360 } /* }}} _Bool graph_matches_field */
362 int graph_inst_foreach (graph_config_t *cfg, /* {{{ */
363 inst_callback_t cb, void *user_data)
368 for (i = 0; i < cfg->instances_num; i++)
370 status = (*cb) (cfg->instances[i], user_data);
376 } /* }}} int graph_inst_foreach */
378 graph_instance_t *graph_inst_find_exact (graph_config_t *cfg, /* {{{ */
379 graph_ident_t *ident)
383 if ((cfg == NULL) || (ident == NULL))
386 for (i = 0; i < cfg->instances_num; i++)
387 if (inst_compare_ident (cfg->instances[i], ident) == 0)
388 return (cfg->instances[i]);
391 } /* }}} graph_instance_t *graph_inst_find_exact */
393 graph_instance_t *graph_inst_find_matching (graph_config_t *cfg, /* {{{ */
394 const graph_ident_t *ident)
398 if ((cfg == NULL) || (ident == NULL))
401 for (i = 0; i < cfg->instances_num; i++)
402 if (inst_ident_matches (cfg->instances[i], ident))
403 return (cfg->instances[i]);
406 } /* }}} graph_instance_t *graph_inst_find_matching */
408 int graph_inst_find_all_matching (graph_config_t *cfg, /* {{{ */
409 const graph_ident_t *ident,
410 graph_inst_callback_t callback, void *user_data)
414 if ((cfg == NULL) || (ident == NULL) || (callback == NULL))
417 for (i = 0; i < cfg->instances_num; i++)
421 if (!inst_matches_ident (cfg->instances[i], ident))
424 status = (*callback) (cfg, cfg->instances[i], user_data);
430 } /* }}} int graph_inst_find_all_matching */
432 /* Lightweight variant of the "graph_search_inst" which is used if the
433 * search_info_t doesn't select any field values explicitely. */
434 static int graph_search_inst_noselector (graph_config_t *cfg, /* {{{ */
435 search_info_t *si, graph_inst_callback_t cb, void *user_data)
441 /* parameters have already been checked in "graph_search_inst" */
443 status = graph_get_title (cfg, title, sizeof (title));
446 fprintf (stderr, "graph_search_inst_noselector: "
447 "graph_get_title failed\n");
452 for (i = 0; i < cfg->instances_num; i++)
454 if (search_graph_inst_matches (si, cfg, cfg->instances[i], title))
456 status = (*cb) (cfg, cfg->instances[i], user_data);
460 } /* for (cfg->instances_num) */
463 } /* }}} int graph_search_inst_noselector */
465 /* When this function is called from graph_list, it will already have checked
466 * that the selector of the graph does not contradict the field selections contained in
467 * the search_info_t. We still have to check if the instance contradicts the
468 * search parameters, though, since the "ANY" wildcard is filled in now -
469 * possibly with contradicting values. */
470 int graph_search_inst (graph_config_t *cfg, search_info_t *si, /* {{{ */
471 graph_inst_callback_t cb,
477 graph_ident_t *search_selector;
479 if ((cfg == NULL) || (si == NULL) || (cb == NULL))
482 if (!search_has_selector (si))
483 return (graph_search_inst_noselector (cfg, si, cb, user_data));
485 search_selector = search_to_ident (si);
486 if (search_selector == NULL)
489 status = graph_get_title (cfg, title, sizeof (title));
492 ident_destroy (search_selector);
493 fprintf (stderr, "graph_search_inst: graph_get_title failed\n");
498 for (i = 0; i < cfg->instances_num; i++)
500 graph_ident_t *inst_selector;
502 inst_selector = inst_get_selector (cfg->instances[i]);
503 if (inst_selector == NULL)
506 /* If the two selectors contradict one another, there is no point in
507 * calling the (more costly) "search_graph_inst_matches" function. */
508 if (!ident_intersect (search_selector, inst_selector))
510 ident_destroy (inst_selector);
514 if (search_graph_inst_matches (si, cfg, cfg->instances[i], title))
516 status = (*cb) (cfg, cfg->instances[i], user_data);
519 ident_destroy (search_selector);
520 ident_destroy (inst_selector);
525 ident_destroy (inst_selector);
526 } /* for (cfg->instances_num) */
528 ident_destroy (search_selector);
530 } /* }}} int graph_search_inst */
532 int graph_search_inst_string (graph_config_t *cfg, const char *term, /* {{{ */
533 graph_inst_callback_t cb,
540 status = graph_get_title (cfg, buffer, sizeof (buffer));
543 fprintf (stderr, "graph_search_inst_string: graph_get_title failed\n");
549 if (strstr (buffer, term) != NULL)
551 for (i = 0; i < cfg->instances_num; i++)
553 status = (*cb) (cfg, cfg->instances[i], user_data);
560 for (i = 0; i < cfg->instances_num; i++)
562 if (inst_matches_string (cfg, cfg->instances[i], term))
564 status = (*cb) (cfg, cfg->instances[i], user_data);
572 } /* }}} int graph_search_inst_string */
574 int graph_inst_search_field (graph_config_t *cfg, /* {{{ */
575 graph_ident_field_t field, const char *field_value,
576 graph_inst_callback_t callback, void *user_data)
579 const char *selector_field;
580 _Bool need_check_instances = 0;
582 if ((cfg == NULL) || (field_value == NULL) || (callback == NULL))
585 if (!graph_matches_field (cfg, field, field_value))
588 selector_field = ident_get_field (cfg->select, field);
589 if (selector_field == NULL)
592 if (IS_ALL (selector_field) || IS_ANY (selector_field))
593 need_check_instances = 1;
595 for (i = 0; i < cfg->instances_num; i++)
599 if (need_check_instances
600 && !inst_matches_field (cfg->instances[i], field, field_value))
603 status = (*callback) (cfg, cfg->instances[i], user_data);
609 } /* }}} int graph_inst_search_field */
611 int graph_compare (graph_config_t *cfg, const graph_ident_t *ident) /* {{{ */
613 if ((cfg == NULL) || (ident == NULL))
616 return (ident_compare (cfg->select, ident));
617 } /* }}} int graph_compare */
619 size_t graph_num_instances (graph_config_t *cfg) /* {{{ */
622 return ((size_t) -1);
624 return (cfg->instances_num);
625 } /* }}} size_t graph_num_instances */
627 int graph_to_json (const graph_config_t *cfg, /* {{{ */
632 if ((cfg == NULL) || (handler == NULL))
635 yajl_gen_map_open (handler);
636 yajl_gen_string (handler,
637 (unsigned char *) "select",
638 (unsigned int) strlen ("select"));
639 ident_to_json (cfg->select, handler);
640 yajl_gen_string (handler,
641 (unsigned char *) "instances",
642 (unsigned int) strlen ("instances"));
643 yajl_gen_array_open (handler);
644 for (i = 0; i < cfg->instances_num; i++)
645 inst_to_json (cfg->instances[i], handler);
646 yajl_gen_array_close (handler);
647 yajl_gen_map_close (handler);
650 } /* }}} int graph_to_json */
652 int graph_def_to_json (const graph_config_t *cfg, /* {{{ */
655 #define yajl_gen_string_cast(h,p,l) \
656 yajl_gen_string (h, (unsigned char *) p, (unsigned int) l)
658 if ((cfg == NULL) || (handler == NULL))
661 yajl_gen_map_open (handler);
663 yajl_gen_string_cast (handler, "select", strlen ("select"));
664 ident_to_json (cfg->select, handler);
665 if (cfg->title != NULL)
667 yajl_gen_string_cast (handler, "title", strlen ("title"));
668 yajl_gen_string_cast (handler, cfg->title, strlen (cfg->title));
670 if (cfg->vertical_label != NULL)
672 yajl_gen_string_cast (handler, "vertical_label", strlen ("vertical_label"));
673 yajl_gen_string_cast (handler, cfg->vertical_label, strlen (cfg->vertical_label));
675 yajl_gen_string_cast (handler, "show_zero", strlen ("show_zero"));
676 yajl_gen_bool (handler, cfg->show_zero);
678 yajl_gen_string_cast (handler, "defs", strlen ("defs"));
679 def_to_json (cfg->defs, handler);
681 yajl_gen_map_close (handler);
684 #undef yajl_gen_string_cast
685 } /* }}} int graph_def_to_json */
687 static int graph_sort_instances_cb (const void *v0, const void *v1) /* {{{ */
689 return (inst_compare (*(graph_instance_t * const *) v0,
690 *(graph_instance_t * const *) v1));
691 } /* }}} int graph_sort_instances_cb */
693 int graph_sort_instances (graph_config_t *cfg) /* {{{ */
698 if (cfg->instances_num < 2)
701 qsort (cfg->instances, cfg->instances_num, sizeof (*cfg->instances),
702 graph_sort_instances_cb);
705 } /* }}} int graph_sort_instances */
707 int graph_clear_instances (graph_config_t *cfg) /* {{{ */
714 for (i = 0; i < cfg->instances_num; i++)
715 inst_destroy (cfg->instances[i]);
716 free (cfg->instances);
717 cfg->instances = NULL;
718 cfg->instances_num = 0;
721 } /* }}} int graph_clear_instances */
723 int graph_get_rrdargs (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
726 if ((cfg == NULL) || (inst == NULL) || (args == NULL))
729 if (cfg->title != NULL)
731 array_append (args->options, "-t");
732 array_append (args->options, cfg->title);
735 if (cfg->vertical_label != NULL)
737 array_append (args->options, "-v");
738 array_append (args->options, cfg->vertical_label);
743 array_append (args->options, "-l");
744 array_append (args->options, "0");
748 } /* }}} int graph_get_rrdargs */
750 /* vim: set sw=2 sts=2 et fdm=marker : */