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;
35 typedef struct graph_instance_s graph_instance_t;
36 struct graph_instance_s
43 graph_instance_t *next;
46 struct graph_config_s;
47 typedef struct graph_config_s graph_config_t;
55 graph_instance_t *instances;
63 static graph_config_t *graph_config_head = NULL;
65 static graph_ident_t *graph_list = NULL;
66 static size_t graph_list_length = 0;
67 static time_t gl_last_update = 0;
72 static int print_files (const graph_instance_t *inst) /* {{{ */
76 for (i = 0; i < inst->files_num; i++)
78 graph_ident_t *file = inst->files + i;
80 printf (" File \"%s/%s-%s/%s-%s\"\n",
82 file->plugin, file->plugin_instance,
83 file->type, file->type_instance);
87 } /* }}} int print_instances */
89 static int print_instances (const graph_config_t *cfg) /* {{{ */
91 graph_instance_t *inst;
93 for (inst = cfg->instances; inst != NULL; inst = inst->next)
95 printf (" Instance \"%s/%s-%s/%s-%s\"\n",
97 inst->select.plugin, inst->select.plugin_instance,
98 inst->select.type, inst->select.type_instance);
104 } /* }}} int print_instances */
106 static int print_graphs (void) /* {{{ */
110 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
112 printf ("Graph \"%s/%s-%s/%s-%s\"\n",
114 cfg->select.plugin, cfg->select.plugin_instance,
115 cfg->select.type, cfg->select.type_instance);
117 print_instances (cfg);
121 } /* }}} int print_graphs */
124 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
125 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
127 if ((s1 == NULL) && (s2 == NULL))
133 assert ((s1 != NULL) && (s2 != NULL));
135 return (strcmp (s1, s2));
136 } /* }}} int strcmp_s */
138 static _Bool part_matches (const char *sel, const char *val) /* {{{ */
140 if ((sel == NULL) && (val == NULL))
143 if (sel == NULL) /* && (val != NULL) */
146 if ((strcasecmp (ALL_TOKEN, sel) == 0)
147 || (strcasecmp (ANY_TOKEN, sel) == 0))
150 if (val == NULL) /* && (sel != NULL) */
153 if (strcmp (sel, val) == 0)
157 } /* }}} _Bool part_matches */
159 static _Bool file_matches (const graph_ident_t *sel, /* {{{ */
160 const graph_ident_t *val)
162 if ((sel == NULL) && (val == NULL))
164 else if (sel == NULL)
166 else if (val == NULL)
169 if (!part_matches (sel->host, val->host))
172 if (!part_matches (sel->plugin, val->plugin))
175 if (!part_matches (sel->plugin_instance, val->plugin_instance))
178 if (!part_matches (sel->type, val->type))
181 if (!part_matches (sel->type_instance, val->type_instance))
185 } /* }}} _Bool ident_compare */
188 * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
189 * copied and returned. This function is used when creating graph_instance_t
190 * from graph_config_t.
192 static char *identifier_copy_part (const char *template, const char *value) /* {{{ */
194 if (template == NULL)
198 else if (strcasecmp (ANY_TOKEN, template) == 0)
200 /* ANY in the graph selection => concrete value in the instance. */
204 return (strdup (value));
206 else if (strcasecmp (ALL_TOKEN, template) == 0)
208 /* ALL in the graph selection => ALL in the instance. */
209 return (strdup (ALL_TOKEN));
213 assert (value != NULL);
214 assert (strcmp (template, value) == 0);
215 return (strdup (template));
217 } /* }}} int identifier_copy_part */
219 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
220 const graph_ident_t *file)
224 if ((cfg == NULL) || (file == NULL))
227 i = malloc (sizeof (*i));
230 memset (i, 0, sizeof (*i));
232 i->select.host = identifier_copy_part (cfg->select.host, file->host);
233 i->select.plugin = identifier_copy_part (cfg->select.plugin, file->plugin);
234 i->select.plugin_instance = identifier_copy_part (cfg->select.plugin_instance,
235 file->plugin_instance);
236 i->select.type = identifier_copy_part (cfg->select.type, file->type);
237 i->select.type_instance = identifier_copy_part (cfg->select.type_instance,
238 file->type_instance);
245 if (cfg->instances == NULL)
249 graph_instance_t *last;
251 last = cfg->instances;
252 while (last->next != NULL)
259 } /* }}} graph_instance_t *instance_create */
261 static int instance_add_file (graph_instance_t *inst, /* {{{ */
262 const graph_ident_t *file)
266 tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
270 tmp = inst->files + inst->files_num;
272 memset (tmp, 0, sizeof (*tmp));
273 tmp->host = strdup (file->host);
274 tmp->plugin = strdup (file->plugin);
275 if (file->plugin_instance != NULL)
276 tmp->plugin_instance = strdup (file->plugin_instance);
278 tmp->plugin_instance = NULL;
279 tmp->type = strdup (file->type);
280 if (file->type_instance != NULL)
281 tmp->type_instance = strdup (file->type_instance);
283 tmp->type_instance = NULL;
288 } /* }}} int instance_add_file */
290 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
291 const graph_ident_t *file)
295 if ((cfg == NULL) || (file == NULL))
298 for (i = cfg->instances; i != NULL; i = i->next)
299 if (file_matches (&i->select, file))
303 } /* }}} graph_instance_t *graph_find_instance */
305 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
307 graph_instance_t *inst;
309 inst = graph_find_instance (cfg, file);
312 inst = instance_create (cfg, file);
317 return (instance_add_file (inst, file));
318 } /* }}} int graph_add_file */
320 static int graph_append (graph_config_t *cfg) /* {{{ */
322 graph_config_t *last;
327 if (graph_config_head == NULL)
329 graph_config_head = cfg;
333 last = graph_config_head;
334 while (last->next != NULL)
340 } /* }}} int graph_append */
342 static int graph_create_from_file (const graph_ident_t *file) /* {{{ */
346 cfg = malloc (sizeof (*cfg));
349 memset (cfg, 0, sizeof (*cfg));
351 cfg->select.host = strdup (file->host);
352 cfg->select.plugin = strdup (file->plugin);
353 cfg->select.plugin_instance = strdup (file->plugin_instance);
354 cfg->select.type = strdup (file->type);
355 cfg->select.type_instance = strdup (file->type_instance);
358 cfg->vertical_label = NULL;
359 cfg->instances = NULL;
364 return (graph_add_file (cfg, file));
365 } /* }}} int graph_create_from_file */
367 static int register_file (const graph_ident_t *file) /* {{{ */
372 for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
376 if (!file_matches (&cfg->select, file))
379 status = graph_add_file (cfg, file);
391 graph_create_from_file (file);
394 } /* }}} int register_file */
396 static int FIXME_graph_create_from_file (const graph_ident_t *file) /* {{{ */
400 cfg = malloc (sizeof (*cfg));
403 memset (cfg, 0, sizeof (*cfg));
405 cfg->select.host = strdup (file->host);
406 cfg->select.plugin = strdup (file->plugin);
407 cfg->select.plugin_instance = strdup (file->plugin_instance);
408 cfg->select.type = strdup (file->type);
409 cfg->select.type_instance = strdup (file->type_instance);
412 cfg->vertical_label = NULL;
413 cfg->instances = NULL;
419 } /* }}} int FIXME_graph_create_from_file */
421 static int read_graph_config (void) /* {{{ */
423 if (graph_config_head != NULL)
429 ident.host = ANY_TOKEN;
430 ident.plugin = "cpu";
431 ident.plugin_instance = ANY_TOKEN;
433 ident.type_instance = ALL_TOKEN;
434 FIXME_graph_create_from_file (&ident);
436 ident.plugin = "memory";
437 ident.plugin_instance = "";
438 ident.type = "memory";
439 FIXME_graph_create_from_file (&ident);
441 ident.plugin = "swap";
442 ident.plugin_instance = "";
444 FIXME_graph_create_from_file (&ident);
446 ident.plugin = ANY_TOKEN;
447 ident.plugin_instance = ANY_TOKEN;
448 ident.type = "ps_state";
449 FIXME_graph_create_from_file (&ident);
451 ident.host = ALL_TOKEN;
452 ident.plugin = "cpu";
453 ident.plugin_instance = ALL_TOKEN;
455 ident.type_instance = "idle";
456 FIXME_graph_create_from_file (&ident);
459 } /* }}} int read_graph_config */
463 static int gl_compare (const void *p0, const void *p1) /* {{{ */
465 const graph_ident_t *gl0 = p0;
466 const graph_ident_t *gl1 = p1;
469 status = strcmp (gl0->host, gl1->host);
473 status = strcmp (gl0->plugin, gl1->plugin);
477 status = strcmp_s (gl0->plugin_instance, gl1->plugin_instance);
481 status = strcmp (gl0->type, gl1->type);
485 return (strcmp_s (gl0->type_instance, gl1->type_instance));
486 } /* }}} int gl_compare */
488 static void gl_clear_entry (graph_ident_t *gl) /* {{{ */
495 free (gl->plugin_instance);
497 free (gl->type_instance);
501 gl->plugin_instance = NULL;
503 gl->type_instance = NULL;
504 } /* }}} void gl_clear_entry */
506 static void gl_clear (void) /* {{{ */
510 for (i = 0; i < graph_list_length; i++)
511 gl_clear_entry (graph_list + i);
515 graph_list_length = 0;
517 } /* }}} void gl_clear */
519 static int gl_add_copy (graph_ident_t *gl) /* {{{ */
527 ptr = realloc (graph_list, sizeof (*graph_list) * (graph_list_length + 1));
532 ptr = graph_list + graph_list_length;
533 memset (ptr, 0, sizeof (*ptr));
536 ptr->plugin_instance = NULL;
538 ptr->type_instance = NULL;
540 #define DUP_OR_BREAK(member) do { \
541 ptr->member = NULL; \
542 if (gl->member != NULL) \
544 ptr->member = strdup (gl->member); \
545 if (ptr->member == NULL) \
554 DUP_OR_BREAK(plugin);
555 DUP_OR_BREAK(plugin_instance);
557 DUP_OR_BREAK(type_instance);
568 free (ptr->plugin_instance);
570 free (ptr->type_instance);
576 } /* }}} int gl_add_copy */
578 static int callback_type (const char *type, void *user_data) /* {{{ */
583 if ((type == NULL) || (user_data == NULL))
587 if ((gl->type != NULL) || (gl->type_instance != NULL))
590 gl->type = strdup (type);
591 if (gl->type == NULL)
594 gl->type_instance = strchr (gl->type, '-');
595 if (gl->type_instance != NULL)
597 *gl->type_instance = 0;
602 gl->type_instance = gl->type + strlen (gl->type);
607 status = gl_add_copy (gl);
611 gl->type_instance = NULL;
614 } /* }}} int callback_type */
616 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
621 if ((plugin == NULL) || (user_data == NULL))
625 if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
628 gl->plugin = strdup (plugin);
629 if (gl->plugin == NULL)
632 gl->plugin_instance = strchr (gl->plugin, '-');
633 if (gl->plugin_instance != NULL)
635 *gl->plugin_instance = 0;
636 gl->plugin_instance++;
640 gl->plugin_instance = gl->plugin + strlen (gl->plugin);
643 status = foreach_type (gl->host, plugin, callback_type, gl);
647 gl->plugin_instance = NULL;
650 } /* }}} int callback_plugin */
652 static int callback_host (const char *host, void *user_data) /* {{{ */
657 if ((host == NULL) || (user_data == NULL))
661 if (gl->host != NULL)
664 gl->host = strdup (host);
665 if (gl->host == NULL)
668 status = foreach_plugin (host, callback_plugin, gl);
674 } /* }}} int callback_host */
679 int gl_update (void) /* {{{ */
685 printf ("Content-Type: text/plain\n\n");
687 read_graph_config ();
691 if ((gl_last_update + UPDATE_INTERVAL) >= now)
696 memset (&gl, 0, sizeof (gl));
699 gl.plugin_instance = NULL;
701 gl.type_instance = NULL;
703 status = foreach_host (callback_host, &gl);
707 if (graph_list_length > 1)
708 qsort (graph_list, graph_list_length, sizeof (*graph_list), gl_compare);
711 } /* }}} int gl_update */
713 int gl_foreach (gl_callback callback, void *user_data) /* {{{ */
717 for (i = 0; i < graph_list_length; i++)
721 status = (*callback) ((void *) (graph_list + i), user_data);
727 } /* }}} int gl_foreach */
729 /* vim: set sw=2 sts=2 et fdm=marker : */