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