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