graph_list.[ch]: Implement "{graph,inst}_get_selected".
[collection4.git] / graph_list.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <time.h>
5 #include <errno.h>
6 #include <assert.h>
7
8 #include <fcgiapp.h>
9 #include <fcgi_stdio.h>
10
11 #include "graph_list.h"
12 #include "common.h"
13 #include "utils_params.h"
14
15 /*
16  * Defines
17  */
18 #define UPDATE_INTERVAL 10
19
20 #define ANY_TOKEN "/any/"
21 #define ALL_TOKEN "/all/"
22
23 /*
24  * Data types
25  */
26 struct graph_ident_s /* {{{ */
27 {
28   char *host;
29   char *plugin;
30   char *plugin_instance;
31   char *type;
32   char *type_instance;
33 }; /* }}} struct graph_ident_s */
34
35 struct graph_instance_s /* {{{ */
36 {
37   graph_ident_t select;
38
39   graph_ident_t *files;
40   size_t files_num;
41
42   graph_instance_t *next;
43 }; /* }}} struct graph_instance_s */
44
45 struct graph_config_s /* {{{ */
46 {
47   graph_ident_t select;
48
49   char *title;
50   char *vertical_label;
51
52   graph_instance_t *instances;
53
54   graph_config_t *next;
55 }; /* }}} struct graph_config_s */
56
57 /*
58  * Global variables
59  */
60 static graph_config_t *graph_config_head = NULL;
61
62 static graph_ident_t *graph_list = NULL;
63 static size_t graph_list_length = 0;
64 static time_t gl_last_update = 0;
65
66 /*
67  * Private functions
68  */
69 /* FIXME: These "print_*" functions are used for debugging. They should be
70  * removed at some point. */
71 static int print_files (const graph_instance_t *inst) /* {{{ */
72 {
73   size_t i;
74
75   for (i = 0; i < inst->files_num; i++)
76   {
77     graph_ident_t *file = inst->files + i;
78
79     printf ("    File \"%s/%s-%s/%s-%s\"\n",
80         file->host,
81         file->plugin, file->plugin_instance,
82         file->type, file->type_instance);
83   }
84
85   return (0);
86 } /* }}} int print_instances */
87
88 static int print_instances (const graph_config_t *cfg) /* {{{ */
89 {
90   graph_instance_t *inst;
91
92   for (inst = cfg->instances; inst != NULL; inst = inst->next)
93   {
94     printf ("  Instance \"%s/%s-%s/%s-%s\"\n",
95         inst->select.host,
96         inst->select.plugin, inst->select.plugin_instance,
97         inst->select.type, inst->select.type_instance);
98
99     print_files (inst);
100   }
101
102   return (0);
103 } /* }}} int print_instances */
104
105 static int print_graphs (void) /* {{{ */
106 {
107   graph_config_t *cfg;
108
109   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
110   {
111     printf ("Graph \"%s/%s-%s/%s-%s\"\n",
112         cfg->select.host,
113         cfg->select.plugin, cfg->select.plugin_instance,
114         cfg->select.type, cfg->select.type_instance);
115
116     print_instances (cfg);
117   }
118
119   return (0);
120 } /* }}} int print_graphs */
121
122 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
123 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
124 {
125   if ((s1 == NULL) && (s2 == NULL))
126     return (0);
127   else if (s1 == NULL)
128     return (1);
129   else if (s2 == NULL)
130     return (-1);
131   assert ((s1 != NULL) && (s2 != NULL));
132
133   return (strcmp (s1, s2));
134 } /* }}} int strcmp_s */
135
136 static _Bool part_matches (const char *sel, const char *val) /* {{{ */
137 {
138   if ((sel == NULL) && (val == NULL))
139     return (1);
140
141   if (sel == NULL) /* && (val != NULL) */
142     return (0);
143
144   if ((strcasecmp (ALL_TOKEN, sel) == 0)
145       || (strcasecmp (ANY_TOKEN, sel) == 0))
146     return (1);
147
148   if (val == NULL) /* && (sel != NULL) */
149     return (0);
150
151   if (strcmp (sel, val) == 0)
152     return (1);
153
154   return (0);
155 } /* }}} _Bool part_matches */
156
157 static _Bool file_matches (const graph_ident_t *sel, /* {{{ */
158     const graph_ident_t *val)
159 {
160   if ((sel == NULL) && (val == NULL))
161     return (0);
162   else if (sel == NULL)
163     return (-1);
164   else if (val == NULL)
165     return (1);
166
167   if (!part_matches (sel->host, val->host))
168     return (0);
169
170   if (!part_matches (sel->plugin, val->plugin))
171     return (0);
172
173   if (!part_matches (sel->plugin_instance, val->plugin_instance))
174     return (0);
175
176   if (!part_matches (sel->type, val->type))
177     return (0);
178
179   if (!part_matches (sel->type_instance, val->type_instance))
180     return (0);
181
182   return (1);
183 } /* }}} _Bool ident_compare */
184
185 /*
186  * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
187  * copied and returned. This function is used when creating graph_instance_t
188  * from graph_config_t.
189  */
190 static char *identifier_copy_part (const char *template, const char *value) /* {{{ */
191 {
192   if (template == NULL)
193   {
194     return (NULL);
195   }
196   else if (strcasecmp (ANY_TOKEN, template) == 0)
197   {
198     /* ANY in the graph selection => concrete value in the instance. */
199     if (value == NULL)
200       return (NULL);
201     else
202       return (strdup (value));
203   }
204   else if (strcasecmp (ALL_TOKEN, template) == 0)
205   {
206     /* ALL in the graph selection => ALL in the instance. */
207     return (strdup (ALL_TOKEN));
208   }
209   else
210   {
211     assert (value != NULL);
212     assert (strcmp (template, value) == 0);
213     return (strdup (template));
214   }
215 } /* }}} int identifier_copy_part */
216
217 static graph_instance_t *instance_create (graph_config_t *cfg, /* {{{ */
218     const graph_ident_t *file)
219 {
220   graph_instance_t *i;
221
222   if ((cfg == NULL) || (file == NULL))
223     return (NULL);
224
225   i = malloc (sizeof (*i));
226   if (i == NULL)
227     return (NULL);
228   memset (i, 0, sizeof (*i));
229
230   i->select.host = identifier_copy_part (cfg->select.host, file->host);
231   i->select.plugin = identifier_copy_part (cfg->select.plugin, file->plugin);
232   i->select.plugin_instance = identifier_copy_part (cfg->select.plugin_instance,
233       file->plugin_instance);
234   i->select.type = identifier_copy_part (cfg->select.type, file->type);
235   i->select.type_instance = identifier_copy_part (cfg->select.type_instance,
236       file->type_instance);
237
238   i->files = NULL;
239   i->files_num = 0;
240
241   i->next = NULL;
242
243   if (cfg->instances == NULL)
244     cfg->instances = i;
245   else
246   {
247     graph_instance_t *last;
248
249     last = cfg->instances;
250     while (last->next != NULL)
251       last = last->next;
252
253     last->next = i;
254   }
255
256   return (i);
257 } /* }}} graph_instance_t *instance_create */
258
259 static int instance_add_file (graph_instance_t *inst, /* {{{ */
260     const graph_ident_t *file)
261 {
262   graph_ident_t *tmp;
263
264   tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
265   if (tmp == NULL)
266     return (ENOMEM);
267   inst->files = tmp;
268   tmp = inst->files + inst->files_num;
269
270   memset (tmp, 0, sizeof (*tmp));
271   tmp->host = strdup (file->host);
272   tmp->plugin = strdup (file->plugin);
273   if (file->plugin_instance != NULL)
274     tmp->plugin_instance = strdup (file->plugin_instance);
275   else
276     tmp->plugin_instance = NULL;
277   tmp->type = strdup (file->type);
278   if (file->type_instance != NULL)
279     tmp->type_instance = strdup (file->type_instance);
280   else
281     tmp->type_instance = NULL;
282
283   inst->files_num++;
284
285   return (0);
286 } /* }}} int instance_add_file */
287
288 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
289     const graph_ident_t *file)
290 {
291   graph_instance_t *i;
292
293   if ((cfg == NULL) || (file == NULL))
294     return (NULL);
295
296   for (i = cfg->instances; i != NULL; i = i->next)
297     if (file_matches (&i->select, file))
298       return (i);
299
300   return (NULL);
301 } /* }}} graph_instance_t *graph_find_instance */
302
303 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
304 {
305   graph_instance_t *inst;
306
307   inst = graph_find_instance (cfg, file);
308   if (inst == NULL)
309   {
310     inst = instance_create (cfg, file);
311     if (inst == NULL)
312       return (ENOMEM);
313   }
314
315   return (instance_add_file (inst, file));
316 } /* }}} int graph_add_file */
317
318 static int graph_append (graph_config_t *cfg) /* {{{ */
319 {
320   graph_config_t *last;
321
322   if (cfg == NULL)
323     return (EINVAL);
324
325   if (graph_config_head == NULL)
326   {
327     graph_config_head = cfg;
328     return (0);
329   }
330
331   last = graph_config_head;
332   while (last->next != NULL)
333     last = last->next;
334
335   last->next = cfg;
336
337   return (0);
338 } /* }}} int graph_append */
339
340 static int graph_create_from_file (const graph_ident_t *file) /* {{{ */
341 {
342   graph_config_t *cfg;
343
344   cfg = malloc (sizeof (*cfg));
345   if (cfg == NULL)
346     return (ENOMEM);
347   memset (cfg, 0, sizeof (*cfg));
348
349   cfg->select.host = strdup (file->host);
350   cfg->select.plugin = strdup (file->plugin);
351   cfg->select.plugin_instance = strdup (file->plugin_instance);
352   cfg->select.type = strdup (file->type);
353   cfg->select.type_instance = strdup (file->type_instance);
354
355   cfg->title = NULL;
356   cfg->vertical_label = NULL;
357   cfg->instances = NULL;
358   cfg->next = NULL;
359
360   graph_append (cfg);
361
362   return (graph_add_file (cfg, file));
363 } /* }}} int graph_create_from_file */
364
365 static int register_file (const graph_ident_t *file) /* {{{ */
366 {
367   graph_config_t *cfg;
368   int num_graphs = 0;
369
370   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
371   {
372     int status;
373
374     if (!file_matches (&cfg->select, file))
375       continue;
376
377     status = graph_add_file (cfg, file);
378     if (status != 0)
379     {
380       /* report error */;
381     }
382     else
383     {
384       num_graphs++;
385     }
386   }
387
388   if (num_graphs == 0)
389     graph_create_from_file (file);
390
391   return (0);
392 } /* }}} int register_file */
393
394 static int FIXME_graph_create_from_file (const graph_ident_t *file) /* {{{ */
395 {
396   graph_config_t *cfg;
397
398   cfg = malloc (sizeof (*cfg));
399   if (cfg == NULL)
400     return (ENOMEM);
401   memset (cfg, 0, sizeof (*cfg));
402
403   cfg->select.host = strdup (file->host);
404   cfg->select.plugin = strdup (file->plugin);
405   cfg->select.plugin_instance = strdup (file->plugin_instance);
406   cfg->select.type = strdup (file->type);
407   cfg->select.type_instance = strdup (file->type_instance);
408
409   cfg->title = NULL;
410   cfg->vertical_label = NULL;
411   cfg->instances = NULL;
412   cfg->next = NULL;
413
414   graph_append (cfg);
415
416   return (0);
417 } /* }}} int FIXME_graph_create_from_file */
418
419 /* FIXME: Actually read the config file here. */
420 static int read_graph_config (void) /* {{{ */
421 {
422   if (graph_config_head != NULL)
423     return (0);
424
425   graph_ident_t ident;
426
427
428   ident.host = ANY_TOKEN;
429   ident.plugin = "cpu";
430   ident.plugin_instance = ANY_TOKEN;
431   ident.type = "cpu";
432   ident.type_instance = ALL_TOKEN;
433   FIXME_graph_create_from_file (&ident);
434
435   ident.plugin = "memory";
436   ident.plugin_instance = "";
437   ident.type = "memory";
438   FIXME_graph_create_from_file (&ident);
439
440   ident.plugin = "swap";
441   ident.plugin_instance = "";
442   ident.type = "swap";
443   FIXME_graph_create_from_file (&ident);
444
445   ident.plugin = ANY_TOKEN;
446   ident.plugin_instance = ANY_TOKEN;
447   ident.type = "ps_state";
448   FIXME_graph_create_from_file (&ident);
449
450   ident.host = ALL_TOKEN;
451   ident.plugin = "cpu";
452   ident.plugin_instance = ALL_TOKEN;
453   ident.type = "cpu";
454   ident.type_instance = "idle";
455   FIXME_graph_create_from_file (&ident);
456
457   return (0);
458 } /* }}} int read_graph_config */
459
460
461
462 static int gl_compare (const void *p0, const void *p1) /* {{{ */
463 {
464   const graph_ident_t *gl0 = p0;
465   const graph_ident_t *gl1 = p1;
466   int status;
467
468   status = strcmp (gl0->host, gl1->host);
469   if (status != 0)
470     return (status);
471
472   status = strcmp (gl0->plugin, gl1->plugin);
473   if (status != 0)
474     return (status);
475
476   status = strcmp_s (gl0->plugin_instance, gl1->plugin_instance);
477   if (status != 0)
478     return (status);
479
480   status = strcmp (gl0->type, gl1->type);
481   if (status != 0)
482     return (status);
483
484   return (strcmp_s (gl0->type_instance, gl1->type_instance));
485 } /* }}} int gl_compare */
486
487 static void gl_clear_entry (graph_ident_t *gl) /* {{{ */
488 {
489   if (gl == NULL)
490     return;
491
492   free (gl->host);
493   free (gl->plugin);
494   free (gl->plugin_instance);
495   free (gl->type);
496   free (gl->type_instance);
497
498   gl->host = NULL;
499   gl->plugin = NULL;
500   gl->plugin_instance = NULL;
501   gl->type = NULL;
502   gl->type_instance = NULL;
503 } /* }}} void gl_clear_entry */
504
505 static void gl_clear (void) /* {{{ */
506 {
507   size_t i;
508
509   for (i = 0; i < graph_list_length; i++)
510     gl_clear_entry (graph_list + i);
511
512   free (graph_list);
513   graph_list = NULL;
514   graph_list_length = 0;
515   gl_last_update = 0;
516 } /* }}} void gl_clear */
517
518 static int gl_add_copy (graph_ident_t *gl) /* {{{ */
519 {
520   graph_ident_t *ptr;
521   int status;
522
523   if (gl == NULL)
524     return (EINVAL);
525
526   ptr = realloc (graph_list, sizeof (*graph_list) * (graph_list_length + 1));
527   if (ptr == NULL)
528     return (ENOMEM);
529   graph_list = ptr;
530
531   ptr = graph_list + graph_list_length;
532   memset (ptr, 0, sizeof (*ptr));
533   ptr->host = NULL;
534   ptr->plugin = NULL;
535   ptr->plugin_instance = NULL;
536   ptr->type = NULL;
537   ptr->type_instance = NULL;
538
539 #define DUP_OR_BREAK(member) do {                    \
540   ptr->member = NULL;                                \
541   if (gl->member != NULL)                            \
542   {                                                  \
543     ptr->member = strdup (gl->member);               \
544     if (ptr->member == NULL)                         \
545       break;                                         \
546   }                                                  \
547 } while (0)
548
549   status = ENOMEM;
550   do
551   {
552     DUP_OR_BREAK(host);
553     DUP_OR_BREAK(plugin);
554     DUP_OR_BREAK(plugin_instance);
555     DUP_OR_BREAK(type);
556     DUP_OR_BREAK(type_instance);
557
558     status = 0;
559   } while (0);
560
561 #undef DUP_OR_BREAK
562
563   if (status != 0)
564   {
565     free (ptr->host);
566     free (ptr->plugin);
567     free (ptr->plugin_instance);
568     free (ptr->type);
569     free (ptr->type_instance);
570     return (status);
571   }
572
573   graph_list_length++;
574   return (0);
575 } /* }}} int gl_add_copy */
576
577 static int callback_type (const char *type, void *user_data) /* {{{ */
578 {
579   graph_ident_t *gl;
580   int status;
581
582   if ((type == NULL) || (user_data == NULL))
583     return (EINVAL);
584
585   gl = user_data;
586   if ((gl->type != NULL) || (gl->type_instance != NULL))
587     return (EINVAL);
588
589   gl->type = strdup (type);
590   if (gl->type == NULL)
591     return (ENOMEM);
592
593   gl->type_instance = strchr (gl->type, '-');
594   if (gl->type_instance != NULL)
595   {
596     *gl->type_instance = 0;
597     gl->type_instance++;
598   }
599   else
600   {
601     gl->type_instance = gl->type + strlen (gl->type);
602   }
603
604   register_file (gl);
605
606   status = gl_add_copy (gl);
607
608   free (gl->type);
609   gl->type = NULL;
610   gl->type_instance = NULL;
611
612   return (status);
613 } /* }}} int callback_type */
614
615 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
616 {
617   graph_ident_t *gl;
618   int status;
619
620   if ((plugin == NULL) || (user_data == NULL))
621     return (EINVAL);
622
623   gl = user_data;
624   if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
625     return (EINVAL);
626
627   gl->plugin = strdup (plugin);
628   if (gl->plugin == NULL)
629     return (ENOMEM);
630
631   gl->plugin_instance = strchr (gl->plugin, '-');
632   if (gl->plugin_instance != NULL)
633   {
634     *gl->plugin_instance = 0;
635     gl->plugin_instance++;
636   }
637   else
638   {
639     gl->plugin_instance = gl->plugin + strlen (gl->plugin);
640   }
641
642   status = foreach_type (gl->host, plugin, callback_type, gl);
643
644   free (gl->plugin);
645   gl->plugin = NULL;
646   gl->plugin_instance = NULL;
647
648   return (status);
649 } /* }}} int callback_plugin */
650
651 static int callback_host (const char *host, void *user_data) /* {{{ */
652 {
653   graph_ident_t *gl;
654   int status;
655
656   if ((host == NULL) || (user_data == NULL))
657     return (EINVAL);
658
659   gl = user_data;
660   if (gl->host != NULL)
661     return (EINVAL);
662
663   gl->host = strdup (host);
664   if (gl->host == NULL)
665     return (ENOMEM);
666
667   status =  foreach_plugin (host, callback_plugin, gl);
668
669   free (gl->host);
670   gl->host = NULL;
671
672   return (status);
673 } /* }}} int callback_host */
674
675 static const char *get_part_from_param (const char *prim_key, /* {{{ */
676     const char *sec_key)
677 {
678   const char *val;
679
680   val = param (prim_key);
681   if (val != NULL)
682     return (val);
683   
684   return (param (sec_key));
685 } /* }}} const char *get_part_from_param */
686
687 /*
688  * Global functions
689  */
690 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
691     char *buffer, size_t buffer_size)
692 {
693   if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
694     return (EINVAL);
695
696   buffer[0] = 0;
697
698 #define COPY_FIELD(field) do {                                  \
699   if (strcmp (cfg->select.field, inst->select.field) == 0)      \
700   {                                                             \
701     strlcat (buffer, #field, buffer_size);                      \
702     strlcat (buffer, "=", buffer_size);                         \
703     strlcat (buffer, cfg->select.field, buffer_size);           \
704   }                                                             \
705   else                                                          \
706   {                                                             \
707     strlcat (buffer, "graph_", buffer_size);                    \
708     strlcat (buffer, #field, buffer_size);                      \
709     strlcat (buffer, "=", buffer_size);                         \
710     strlcat (buffer, cfg->select.field, buffer_size);           \
711     strlcat (buffer, ";", buffer_size);                         \
712     strlcat (buffer, "inst_", buffer_size);                     \
713     strlcat (buffer, #field, buffer_size);                      \
714     strlcat (buffer, "=", buffer_size);                         \
715     strlcat (buffer, inst->select.field, buffer_size);          \
716   }                                                             \
717 } while (0)
718
719   COPY_FIELD(host);
720   strlcat (buffer, ";", buffer_size);
721   COPY_FIELD(plugin);
722   strlcat (buffer, ";", buffer_size);
723   COPY_FIELD(plugin_instance);
724   strlcat (buffer, ";", buffer_size);
725   COPY_FIELD(type);
726   strlcat (buffer, ";", buffer_size);
727   COPY_FIELD(type_instance);
728
729 #undef COPY_FIELD
730
731   return (0);
732 } /* }}} int gl_instance_get_params */
733
734 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
735 {
736   const char *host = get_part_from_param ("inst_host", "host");
737   const char *plugin = get_part_from_param ("inst_plugin", "plugin");
738   const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
739   const char *type = get_part_from_param ("inst_type", "type");
740   const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
741   graph_instance_t *inst;
742
743   if (cfg == NULL)
744     cfg = graph_get_selected ();
745
746   if (cfg == NULL)
747     return (NULL);
748
749   if ((host == NULL)
750       || (plugin == NULL) || (plugin_instance == NULL)
751       || (type == NULL) || (type_instance == NULL))
752     return (NULL);
753
754   for (inst = cfg->instances; inst != NULL; inst = inst->next)
755   {
756     if ((strcmp (inst->select.host, host) != 0)
757         || (strcmp (inst->select.plugin, plugin) != 0)
758         || (strcmp (inst->select.plugin_instance, plugin_instance) != 0)
759         || (strcmp (inst->select.type, type) != 0)
760         || (strcmp (inst->select.type_instance, type_instance) != 0))
761       continue;
762
763     return (inst);
764   }
765
766   return (NULL);
767 } /* }}} graph_instance_t *inst_get_selected */
768
769 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
770     void *user_data)
771 {
772   graph_config_t *cfg;
773
774   if (callback == NULL)
775     return (EINVAL);
776
777   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
778   {
779     int status;
780
781     status = (*callback) (cfg, user_data);
782     if (status != 0)
783       return (status);
784   }
785
786   return (0);
787 } /* }}} int gl_graph_get_all */
788
789 graph_config_t *graph_get_selected (void) /* {{{ */
790 {
791   const char *host = get_part_from_param ("graph_host", "host");
792   const char *plugin = get_part_from_param ("graph_plugin", "plugin");
793   const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
794   const char *type = get_part_from_param ("graph_type", "type");
795   const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
796   graph_config_t *cfg;
797
798   if ((host == NULL)
799       || (plugin == NULL) || (plugin_instance == NULL)
800       || (type == NULL) || (type_instance == NULL))
801     return (NULL);
802
803   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
804   {
805     if ((strcmp (cfg->select.host, host) != 0)
806         || (strcmp (cfg->select.plugin, plugin) != 0)
807         || (strcmp (cfg->select.plugin_instance, plugin_instance) != 0)
808         || (strcmp (cfg->select.type, type) != 0)
809         || (strcmp (cfg->select.type_instance, type_instance) != 0))
810       continue;
811
812     return (cfg);
813   }
814
815   return (NULL);
816 } /* }}} graph_config_t *graph_get_selected */
817
818 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
819     gl_inst_callback callback, void *user_data)
820 {
821   graph_instance_t *inst;
822
823   if ((cfg == NULL) || (callback == NULL))
824     return (EINVAL);
825
826   for (inst = cfg->instances; inst != NULL; inst = inst->next)
827   {
828     int status;
829
830     status = (*callback) (cfg, inst, user_data);
831     if (status != 0)
832       return (status);
833   }
834
835   return (0);
836 } /* }}} int gl_graph_instance_get_all */
837
838 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
839     char *buffer, size_t buffer_size)
840 {
841   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
842     return (EINVAL);
843
844   buffer[0] = 0;
845   strlcat (buffer, cfg->select.host, buffer_size);
846   strlcat (buffer, "/", buffer_size);
847   strlcat (buffer, cfg->select.plugin, buffer_size);
848   if (cfg->select.plugin_instance[0] != 0)
849   {
850     strlcat (buffer, "-", buffer_size);
851     strlcat (buffer, cfg->select.plugin_instance, buffer_size);
852   }
853   strlcat (buffer, "/", buffer_size);
854   strlcat (buffer, cfg->select.type, buffer_size);
855   if (cfg->select.type_instance[0] != 0)
856   {
857     strlcat (buffer, "-", buffer_size);
858     strlcat (buffer, cfg->select.type_instance, buffer_size);
859   }
860
861   return (0);
862 } /* }}} int gl_graph_get_title */
863
864 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
865     void *user_data)
866 {
867   graph_config_t *cfg;
868
869   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
870   {
871     graph_instance_t *inst;
872
873     for (inst = cfg->instances; inst != NULL; inst = inst->next)
874     {
875       int status;
876
877       status = (*callback) (cfg, inst, user_data);
878       if (status != 0)
879         return (status);
880     }
881   }
882
883   return (0);
884 } /* }}} int gl_instance_get_all */
885
886 int gl_update (void) /* {{{ */
887 {
888   time_t now;
889   graph_ident_t gl;
890   int status;
891
892   /*
893   printf ("Content-Type: text/plain\n\n");
894   */
895
896   read_graph_config ();
897
898   now = time (NULL);
899
900   if ((gl_last_update + UPDATE_INTERVAL) >= now)
901     return (0);
902
903   gl_clear ();
904
905   memset (&gl, 0, sizeof (gl));
906   gl.host = NULL;
907   gl.plugin = NULL;
908   gl.plugin_instance = NULL;
909   gl.type = NULL;
910   gl.type_instance = NULL;
911
912   status = foreach_host (callback_host, &gl);
913
914   /* print_graphs (); */
915
916   if (graph_list_length > 1)
917     qsort (graph_list, graph_list_length, sizeof (*graph_list), gl_compare);
918
919   return (status);
920 } /* }}} int gl_update */
921
922 int gl_foreach (gl_callback callback, void *user_data) /* {{{ */
923 {
924   size_t i;
925
926   for (i = 0; i < graph_list_length; i++)
927   {
928     int status;
929
930     status = (*callback) ((void *) (graph_list + i), user_data);
931     if (status != 0)
932       return (status);
933   }
934
935   return (0);
936 } /* }}} int gl_foreach */
937
938 /* vim: set sw=2 sts=2 et fdm=marker : */