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