5b37f2d33162075ebf0a15778cd759204a6f3ec8
[collection4.git] / graph_list.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <inttypes.h>
5 #include <string.h>
6 #include <time.h>
7 #include <errno.h>
8 #include <assert.h>
9
10 #include "graph_list.h"
11 #include "graph_ident.h"
12 #include "graph_def.h"
13 #include "graph_config.h"
14 #include "common.h"
15 #include "utils_params.h"
16
17 #include <fcgiapp.h>
18 #include <fcgi_stdio.h>
19
20 /*
21  * Defines
22  */
23 #define UPDATE_INTERVAL 10
24
25 #define ANY_TOKEN "/any/"
26 #define ALL_TOKEN "/all/"
27
28 /*
29  * Data types
30  */
31 struct gl_ident_stage_s /* {{{ */
32 {
33   char *host;
34   char *plugin;
35   char *plugin_instance;
36   char *type;
37   char *type_instance;
38 }; /* }}} */
39 typedef struct gl_ident_stage_s gl_ident_stage_t;
40
41 struct graph_config_s /* {{{ */
42 {
43   graph_ident_t *select;
44
45   char *title;
46   char *vertical_label;
47
48   graph_def_t *defs;
49
50   graph_instance_t *instances;
51
52   graph_config_t *next;
53 }; /* }}} struct graph_config_s */
54
55 /*
56  * Global variables
57  */
58 static graph_config_t *graph_config_head = NULL;
59 static graph_config_t *graph_config_staging = NULL;
60
61 static time_t gl_last_update = 0;
62
63 /*
64  * Private functions
65  */
66 #if 0
67 /* "Safe" version of strcmp(3): Either or both pointers may be NULL. */
68 static int strcmp_s (const char *s1, const char *s2) /* {{{ */
69 {
70   if ((s1 == NULL) && (s2 == NULL))
71     return (0);
72   else if (s1 == NULL)
73     return (1);
74   else if (s2 == NULL)
75     return (-1);
76   assert ((s1 != NULL) && (s2 != NULL));
77
78   return (strcmp (s1, s2));
79 } /* }}} int strcmp_s */
80 #endif
81
82 /*
83  * Copy part of an identifier. If the "template" value is ANY_TOKEN, "value" is
84  * copied and returned. This function is used when creating graph_instance_t
85  * from graph_config_t.
86  */
87
88 static graph_instance_t *graph_find_instance (graph_config_t *cfg, /* {{{ */
89     const graph_ident_t *ident)
90 {
91   if ((cfg == NULL) || (ident == NULL))
92     return (NULL);
93
94   return (inst_find_matching (cfg->instances, ident));
95 } /* }}} graph_instance_t *graph_find_instance */
96
97 static int graph_add_file (graph_config_t *cfg, const graph_ident_t *file) /* {{{ */
98 {
99   graph_instance_t *inst;
100
101   inst = graph_find_instance (cfg, file);
102   if (inst == NULL)
103   {
104     inst = inst_create (cfg, file);
105     if (inst == NULL)
106       return (ENOMEM);
107
108     if (cfg->instances == NULL)
109       cfg->instances = inst;
110     else
111       inst_append (cfg->instances, inst);
112   }
113
114   return (inst_add_file (inst, file));
115 } /* }}} int graph_add_file */
116
117 static int graph_append (graph_config_t **head, /* {{{ */
118     graph_config_t *cfg)
119 {
120   graph_config_t *last;
121
122   if (cfg == NULL)
123     return (EINVAL);
124
125   if (head == NULL)
126     head = &graph_config_head;
127
128   if (*head == NULL)
129   {
130     *head = cfg;
131     return (0);
132   }
133
134   last = *head;
135   while (last->next != NULL)
136     last = last->next;
137
138   last->next = cfg;
139
140   return (0);
141 } /* }}} int graph_append */
142
143 static graph_config_t *graph_create (const graph_ident_t *selector) /* {{{ */
144 {
145   graph_config_t *cfg;
146
147   cfg = malloc (sizeof (*cfg));
148   if (cfg == NULL)
149     return (NULL);
150   memset (cfg, 0, sizeof (*cfg));
151
152   if (selector != NULL)
153     cfg->select = ident_clone (selector);
154   else
155     cfg->select = NULL;
156
157   cfg->title = NULL;
158   cfg->vertical_label = NULL;
159   cfg->defs = NULL;
160   cfg->instances = NULL;
161   cfg->next = NULL;
162
163   return (cfg);
164 } /* }}} int graph_create */
165
166 static void graph_destroy (graph_config_t *cfg) /* {{{ */
167 {
168   graph_config_t *next;
169
170   if (cfg == NULL)
171     return;
172
173   next = cfg->next;
174
175   ident_destroy (cfg->select);
176
177   free (cfg->title);
178   free (cfg->vertical_label);
179
180   def_destroy (cfg->defs);
181   inst_destroy (cfg->instances);
182
183   graph_destroy (next);
184 } /* }}} void graph_destroy */
185
186 static int register_file (const graph_ident_t *file) /* {{{ */
187 {
188   graph_config_t *cfg;
189   int num_graphs = 0;
190
191   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
192   {
193     int status;
194
195     if (!ident_matches (cfg->select, file))
196       continue;
197
198     status = graph_add_file (cfg, file);
199     if (status != 0)
200     {
201       /* report error */;
202     }
203     else
204     {
205       num_graphs++;
206     }
207   }
208
209   if (num_graphs == 0)
210   {
211     cfg = graph_create (file);
212     graph_append (/* head = */ NULL, cfg);
213     graph_add_file (cfg, file);
214   }
215
216   return (0);
217 } /* }}} int register_file */
218
219 static int callback_type (const char *type, void *user_data) /* {{{ */
220 {
221   gl_ident_stage_t *gl;
222   graph_ident_t *ident;
223   int status;
224
225   if ((type == NULL) || (user_data == NULL))
226     return (EINVAL);
227
228   gl = user_data;
229   if ((gl->type != NULL) || (gl->type_instance != NULL))
230     return (EINVAL);
231
232   gl->type = strdup (type);
233   if (gl->type == NULL)
234     return (ENOMEM);
235
236   gl->type_instance = strchr (gl->type, '-');
237   if (gl->type_instance != NULL)
238   {
239     *gl->type_instance = 0;
240     gl->type_instance++;
241   }
242   else
243   {
244     gl->type_instance = gl->type + strlen (gl->type);
245   }
246
247   ident = ident_create (gl->host,
248       gl->plugin, gl->plugin_instance,
249       gl->type, gl->type_instance);
250   if (ident == 0)
251   {
252     status = -1;
253   }
254   else
255   {
256     status = register_file (ident);
257     ident_destroy (ident);
258   }
259
260   free (gl->type);
261   gl->type = NULL;
262   gl->type_instance = NULL;
263
264   return (status);
265 } /* }}} int callback_type */
266
267 static int callback_plugin (const char *plugin, void *user_data) /* {{{ */
268 {
269   gl_ident_stage_t *gl;
270   int status;
271
272   if ((plugin == NULL) || (user_data == NULL))
273     return (EINVAL);
274
275   gl = user_data;
276   if ((gl->plugin != NULL) || (gl->plugin_instance != NULL))
277     return (EINVAL);
278
279   gl->plugin = strdup (plugin);
280   if (gl->plugin == NULL)
281     return (ENOMEM);
282
283   gl->plugin_instance = strchr (gl->plugin, '-');
284   if (gl->plugin_instance != NULL)
285   {
286     *gl->plugin_instance = 0;
287     gl->plugin_instance++;
288   }
289   else
290   {
291     gl->plugin_instance = gl->plugin + strlen (gl->plugin);
292   }
293
294   status = foreach_type (gl->host, plugin, callback_type, gl);
295
296   free (gl->plugin);
297   gl->plugin = NULL;
298   gl->plugin_instance = NULL;
299
300   return (status);
301 } /* }}} int callback_plugin */
302
303 static int callback_host (const char *host, void *user_data) /* {{{ */
304 {
305   gl_ident_stage_t *gl;
306   int status;
307
308   if ((host == NULL) || (user_data == NULL))
309     return (EINVAL);
310
311   gl = user_data;
312   if (gl->host != NULL)
313     return (EINVAL);
314
315   gl->host = strdup (host);
316   if (gl->host == NULL)
317     return (ENOMEM);
318
319   status =  foreach_plugin (host, callback_plugin, gl);
320
321   free (gl->host);
322   gl->host = NULL;
323
324   return (status);
325 } /* }}} int callback_host */
326
327 static const char *get_part_from_param (const char *prim_key, /* {{{ */
328     const char *sec_key)
329 {
330   const char *val;
331
332   val = param (prim_key);
333   if (val != NULL)
334     return (val);
335   
336   return (param (sec_key));
337 } /* }}} const char *get_part_from_param */
338
339 static int gl_clear_instances (void) /* {{{ */
340 {
341   graph_config_t *cfg;
342
343   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
344   {
345     inst_destroy (cfg->instances);
346     cfg->instances = NULL;
347   }
348
349   return (0);
350 } /* }}} int gl_clear_instances */
351
352
353 /*
354  * Config functions
355  */
356 static graph_ident_t *graph_config_get_selector (const oconfig_item_t *ci) /* {{{ */
357 {
358   char *host = NULL;
359   char *plugin = NULL;
360   char *plugin_instance = NULL;
361   char *type = NULL;
362   char *type_instance = NULL;
363   graph_ident_t *ret;
364   int i;
365
366   for (i = 0; i < ci->children_num; i++)
367   {
368     oconfig_item_t *child;
369
370     child = ci->children + i;
371
372     if (strcasecmp ("Host", child->key) == 0)
373       graph_config_get_string (child, &host);
374     else if (strcasecmp ("Plugin", child->key) == 0)
375       graph_config_get_string (child, &plugin);
376     else if (strcasecmp ("PluginInstance", child->key) == 0)
377       graph_config_get_string (child, &plugin_instance);
378     else if (strcasecmp ("Type", child->key) == 0)
379       graph_config_get_string (child, &type);
380     else if (strcasecmp ("TypeInstance", child->key) == 0)
381       graph_config_get_string (child, &type_instance);
382     /* else: ignore all other directives here. */
383   } /* for */
384
385   ret = ident_create (host, plugin, plugin_instance, type, type_instance);
386
387   free (host);
388   free (plugin);
389   free (plugin_instance);
390   free (type);
391   free (type_instance);
392
393   return (ret);
394 } /* }}} int graph_config_get_selector */
395
396 /*
397  * Global functions
398  */
399 int graph_config_add (const oconfig_item_t *ci) /* {{{ */
400 {
401   graph_ident_t *select;
402   graph_config_t *cfg = NULL;
403   int i;
404
405   select = graph_config_get_selector (ci);
406   if (select == NULL)
407     return (EINVAL);
408
409   cfg = graph_create (/* selector = */ NULL);
410   if (cfg == NULL)
411     return (ENOMEM);
412
413   cfg->select = select;
414
415   for (i = 0; i < ci->children_num; i++)
416   {
417     oconfig_item_t *child;
418
419     child = ci->children + i;
420
421     if (strcasecmp ("Title", child->key) == 0)
422       graph_config_get_string (child, &cfg->title);
423     else if (strcasecmp ("VerticalLabel", child->key) == 0)
424       graph_config_get_string (child, &cfg->vertical_label);
425     else if (strcasecmp ("DEF", child->key) == 0)
426       def_config (cfg, child);
427   } /* for */
428
429   graph_append (&graph_config_staging, cfg);
430
431   return (0);
432 } /* }}} graph_config_add */
433
434 int graph_config_submit (void) /* {{{ */
435 {
436   graph_config_t *tmp;
437
438   tmp = graph_config_head;
439   graph_config_head = graph_config_staging;
440   graph_config_staging = NULL;
441
442   graph_destroy (tmp);
443
444   return (0);
445 } /* }}} int graph_config_submit */
446
447 int gl_graph_get_all (gl_cfg_callback callback, /* {{{ */
448     void *user_data)
449 {
450   graph_config_t *cfg;
451
452   if (callback == NULL)
453     return (EINVAL);
454
455   gl_update ();
456
457   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
458   {
459     int status;
460
461     status = (*callback) (cfg, user_data);
462     if (status != 0)
463       return (status);
464   }
465
466   return (0);
467 } /* }}} int gl_graph_get_all */
468
469 graph_config_t *graph_get_selected (void) /* {{{ */
470 {
471   const char *host = get_part_from_param ("graph_host", "host");
472   const char *plugin = get_part_from_param ("graph_plugin", "plugin");
473   const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
474   const char *type = get_part_from_param ("graph_type", "type");
475   const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
476   graph_ident_t *ident;
477   graph_config_t *cfg;
478
479   if ((host == NULL)
480       || (plugin == NULL) || (plugin_instance == NULL)
481       || (type == NULL) || (type_instance == NULL))
482     return (NULL);
483
484   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
485
486   gl_update ();
487
488   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
489   {
490     if (ident_compare (ident, cfg->select) != 0)
491       continue;
492
493     ident_destroy (ident);
494     return (cfg);
495   }
496
497   ident_destroy (ident);
498   return (NULL);
499 } /* }}} graph_config_t *graph_get_selected */
500
501 /* gl_instance_get_all, gl_graph_instance_get_all {{{ */
502 struct gl_inst_callback_data /* {{{ */
503 {
504   graph_config_t *cfg;
505   gl_inst_callback callback;
506   void *user_data;
507 }; /* }}} struct gl_inst_callback_data */
508
509 static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
510     void *user_data)
511 {
512   struct gl_inst_callback_data *data = user_data;
513
514   return ((*data->callback) (data->cfg, inst, data->user_data));
515 } /* }}} int gl_inst_callback_handler */
516
517 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
518     gl_inst_callback callback, void *user_data)
519 {
520   struct gl_inst_callback_data data =
521   {
522     cfg,
523     callback,
524     user_data
525   };
526
527   if ((cfg == NULL) || (callback == NULL))
528     return (EINVAL);
529
530   return (inst_foreach (cfg->instances, gl_inst_callback_handler, &data));
531 } /* }}} int gl_graph_instance_get_all */
532
533 int gl_instance_get_all (gl_inst_callback callback, /* {{{ */
534     void *user_data)
535 {
536   graph_config_t *cfg;
537
538   gl_update ();
539
540   for (cfg = graph_config_head; cfg != NULL; cfg = cfg->next)
541   {
542     int status;
543
544     status = gl_graph_instance_get_all (cfg, callback, user_data);
545     if (status != 0)
546       return (status);
547   }
548
549   return (0);
550 } /* }}} int gl_instance_get_all */
551 /* }}} gl_instance_get_all, gl_graph_instance_get_all */
552
553 int gl_graph_get_title (graph_config_t *cfg, /* {{{ */
554     char *buffer, size_t buffer_size)
555 {
556   if ((cfg == NULL) || (buffer == NULL) || (buffer_size < 1))
557     return (EINVAL);
558
559   if (cfg->title == NULL)
560     cfg->title = ident_to_string (cfg->select);
561
562   if (cfg->title == NULL)
563     return (ENOMEM);
564
565   strncpy (buffer, cfg->title, buffer_size);
566   buffer[buffer_size - 1] = 0;
567
568   return (0);
569 } /* }}} int gl_graph_get_title */
570
571 graph_ident_t *gl_graph_get_selector (graph_config_t *cfg) /* {{{ */
572 {
573   if (cfg == NULL)
574     return (NULL);
575
576   return (ident_clone (cfg->select));
577 } /* }}} graph_ident_t *gl_graph_get_selector */
578
579 graph_instance_t *gl_graph_get_instances (graph_config_t *cfg) /* {{{ */
580 {
581   if (cfg == NULL)
582     return (NULL);
583
584   return (cfg->instances);
585 } /* }}} graph_instance_t *gl_graph_get_instances */
586
587 graph_def_t *gl_graph_get_defs (graph_config_t *cfg) /* {{{ */
588 {
589   if (cfg == NULL)
590     return (NULL);
591
592   return (cfg->defs);
593 } /* }}} graph_def_t *gl_graph_get_defs */
594
595 int gl_graph_add_def (graph_config_t *cfg, graph_def_t *def) /* {{{ */
596 {
597   if ((cfg == NULL) || (def == NULL))
598     return (EINVAL);
599
600   if (cfg->defs == NULL)
601   {
602     cfg->defs = def;
603     return (0);
604   }
605
606   return (def_append (cfg->defs, def));
607 } /* }}} int gl_graph_add_def */
608
609 int gl_update (void) /* {{{ */
610 {
611   time_t now;
612   gl_ident_stage_t gl;
613   int status;
614
615   /*
616   printf ("Content-Type: text/plain\n\n");
617   */
618
619   now = time (NULL);
620
621   if ((gl_last_update + UPDATE_INTERVAL) >= now)
622     return (0);
623
624   graph_read_config ();
625
626   memset (&gl, 0, sizeof (gl));
627   gl.host = NULL;
628   gl.plugin = NULL;
629   gl.plugin_instance = NULL;
630   gl.type = NULL;
631   gl.type_instance = NULL;
632
633   gl_clear_instances ();
634   status = foreach_host (callback_host, &gl);
635
636   gl_last_update = now;
637
638   return (status);
639 } /* }}} int gl_update */
640
641 /* vim: set sw=2 sts=2 et fdm=marker : */