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