9 #include <fcgi_stdio.h>
11 #include "graph_list.h"
17 #define UPDATE_INTERVAL 10
19 #define ANY_TOKEN "/any/"
20 #define ALL_TOKEN "/all/"
25 struct graph_ident_s /* {{{ */
29 char *plugin_instance;
32 }; /* }}} struct graph_ident_s */
34 struct graph_instance_s /* {{{ */
41 graph_instance_t *next;
42 }; /* }}} struct graph_instance_s */
44 struct graph_config_s /* {{{ */
51 graph_instance_t *instances;
54 }; /* }}} struct graph_config_s */
59 static graph_config_t *graph_config_head = NULL;
61 static graph_ident_t *graph_list = NULL;
62 static size_t graph_list_length = 0;
63 static time_t gl_last_update = 0;
68 /* FIXME: These "print_*" functions are used for debugging. They should be
69 * removed at some point. */
70 static int print_files (const graph_instance_t *inst) /* {{{ */
74 for (i = 0; i < inst->files_num; i++)
76 graph_ident_t *file = inst->files + i;
78 printf (" File \"%s/%s-%s/%s-%s\"\n",
80 file->plugin, file->plugin_instance,
81 file->type, file->type_instance);
85 } /* }}} int print_instances */
87 static int print_instances (const graph_config_t *cfg) /* {{{ */
89 graph_instance_t *inst;
91 for (inst = cfg->instances; inst != NULL; inst = inst->next)
93 printf (" Instance \"%s/%s-%s/%s-%s\"\n",
95 inst->select.plugin, inst->select.plugin_instance,
96 inst->select.type, inst->select.type_instance);
102 } /* }}} int print_instances */
104 static int print_graphs (void) /* {{{ */
108 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
110 printf ("Graph \"%s/%s-%s/%s-%s\"\n",
112 cfg->select.plugin, cfg->select.plugin_instance,
113 cfg->select.type, cfg->select.type_instance);
115 print_instances (cfg);
119 } /* }}} int print_graphs */
121 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
122 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
124 if ((s1 == NULL) && (s2 == NULL))
130 assert ((s1 != NULL) && (s2 != NULL));
132 return (strcmp (s1, s2));
133 } /* }}} int strcmp_s */
135 static _Bool part_matches (const char *sel, const char *val) /* {{{ */
137 if ((sel == NULL) && (val == NULL))
140 if (sel == NULL) /* && (val != NULL) */
143 if ((strcasecmp (ALL_TOKEN, sel) == 0)
144 || (strcasecmp (ANY_TOKEN, sel) == 0))
147 if (val == NULL) /* && (sel != NULL) */
150 if (strcmp (sel, val) == 0)
154 } /* }}} _Bool part_matches */
156 static _Bool file_matches (const graph_ident_t *sel, /* {{{ */
157 const graph_ident_t *val)
159 if ((sel == NULL) && (val == NULL))
161 else if (sel == NULL)
163 else if (val == NULL)
166 if (!part_matches (sel->host, val->host))
169 if (!part_matches (sel->plugin, val->plugin))
172 if (!part_matches (sel->plugin_instance, val->plugin_instance))
175 if (!part_matches (sel->type, val->type))
178 if (!part_matches (sel->type_instance, val->type_instance))
182 } /* }}} _Bool ident_compare */
185 * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
186 * copied and returned. This function is used when creating graph_instance_t
187 * from graph_config_t.
189 static char *identifier_copy_part (const char *template, const char *value) /* {{{ */
191 if (template == NULL)
195 else if (strcasecmp (ANY_TOKEN, template) == 0)
197 /* ANY in the graph selection => concrete value in the instance. */
201 return (strdup (value));
203 else if (strcasecmp (ALL_TOKEN, template) == 0)
205 /* ALL in the graph selection => ALL in the instance. */
206 return (strdup (ALL_TOKEN));
210 assert (value != NULL);
211 assert (strcmp (template, value) == 0);
212 return (strdup (template));
214 } /* }}} int identifier_copy_part */
216 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
217 const graph_ident_t *file)
221 if ((cfg == NULL) || (file == NULL))
224 i = malloc (sizeof (*i));
227 memset (i, 0, sizeof (*i));
229 i->select.host = identifier_copy_part (cfg->select.host, file->host);
230 i->select.plugin = identifier_copy_part (cfg->select.plugin, file->plugin);
231 i->select.plugin_instance = identifier_copy_part (cfg->select.plugin_instance,
232 file->plugin_instance);
233 i->select.type = identifier_copy_part (cfg->select.type, file->type);
234 i->select.type_instance = identifier_copy_part (cfg->select.type_instance,
235 file->type_instance);
242 if (cfg->instances == NULL)
246 graph_instance_t *last;
248 last = cfg->instances;
249 while (last->next != NULL)
256 } /* }}} graph_instance_t *instance_create */
258 static int instance_add_file (graph_instance_t *inst, /* {{{ */
259 const graph_ident_t *file)
263 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
267 tmp = inst->files + inst->files_num;
269 memset (tmp, 0, sizeof (*tmp));
270 tmp->host = strdup (file->host);
271 tmp->plugin = strdup (file->plugin);
272 if (file->plugin_instance != NULL)
273 tmp->plugin_instance = strdup (file->plugin_instance);
275 tmp->plugin_instance = NULL;
276 tmp->type = strdup (file->type);
277 if (file->type_instance != NULL)
278 tmp->type_instance = strdup (file->type_instance);
280 tmp->type_instance = NULL;
285 } /* }}} int instance_add_file */
287 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
288 const graph_ident_t *file)
292 if ((cfg == NULL) || (file == NULL))
295 for (i = cfg->instances; i != NULL; i = i->next)
296 if (file_matches (&i->select, file))
300 } /* }}} graph_instance_t *graph_find_instance */
302 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
304 graph_instance_t *inst;
306 inst = graph_find_instance (cfg, file);
309 inst = instance_create (cfg, file);
314 return (instance_add_file (inst, file));
315 } /* }}} int graph_add_file */
317 static int graph_append (graph_config_t *cfg) /* {{{ */
319 graph_config_t *last;
324 if (graph_config_head == NULL)
326 graph_config_head = cfg;
330 last = graph_config_head;
331 while (last->next != NULL)
337 } /* }}} int graph_append */
339 static int graph_create_from_file (const graph_ident_t *file) /* {{{ */
343 cfg = malloc (sizeof (*cfg));
346 memset (cfg, 0, sizeof (*cfg));
348 cfg->select.host = strdup (file->host);
349 cfg->select.plugin = strdup (file->plugin);
350 cfg->select.plugin_instance = strdup (file->plugin_instance);
351 cfg->select.type = strdup (file->type);
352 cfg->select.type_instance = strdup (file->type_instance);
355 cfg->vertical_label = NULL;
356 cfg->instances = NULL;
361 return (graph_add_file (cfg, file));
362 } /* }}} int graph_create_from_file */
364 static int register_file (const graph_ident_t *file) /* {{{ */
369 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
373 if (!file_matches (&cfg->select, file))
376 status = graph_add_file (cfg, file);
388 graph_create_from_file (file);
391 } /* }}} int register_file */
393 static int FIXME_graph_create_from_file (const graph_ident_t *file) /* {{{ */
397 cfg = malloc (sizeof (*cfg));
400 memset (cfg, 0, sizeof (*cfg));
402 cfg->select.host = strdup (file->host);
403 cfg->select.plugin = strdup (file->plugin);
404 cfg->select.plugin_instance = strdup (file->plugin_instance);
405 cfg->select.type = strdup (file->type);
406 cfg->select.type_instance = strdup (file->type_instance);
409 cfg->vertical_label = NULL;
410 cfg->instances = NULL;
416 } /* }}} int FIXME_graph_create_from_file */
418 /* FIXME: Actually read the config file here. */
419 static int read_graph_config (void) /* {{{ */
421 if (graph_config_head != NULL)
427 ident.host = ANY_TOKEN;
428 ident.plugin = "cpu";
429 ident.plugin_instance = ANY_TOKEN;
431 ident.type_instance = ALL_TOKEN;
432 FIXME_graph_create_from_file (&ident);
434 ident.plugin = "memory";
435 ident.plugin_instance = "";
436 ident.type = "memory";
437 FIXME_graph_create_from_file (&ident);
439 ident.plugin = "swap";
440 ident.plugin_instance = "";
442 FIXME_graph_create_from_file (&ident);
444 ident.plugin = ANY_TOKEN;
445 ident.plugin_instance = ANY_TOKEN;
446 ident.type = "ps_state";
447 FIXME_graph_create_from_file (&ident);
449 ident.host = ALL_TOKEN;
450 ident.plugin = "cpu";
451 ident.plugin_instance = ALL_TOKEN;
453 ident.type_instance = "idle";
454 FIXME_graph_create_from_file (&ident);
457 } /* }}} int read_graph_config */
461 static int gl_compare (const void *p0, const void *p1) /* {{{ */
463 const graph_ident_t *gl0 = p0;
464 const graph_ident_t *gl1 = p1;
467 status = strcmp (gl0->host, gl1->host);
471 status = strcmp (gl0->plugin, gl1->plugin);
475 status = strcmp_s (gl0->plugin_instance, gl1->plugin_instance);
479 status = strcmp (gl0->type, gl1->type);
483 return (strcmp_s (gl0->type_instance, gl1->type_instance));
484 } /* }}} int gl_compare */
486 static void gl_clear_entry (graph_ident_t *gl) /* {{{ */
493 free (gl->plugin_instance);
495 free (gl->type_instance);
499 gl->plugin_instance = NULL;
501 gl->type_instance = NULL;
502 } /* }}} void gl_clear_entry */
504 static void gl_clear (void) /* {{{ */
508 for (i = 0; i < graph_list_length; i++)
509 gl_clear_entry (graph_list + i);
513 graph_list_length = 0;
515 } /* }}} void gl_clear */
517 static int gl_add_copy (graph_ident_t *gl) /* {{{ */
525 ptr = realloc (graph_list, sizeof (*graph_list) * (graph_list_length + 1));
530 ptr = graph_list + graph_list_length;
531 memset (ptr, 0, sizeof (*ptr));
534 ptr->plugin_instance = NULL;
536 ptr->type_instance = NULL;
538 #define DUP_OR_BREAK(member) do { \
539 ptr->member = NULL; \
540 if (gl->member != NULL) \
542 ptr->member = strdup (gl->member); \
543 if (ptr->member == NULL) \
552 DUP_OR_BREAK(plugin);
553 DUP_OR_BREAK(plugin_instance);
555 DUP_OR_BREAK(type_instance);
566 free (ptr->plugin_instance);
568 free (ptr->type_instance);
574 } /* }}} int gl_add_copy */
576 static int callback_type (const char *type, void *user_data) /* {{{ */
581 if ((type == NULL) || (user_data == NULL))
585 if ((gl->type != NULL) || (gl->type_instance != NULL))
588 gl->type = strdup (type);
589 if (gl->type == NULL)
592 gl->type_instance = strchr (gl->type, '-');
593 if (gl->type_instance != NULL)
595 *gl->type_instance = 0;
600 gl->type_instance = gl->type + strlen (gl->type);
605 status = gl_add_copy (gl);
609 gl->type_instance = NULL;
612 } /* }}} int callback_type */
614 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
619 if ((plugin == NULL) || (user_data == NULL))
623 if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
626 gl->plugin = strdup (plugin);
627 if (gl->plugin == NULL)
630 gl->plugin_instance = strchr (gl->plugin, '-');
631 if (gl->plugin_instance != NULL)
633 *gl->plugin_instance = 0;
634 gl->plugin_instance++;
638 gl->plugin_instance = gl->plugin + strlen (gl->plugin);
641 status = foreach_type (gl->host, plugin, callback_type, gl);
645 gl->plugin_instance = NULL;
648 } /* }}} int callback_plugin */
650 static int callback_host (const char *host, void *user_data) /* {{{ */
655 if ((host == NULL) || (user_data == NULL))
659 if (gl->host != NULL)
662 gl->host = strdup (host);
663 if (gl->host == NULL)
666 status = foreach_plugin (host, callback_plugin, gl);
672 } /* }}} int callback_host */
677 int gl_instance_get_ident (graph_instance_t *inst, /* {{{ */
678 char *buffer, size_t buffer_size)
680 if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
683 snprintf (buffer, buffer_size, "%s/%s-%s/%s-%s",
685 inst->select.plugin, inst->select.plugin_instance,
686 inst->select.type, inst->select.type_instance);
687 buffer[buffer_size - 1] = 0;
690 } /* }}} int gl_instance_get_ident */
692 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
697 if (callback == NULL)
700 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
704 status = (*callback) (cfg, user_data);
710 } /* }}} int gl_graph_get_all */
712 int gl_graph_instance_get_all (graph_config_t *cfg,
713 gl_inst_callback callback, void *user_data)
715 graph_instance_t *inst;
717 if ((cfg == NULL) || (callback == NULL))
720 for (inst = cfg->instances; inst != NULL; inst = inst->next)
724 status = (*callback) (cfg, inst, user_data);
730 } /* }}} int gl_graph_instance_get_all */
732 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
737 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
739 graph_instance_t *inst;
741 for (inst = cfg->instances; inst != NULL; inst = inst->next)
745 status = (*callback) (cfg, inst, user_data);
752 } /* }}} int gl_instance_get_all */
754 int gl_update (void) /* {{{ */
761 printf ("Content-Type: text/plain\n\n");
764 read_graph_config ();
768 if ((gl_last_update + UPDATE_INTERVAL) >= now)
773 memset (&gl, 0, sizeof (gl));
776 gl.plugin_instance = NULL;
778 gl.type_instance = NULL;
780 status = foreach_host (callback_host, &gl);
782 /* print_graphs (); */
784 if (graph_list_length > 1)
785 qsort (graph_list, graph_list_length, sizeof (*graph_list), gl_compare);
788 } /* }}} int gl_update */
790 int gl_foreach (gl_callback callback, void *user_data) /* {{{ */
794 for (i = 0; i < graph_list_length; i++)
798 status = (*callback) ((void *) (graph_list + i), user_data);
804 } /* }}} int gl_foreach */
806 /* vim: set sw=2 sts=2 et fdm=marker : */