10 #include "graph_list.h"
11 #include "graph_ident.h"
12 #include "graph_def.h"
13 #include "graph_config.h"
15 #include "utils_params.h"
18 #include <fcgi_stdio.h>
23 #define UPDATE_INTERVAL 10
25 #define ANY_TOKEN "/any/"
26 #define ALL_TOKEN "/all/"
31 struct gl_ident_stage_s /* {{{ */
35 char *plugin_instance;
39 typedef struct gl_ident_stage_s gl_ident_stage_t;
41 struct graph_instance_s /* {{{ */
43 graph_ident_t *select;
45 graph_ident_t **files;
48 graph_instance_t *next;
49 }; /* }}} struct graph_instance_s */
51 struct graph_config_s /* {{{ */
53 graph_ident_t *select;
60 graph_instance_t *instances;
63 }; /* }}} struct graph_config_s */
65 struct def_callback_data_s
67 graph_instance_t *inst;
70 typedef struct def_callback_data_s def_callback_data_t;
75 static graph_config_t *graph_config_head = NULL;
76 static graph_config_t *graph_config_staging = NULL;
78 static time_t gl_last_update = 0;
83 /* FIXME: These "print_*" functions are used for debugging. They should be
84 * removed at some point. */
85 static int print_files (const graph_instance_t *inst) /* {{{ */
89 for (i = 0; i < inst->files_num; i++)
91 graph_ident_t *ident = inst->files[i];
94 file = ident_to_file (ident);
95 printf (" File \"%s\"\n", file);
100 } /* }}} int print_instances */
102 static int print_instances (const graph_config_t *cfg) /* {{{ */
104 graph_instance_t *inst;
106 for (inst = cfg->instances; inst != NULL; inst = inst->next)
110 str = ident_to_string (inst->select);
111 printf (" Instance \"%s\"\n", str);
118 } /* }}} int print_instances */
120 static int print_graphs (void) /* {{{ */
124 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
128 str = ident_to_string (cfg->select);
129 printf ("Graph \"%s\"\n", str);
132 print_instances (cfg);
136 } /* }}} int print_graphs */
139 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
140 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
142 if ((s1 == NULL) && (s2 == NULL))
148 assert ((s1 != NULL) && (s2 != NULL));
150 return (strcmp (s1, s2));
151 } /* }}} int strcmp_s */
154 static void instance_destroy (graph_instance_t *inst) /* {{{ */
156 graph_instance_t *next;
164 ident_destroy (inst->select);
166 for (i = 0; i < inst->files_num; i++)
167 ident_destroy (inst->files[i]);
172 instance_destroy (next);
173 } /* }}} void instance_destroy */
176 * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
177 * copied and returned. This function is used when creating graph_instance_t
178 * from graph_config_t.
180 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
181 const graph_ident_t *file)
185 if ((cfg == NULL) || (file == NULL))
188 i = malloc (sizeof (*i));
191 memset (i, 0, sizeof (*i));
193 i->select = ident_copy_with_selector (cfg->select, file,
194 IDENT_FLAG_REPLACE_ANY);
195 if (i->select == NULL)
197 DEBUG ("instance_create: ident_copy_with_selector returned NULL.\n");
207 if (cfg->instances == NULL)
211 graph_instance_t *last;
213 last = cfg->instances;
214 while (last->next != NULL)
221 } /* }}} graph_instance_t *instance_create */
223 static int instance_add_file (graph_instance_t *inst, /* {{{ */
224 const graph_ident_t *file)
228 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
233 inst->files[inst->files_num] = ident_clone (file);
234 if (inst->files[inst->files_num] == NULL)
240 } /* }}} int instance_add_file */
242 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
243 const graph_ident_t *file)
247 if ((cfg == NULL) || (file == NULL))
250 for (i = cfg->instances; i != NULL; i = i->next)
251 if (ident_matches (i->select, file))
255 } /* }}} graph_instance_t *graph_find_instance */
257 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
259 graph_instance_t *inst;
261 inst = graph_find_instance (cfg, file);
264 inst = instance_create (cfg, file);
269 return (instance_add_file (inst, file));
270 } /* }}} int graph_add_file */
272 static int graph_append (graph_config_t **head, /* {{{ */
275 graph_config_t *last;
281 head = &graph_config_head;
290 while (last->next != NULL)
296 } /* }}} int graph_append */
298 static graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
302 cfg = malloc (sizeof (*cfg));
305 memset (cfg, 0, sizeof (*cfg));
307 if (selector != NULL)
308 cfg->select = ident_clone (selector);
313 cfg->vertical_label = NULL;
315 cfg->instances = NULL;
319 } /* }}} int graph_create */
321 static void graph_destroy (graph_config_t *cfg) /* {{{ */
323 graph_config_t *next;
330 ident_destroy (cfg->select);
333 free (cfg->vertical_label);
335 def_destroy (cfg->defs);
336 instance_destroy (cfg->instances);
338 graph_destroy (next);
339 } /* }}} void graph_destroy */
341 static int register_file (const graph_ident_t *file) /* {{{ */
346 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
350 if (!ident_matches (cfg->select, file))
353 status = graph_add_file (cfg, file);
366 cfg = graph_create (file);
367 graph_append (/* head = */ NULL, cfg);
368 graph_add_file (cfg, file);
372 } /* }}} int register_file */
374 static int callback_type (const char *type, void *user_data) /* {{{ */
376 gl_ident_stage_t *gl;
377 graph_ident_t *ident;
380 if ((type == NULL) || (user_data == NULL))
384 if ((gl->type != NULL) || (gl->type_instance != NULL))
387 gl->type = strdup (type);
388 if (gl->type == NULL)
391 gl->type_instance = strchr (gl->type, '-');
392 if (gl->type_instance != NULL)
394 *gl->type_instance = 0;
399 gl->type_instance = gl->type + strlen (gl->type);
402 ident = ident_create (gl->host,
403 gl->plugin, gl->plugin_instance,
404 gl->type, gl->type_instance);
411 status = register_file (ident);
412 ident_destroy (ident);
417 gl->type_instance = NULL;
420 } /* }}} int callback_type */
422 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
424 gl_ident_stage_t *gl;
427 if ((plugin == NULL) || (user_data == NULL))
431 if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
434 gl->plugin = strdup (plugin);
435 if (gl->plugin == NULL)
438 gl->plugin_instance = strchr (gl->plugin, '-');
439 if (gl->plugin_instance != NULL)
441 *gl->plugin_instance = 0;
442 gl->plugin_instance++;
446 gl->plugin_instance = gl->plugin + strlen (gl->plugin);
449 status = foreach_type (gl->host, plugin, callback_type, gl);
453 gl->plugin_instance = NULL;
456 } /* }}} int callback_plugin */
458 static int callback_host (const char *host, void *user_data) /* {{{ */
460 gl_ident_stage_t *gl;
463 if ((host == NULL) || (user_data == NULL))
467 if (gl->host != NULL)
470 gl->host = strdup (host);
471 if (gl->host == NULL)
474 status = foreach_plugin (host, callback_plugin, gl);
480 } /* }}} int callback_host */
482 static const char *get_part_from_param (const char *prim_key, /* {{{ */
487 val = param (prim_key);
491 return (param (sec_key));
492 } /* }}} const char *get_part_from_param */
494 /* Create one DEF for each data source in the file. Called by
495 * "gl_inst_get_default_defs" for each file. */
496 static graph_def_t *gl_ident_get_default_defs (graph_config_t *cfg, /* {{{ */
497 graph_ident_t *ident, graph_def_t *def_head)
499 graph_def_t *defs = NULL;
506 if ((cfg == NULL) || (ident == NULL))
509 file = ident_to_file (ident);
512 DEBUG ("gl_ident_get_default_defs: ident_to_file returned NULL.\n");
516 DEBUG ("gl_ident_get_default_defs: file = %s;\n", file);
518 status = ds_list_from_rrd_file (file, &dses_num, &dses);
525 for (i = 0; i < dses_num; i++)
529 def = def_search (def_head, ident, dses[i]);
533 def = def_create (cfg, ident, dses[i]);
540 def_append (defs, def);
549 } /* }}} int gl_ident_get_default_defs */
551 /* Create one or more DEFs for each file in the graph instance. The number
552 * depends on the number of data sources in each of the files. Called from
553 * "gl_instance_get_rrdargs" if no DEFs are available from the configuration.
555 static graph_def_t *gl_inst_get_default_defs (graph_config_t *cfg, /* {{{ */
556 graph_instance_t *inst)
558 graph_def_t *defs = NULL;
561 if ((cfg == NULL) || (inst == NULL))
564 for (i = 0; i < inst->files_num; i++)
568 def = gl_ident_get_default_defs (cfg, inst->files[i], defs);
575 def_append (defs, def);
579 } /* }}} graph_def_t *gl_inst_get_default_defs */
581 /* Called with each DEF in turn. Calls "def_get_rrdargs" with every appropriate
582 * file / DEF pair. */
583 static int gl_instance_get_rrdargs_cb (graph_def_t *def, void *user_data) /* {{{ */
585 def_callback_data_t *data = user_data;
586 graph_instance_t *inst = data->inst;
587 str_array_t *args = data->args;
591 for (i = 0; i < inst->files_num; i++)
593 if (!def_matches (def, inst->files[i]))
596 def_get_rrdargs (def, inst->files[i], args);
600 } /* }}} int gl_instance_get_rrdargs_cb */
602 static int gl_clear_instances (void) /* {{{ */
606 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
608 instance_destroy (cfg->instances);
609 cfg->instances = NULL;
613 } /* }}} int gl_clear_instances */
619 static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
623 char *plugin_instance = NULL;
625 char *type_instance = NULL;
629 for (i = 0; i < ci->children_num; i++)
631 oconfig_item_t *child;
633 child = ci->children + i;
635 if (strcasecmp ("Host", child->key) == 0)
636 graph_config_get_string (child, &host);
637 else if (strcasecmp ("Plugin", child->key) == 0)
638 graph_config_get_string (child, &plugin);
639 else if (strcasecmp ("PluginInstance", child->key) == 0)
640 graph_config_get_string (child, &plugin_instance);
641 else if (strcasecmp ("Type", child->key) == 0)
642 graph_config_get_string (child, &type);
643 else if (strcasecmp ("TypeInstance", child->key) == 0)
644 graph_config_get_string (child, &type_instance);
645 /* else: ignore all other directives here. */
648 ret = ident_create (host, plugin, plugin_instance, type, type_instance);
652 free (plugin_instance);
654 free (type_instance);
657 } /* }}} int graph_config_get_selector */
663 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
665 graph_ident_t *select;
666 graph_config_t *cfg = NULL;
669 select = graph_config_get_selector (ci);
673 cfg = graph_create (/* selector = */ NULL);
677 cfg->select = select;
679 for (i = 0; i < ci->children_num; i++)
681 oconfig_item_t *child;
683 child = ci->children + i;
685 if (strcasecmp ("Title", child->key) == 0)
686 graph_config_get_string (child, &cfg->title);
687 else if (strcasecmp ("VerticalLabel", child->key) == 0)
688 graph_config_get_string (child, &cfg->vertical_label);
689 else if (strcasecmp ("DEF", child->key) == 0)
690 def_config (cfg, child);
693 graph_append (&graph_config_staging, cfg);
696 } /* }}} graph_config_add */
698 int graph_config_submit (void) /* {{{ */
702 tmp = graph_config_head;
703 graph_config_head = graph_config_staging;
704 graph_config_staging = NULL;
709 } /* }}} int graph_config_submit */
711 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
712 char *buffer, size_t buffer_size)
714 if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
719 #define COPY_FIELD(field) do { \
720 const char *cfg_f = ident_get_##field (cfg->select); \
721 const char *inst_f = ident_get_##field (inst->select); \
722 if (strcmp (cfg_f, inst_f) == 0) \
724 strlcat (buffer, #field, buffer_size); \
725 strlcat (buffer, "=", buffer_size); \
726 strlcat (buffer, cfg_f, buffer_size); \
730 strlcat (buffer, "graph_", buffer_size); \
731 strlcat (buffer, #field, buffer_size); \
732 strlcat (buffer, "=", buffer_size); \
733 strlcat (buffer, cfg_f, buffer_size); \
734 strlcat (buffer, ";", buffer_size); \
735 strlcat (buffer, "inst_", buffer_size); \
736 strlcat (buffer, #field, buffer_size); \
737 strlcat (buffer, "=", buffer_size); \
738 strlcat (buffer, inst_f, buffer_size); \
743 strlcat (buffer, ";", buffer_size);
745 strlcat (buffer, ";", buffer_size);
746 COPY_FIELD(plugin_instance);
747 strlcat (buffer, ";", buffer_size);
749 strlcat (buffer, ";", buffer_size);
750 COPY_FIELD(type_instance);
755 } /* }}} int gl_instance_get_params */
757 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
759 const char *host = get_part_from_param ("inst_host", "host");
760 const char *plugin = get_part_from_param ("inst_plugin", "plugin");
761 const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
762 const char *type = get_part_from_param ("inst_type", "type");
763 const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
764 graph_ident_t *ident;
765 graph_instance_t *inst;
768 cfg = graph_get_selected ();
772 DEBUG ("inst_get_selected: cfg == NULL;\n");
777 || (plugin == NULL) || (plugin_instance == NULL)
778 || (type == NULL) || (type_instance == NULL))
780 DEBUG ("inst_get_selected: A parameter is NULL.\n");
784 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
786 for (inst = cfg->instances; inst != NULL; inst = inst->next)
788 if (ident_compare (ident, inst->select) != 0)
791 ident_destroy (ident);
795 DEBUG ("inst_get_selected: No match found.\n");
796 ident_destroy (ident);
798 } /* }}} graph_instance_t *inst_get_selected */
800 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
805 if (callback == NULL)
810 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
814 status = (*callback) (cfg, user_data);
820 } /* }}} int gl_graph_get_all */
822 graph_config_t *graph_get_selected (void) /* {{{ */
824 const char *host = get_part_from_param ("graph_host", "host");
825 const char *plugin = get_part_from_param ("graph_plugin", "plugin");
826 const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
827 const char *type = get_part_from_param ("graph_type", "type");
828 const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
829 graph_ident_t *ident;
833 || (plugin == NULL) || (plugin_instance == NULL)
834 || (type == NULL) || (type_instance == NULL))
837 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
841 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
843 if (ident_compare (ident, cfg->select) != 0)
846 ident_destroy (ident);
850 ident_destroy (ident);
852 } /* }}} graph_config_t *graph_get_selected */
854 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
855 gl_inst_callback callback, void *user_data)
857 graph_instance_t *inst;
859 if ((cfg == NULL) || (callback == NULL))
862 for (inst = cfg->instances; inst != NULL; inst = inst->next)
866 status = (*callback) (cfg, inst, user_data);
872 } /* }}} int gl_graph_instance_get_all */
874 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
875 char *buffer, size_t buffer_size)
877 if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
880 if (cfg->title == NULL)
881 cfg->title = ident_to_string (cfg->select);
883 if (cfg->title == NULL)
886 strncpy (buffer, cfg->title, buffer_size);
887 buffer[buffer_size - 1] = 0;
890 } /* }}} int gl_graph_get_title */
892 graph_ident_t *gl_graph_get_selector (graph_config_t *cfg) /* {{{ */
897 return (ident_clone (cfg->select));
898 } /* }}} graph_ident_t *gl_graph_get_selector */
900 int gl_graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
902 if ((cfg == NULL) || (def == NULL))
905 if (cfg->defs == NULL)
911 return (def_append (cfg->defs, def));
912 } /* }}} int gl_graph_add_def */
915 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
922 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
924 graph_instance_t *inst;
926 for (inst = cfg->instances; inst != NULL; inst = inst->next)
930 status = (*callback) (cfg, inst, user_data);
937 } /* }}} int gl_instance_get_all */
939 int gl_instance_get_rrdargs (graph_config_t *cfg, /* {{{ */
940 graph_instance_t *inst,
943 def_callback_data_t data = { inst, args };
944 graph_def_t *default_defs;
947 if ((cfg == NULL) || (inst == NULL) || (args == NULL))
950 if (cfg->title != NULL)
952 array_append (args, "-t");
953 array_append (args, cfg->title);
956 if (cfg->vertical_label != NULL)
958 array_append (args, "-v");
959 array_append (args, cfg->vertical_label);
962 if (cfg->defs == NULL)
964 default_defs = gl_inst_get_default_defs (cfg, inst);
966 if (default_defs == NULL)
969 status = def_foreach (default_defs, gl_instance_get_rrdargs_cb, &data);
971 if (default_defs != NULL)
972 def_destroy (default_defs);
976 status = def_foreach (cfg->defs, gl_instance_get_rrdargs_cb, &data);
980 } /* }}} int gl_instance_get_rrdargs */
982 graph_ident_t *gl_instance_get_selector (graph_instance_t *inst) /* {{{ */
987 return (ident_clone (inst->select));
988 } /* }}} graph_ident_t *gl_instance_get_selector */
990 int gl_update (void) /* {{{ */
997 printf ("Content-Type: text/plain\n\n");
1002 if ((gl_last_update + UPDATE_INTERVAL) >= now)
1005 graph_read_config ();
1007 memset (&gl, 0, sizeof (gl));
1010 gl.plugin_instance = NULL;
1012 gl.type_instance = NULL;
1014 gl_clear_instances ();
1015 status = foreach_host (callback_host, &gl);
1017 gl_last_update = now;
1020 } /* }}} int gl_update */
1022 /* vim: set sw=2 sts=2 et fdm=marker : */