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 **/
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>
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"
41 #include <fcgiapp.h>
42 #include <fcgi_stdio.h>
44 /*
45 * Defines
46 */
47 #define UPDATE_INTERVAL 900
49 /*
50 * Global variables
51 */
52 static graph_config_t **gl_active = NULL;
53 static size_t gl_active_num = 0;
55 static graph_config_t **gl_staging = NULL;
56 static size_t gl_staging_num = 0;
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;
63 static char **host_list = NULL;
64 static size_t host_list_len = 0;
66 static time_t gl_last_update = 0;
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;
76 #define ARRAY_PTR (*gl_array)
77 #define ARRAY_SIZE (*gl_array_num)
79 if (cfg == NULL)
80 return (EINVAL);
82 tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
83 if (tmp == NULL)
84 return (ENOMEM);
85 ARRAY_PTR = tmp;
87 ARRAY_PTR[ARRAY_SIZE] = cfg;
88 ARRAY_SIZE++;
90 #undef ARRAY_SIZE
91 #undef ARRAY_PTR
93 return (0);
94 } /* }}} int gl_add_graph_internal */
96 static void gl_destroy (graph_config_t ***gl_array, /* {{{ */
97 size_t *gl_array_num)
98 {
99 size_t i;
101 if ((gl_array == NULL) || (gl_array_num == NULL))
102 return;
104 #define ARRAY_PTR (*gl_array)
105 #define ARRAY_SIZE (*gl_array_num)
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;
116 #undef ARRAY_SIZE
117 #undef ARRAY_PTR
118 } /* }}} void gl_destroy */
120 static int gl_register_host (const char *host) /* {{{ */
121 {
122 char **tmp;
123 size_t i;
125 if (host == NULL)
126 return (EINVAL);
128 for (i = 0; i < host_list_len; i++)
129 if (strcmp (host_list[i], host) == 0)
130 return (0);
132 tmp = realloc (host_list, sizeof (*host_list) * (host_list_len + 1));
133 if (tmp == NULL)
134 return (ENOMEM);
135 host_list = tmp;
137 host_list[host_list_len] = strdup (host);
138 if (host_list[host_list_len] == NULL)
139 return (ENOMEM);
141 host_list_len++;
142 return (0);
143 } /* }}} int gl_register_host */
145 static int gl_clear_hosts (void) /* {{{ */
146 {
147 size_t i;
149 for (i = 0; i < host_list_len; i++)
150 free (host_list[i]);
151 free (host_list);
153 host_list = NULL;
154 host_list_len = 0;
156 return (0);
157 } /* }}} int gl_clear_hosts */
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 */
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;
171 for (i = 0; i < gl_active_num; i++)
172 {
173 graph_config_t *cfg = gl_active[i];
174 int status;
176 if (!graph_matches_ident (cfg, file))
177 continue;
179 status = graph_add_file (cfg, file);
180 if (status != 0)
181 {
182 /* report error */;
183 }
184 else
185 {
186 num_graphs++;
187 }
188 }
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 }
197 gl_register_host (ident_get_host (file));
199 return (0);
200 } /* }}} int gl_register_file */
202 static const char *get_part_from_param (const char *prim_key, /* {{{ */
203 const char *sec_key)
204 {
205 const char *val;
207 val = param (prim_key);
208 if (val != NULL)
209 return (val);
211 return (param (sec_key));
212 } /* }}} const char *get_part_from_param */
214 static int gl_clear_instances (void) /* {{{ */
215 {
216 size_t i;
218 for (i = 0; i < gl_active_num; i++)
219 graph_clear_instances (gl_active[i]);
221 return (0);
222 } /* }}} int gl_clear_instances */
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 */
232 int gl_config_submit (void) /* {{{ */
233 {
234 graph_config_t **old;
235 size_t old_num;
237 old = gl_active;
238 old_num = gl_active_num;
240 gl_active = gl_staging;
241 gl_active_num = gl_staging_num;
243 gl_staging = NULL;
244 gl_staging_num = 0;
246 gl_destroy (&old, &old_num);
248 return (0);
249 } /* }}} int graph_config_submit */
251 int gl_graph_get_all (graph_callback_t callback, /* {{{ */
252 void *user_data)
253 {
254 size_t i;
256 if (callback == NULL)
257 return (EINVAL);
259 gl_update ();
261 for (i = 0; i < gl_active_num; i++)
262 {
263 int status;
265 status = (*callback) (gl_active[i], user_data);
266 if (status != 0)
267 return (status);
268 }
270 for (i = 0; i < gl_dynamic_num; i++)
271 {
272 int status;
274 status = (*callback) (gl_dynamic[i], user_data);
275 if (status != 0)
276 return (status);
277 }
279 return (0);
280 } /* }}} int gl_graph_get_all */
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;
292 if ((host == NULL)
293 || (plugin == NULL) || (plugin_instance == NULL)
294 || (type == NULL) || (type_instance == NULL))
295 return (NULL);
297 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
299 gl_update ();
301 for (i = 0; i < gl_active_num; i++)
302 {
303 if (graph_compare (gl_active[i], ident) != 0)
304 continue;
306 ident_destroy (ident);
307 return (gl_active[i]);
308 }
310 for (i = 0; i < gl_dynamic_num; i++)
311 {
312 if (graph_compare (gl_dynamic[i], ident) != 0)
313 continue;
315 ident_destroy (ident);
316 return (gl_dynamic[i]);
317 }
319 ident_destroy (ident);
320 return (NULL);
321 } /* }}} graph_config_t *gl_graph_get_selected */
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 */
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;
336 return ((*data->callback) (data->cfg, inst, data->user_data));
337 } /* }}} int gl_inst_callback_handler */
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 };
349 if ((cfg == NULL) || (callback == NULL))
350 return (EINVAL);
352 return (graph_inst_foreach (cfg, gl_inst_callback_handler, &data));
353 } /* }}} int gl_graph_instance_get_all */
355 int gl_instance_get_all (graph_inst_callback_t callback, /* {{{ */
356 void *user_data)
357 {
358 size_t i;
360 gl_update ();
362 for (i = 0; i < gl_active_num; i++)
363 {
364 int status;
366 status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
367 if (status != 0)
368 return (status);
369 }
371 for (i = 0; i < gl_dynamic_num; i++)
372 {
373 int status;
375 status = gl_graph_instance_get_all (gl_dynamic[i], callback, user_data);
376 if (status != 0)
377 return (status);
378 }
380 return (0);
381 } /* }}} int gl_instance_get_all */
382 /* }}} gl_instance_get_all, gl_graph_instance_get_all */
384 int gl_search (const char *term, graph_inst_callback_t callback, /* {{{ */
385 void *user_data)
386 {
387 size_t i;
389 for (i = 0; i < gl_active_num; i++)
390 {
391 int status;
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 }
400 for (i = 0; i < gl_dynamic_num; i++)
401 {
402 int status;
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 }
411 return (0);
412 } /* }}} int gl_search */
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;
420 if ((field_value == NULL) || (callback == NULL))
421 return (EINVAL);
423 for (i = 0; i < gl_active_num; i++)
424 {
425 int status;
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 }
435 for (i = 0; i < gl_dynamic_num; i++)
436 {
437 int status;
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 }
447 return (0);
448 } /* }}} int gl_search_field */
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;
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 }
463 return (0);
464 } /* }}} int gl_foreach_host */
466 int gl_update (void) /* {{{ */
467 {
468 time_t now;
469 int status;
471 /*
472 printf ("Content-Type: text/plain\n\n");
473 */
475 now = time (NULL);
477 if ((gl_last_update + UPDATE_INTERVAL) >= now)
478 return (0);
480 /* Clear state */
481 gl_clear_instances ();
482 gl_clear_hosts ();
483 gl_destroy (&gl_dynamic, &gl_dynamic_num);
485 graph_read_config ();
487 status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL);
489 if (host_list_len > 0)
490 qsort (host_list, host_list_len, sizeof (*host_list),
491 gl_compare_hosts);
493 gl_last_update = now;
495 return (status);
496 } /* }}} int gl_update */
498 /* vim: set sw=2 sts=2 et fdm=marker : */