src/graph_list.c: Sort the instances of all graphs.
[collection4.git] / src / graph_list.c
1 /**
2  * collection4 - graph_list.c
3  * Copyright (C) 2010  Florian octo Forster
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Florian octo Forster <ff at octo.it>
22  **/
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <inttypes.h>
28 #include <string.h>
29 #include <time.h>
30 #include <errno.h>
31
32 #include "graph_list.h"
33 #include "common.h"
34 #include "filesystem.h"
35 #include "graph.h"
36 #include "graph_config.h"
37 #include "graph_def.h"
38 #include "graph_ident.h"
39 #include "utils_cgi.h"
40
41 #include <fcgiapp.h>
42 #include <fcgi_stdio.h>
43
44 /*
45  * Defines
46  */
47 #define UPDATE_INTERVAL 900
48
49 /*
50  * Global variables
51  */
52 static graph_config_t **gl_active = NULL;
53 static size_t gl_active_num = 0;
54
55 static graph_config_t **gl_staging = NULL;
56 static size_t gl_staging_num = 0;
57
58 /* Graphs created on-the-fly for files which don't match any existing graph
59  * definition. */
60 static graph_config_t **gl_dynamic = NULL;
61 static size_t gl_dynamic_num = 0;
62
63 static char **host_list = NULL;
64 static size_t host_list_len = 0;
65
66 static time_t gl_last_update = 0;
67
68 /*
69  * Private functions
70  */
71 static int gl_add_graph_internal (graph_config_t *cfg, /* {{{ */
72     graph_config_t ***gl_array, size_t *gl_array_num)
73 {
74   graph_config_t **tmp;
75
76 #define ARRAY_PTR  (*gl_array)
77 #define ARRAY_SIZE (*gl_array_num)
78
79   if (cfg == NULL)
80     return (EINVAL);
81
82   tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
83   if (tmp == NULL)
84     return (ENOMEM);
85   ARRAY_PTR = tmp;
86
87   ARRAY_PTR[ARRAY_SIZE] = cfg;
88   ARRAY_SIZE++;
89
90 #undef ARRAY_SIZE
91 #undef ARRAY_PTR
92
93   return (0);
94 } /* }}} int gl_add_graph_internal */
95
96 static void gl_destroy (graph_config_t ***gl_array, /* {{{ */
97     size_t *gl_array_num)
98 {
99   size_t i;
100
101   if ((gl_array == NULL) || (gl_array_num == NULL))
102     return;
103
104 #define ARRAY_PTR  (*gl_array)
105 #define ARRAY_SIZE (*gl_array_num)
106
107   for (i = 0; i < ARRAY_SIZE; i++)
108   {
109     graph_destroy (ARRAY_PTR[i]);
110     ARRAY_PTR[i] = NULL;
111   }
112   free (ARRAY_PTR);
113   ARRAY_PTR = NULL;
114   ARRAY_SIZE = 0;
115
116 #undef ARRAY_SIZE
117 #undef ARRAY_PTR
118 } /* }}} void gl_destroy */
119
120 static int gl_register_host (const char *host) /* {{{ */
121 {
122   char **tmp;
123   size_t i;
124
125   if (host == NULL)
126     return (EINVAL);
127
128   for (i = 0; i < host_list_len; i++)
129     if (strcmp (host_list[i], host) == 0)
130       return (0);
131
132   tmp = realloc (host_list, sizeof (*host_list) * (host_list_len + 1));
133   if (tmp == NULL)
134     return (ENOMEM);
135   host_list = tmp;
136
137   host_list[host_list_len] = strdup (host);
138   if (host_list[host_list_len] == NULL)
139     return (ENOMEM);
140
141   host_list_len++;
142   return (0);
143 } /* }}} int gl_register_host */
144
145 static int gl_clear_hosts (void) /* {{{ */
146 {
147   size_t i;
148
149   for (i = 0; i < host_list_len; i++)
150     free (host_list[i]);
151   free (host_list);
152
153   host_list = NULL;
154   host_list_len = 0;
155
156   return (0);
157 } /* }}} int gl_clear_hosts */
158
159 static int gl_compare_hosts (const void *v0, const void *v1) /* {{{ */
160 {
161   return (strcmp (*(char * const *) v0, *(char * const *) v1));
162 } /* }}} int gl_compare_hosts */
163
164 static int gl_register_file (const graph_ident_t *file, /* {{{ */
165     __attribute__((unused)) void *user_data)
166 {
167   graph_config_t *cfg;
168   int num_graphs = 0;
169   size_t i;
170
171   for (i = 0; i < gl_active_num; i++)
172   {
173     graph_config_t *cfg = gl_active[i];
174     int status;
175
176     if (!graph_matches_ident (cfg, file))
177       continue;
178
179     status = graph_add_file (cfg, file);
180     if (status != 0)
181     {
182       /* report error */;
183     }
184     else
185     {
186       num_graphs++;
187     }
188   }
189
190   if (num_graphs == 0)
191   {
192     cfg = graph_create (file);
193     gl_add_graph_internal (cfg, &gl_dynamic, &gl_dynamic_num);
194     graph_add_file (cfg, file);
195   }
196
197   gl_register_host (ident_get_host (file));
198
199   return (0);
200 } /* }}} int gl_register_file */
201
202 static const char *get_part_from_param (const char *prim_key, /* {{{ */
203     const char *sec_key)
204 {
205   const char *val;
206
207   val = param (prim_key);
208   if (val != NULL)
209     return (val);
210   
211   return (param (sec_key));
212 } /* }}} const char *get_part_from_param */
213
214 static int gl_clear_instances (void) /* {{{ */
215 {
216   size_t i;
217
218   for (i = 0; i < gl_active_num; i++)
219     graph_clear_instances (gl_active[i]);
220
221   return (0);
222 } /* }}} int gl_clear_instances */
223
224 /*
225  * Global functions
226  */
227 int gl_add_graph (graph_config_t *cfg) /* {{{ */
228 {
229   return (gl_add_graph_internal (cfg, &gl_staging, &gl_staging_num));
230 } /* }}} int gl_add_graph */
231
232 int gl_config_submit (void) /* {{{ */
233 {
234   graph_config_t **old;
235   size_t old_num;
236
237   old = gl_active;
238   old_num = gl_active_num;
239
240   gl_active = gl_staging;
241   gl_active_num = gl_staging_num;
242
243   gl_staging = NULL;
244   gl_staging_num = 0;
245
246   gl_destroy (&old, &old_num);
247
248   return (0);
249 } /* }}} int graph_config_submit */
250
251 int gl_graph_get_all (graph_callback_t callback, /* {{{ */
252     void *user_data)
253 {
254   size_t i;
255
256   if (callback == NULL)
257     return (EINVAL);
258
259   gl_update ();
260
261   for (i = 0; i < gl_active_num; i++)
262   {
263     int status;
264
265     status = (*callback) (gl_active[i], user_data);
266     if (status != 0)
267       return (status);
268   }
269
270   for (i = 0; i < gl_dynamic_num; i++)
271   {
272     int status;
273
274     status = (*callback) (gl_dynamic[i], user_data);
275     if (status != 0)
276       return (status);
277   }
278
279   return (0);
280 } /* }}} int gl_graph_get_all */
281
282 graph_config_t *gl_graph_get_selected (void) /* {{{ */
283 {
284   const char *host = get_part_from_param ("graph_host", "host");
285   const char *plugin = get_part_from_param ("graph_plugin", "plugin");
286   const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
287   const char *type = get_part_from_param ("graph_type", "type");
288   const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
289   graph_ident_t *ident;
290   size_t i;
291
292   if ((host == NULL)
293       || (plugin == NULL) || (plugin_instance == NULL)
294       || (type == NULL) || (type_instance == NULL))
295     return (NULL);
296
297   ident = ident_create (host, plugin, plugin_instance, type, type_instance);
298
299   gl_update ();
300
301   for (i = 0; i < gl_active_num; i++)
302   {
303     if (graph_compare (gl_active[i], ident) != 0)
304       continue;
305
306     ident_destroy (ident);
307     return (gl_active[i]);
308   }
309
310   for (i = 0; i < gl_dynamic_num; i++)
311   {
312     if (graph_compare (gl_dynamic[i], ident) != 0)
313       continue;
314
315     ident_destroy (ident);
316     return (gl_dynamic[i]);
317   }
318
319   ident_destroy (ident);
320   return (NULL);
321 } /* }}} graph_config_t *gl_graph_get_selected */
322
323 /* gl_instance_get_all, gl_graph_instance_get_all {{{ */
324 struct gl_inst_callback_data /* {{{ */
325 {
326   graph_config_t *cfg;
327   graph_inst_callback_t callback;
328   void *user_data;
329 }; /* }}} struct gl_inst_callback_data */
330
331 static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
332     void *user_data)
333 {
334   struct gl_inst_callback_data *data = user_data;
335
336   return ((*data->callback) (data->cfg, inst, data->user_data));
337 } /* }}} int gl_inst_callback_handler */
338
339 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
340     graph_inst_callback_t callback, void *user_data)
341 {
342   struct gl_inst_callback_data data =
343   {
344     cfg,
345     callback,
346     user_data
347   };
348
349   if ((cfg == NULL) || (callback == NULL))
350     return (EINVAL);
351
352   return (graph_inst_foreach (cfg, gl_inst_callback_handler, &data));
353 } /* }}} int gl_graph_instance_get_all */
354
355 int gl_instance_get_all (graph_inst_callback_t callback, /* {{{ */
356     void *user_data)
357 {
358   size_t i;
359
360   gl_update ();
361
362   for (i = 0; i < gl_active_num; i++)
363   {
364     int status;
365
366     status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
367     if (status != 0)
368       return (status);
369   }
370
371   for (i = 0; i < gl_dynamic_num; i++)
372   {
373     int status;
374
375     status = gl_graph_instance_get_all (gl_dynamic[i], callback, user_data);
376     if (status != 0)
377       return (status);
378   }
379
380   return (0);
381 } /* }}} int gl_instance_get_all */
382 /* }}} gl_instance_get_all, gl_graph_instance_get_all */
383
384 int gl_search (const char *term, graph_inst_callback_t callback, /* {{{ */
385     void *user_data)
386 {
387   size_t i;
388
389   for (i = 0; i < gl_active_num; i++)
390   {
391     int status;
392
393     status = graph_inst_search (gl_active[i], term,
394         /* callback  = */ callback,
395         /* user data = */ user_data);
396     if (status != 0)
397       return (status);
398   }
399
400   for (i = 0; i < gl_dynamic_num; i++)
401   {
402     int status;
403
404     status = graph_inst_search (gl_dynamic[i], term,
405         /* callback  = */ callback,
406         /* user data = */ user_data);
407     if (status != 0)
408       return (status);
409   }
410
411   return (0);
412 } /* }}} int gl_search */
413
414 int gl_search_field (graph_ident_field_t field, /* {{{ */
415     const char *field_value,
416     graph_inst_callback_t callback, void *user_data)
417 {
418   size_t i;
419
420   if ((field_value == NULL) || (callback == NULL))
421     return (EINVAL);
422
423   for (i = 0; i < gl_active_num; i++)
424   {
425     int status;
426
427     status = graph_inst_search_field (gl_active[i],
428         field, field_value,
429         /* callback  = */ callback,
430         /* user data = */ user_data);
431     if (status != 0)
432       return (status);
433   }
434
435   for (i = 0; i < gl_dynamic_num; i++)
436   {
437     int status;
438
439     status = graph_inst_search_field (gl_dynamic[i],
440         field, field_value,
441         /* callback  = */ callback,
442         /* user data = */ user_data);
443     if (status != 0)
444       return (status);
445   }
446
447   return (0);
448 } /* }}} int gl_search_field */
449
450 int gl_foreach_host (int (*callback) (const char *host, void *user_data), /* {{{ */
451     void *user_data)
452 {
453   int status;
454   size_t i;
455
456   for (i = 0; i < host_list_len; i++)
457   {
458     status = (*callback) (host_list[i], user_data);
459     if (status != 0)
460       return (status);
461   }
462
463   return (0);
464 } /* }}} int gl_foreach_host */
465
466 int gl_update (void) /* {{{ */
467 {
468   time_t now;
469   int status;
470   size_t i;
471
472   /*
473   printf ("Content-Type: text/plain\n\n");
474   */
475
476   now = time (NULL);
477
478   if ((gl_last_update + UPDATE_INTERVAL) >= now)
479     return (0);
480
481   /* Clear state */
482   gl_clear_instances ();
483   gl_clear_hosts ();
484   gl_destroy (&gl_dynamic, &gl_dynamic_num);
485
486   graph_read_config ();
487
488   status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL);
489
490   if (host_list_len > 0)
491     qsort (host_list, host_list_len, sizeof (*host_list),
492         gl_compare_hosts);
493
494   gl_last_update = now;
495
496   for (i = 0; i < gl_active_num; i++)
497     graph_sort_instances (gl_active[i]);
498
499   return (status);
500 } /* }}} int gl_update */
501
502 /* vim: set sw=2 sts=2 et fdm=marker : */