10 #include "graph_list.h"
11 #include "graph_ident.h"
13 #include "utils_params.h"
16 #include <fcgi_stdio.h>
21 #define UPDATE_INTERVAL 10
23 #define ANY_TOKEN "/any/"
24 #define ALL_TOKEN "/all/"
26 #define IS_ANY(str) (((str) != NULL) && (strcmp (ANY_TOKEN, (str)) == 0))
27 #define IS_ALL(str) (((str) != NULL) && (strcmp (ALL_TOKEN, (str)) == 0))
32 struct gl_ident_stage_s /* {{{ */
36 char *plugin_instance;
40 typedef struct gl_ident_stage_s gl_ident_stage_t;
42 struct graph_instance_s /* {{{ */
44 graph_ident_t *select;
46 graph_ident_t **files;
49 graph_instance_t *next;
50 }; /* }}} struct graph_instance_s */
53 typedef struct graph_def_s graph_def_t;
54 struct graph_def_s /* {{{ */
56 graph_ident_t *select;
66 }; /* }}} struct graph_def_s */
68 struct graph_config_s /* {{{ */
70 graph_ident_t *select;
75 graph_instance_t *instances;
78 }; /* }}} struct graph_config_s */
83 static graph_config_t *graph_config_head = NULL;
85 static time_t gl_last_update = 0;
90 /* FIXME: These "print_*" functions are used for debugging. They should be
91 * removed at some point. */
92 static int print_files (const graph_instance_t *inst) /* {{{ */
96 for (i = 0; i < inst->files_num; i++)
98 graph_ident_t *ident = inst->files[i];
101 file = ident_to_file (ident);
102 printf (" File \"%s\"\n", file);
107 } /* }}} int print_instances */
109 static int print_instances (const graph_config_t *cfg) /* {{{ */
111 graph_instance_t *inst;
113 for (inst = cfg->instances; inst != NULL; inst = inst->next)
117 str = ident_to_string (inst->select);
118 printf (" Instance \"%s\"\n", str);
125 } /* }}} int print_instances */
127 static int print_graphs (void) /* {{{ */
131 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
135 str = ident_to_string (cfg->select);
136 printf ("Graph \"%s\"\n", str);
139 print_instances (cfg);
143 } /* }}} int print_graphs */
146 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
147 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
149 if ((s1 == NULL) && (s2 == NULL))
155 assert ((s1 != NULL) && (s2 != NULL));
157 return (strcmp (s1, s2));
158 } /* }}} int strcmp_s */
161 static void instance_destroy (graph_instance_t *inst) /* {{{ */
163 graph_instance_t *next;
171 ident_destroy (inst->select);
173 for (i = 0; i < inst->files_num; i++)
174 ident_destroy (inst->files[i]);
179 instance_destroy (next);
180 } /* }}} void instance_destroy */
182 static void graph_destroy (graph_config_t *cfg) /* {{{ */
184 graph_config_t *next;
191 ident_destroy (cfg->select);
194 free (cfg->vertical_label);
196 instance_destroy (cfg->instances);
198 graph_destroy (next);
199 } /* }}} void graph_destroy */
202 * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
203 * copied and returned. This function is used when creating graph_instance_t
204 * from graph_config_t.
206 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
207 const graph_ident_t *file)
211 if ((cfg == NULL) || (file == NULL))
214 i = malloc (sizeof (*i));
217 memset (i, 0, sizeof (*i));
219 i->select = ident_copy_with_selector (cfg->select, file,
220 /* keep_all_selector = */ 1);
227 if (cfg->instances == NULL)
231 graph_instance_t *last;
233 last = cfg->instances;
234 while (last->next != NULL)
241 } /* }}} graph_instance_t *instance_create */
243 static int instance_add_file (graph_instance_t *inst, /* {{{ */
244 const graph_ident_t *file)
248 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
253 inst->files[inst->files_num] = ident_clone (file);
254 if (inst->files[inst->files_num] == NULL)
260 } /* }}} int instance_add_file */
262 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
263 const graph_ident_t *file)
267 if ((cfg == NULL) || (file == NULL))
270 for (i = cfg->instances; i != NULL; i = i->next)
271 if (ident_matches (i->select, file))
275 } /* }}} graph_instance_t *graph_find_instance */
277 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
279 graph_instance_t *inst;
281 inst = graph_find_instance (cfg, file);
284 inst = instance_create (cfg, file);
289 return (instance_add_file (inst, file));
290 } /* }}} int graph_add_file */
292 static int graph_append (graph_config_t *cfg) /* {{{ */
294 graph_config_t *last;
299 if (graph_config_head == NULL)
301 graph_config_head = cfg;
305 last = graph_config_head;
306 while (last->next != NULL)
312 } /* }}} int graph_append */
314 static int graph_create_from_file (const graph_ident_t *file) /* {{{ */
318 cfg = malloc (sizeof (*cfg));
321 memset (cfg, 0, sizeof (*cfg));
323 cfg->select = ident_clone (file);
326 cfg->vertical_label = NULL;
327 cfg->instances = NULL;
332 return (graph_add_file (cfg, file));
333 } /* }}} int graph_create_from_file */
335 static int register_file (const graph_ident_t *file) /* {{{ */
340 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
344 if (!ident_matches (cfg->select, file))
347 status = graph_add_file (cfg, file);
359 graph_create_from_file (file);
362 } /* }}} int register_file */
364 static int FIXME_graph_create_from_file (const char *host, /* {{{ */
365 const char *plugin, const char *plugin_instance,
366 const char *type, const char *type_instance,
371 cfg = malloc (sizeof (*cfg));
374 memset (cfg, 0, sizeof (*cfg));
376 cfg->select = ident_create (host, plugin, plugin_instance, type, type_instance);
380 cfg->title = strdup (title);
381 cfg->vertical_label = NULL;
382 cfg->instances = NULL;
388 } /* }}} int FIXME_graph_create_from_file */
390 /* FIXME: Actually read the config file here. */
391 static int read_graph_config (void) /* {{{ */
393 if (graph_config_head != NULL)
396 FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ANY_TOKEN, "cpu", ALL_TOKEN,
397 "CPU {instance} usage");
398 FIXME_graph_create_from_file (ANY_TOKEN, "memory", "", "memory", ALL_TOKEN,
400 FIXME_graph_create_from_file (ANY_TOKEN, "swap", "", "swap", ALL_TOKEN,
402 FIXME_graph_create_from_file (ANY_TOKEN, ANY_TOKEN, ANY_TOKEN, "ps_state", ALL_TOKEN,
404 FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ALL_TOKEN, "cpu", "idle",
405 "CPU idle overview");
408 } /* }}} int read_graph_config */
410 static void gl_clear (void) /* {{{ */
414 cfg = graph_config_head;
415 graph_config_head = NULL;
419 } /* }}} void gl_clear */
421 static int callback_type (const char *type, void *user_data) /* {{{ */
423 gl_ident_stage_t *gl;
424 graph_ident_t *ident;
427 if ((type == NULL) || (user_data == NULL))
431 if ((gl->type != NULL) || (gl->type_instance != NULL))
434 gl->type = strdup (type);
435 if (gl->type == NULL)
438 gl->type_instance = strchr (gl->type, '-');
439 if (gl->type_instance != NULL)
441 *gl->type_instance = 0;
446 gl->type_instance = gl->type + strlen (gl->type);
449 ident = ident_create (gl->host,
450 gl->plugin, gl->plugin_instance,
451 gl->type, gl->type_instance);
458 status = register_file (ident);
459 ident_destroy (ident);
464 gl->type_instance = NULL;
467 } /* }}} int callback_type */
469 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
471 gl_ident_stage_t *gl;
474 if ((plugin == NULL) || (user_data == NULL))
478 if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
481 gl->plugin = strdup (plugin);
482 if (gl->plugin == NULL)
485 gl->plugin_instance = strchr (gl->plugin, '-');
486 if (gl->plugin_instance != NULL)
488 *gl->plugin_instance = 0;
489 gl->plugin_instance++;
493 gl->plugin_instance = gl->plugin + strlen (gl->plugin);
496 status = foreach_type (gl->host, plugin, callback_type, gl);
500 gl->plugin_instance = NULL;
503 } /* }}} int callback_plugin */
505 static int callback_host (const char *host, void *user_data) /* {{{ */
507 gl_ident_stage_t *gl;
510 if ((host == NULL) || (user_data == NULL))
514 if (gl->host != NULL)
517 gl->host = strdup (host);
518 if (gl->host == NULL)
521 status = foreach_plugin (host, callback_plugin, gl);
527 } /* }}} int callback_host */
529 static const char *get_part_from_param (const char *prim_key, /* {{{ */
534 val = param (prim_key);
538 return (param (sec_key));
539 } /* }}} const char *get_part_from_param */
541 int gl_ident_get_rrdargs (graph_config_t *cfg, /* {{{ */
542 graph_instance_t *inst,
543 graph_ident_t *ident,
552 if ((cfg == NULL) || (inst == NULL) || (ident == NULL) || (args == NULL))
555 file = ident_to_file (ident);
558 DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
562 DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
564 status = ds_list_from_rrd_file (file, &dses_num, &dses);
571 for (i = 0; i < dses_num; i++)
575 DEBUG ("gl_ident_get_rrdargs: ds[%lu] = %s;\n", (unsigned long) i, dses[i]);
577 index = array_argc (args);
580 array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
581 index, file, dses[i]);
582 array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
583 index, file, dses[i]);
584 array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
585 index, file, dses[i]);
587 array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
589 array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
591 array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
593 array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
597 array_append_format (args, "LINE1:def_%04i_avg#%06"PRIx32":%s",
598 index, get_random_color (), dses[i]);
599 array_append_format (args, "GPRINT:vdef_%04i_min:%%lg min,", index);
600 array_append_format (args, "GPRINT:vdef_%04i_avg:%%lg avg,", index);
601 array_append_format (args, "GPRINT:vdef_%04i_max:%%lg max,", index);
602 array_append_format (args, "GPRINT:vdef_%04i_lst:%%lg last\\l", index);
611 } /* }}} int gl_ident_get_rrdargs */
616 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
617 char *buffer, size_t buffer_size)
619 if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
624 #define COPY_FIELD(field) do { \
625 const char *cfg_f = ident_get_##field (cfg->select); \
626 const char *inst_f = ident_get_##field (inst->select); \
627 if (strcmp (cfg_f, inst_f) == 0) \
629 strlcat (buffer, #field, buffer_size); \
630 strlcat (buffer, "=", buffer_size); \
631 strlcat (buffer, cfg_f, buffer_size); \
635 strlcat (buffer, "graph_", buffer_size); \
636 strlcat (buffer, #field, buffer_size); \
637 strlcat (buffer, "=", buffer_size); \
638 strlcat (buffer, cfg_f, buffer_size); \
639 strlcat (buffer, ";", buffer_size); \
640 strlcat (buffer, "inst_", buffer_size); \
641 strlcat (buffer, #field, buffer_size); \
642 strlcat (buffer, "=", buffer_size); \
643 strlcat (buffer, inst_f, buffer_size); \
648 strlcat (buffer, ";", buffer_size);
650 strlcat (buffer, ";", buffer_size);
651 COPY_FIELD(plugin_instance);
652 strlcat (buffer, ";", buffer_size);
654 strlcat (buffer, ";", buffer_size);
655 COPY_FIELD(type_instance);
660 } /* }}} int gl_instance_get_params */
662 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
664 const char *host = get_part_from_param ("inst_host", "host");
665 const char *plugin = get_part_from_param ("inst_plugin", "plugin");
666 const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
667 const char *type = get_part_from_param ("inst_type", "type");
668 const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
669 graph_ident_t *ident;
670 graph_instance_t *inst;
673 cfg = graph_get_selected ();
677 DEBUG ("inst_get_selected: cfg == NULL;\n");
682 || (plugin == NULL) || (plugin_instance == NULL)
683 || (type == NULL) || (type_instance == NULL))
685 DEBUG ("inst_get_selected: A parameter is NULL.\n");
689 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
691 for (inst = cfg->instances; inst != NULL; inst = inst->next)
693 if (ident_compare (ident, inst->select) != 0)
696 ident_destroy (ident);
700 DEBUG ("inst_get_selected: No match found.\n");
701 ident_destroy (ident);
703 } /* }}} graph_instance_t *inst_get_selected */
705 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
710 if (callback == NULL)
715 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
719 status = (*callback) (cfg, user_data);
725 } /* }}} int gl_graph_get_all */
727 graph_config_t *graph_get_selected (void) /* {{{ */
729 const char *host = get_part_from_param ("graph_host", "host");
730 const char *plugin = get_part_from_param ("graph_plugin", "plugin");
731 const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
732 const char *type = get_part_from_param ("graph_type", "type");
733 const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
734 graph_ident_t *ident;
738 || (plugin == NULL) || (plugin_instance == NULL)
739 || (type == NULL) || (type_instance == NULL))
742 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
746 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
748 if (ident_compare (ident, cfg->select) != 0)
751 ident_destroy (ident);
755 ident_destroy (ident);
757 } /* }}} graph_config_t *graph_get_selected */
759 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
760 gl_inst_callback callback, void *user_data)
762 graph_instance_t *inst;
764 if ((cfg == NULL) || (callback == NULL))
767 for (inst = cfg->instances; inst != NULL; inst = inst->next)
771 status = (*callback) (cfg, inst, user_data);
777 } /* }}} int gl_graph_instance_get_all */
779 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
780 char *buffer, size_t buffer_size)
784 if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
787 if (cfg->title != NULL)
790 str = ident_to_string (cfg->select);
795 strncpy (buffer, str, buffer_size);
796 buffer[buffer_size - 1] = 0;
801 } /* }}} int gl_graph_get_title */
803 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
810 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
812 graph_instance_t *inst;
814 for (inst = cfg->instances; inst != NULL; inst = inst->next)
818 status = (*callback) (cfg, inst, user_data);
825 } /* }}} int gl_instance_get_all */
827 int gl_instance_get_rrdargs (graph_config_t *cfg, /* {{{ */
828 graph_instance_t *inst,
833 if ((cfg == NULL) || (inst == NULL) || (args == NULL))
836 if (cfg->title != NULL)
838 array_append (args, "-t");
839 array_append (args, cfg->title);
842 for (i = 0; i < inst->files_num; i++)
846 status = gl_ident_get_rrdargs (cfg, inst, inst->files[i], args);
852 } /* }}} int gl_instance_get_rrdargs */
854 graph_ident_t *gl_instance_get_selector (graph_instance_t *inst) /* {{{ */
859 return (ident_clone (inst->select));
860 } /* }}} graph_ident_t *gl_instance_get_selector */
864 int gl_update (void) /* {{{ */
871 printf ("Content-Type: text/plain\n\n");
876 if ((gl_last_update + UPDATE_INTERVAL) >= now)
881 read_graph_config ();
883 memset (&gl, 0, sizeof (gl));
886 gl.plugin_instance = NULL;
888 gl.type_instance = NULL;
890 status = foreach_host (callback_host, &gl);
892 /* print_graphs (); */
895 } /* }}} int gl_update */
897 /* vim: set sw=2 sts=2 et fdm=marker : */