graph_list.c: Clear instances before re-scanning the directory.
[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 int config_get_string (const oconfig_item_t *ci, /* {{{ */
620     char **ret_str)
621 {
622   char *tmp;
623
624   if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
625     return (EINVAL);
626
627   tmp = strdup (ci->values[0].value.string);
628   if (tmp == NULL)
629     return (ENOMEM);
630
631   free (*ret_str);
632   *ret_str = tmp;
633
634   return (0);
635 } /* }}} int config_get_string */
636
637 /*
638  * Global functions
639  */
640 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
641 {
642   char *host = NULL;
643   char *plugin = NULL;
644   char *plugin_instance = NULL;
645   char *type = NULL;
646   char *type_instance = NULL;
647   graph_config_t *cfg = NULL;
648   int i;
649
650   cfg = graph_create (/* selector = */ NULL);
651   if (cfg == NULL)
652     return (ENOMEM);
653
654   for (i = 0; i < ci->children_num; i++)
655   {
656     oconfig_item_t *child;
657
658     child = ci->children + i;
659
660     if (strcasecmp ("Host", child->key) == 0)
661       config_get_string (child, &host);
662     else if (strcasecmp ("Plugin", child->key) == 0)
663       config_get_string (child, &plugin);
664     else if (strcasecmp ("PluginInstance", child->key) == 0)
665       config_get_string (child, &plugin_instance);
666     else if (strcasecmp ("Type", child->key) == 0)
667       config_get_string (child, &type);
668     else if (strcasecmp ("TypeInstance", child->key) == 0)
669       config_get_string (child, &type_instance);
670     else if (strcasecmp ("Title", child->key) == 0)
671       config_get_string (child, &cfg->title);
672     else if (strcasecmp ("VerticalLabel", child->key) == 0)
673       config_get_string (child, &cfg->vertical_label);
674     /* TODO: DEFs! */
675   } /* for */
676
677   cfg->select = ident_create (host, plugin, plugin_instance,
678       type, type_instance);
679   if (cfg->select == NULL)
680   {
681     graph_destroy (cfg);
682     return (EINVAL);
683   }
684
685   graph_append (&graph_config_staging, cfg);
686
687   return (0);
688 } /* }}} graph_config_add */
689
690 int graph_config_submit (void) /* {{{ */
691 {
692   graph_config_t *tmp;
693
694   tmp = graph_config_head;
695   graph_config_head = graph_config_staging;
696   graph_config_staging = NULL;
697
698   graph_destroy (tmp);
699
700   return (0);
701 } /* }}} int graph_config_submit */
702
703 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
704     char *buffer, size_t buffer_size)
705 {
706   if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
707     return (EINVAL);
708
709   buffer[0] = 0;
710
711 #define COPY_FIELD(field) do {                                  \
712   const char *cfg_f  = ident_get_##field (cfg->select);         \
713   const char *inst_f = ident_get_##field (inst->select);        \
714   if (strcmp (cfg_f, inst_f) == 0)                              \
715   {                                                             \
716     strlcat (buffer, #field, buffer_size);                      \
717     strlcat (buffer, "=", buffer_size);                         \
718     strlcat (buffer, cfg_f, buffer_size);                       \
719   }                                                             \
720   else                                                          \
721   {                                                             \
722     strlcat (buffer, "graph_", buffer_size);                    \
723     strlcat (buffer, #field, buffer_size);                      \
724     strlcat (buffer, "=", buffer_size);                         \
725     strlcat (buffer, cfg_f, buffer_size);                       \
726     strlcat (buffer, ";", buffer_size);                         \
727     strlcat (buffer, "inst_", buffer_size);                     \
728     strlcat (buffer, #field, buffer_size);                      \
729     strlcat (buffer, "=", buffer_size);                         \
730     strlcat (buffer, inst_f, buffer_size);                      \
731   }                                                             \
732 } while (0)
733
734   COPY_FIELD(host);
735   strlcat (buffer, ";", buffer_size);
736   COPY_FIELD(plugin);
737   strlcat (buffer, ";", buffer_size);
738   COPY_FIELD(plugin_instance);
739   strlcat (buffer, ";", buffer_size);
740   COPY_FIELD(type);
741   strlcat (buffer, ";", buffer_size);
742   COPY_FIELD(type_instance);
743
744 #undef COPY_FIELD
745
746   return (0);
747 } /* }}} int gl_instance_get_params */
748
749 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
750 {
751   const char *host = get_part_from_param ("inst_host", "host");
752   const char *plugin = get_part_from_param ("inst_plugin", "plugin");
753   const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
754   const char *type = get_part_from_param ("inst_type", "type");
755   const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
756   graph_ident_t *ident;
757   graph_instance_t *inst;
758
759   if (cfg == NULL)
760     cfg = graph_get_selected ();
761
762   if (cfg == NULL)
763   {
764     DEBUG ("inst_get_selected: cfg == NULL;\n");
765     return (NULL);
766   }
767
768   if ((host == NULL)
769       || (plugin == NULL) || (plugin_instance == NULL)
770       || (type == NULL) || (type_instance == NULL))
771   {
772     DEBUG ("inst_get_selected: A parameter is NULL.\n");
773     return (NULL);
774   }
775
776   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
777
778   for (inst = cfg->instances; inst != NULL; inst = inst->next)
779   {
780     if (ident_compare (ident, inst->select) != 0)
781       continue;
782
783     ident_destroy (ident);
784     return (inst);
785   }
786
787   DEBUG ("inst_get_selected: No match found.\n");
788   ident_destroy (ident);
789   return (NULL);
790 } /* }}} graph_instance_t *inst_get_selected */
791
792 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
793     void *user_data)
794 {
795   graph_config_t *cfg;
796
797   if (callback == NULL)
798     return (EINVAL);
799
800   gl_update ();
801
802   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
803   {
804     int status;
805
806     status = (*callback) (cfg, user_data);
807     if (status != 0)
808       return (status);
809   }
810
811   return (0);
812 } /* }}} int gl_graph_get_all */
813
814 graph_config_t *graph_get_selected (void) /* {{{ */
815 {
816   const char *host = get_part_from_param ("graph_host", "host");
817   const char *plugin = get_part_from_param ("graph_plugin", "plugin");
818   const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
819   const char *type = get_part_from_param ("graph_type", "type");
820   const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
821   graph_ident_t *ident;
822   graph_config_t *cfg;
823
824   if ((host == NULL)
825       || (plugin == NULL) || (plugin_instance == NULL)
826       || (type == NULL) || (type_instance == NULL))
827     return (NULL);
828
829   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
830
831   gl_update ();
832
833   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
834   {
835     if (ident_compare (ident, cfg->select) != 0)
836       continue;
837
838     ident_destroy (ident);
839     return (cfg);
840   }
841
842   ident_destroy (ident);
843   return (NULL);
844 } /* }}} graph_config_t *graph_get_selected */
845
846 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
847     gl_inst_callback callback, void *user_data)
848 {
849   graph_instance_t *inst;
850
851   if ((cfg == NULL) || (callback == NULL))
852     return (EINVAL);
853
854   for (inst = cfg->instances; inst != NULL; inst = inst->next)
855   {
856     int status;
857
858     status = (*callback) (cfg, inst, user_data);
859     if (status != 0)
860       return (status);
861   }
862
863   return (0);
864 } /* }}} int gl_graph_instance_get_all */
865
866 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
867     char *buffer, size_t buffer_size)
868 {
869   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
870     return (EINVAL);
871
872   if (cfg->title == NULL)
873     cfg->title = ident_to_string (cfg->select);
874
875   if (cfg->title == NULL)
876     return (ENOMEM);
877
878   strncpy (buffer, cfg->title, buffer_size);
879   buffer[buffer_size - 1] = 0;
880
881   return (0);
882 } /* }}} int gl_graph_get_title */
883
884 graph_ident_t *gl_graph_get_selector (graph_config_t *cfg) /* {{{ */
885 {
886   if (cfg == NULL)
887     return (NULL);
888
889   return (ident_clone (cfg->select));
890 } /* }}} graph_ident_t *gl_graph_get_selector */
891
892 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
893     void *user_data)
894 {
895   graph_config_t *cfg;
896
897   gl_update ();
898
899   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
900   {
901     graph_instance_t *inst;
902
903     for (inst = cfg->instances; inst != NULL; inst = inst->next)
904     {
905       int status;
906
907       status = (*callback) (cfg, inst, user_data);
908       if (status != 0)
909         return (status);
910     }
911   }
912
913   return (0);
914 } /* }}} int gl_instance_get_all */
915
916 int gl_instance_get_rrdargs (graph_config_t *cfg, /* {{{ */
917     graph_instance_t *inst,
918     str_array_t *args)
919 {
920   def_callback_data_t data = { inst, args };
921   graph_def_t *default_defs;
922   int status;
923
924   if ((cfg == NULL) || (inst == NULL) || (args == NULL))
925     return (EINVAL);
926
927   if (cfg->title != NULL)
928   {
929     array_append (args, "-t");
930     array_append (args, cfg->title);
931   }
932
933   if (cfg->vertical_label != NULL)
934   {
935     array_append (args, "-v");
936     array_append (args, cfg->vertical_label);
937   }
938
939   if (cfg->defs == NULL)
940   {
941     default_defs = gl_inst_get_default_defs (cfg, inst);
942
943     if (default_defs == NULL)
944       return (-1);
945
946     status = def_foreach (default_defs, gl_instance_get_rrdargs_cb, &data);
947
948     if (default_defs != NULL)
949       def_destroy (default_defs);
950   }
951   else
952   {
953     status = def_foreach (cfg->defs, gl_instance_get_rrdargs_cb, &data);
954   }
955
956   return (status);
957 } /* }}} int gl_instance_get_rrdargs */
958
959 graph_ident_t *gl_instance_get_selector (graph_instance_t *inst) /* {{{ */
960 {
961   if (inst == NULL)
962     return (NULL);
963
964   return (ident_clone (inst->select));
965 } /* }}} graph_ident_t *gl_instance_get_selector */
966
967 int gl_update (void) /* {{{ */
968 {
969   time_t now;
970   gl_ident_stage_t gl;
971   int status;
972
973   /*
974   printf ("Content-Type: text/plain\n\n");
975   */
976
977   now = time (NULL);
978
979   if ((gl_last_update + UPDATE_INTERVAL) >= now)
980     return (0);
981
982   graph_read_config ();
983
984   memset (&gl, 0, sizeof (gl));
985   gl.host = NULL;
986   gl.plugin = NULL;
987   gl.plugin_instance = NULL;
988   gl.type = NULL;
989   gl.type_instance = NULL;
990
991   gl_clear_instances ();
992   status = foreach_host (callback_host, &gl);
993
994   gl_last_update = now;
995
996   return (status);
997 } /* }}} int gl_update */
998
999 /* vim: set sw=2 sts=2 et fdm=marker : */