graph_ident.c: Fix a logic error in "part_copy_with_selector".
[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
187   i->files = NULL;
188   i->files_num = 0;
189
190   i->next = NULL;
191
192   if (cfg->instances == NULL)
193     cfg->instances = i;
194   else
195   {
196     graph_instance_t *last;
197
198     last = cfg->instances;
199     while (last->next != NULL)
200       last = last->next;
201
202     last->next = i;
203   }
204
205   return (i);
206 } /* }}} graph_instance_t *instance_create */
207
208 static int instance_add_file (graph_instance_t *inst, /* {{{ */
209     const graph_ident_t *file)
210 {
211   graph_ident_t **tmp;
212
213   tmp = realloc (inst->files, sizeof (*inst->files) * (inst->files_num + 1));
214   if (tmp == NULL)
215     return (ENOMEM);
216   inst->files = tmp;
217
218   inst->files[inst->files_num] = ident_clone (file);
219   if (inst->files[inst->files_num] == NULL)
220     return (ENOMEM);
221
222   inst->files_num++;
223
224   return (0);
225 } /* }}} int instance_add_file */
226
227 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
228     const graph_ident_t *file)
229 {
230   graph_instance_t *i;
231
232   if ((cfg == NULL) || (file == NULL))
233     return (NULL);
234
235   for (i = cfg->instances; i != NULL; i = i->next)
236     if (ident_matches (i->select, file))
237       return (i);
238
239   return (NULL);
240 } /* }}} graph_instance_t *graph_find_instance */
241
242 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
243 {
244   graph_instance_t *inst;
245
246   inst = graph_find_instance (cfg, file);
247   if (inst == NULL)
248   {
249     inst = instance_create (cfg, file);
250     if (inst == NULL)
251       return (ENOMEM);
252   }
253
254   return (instance_add_file (inst, file));
255 } /* }}} int graph_add_file */
256
257 static int graph_append (graph_config_t *cfg) /* {{{ */
258 {
259   graph_config_t *last;
260
261   if (cfg == NULL)
262     return (EINVAL);
263
264   if (graph_config_head == NULL)
265   {
266     graph_config_head = cfg;
267     return (0);
268   }
269
270   last = graph_config_head;
271   while (last->next != NULL)
272     last = last->next;
273
274   last->next = cfg;
275
276   return (0);
277 } /* }}} int graph_append */
278
279 static graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
280 {
281   graph_config_t *cfg;
282
283   cfg = malloc (sizeof (*cfg));
284   if (cfg == NULL)
285     return (NULL);
286   memset (cfg, 0, sizeof (*cfg));
287
288   cfg->select = ident_clone (selector);
289
290   cfg->title = NULL;
291   cfg->vertical_label = NULL;
292   cfg->defs = NULL;
293   cfg->instances = NULL;
294   cfg->next = NULL;
295
296   return (cfg);
297 } /* }}} int graph_create */
298
299 static void graph_destroy (graph_config_t *cfg) /* {{{ */
300 {
301   graph_config_t *next;
302
303   if (cfg == NULL)
304     return;
305
306   next = cfg->next;
307
308   ident_destroy (cfg->select);
309
310   free (cfg->title);
311   free (cfg->vertical_label);
312
313   def_destroy (cfg->defs);
314   instance_destroy (cfg->instances);
315
316   graph_destroy (next);
317 } /* }}} void graph_destroy */
318
319 static int register_file (const graph_ident_t *file) /* {{{ */
320 {
321   graph_config_t *cfg;
322   int num_graphs = 0;
323
324   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
325   {
326     int status;
327
328     if (!ident_matches (cfg->select, file))
329       continue;
330
331     status = graph_add_file (cfg, file);
332     if (status != 0)
333     {
334       /* report error */;
335     }
336     else
337     {
338       num_graphs++;
339     }
340   }
341
342   if (num_graphs == 0)
343   {
344     cfg = graph_create (file);
345     graph_append (cfg);
346     graph_add_file (cfg, file);
347   }
348
349   return (0);
350 } /* }}} int register_file */
351
352 static int FIXME_graph_create_from_file (const char *host, /* {{{ */
353     const char *plugin, const char *plugin_instance,
354     const char *type, const char *type_instance,
355     const char *title)
356 {
357   graph_config_t *cfg;
358
359   cfg = malloc (sizeof (*cfg));
360   if (cfg == NULL)
361     return (ENOMEM);
362   memset (cfg, 0, sizeof (*cfg));
363
364   cfg->select = ident_create (host, plugin, plugin_instance, type, type_instance);
365
366   cfg->title = NULL;
367   if (title != NULL)
368     cfg->title = strdup (title);
369   cfg->vertical_label = NULL;
370   cfg->instances = NULL;
371   cfg->next = NULL;
372
373   graph_append (cfg);
374
375   return (0);
376 } /* }}} int FIXME_graph_create_from_file */
377
378 /* FIXME: Actually read the config file here. */
379 static int read_graph_config (void) /* {{{ */
380 {
381   if (graph_config_head != NULL)
382     return (0);
383
384   FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ANY_TOKEN, "cpu", ALL_TOKEN,
385       "CPU {instance} usage");
386   FIXME_graph_create_from_file (ANY_TOKEN, "memory", "", "memory", ALL_TOKEN,
387       "Memory usage");
388   FIXME_graph_create_from_file (ANY_TOKEN, "swap", "", "swap", ALL_TOKEN,
389       "Swap");
390   FIXME_graph_create_from_file (ANY_TOKEN, ANY_TOKEN, ANY_TOKEN, "ps_state", ALL_TOKEN,
391       "Processes");
392   FIXME_graph_create_from_file (ANY_TOKEN, "cpu", ALL_TOKEN, "cpu", "idle",
393       "CPU idle overview");
394
395   return (0);
396 } /* }}} int read_graph_config */
397
398 static void gl_clear (void) /* {{{ */
399 {
400   graph_config_t *cfg;
401
402   cfg = graph_config_head;
403   graph_config_head = NULL;
404   graph_destroy (cfg);
405
406   gl_last_update = 0;
407 } /* }}} void gl_clear */
408
409 static int callback_type (const char *type, void *user_data) /* {{{ */
410 {
411   gl_ident_stage_t *gl;
412   graph_ident_t *ident;
413   int status;
414
415   if ((type == NULL) || (user_data == NULL))
416     return (EINVAL);
417
418   gl = user_data;
419   if ((gl->type != NULL) || (gl->type_instance != NULL))
420     return (EINVAL);
421
422   gl->type = strdup (type);
423   if (gl->type == NULL)
424     return (ENOMEM);
425
426   gl->type_instance = strchr (gl->type, '-');
427   if (gl->type_instance != NULL)
428   {
429     *gl->type_instance = 0;
430     gl->type_instance++;
431   }
432   else
433   {
434     gl->type_instance = gl->type + strlen (gl->type);
435   }
436
437   ident = ident_create (gl->host,
438       gl->plugin, gl->plugin_instance,
439       gl->type, gl->type_instance);
440   if (ident == 0)
441   {
442     status = -1;
443   }
444   else
445   {
446     status = register_file (ident);
447     ident_destroy (ident);
448   }
449
450   free (gl->type);
451   gl->type = NULL;
452   gl->type_instance = NULL;
453
454   return (status);
455 } /* }}} int callback_type */
456
457 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
458 {
459   gl_ident_stage_t *gl;
460   int status;
461
462   if ((plugin == NULL) || (user_data == NULL))
463     return (EINVAL);
464
465   gl = user_data;
466   if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
467     return (EINVAL);
468
469   gl->plugin = strdup (plugin);
470   if (gl->plugin == NULL)
471     return (ENOMEM);
472
473   gl->plugin_instance = strchr (gl->plugin, '-');
474   if (gl->plugin_instance != NULL)
475   {
476     *gl->plugin_instance = 0;
477     gl->plugin_instance++;
478   }
479   else
480   {
481     gl->plugin_instance = gl->plugin + strlen (gl->plugin);
482   }
483
484   status = foreach_type (gl->host, plugin, callback_type, gl);
485
486   free (gl->plugin);
487   gl->plugin = NULL;
488   gl->plugin_instance = NULL;
489
490   return (status);
491 } /* }}} int callback_plugin */
492
493 static int callback_host (const char *host, void *user_data) /* {{{ */
494 {
495   gl_ident_stage_t *gl;
496   int status;
497
498   if ((host == NULL) || (user_data == NULL))
499     return (EINVAL);
500
501   gl = user_data;
502   if (gl->host != NULL)
503     return (EINVAL);
504
505   gl->host = strdup (host);
506   if (gl->host == NULL)
507     return (ENOMEM);
508
509   status =  foreach_plugin (host, callback_plugin, gl);
510
511   free (gl->host);
512   gl->host = NULL;
513
514   return (status);
515 } /* }}} int callback_host */
516
517 static const char *get_part_from_param (const char *prim_key, /* {{{ */
518     const char *sec_key)
519 {
520   const char *val;
521
522   val = param (prim_key);
523   if (val != NULL)
524     return (val);
525   
526   return (param (sec_key));
527 } /* }}} const char *get_part_from_param */
528
529 int gl_ident_get_rrdargs (graph_config_t *cfg, /* {{{ */
530     graph_instance_t *inst,
531     graph_ident_t *ident,
532     str_array_t *args)
533 {
534   char *file;
535   char **dses = NULL;
536   size_t dses_num = 0;
537   int status;
538   size_t i;
539
540   if ((cfg == NULL) || (inst == NULL) || (ident == NULL) || (args == NULL))
541     return (EINVAL);
542
543   file = ident_to_file (ident);
544   if (file == NULL)
545   {
546     DEBUG ("gl_ident_get_rrdargs: ident_to_file returned NULL.\n");
547     return (-1);
548   }
549
550   DEBUG ("gl_ident_get_rrdargs: file = %s;\n", file);
551
552   status = ds_list_from_rrd_file (file, &dses_num, &dses);
553   if (status != 0)
554   {
555     free (file);
556     return (status);
557   }
558
559   for (i = 0; i < dses_num; i++)
560   {
561     int index;
562
563     DEBUG ("gl_ident_get_rrdargs: ds[%lu] = %s;\n", (unsigned long) i, dses[i]);
564
565     index = array_argc (args);
566
567     /* CDEFs */
568     array_append_format (args, "DEF:def_%04i_min=%s:%s:MIN",
569         index, file, dses[i]);
570     array_append_format (args, "DEF:def_%04i_avg=%s:%s:AVERAGE",
571         index, file, dses[i]);
572     array_append_format (args, "DEF:def_%04i_max=%s:%s:MAX",
573         index, file, dses[i]);
574     /* VDEFs */
575     array_append_format (args, "VDEF:vdef_%04i_min=def_%04i_min,MINIMUM",
576         index, index);
577     array_append_format (args, "VDEF:vdef_%04i_avg=def_%04i_avg,AVERAGE",
578         index, index);
579     array_append_format (args, "VDEF:vdef_%04i_max=def_%04i_max,MAXIMUM",
580         index, index);
581     array_append_format (args, "VDEF:vdef_%04i_lst=def_%04i_avg,LAST",
582         index, index);
583
584     /* Graph part */
585     array_append_format (args, "LINE1:def_%04i_avg#%06"PRIx32":%s",
586         index, get_random_color (), dses[i]);
587     array_append_format (args, "GPRINT:vdef_%04i_min:%%lg min,", index);
588     array_append_format (args, "GPRINT:vdef_%04i_avg:%%lg avg,", index);
589     array_append_format (args, "GPRINT:vdef_%04i_max:%%lg max,", index);
590     array_append_format (args, "GPRINT:vdef_%04i_lst:%%lg last\\l", index);
591
592     free (dses[i]);
593   }
594   free (dses);
595
596   free (file);
597
598   return (0);
599 } /* }}} int gl_ident_get_rrdargs */
600
601 /*
602  * Global functions
603  */
604 int gl_instance_get_params (graph_config_t *cfg, graph_instance_t *inst, /* {{{ */
605     char *buffer, size_t buffer_size)
606 {
607   if ((inst == NULL) || (buffer == NULL) || (buffer_size < 1))
608     return (EINVAL);
609
610   buffer[0] = 0;
611
612 #define COPY_FIELD(field) do {                                  \
613   const char *cfg_f  = ident_get_##field (cfg->select);         \
614   const char *inst_f = ident_get_##field (inst->select);        \
615   if (strcmp (cfg_f, inst_f) == 0)                              \
616   {                                                             \
617     strlcat (buffer, #field, buffer_size);                      \
618     strlcat (buffer, "=", buffer_size);                         \
619     strlcat (buffer, cfg_f, buffer_size);                       \
620   }                                                             \
621   else                                                          \
622   {                                                             \
623     strlcat (buffer, "graph_", buffer_size);                    \
624     strlcat (buffer, #field, buffer_size);                      \
625     strlcat (buffer, "=", buffer_size);                         \
626     strlcat (buffer, cfg_f, buffer_size);                       \
627     strlcat (buffer, ";", buffer_size);                         \
628     strlcat (buffer, "inst_", buffer_size);                     \
629     strlcat (buffer, #field, buffer_size);                      \
630     strlcat (buffer, "=", buffer_size);                         \
631     strlcat (buffer, inst_f, buffer_size);                      \
632   }                                                             \
633 } while (0)
634
635   COPY_FIELD(host);
636   strlcat (buffer, ";", buffer_size);
637   COPY_FIELD(plugin);
638   strlcat (buffer, ";", buffer_size);
639   COPY_FIELD(plugin_instance);
640   strlcat (buffer, ";", buffer_size);
641   COPY_FIELD(type);
642   strlcat (buffer, ";", buffer_size);
643   COPY_FIELD(type_instance);
644
645 #undef COPY_FIELD
646
647   return (0);
648 } /* }}} int gl_instance_get_params */
649
650 graph_instance_t *inst_get_selected (graph_config_t *cfg) /* {{{ */
651 {
652   const char *host = get_part_from_param ("inst_host", "host");
653   const char *plugin = get_part_from_param ("inst_plugin", "plugin");
654   const char *plugin_instance = get_part_from_param ("inst_plugin_instance", "plugin_instance");
655   const char *type = get_part_from_param ("inst_type", "type");
656   const char *type_instance = get_part_from_param ("inst_type_instance", "type_instance");
657   graph_ident_t *ident;
658   graph_instance_t *inst;
659
660   if (cfg == NULL)
661     cfg = graph_get_selected ();
662
663   if (cfg == NULL)
664   {
665     DEBUG ("inst_get_selected: cfg == NULL;\n");
666     return (NULL);
667   }
668
669   if ((host == NULL)
670       || (plugin == NULL) || (plugin_instance == NULL)
671       || (type == NULL) || (type_instance == NULL))
672   {
673     DEBUG ("inst_get_selected: A parameter is NULL.\n");
674     return (NULL);
675   }
676
677   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
678
679   for (inst = cfg->instances; inst != NULL; inst = inst->next)
680   {
681     if (ident_compare (ident, inst->select) != 0)
682       continue;
683
684     ident_destroy (ident);
685     return (inst);
686   }
687
688   DEBUG ("inst_get_selected: No match found.\n");
689   ident_destroy (ident);
690   return (NULL);
691 } /* }}} graph_instance_t *inst_get_selected */
692
693 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
694     void *user_data)
695 {
696   graph_config_t *cfg;
697
698   if (callback == NULL)
699     return (EINVAL);
700
701   gl_update ();
702
703   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
704   {
705     int status;
706
707     status = (*callback) (cfg, user_data);
708     if (status != 0)
709       return (status);
710   }
711
712   return (0);
713 } /* }}} int gl_graph_get_all */
714
715 graph_config_t *graph_get_selected (void) /* {{{ */
716 {
717   const char *host = get_part_from_param ("graph_host", "host");
718   const char *plugin = get_part_from_param ("graph_plugin", "plugin");
719   const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
720   const char *type = get_part_from_param ("graph_type", "type");
721   const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
722   graph_ident_t *ident;
723   graph_config_t *cfg;
724
725   if ((host == NULL)
726       || (plugin == NULL) || (plugin_instance == NULL)
727       || (type == NULL) || (type_instance == NULL))
728     return (NULL);
729
730   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
731
732   gl_update ();
733
734   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
735   {
736     if (ident_compare (ident, cfg->select) != 0)
737       continue;
738
739     ident_destroy (ident);
740     return (cfg);
741   }
742
743   ident_destroy (ident);
744   return (NULL);
745 } /* }}} graph_config_t *graph_get_selected */
746
747 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
748     gl_inst_callback callback, void *user_data)
749 {
750   graph_instance_t *inst;
751
752   if ((cfg == NULL) || (callback == NULL))
753     return (EINVAL);
754
755   for (inst = cfg->instances; inst != NULL; inst = inst->next)
756   {
757     int status;
758
759     status = (*callback) (cfg, inst, user_data);
760     if (status != 0)
761       return (status);
762   }
763
764   return (0);
765 } /* }}} int gl_graph_instance_get_all */
766
767 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
768     char *buffer, size_t buffer_size)
769 {
770   char *str;
771
772   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
773     return (EINVAL);
774
775   if (cfg->title != NULL)
776     str = cfg->title;
777   else
778     str = ident_to_string (cfg->select);
779
780   if (str == NULL)
781     return (ENOMEM);
782
783   strncpy (buffer, str, buffer_size);
784   buffer[buffer_size - 1] = 0;
785
786   free (str);
787
788   return (0);
789 } /* }}} int gl_graph_get_title */
790
791 graph_ident_t *gl_graph_get_selector (graph_config_t *cfg) /* {{{ */
792 {
793   if (cfg == NULL)
794     return (NULL);
795
796   return (ident_clone (cfg->select));
797 } /* }}} graph_ident_t *gl_graph_get_selector */
798
799 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
800     void *user_data)
801 {
802   graph_config_t *cfg;
803
804   gl_update ();
805
806   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
807   {
808     graph_instance_t *inst;
809
810     for (inst = cfg->instances; inst != NULL; inst = inst->next)
811     {
812       int status;
813
814       status = (*callback) (cfg, inst, user_data);
815       if (status != 0)
816         return (status);
817     }
818   }
819
820   return (0);
821 } /* }}} int gl_instance_get_all */
822
823 int gl_instance_get_rrdargs (graph_config_t *cfg, /* {{{ */
824     graph_instance_t *inst,
825     str_array_t *args)
826 {
827   size_t i;
828
829   if ((cfg == NULL) || (inst == NULL) || (args == NULL))
830     return (EINVAL);
831
832   if (cfg->title != NULL)
833   {
834     array_append (args, "-t");
835     array_append (args, cfg->title);
836   }
837
838   for (i = 0; i < inst->files_num; i++)
839   {
840     graph_def_t *def;
841     int status;
842
843     def = def_search (cfg->defs, inst->files[i]);
844     if (def == NULL)
845     {
846       def = def_create (cfg, inst->files[i]);
847       if (def == NULL)
848         return (-1);
849
850       if (cfg->defs == NULL)
851         cfg->defs = def;
852       else
853         def_append (cfg->defs, def);
854     }
855
856     status = def_get_rrdargs (def, inst->files[i], args);
857     if (status != 0)
858       return (status);
859   }
860
861   return (0);
862 } /* }}} int gl_instance_get_rrdargs */
863
864 graph_ident_t *gl_instance_get_selector (graph_instance_t *inst) /* {{{ */
865 {
866   if (inst == NULL)
867     return (NULL);
868
869   return (ident_clone (inst->select));
870 } /* }}} graph_ident_t *gl_instance_get_selector */
871
872 /* DELETEME */
873
874 int gl_update (void) /* {{{ */
875 {
876   time_t now;
877   gl_ident_stage_t gl;
878   int status;
879
880   /*
881   printf ("Content-Type: text/plain\n\n");
882   */
883
884   now = time (NULL);
885
886   if ((gl_last_update + UPDATE_INTERVAL) >= now)
887     return (0);
888
889   gl_clear ();
890
891   read_graph_config ();
892
893   memset (&gl, 0, sizeof (gl));
894   gl.host = NULL;
895   gl.plugin = NULL;
896   gl.plugin_instance = NULL;
897   gl.type = NULL;
898   gl.type_instance = NULL;
899
900   status = foreach_host (callback_host, &gl);
901
902   /* print_graphs (); */
903
904   return (status);
905 } /* }}} int gl_update */
906
907 /* vim: set sw=2 sts=2 et fdm=marker : */