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