10 #include "graph_list.h"
11 #include "graph_ident.h"
12 #include "graph_def.h"
14 #include "utils_params.h"
17 #include <fcgi_stdio.h>
22 #define UPDATE_INTERVAL 10
24 #define ANY_TOKEN "/any/"
25 #define ALL_TOKEN "/all/"
30 struct gl_ident_stage_s /* {{{ */
34 char *plugin_instance;
38 typedef struct gl_ident_stage_s gl_ident_stage_t;
40 struct graph_instance_s /* {{{ */
42 graph_ident_t *select;
44 graph_ident_t **files;
47 graph_instance_t *next;
48 }; /* }}} struct graph_instance_s */
50 struct graph_config_s /* {{{ */
52 graph_ident_t *select;
59 graph_instance_t *instances;
62 }; /* }}} struct graph_config_s */
64 struct def_callback_data_s
66 graph_instance_t *inst;
69 typedef struct def_callback_data_s def_callback_data_t;
74 static graph_config_t *graph_config_head = NULL;
76 static time_t gl_last_update = 0;
81 /* FIXME: These "print_*" functions are used for debugging. They should be
82 * removed at some point. */
83 static int print_files (const graph_instance_t *inst) /* {{{ */
87 for (i = 0; i < inst->files_num; i++)
89 graph_ident_t *ident = inst->files[i];
92 file = ident_to_file (ident);
93 printf (" File \"%s\"\n", file);
98 } /* }}} int print_instances */
100 static int print_instances (const graph_config_t *cfg) /* {{{ */
102 graph_instance_t *inst;
104 for (inst = cfg->instances; inst != NULL; inst = inst->next)
108 str = ident_to_string (inst->select);
109 printf (" Instance \"%s\"\n", str);
116 } /* }}} int print_instances */
118 static int print_graphs (void) /* {{{ */
122 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
126 str = ident_to_string (cfg->select);
127 printf ("Graph \"%s\"\n", str);
130 print_instances (cfg);
134 } /* }}} int print_graphs */
137 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
138 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
140 if ((s1 == NULL) && (s2 == NULL))
146 assert ((s1 != NULL) && (s2 != NULL));
148 return (strcmp (s1, s2));
149 } /* }}} int strcmp_s */
152 static void instance_destroy (graph_instance_t *inst) /* {{{ */
154 graph_instance_t *next;
162 ident_destroy (inst->select);
164 for (i = 0; i < inst->files_num; i++)
165 ident_destroy (inst->files[i]);
170 instance_destroy (next);
171 } /* }}} void instance_destroy */
174 * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
175 * copied and returned. This function is used when creating graph_instance_t
176 * from graph_config_t.
178 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
179 const graph_ident_t *file)
183 if ((cfg == NULL) || (file == NULL))
186 i = malloc (sizeof (*i));
189 memset (i, 0, sizeof (*i));
191 i->select = ident_copy_with_selector (cfg->select, file,
192 IDENT_FLAG_REPLACE_ANY);
193 if (i->select == NULL)
195 DEBUG ("instance_create: ident_copy_with_selector returned NULL.\n");
205 if (cfg->instances == NULL)
209 graph_instance_t *last;
211 last = cfg->instances;
212 while (last->next != NULL)
219 } /* }}} graph_instance_t *instance_create */
221 static int instance_add_file (graph_instance_t *inst, /* {{{ */
222 const graph_ident_t *file)
226 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
231 inst->files[inst->files_num] = ident_clone (file);
232 if (inst->files[inst->files_num] == NULL)
238 } /* }}} int instance_add_file */
240 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
241 const graph_ident_t *file)
245 if ((cfg == NULL) || (file == NULL))
248 for (i = cfg->instances; i != NULL; i = i->next)
249 if (ident_matches (i->select, file))
253 } /* }}} graph_instance_t *graph_find_instance */
255 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
257 graph_instance_t *inst;
259 inst = graph_find_instance (cfg, file);
262 inst = instance_create (cfg, file);
267 return (instance_add_file (inst, file));
268 } /* }}} int graph_add_file */
270 static int graph_append (graph_config_t *cfg) /* {{{ */
272 graph_config_t *last;
277 if (graph_config_head == NULL)
279 graph_config_head = cfg;
283 last = graph_config_head;
284 while (last->next != NULL)
290 } /* }}} int graph_append */
292 static graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
296 cfg = malloc (sizeof (*cfg));
299 memset (cfg, 0, sizeof (*cfg));
301 cfg->select = ident_clone (selector);
304 cfg->vertical_label = NULL;
306 cfg->instances = NULL;
310 } /* }}} int graph_create */
312 static void graph_destroy (graph_config_t *cfg) /* {{{ */
314 graph_config_t *next;
321 ident_destroy (cfg->select);
324 free (cfg->vertical_label);
326 def_destroy (cfg->defs);
327 instance_destroy (cfg->instances);
329 graph_destroy (next);
330 } /* }}} void graph_destroy */
332 static int register_file (const graph_ident_t *file) /* {{{ */
337 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
341 if (!ident_matches (cfg->select, file))
344 status = graph_add_file (cfg, file);
357 cfg = graph_create (file);
359 graph_add_file (cfg, file);
363 } /* }}} int register_file */
365 static int FIXME_graph_create_from_file (const char *host, /* {{{ */
366 const char *plugin, const char *plugin_instance,
367 const char *type, const char *type_instance,
372 cfg = malloc (sizeof (*cfg));
375 memset (cfg, 0, sizeof (*cfg));
377 cfg->select = ident_create (host, plugin, plugin_instance, type, type_instance);
381 cfg->title = strdup (title);
382 cfg->vertical_label = NULL;
383 cfg->instances = NULL;
389 } /* }}} int FIXME_graph_create_from_file */
391 /* FIXME: Actually read the config file here. */
392 static int read_graph_config (void) /* {{{ */
394 if (graph_config_head != NULL)
397 FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ANY_TOKEN, "cpu", ALL_TOKEN,
398 "CPU {instance} usage");
399 FIXME_graph_create_from_file (ANY_TOKEN, "memory", "", "memory", ALL_TOKEN,
401 FIXME_graph_create_from_file (ANY_TOKEN, "swap", "", "swap", ALL_TOKEN,
403 FIXME_graph_create_from_file (ANY_TOKEN, ANY_TOKEN, ANY_TOKEN, "ps_state", ALL_TOKEN,
405 FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ALL_TOKEN, "cpu", "idle",
406 "CPU idle overview");
409 } /* }}} int read_graph_config */
411 static void gl_clear (void) /* {{{ */
415 cfg = graph_config_head;
416 graph_config_head = NULL;
420 } /* }}} void gl_clear */
422 static int callback_type (const char *type, void *user_data) /* {{{ */
424 gl_ident_stage_t *gl;
425 graph_ident_t *ident;
428 if ((type == NULL) || (user_data == NULL))
432 if ((gl->type != NULL) || (gl->type_instance != NULL))
435 gl->type = strdup (type);
436 if (gl->type == NULL)
439 gl->type_instance = strchr (gl->type, '-');
440 if (gl->type_instance != NULL)
442 *gl->type_instance = 0;
447 gl->type_instance = gl->type + strlen (gl->type);
450 ident = ident_create (gl->host,
451 gl->plugin, gl->plugin_instance,
452 gl->type, gl->type_instance);
459 status = register_file (ident);
460 ident_destroy (ident);
465 gl->type_instance = NULL;
468 } /* }}} int callback_type */
470 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
472 gl_ident_stage_t *gl;
475 if ((plugin == NULL) || (user_data == NULL))
479 if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
482 gl->plugin = strdup (plugin);
483 if (gl->plugin == NULL)
486 gl->plugin_instance = strchr (gl->plugin, '-');
487 if (gl->plugin_instance != NULL)
489 *gl->plugin_instance = 0;
490 gl->plugin_instance++;
494 gl->plugin_instance = gl->plugin + strlen (gl->plugin);
497 status = foreach_type (gl->host, plugin, callback_type, gl);
501 gl->plugin_instance = NULL;
504 } /* }}} int callback_plugin */
506 static int callback_host (const char *host, void *user_data) /* {{{ */
508 gl_ident_stage_t *gl;
511 if ((host == NULL) || (user_data == NULL))
515 if (gl->host != NULL)
518 gl->host = strdup (host);
519 if (gl->host == NULL)
522 status = foreach_plugin (host, callback_plugin, gl);
528 } /* }}} int callback_host */
530 static const char *get_part_from_param (const char *prim_key, /* {{{ */
535 val = param (prim_key);
539 return (param (sec_key));
540 } /* }}} const char *get_part_from_param */
542 /* Create one DEF for each data source in the file. Called by
543 * "gl_inst_get_default_defs" for each file. */
544 static graph_def_t *gl_ident_get_default_defs (graph_config_t *cfg, /* {{{ */
545 graph_ident_t *ident, graph_def_t *def_head)
547 graph_def_t *defs = NULL;
554 if ((cfg == NULL) || (ident == NULL))
557 file = ident_to_file (ident);
560 DEBUG ("gl_ident_get_default_defs: ident_to_file returned NULL.\n");
564 DEBUG ("gl_ident_get_default_defs: file = %s;\n", file);
566 status = ds_list_from_rrd_file (file, &dses_num, &dses);
573 for (i = 0; i < dses_num; i++)
577 def = def_search (def_head, ident, dses[i]);
581 def = def_create (cfg, ident, dses[i]);
588 def_append (defs, def);
597 } /* }}} int gl_ident_get_default_defs */
599 /* Create one or more DEFs for each file in the graph instance. The number
600 * depends on the number of data sources in each of the files. Called from
601 * "gl_instance_get_rrdargs" if no DEFs are available from the configuration.
603 static graph_def_t *gl_inst_get_default_defs (graph_config_t *cfg, /* {{{ */
604 graph_instance_t *inst)
606 graph_def_t *defs = NULL;
609 if ((cfg == NULL) || (inst == NULL))
612 for (i = 0; i < inst->files_num; i++)
616 def = gl_ident_get_default_defs (cfg, inst->files[i], defs);
623 def_append (defs, def);
627 } /* }}} graph_def_t *gl_inst_get_default_defs */
629 /* Called with each DEF in turn. Calls "def_get_rrdargs" with every appropriate
630 * file / DEF pair. */
631 static int gl_instance_get_rrdargs_cb (graph_def_t *def, void *user_data) /* {{{ */
633 def_callback_data_t *data = user_data;
634 graph_instance_t *inst = data->inst;
635 str_array_t *args = data->args;
639 for (i = 0; i < inst->files_num; i++)
641 if (!def_matches (def, inst->files[i]))
644 def_get_rrdargs (def, inst->files[i], args);
648 } /* }}} int gl_instance_get_rrdargs_cb */
653 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
654 char *buffer, size_t buffer_size)
656 if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
661 #define COPY_FIELD(field) do { \
662 const char *cfg_f = ident_get_##field (cfg->select); \
663 const char *inst_f = ident_get_##field (inst->select); \
664 if (strcmp (cfg_f, inst_f) == 0) \
666 strlcat (buffer, #field, buffer_size); \
667 strlcat (buffer, "=", buffer_size); \
668 strlcat (buffer, cfg_f, buffer_size); \
672 strlcat (buffer, "graph_", buffer_size); \
673 strlcat (buffer, #field, buffer_size); \
674 strlcat (buffer, "=", buffer_size); \
675 strlcat (buffer, cfg_f, buffer_size); \
676 strlcat (buffer, ";", buffer_size); \
677 strlcat (buffer, "inst_", buffer_size); \
678 strlcat (buffer, #field, buffer_size); \
679 strlcat (buffer, "=", buffer_size); \
680 strlcat (buffer, inst_f, buffer_size); \
685 strlcat (buffer, ";", buffer_size);
687 strlcat (buffer, ";", buffer_size);
688 COPY_FIELD(plugin_instance);
689 strlcat (buffer, ";", buffer_size);
691 strlcat (buffer, ";", buffer_size);
692 COPY_FIELD(type_instance);
697 } /* }}} int gl_instance_get_params */
699 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
701 const char *host = get_part_from_param ("inst_host", "host");
702 const char *plugin = get_part_from_param ("inst_plugin", "plugin");
703 const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
704 const char *type = get_part_from_param ("inst_type", "type");
705 const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
706 graph_ident_t *ident;
707 graph_instance_t *inst;
710 cfg = graph_get_selected ();
714 DEBUG ("inst_get_selected: cfg == NULL;\n");
719 || (plugin == NULL) || (plugin_instance == NULL)
720 || (type == NULL) || (type_instance == NULL))
722 DEBUG ("inst_get_selected: A parameter is NULL.\n");
726 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
728 for (inst = cfg->instances; inst != NULL; inst = inst->next)
730 if (ident_compare (ident, inst->select) != 0)
733 ident_destroy (ident);
737 DEBUG ("inst_get_selected: No match found.\n");
738 ident_destroy (ident);
740 } /* }}} graph_instance_t *inst_get_selected */
742 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
747 if (callback == NULL)
752 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
756 status = (*callback) (cfg, user_data);
762 } /* }}} int gl_graph_get_all */
764 graph_config_t *graph_get_selected (void) /* {{{ */
766 const char *host = get_part_from_param ("graph_host", "host");
767 const char *plugin = get_part_from_param ("graph_plugin", "plugin");
768 const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
769 const char *type = get_part_from_param ("graph_type", "type");
770 const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
771 graph_ident_t *ident;
775 || (plugin == NULL) || (plugin_instance == NULL)
776 || (type == NULL) || (type_instance == NULL))
779 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
783 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
785 if (ident_compare (ident, cfg->select) != 0)
788 ident_destroy (ident);
792 ident_destroy (ident);
794 } /* }}} graph_config_t *graph_get_selected */
796 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
797 gl_inst_callback callback, void *user_data)
799 graph_instance_t *inst;
801 if ((cfg == NULL) || (callback == NULL))
804 for (inst = cfg->instances; inst != NULL; inst = inst->next)
808 status = (*callback) (cfg, inst, user_data);
814 } /* }}} int gl_graph_instance_get_all */
816 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
817 char *buffer, size_t buffer_size)
821 if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
824 if (cfg->title != NULL)
827 str = ident_to_string (cfg->select);
832 strncpy (buffer, str, buffer_size);
833 buffer[buffer_size - 1] = 0;
838 } /* }}} int gl_graph_get_title */
840 graph_ident_t *gl_graph_get_selector (graph_config_t *cfg) /* {{{ */
845 return (ident_clone (cfg->select));
846 } /* }}} graph_ident_t *gl_graph_get_selector */
848 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
855 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
857 graph_instance_t *inst;
859 for (inst = cfg->instances; inst != NULL; inst = inst->next)
863 status = (*callback) (cfg, inst, user_data);
870 } /* }}} int gl_instance_get_all */
872 int gl_instance_get_rrdargs (graph_config_t *cfg, /* {{{ */
873 graph_instance_t *inst,
876 def_callback_data_t data = { inst, args };
877 graph_def_t *default_defs;
880 if ((cfg == NULL) || (inst == NULL) || (args == NULL))
883 if (cfg->title != NULL)
885 array_append (args, "-t");
886 array_append (args, cfg->title);
889 if (cfg->defs == NULL)
891 default_defs = gl_inst_get_default_defs (cfg, inst);
893 if (default_defs == NULL)
896 status = def_foreach (default_defs, gl_instance_get_rrdargs_cb, &data);
898 if (default_defs != NULL)
899 def_destroy (default_defs);
903 status = def_foreach (cfg->defs, gl_instance_get_rrdargs_cb, &data);
907 } /* }}} int gl_instance_get_rrdargs */
909 graph_ident_t *gl_instance_get_selector (graph_instance_t *inst) /* {{{ */
914 return (ident_clone (inst->select));
915 } /* }}} graph_ident_t *gl_instance_get_selector */
919 int gl_update (void) /* {{{ */
926 printf ("Content-Type: text/plain\n\n");
931 if ((gl_last_update + UPDATE_INTERVAL) >= now)
936 read_graph_config ();
938 memset (&gl, 0, sizeof (gl));
941 gl.plugin_instance = NULL;
943 gl.type_instance = NULL;
945 status = foreach_host (callback_host, &gl);
947 /* print_graphs (); */
950 } /* }}} int gl_update */
952 /* vim: set sw=2 sts=2 et fdm=marker : */