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