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"
40 #include "utils_search.h"
42 #include <fcgiapp.h>
43 #include <fcgi_stdio.h>
45 /*
46 * Defines
47 */
48 #define UPDATE_INTERVAL 900
50 /*
51 * Global variables
52 */
53 static graph_config_t **gl_active = NULL;
54 static size_t gl_active_num = 0;
56 static graph_config_t **gl_staging = NULL;
57 static size_t gl_staging_num = 0;
59 /* Graphs created on-the-fly for files which don't match any existing graph
60 * definition. */
61 static graph_config_t **gl_dynamic = NULL;
62 static size_t gl_dynamic_num = 0;
64 static char **host_list = NULL;
65 static size_t host_list_len = 0;
67 static time_t gl_last_update = 0;
69 /*
70 * Private functions
71 */
72 static int gl_add_graph_internal (graph_config_t *cfg, /* {{{ */
73 graph_config_t ***gl_array, size_t *gl_array_num)
74 {
75 graph_config_t **tmp;
77 #define ARRAY_PTR (*gl_array)
78 #define ARRAY_SIZE (*gl_array_num)
80 if (cfg == NULL)
81 return (EINVAL);
83 tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
84 if (tmp == NULL)
85 return (ENOMEM);
86 ARRAY_PTR = tmp;
88 ARRAY_PTR[ARRAY_SIZE] = cfg;
89 ARRAY_SIZE++;
91 #undef ARRAY_SIZE
92 #undef ARRAY_PTR
94 return (0);
95 } /* }}} int gl_add_graph_internal */
97 static void gl_destroy (graph_config_t ***gl_array, /* {{{ */
98 size_t *gl_array_num)
99 {
100 size_t i;
102 if ((gl_array == NULL) || (gl_array_num == NULL))
103 return;
105 #define ARRAY_PTR (*gl_array)
106 #define ARRAY_SIZE (*gl_array_num)
108 for (i = 0; i < ARRAY_SIZE; i++)
109 {
110 graph_destroy (ARRAY_PTR[i]);
111 ARRAY_PTR[i] = NULL;
112 }
113 free (ARRAY_PTR);
114 ARRAY_PTR = NULL;
115 ARRAY_SIZE = 0;
117 #undef ARRAY_SIZE
118 #undef ARRAY_PTR
119 } /* }}} void gl_destroy */
121 static int gl_register_host (const char *host) /* {{{ */
122 {
123 char **tmp;
124 size_t i;
126 if (host == NULL)
127 return (EINVAL);
129 for (i = 0; i < host_list_len; i++)
130 if (strcmp (host_list[i], host) == 0)
131 return (0);
133 tmp = realloc (host_list, sizeof (*host_list) * (host_list_len + 1));
134 if (tmp == NULL)
135 return (ENOMEM);
136 host_list = tmp;
138 host_list[host_list_len] = strdup (host);
139 if (host_list[host_list_len] == NULL)
140 return (ENOMEM);
142 host_list_len++;
143 return (0);
144 } /* }}} int gl_register_host */
146 static int gl_clear_hosts (void) /* {{{ */
147 {
148 size_t i;
150 for (i = 0; i < host_list_len; i++)
151 free (host_list[i]);
152 free (host_list);
154 host_list = NULL;
155 host_list_len = 0;
157 return (0);
158 } /* }}} int gl_clear_hosts */
160 static int gl_compare_hosts (const void *v0, const void *v1) /* {{{ */
161 {
162 return (strcmp (*(char * const *) v0, *(char * const *) v1));
163 } /* }}} int gl_compare_hosts */
165 static int gl_register_file (const graph_ident_t *file, /* {{{ */
166 __attribute__((unused)) void *user_data)
167 {
168 graph_config_t *cfg;
169 int num_graphs = 0;
170 size_t i;
172 for (i = 0; i < gl_active_num; i++)
173 {
174 graph_config_t *cfg = gl_active[i];
175 int status;
177 if (!graph_ident_matches (cfg, file))
178 continue;
180 status = graph_add_file (cfg, file);
181 if (status != 0)
182 {
183 /* report error */;
184 }
185 else
186 {
187 num_graphs++;
188 }
189 }
191 if (num_graphs == 0)
192 {
193 cfg = graph_create (file);
194 gl_add_graph_internal (cfg, &gl_dynamic, &gl_dynamic_num);
195 graph_add_file (cfg, file);
196 }
198 gl_register_host (ident_get_host (file));
200 return (0);
201 } /* }}} int gl_register_file */
203 static const char *get_part_from_param (const char *prim_key, /* {{{ */
204 const char *sec_key)
205 {
206 const char *val;
208 val = param (prim_key);
209 if (val != NULL)
210 return (val);
212 return (param (sec_key));
213 } /* }}} const char *get_part_from_param */
215 static int gl_clear_instances (void) /* {{{ */
216 {
217 size_t i;
219 for (i = 0; i < gl_active_num; i++)
220 graph_clear_instances (gl_active[i]);
222 return (0);
223 } /* }}} int gl_clear_instances */
225 static void gl_dump_cb (void *ctx, /* {{{ */
226 const char *str, unsigned int len)
227 {
228 FILE *fh = ctx;
230 /* FIXME: Has everything been written? */
231 fwrite ((void *) str, /* size = */ 1, /* nmemb = */ len, fh);
232 } /* }}} void gl_dump_cb */
234 static int gl_dump (void) /* {{{ */
235 {
236 FILE *fh;
237 yajl_gen handler;
238 yajl_gen_config handler_config = { /* pretty = */ 1, /* indent = */ " " };
239 size_t i;
241 /* FIXME: Lock the file */
242 fh = fopen ("/tmp/collection4.json", "w");
243 if (fh == NULL)
244 return (errno);
246 handler = yajl_gen_alloc2 (gl_dump_cb, &handler_config,
247 /* alloc funcs = */ NULL, /* ctx = */ fh);
248 if (handler == NULL)
249 {
250 fclose (fh);
251 return (-1);
252 }
254 yajl_gen_array_open (handler);
256 for (i = 0; i < gl_active_num; i++)
257 graph_to_json (gl_active[i], handler);
259 for (i = 0; i < gl_dynamic_num; i++)
260 graph_to_json (gl_dynamic[i], handler);
262 yajl_gen_array_close (handler);
264 yajl_gen_free (handler);
265 fclose (fh);
267 return (0);
268 } /* }}} int gl_dump */
270 /*
271 * Global functions
272 */
273 int gl_add_graph (graph_config_t *cfg) /* {{{ */
274 {
275 return (gl_add_graph_internal (cfg, &gl_staging, &gl_staging_num));
276 } /* }}} int gl_add_graph */
278 int gl_config_submit (void) /* {{{ */
279 {
280 graph_config_t **old;
281 size_t old_num;
283 old = gl_active;
284 old_num = gl_active_num;
286 gl_active = gl_staging;
287 gl_active_num = gl_staging_num;
289 gl_staging = NULL;
290 gl_staging_num = 0;
292 gl_destroy (&old, &old_num);
294 return (0);
295 } /* }}} int graph_config_submit */
297 int gl_graph_get_all (graph_callback_t callback, /* {{{ */
298 void *user_data)
299 {
300 size_t i;
302 if (callback == NULL)
303 return (EINVAL);
305 gl_update ();
307 for (i = 0; i < gl_active_num; i++)
308 {
309 int status;
311 status = (*callback) (gl_active[i], user_data);
312 if (status != 0)
313 return (status);
314 }
316 for (i = 0; i < gl_dynamic_num; i++)
317 {
318 int status;
320 status = (*callback) (gl_dynamic[i], user_data);
321 if (status != 0)
322 return (status);
323 }
325 return (0);
326 } /* }}} int gl_graph_get_all */
328 graph_config_t *gl_graph_get_selected (void) /* {{{ */
329 {
330 const char *host = get_part_from_param ("graph_host", "host");
331 const char *plugin = get_part_from_param ("graph_plugin", "plugin");
332 const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
333 const char *type = get_part_from_param ("graph_type", "type");
334 const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
335 graph_ident_t *ident;
336 size_t i;
338 if ((host == NULL)
339 || (plugin == NULL) || (plugin_instance == NULL)
340 || (type == NULL) || (type_instance == NULL))
341 return (NULL);
343 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
345 gl_update ();
347 for (i = 0; i < gl_active_num; i++)
348 {
349 if (graph_compare (gl_active[i], ident) != 0)
350 continue;
352 ident_destroy (ident);
353 return (gl_active[i]);
354 }
356 for (i = 0; i < gl_dynamic_num; i++)
357 {
358 if (graph_compare (gl_dynamic[i], ident) != 0)
359 continue;
361 ident_destroy (ident);
362 return (gl_dynamic[i]);
363 }
365 ident_destroy (ident);
366 return (NULL);
367 } /* }}} graph_config_t *gl_graph_get_selected */
369 /* gl_instance_get_all, gl_graph_instance_get_all {{{ */
370 struct gl_inst_callback_data /* {{{ */
371 {
372 graph_config_t *cfg;
373 graph_inst_callback_t callback;
374 void *user_data;
375 }; /* }}} struct gl_inst_callback_data */
377 static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
378 void *user_data)
379 {
380 struct gl_inst_callback_data *data = user_data;
382 return ((*data->callback) (data->cfg, inst, data->user_data));
383 } /* }}} int gl_inst_callback_handler */
385 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
386 graph_inst_callback_t callback, void *user_data)
387 {
388 struct gl_inst_callback_data data =
389 {
390 cfg,
391 callback,
392 user_data
393 };
395 if ((cfg == NULL) || (callback == NULL))
396 return (EINVAL);
398 return (graph_inst_foreach (cfg, gl_inst_callback_handler, &data));
399 } /* }}} int gl_graph_instance_get_all */
401 int gl_instance_get_all (graph_inst_callback_t callback, /* {{{ */
402 void *user_data)
403 {
404 size_t i;
406 gl_update ();
408 for (i = 0; i < gl_active_num; i++)
409 {
410 int status;
412 status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
413 if (status != 0)
414 return (status);
415 }
417 for (i = 0; i < gl_dynamic_num; i++)
418 {
419 int status;
421 status = gl_graph_instance_get_all (gl_dynamic[i], callback, user_data);
422 if (status != 0)
423 return (status);
424 }
426 return (0);
427 } /* }}} int gl_instance_get_all */
428 /* }}} gl_instance_get_all, gl_graph_instance_get_all */
430 int gl_search (search_info_t *si, /* {{{ */
431 graph_inst_callback_t callback, void *user_data)
432 {
433 size_t i;
434 graph_ident_t *ident;
436 if ((si == NULL) || (callback == NULL))
437 return (EINVAL);
439 if (search_has_selector (si))
440 {
441 ident = search_to_ident (si);
442 if (ident == NULL)
443 {
444 fprintf (stderr, "gl_search: search_to_ident failed\n");
445 return (-1);
446 }
447 }
448 else
449 {
450 ident = NULL;
451 }
453 for (i = 0; i < gl_active_num; i++)
454 {
455 int status;
457 if ((ident != NULL) && !graph_ident_intersect (gl_active[i], ident))
458 continue;
460 status = graph_search_inst (gl_active[i], si,
461 /* callback = */ callback,
462 /* user data = */ user_data);
463 if (status != 0)
464 return (status);
465 }
467 for (i = 0; i < gl_dynamic_num; i++)
468 {
469 int status;
471 if ((ident != NULL) && !graph_ident_intersect (gl_dynamic[i], ident))
472 continue;
474 status = graph_search_inst (gl_dynamic[i], si,
475 /* callback = */ callback,
476 /* user data = */ user_data);
477 if (status != 0)
478 return (status);
479 }
481 return (0);
482 } /* }}} int gl_search */
484 int gl_search_string (const char *term, graph_inst_callback_t callback, /* {{{ */
485 void *user_data)
486 {
487 size_t i;
489 for (i = 0; i < gl_active_num; i++)
490 {
491 int status;
493 status = graph_search_inst_string (gl_active[i], term,
494 /* callback = */ callback,
495 /* user data = */ user_data);
496 if (status != 0)
497 return (status);
498 }
500 for (i = 0; i < gl_dynamic_num; i++)
501 {
502 int status;
504 status = graph_search_inst_string (gl_dynamic[i], term,
505 /* callback = */ callback,
506 /* user data = */ user_data);
507 if (status != 0)
508 return (status);
509 }
511 return (0);
512 } /* }}} int gl_search_string */
514 int gl_search_field (graph_ident_field_t field, /* {{{ */
515 const char *field_value,
516 graph_inst_callback_t callback, void *user_data)
517 {
518 size_t i;
520 if ((field_value == NULL) || (callback == NULL))
521 return (EINVAL);
523 for (i = 0; i < gl_active_num; i++)
524 {
525 int status;
527 status = graph_inst_search_field (gl_active[i],
528 field, field_value,
529 /* callback = */ callback,
530 /* user data = */ user_data);
531 if (status != 0)
532 return (status);
533 }
535 for (i = 0; i < gl_dynamic_num; i++)
536 {
537 int status;
539 status = graph_inst_search_field (gl_dynamic[i],
540 field, field_value,
541 /* callback = */ callback,
542 /* user data = */ user_data);
543 if (status != 0)
544 return (status);
545 }
547 return (0);
548 } /* }}} int gl_search_field */
550 int gl_foreach_host (int (*callback) (const char *host, void *user_data), /* {{{ */
551 void *user_data)
552 {
553 int status;
554 size_t i;
556 for (i = 0; i < host_list_len; i++)
557 {
558 status = (*callback) (host_list[i], user_data);
559 if (status != 0)
560 return (status);
561 }
563 return (0);
564 } /* }}} int gl_foreach_host */
566 int gl_update (void) /* {{{ */
567 {
568 time_t now;
569 int status;
570 size_t i;
572 /*
573 printf ("Content-Type: text/plain\n\n");
574 */
576 now = time (NULL);
578 if ((gl_last_update + UPDATE_INTERVAL) >= now)
579 return (0);
581 /* Clear state */
582 gl_clear_instances ();
583 gl_clear_hosts ();
584 gl_destroy (&gl_dynamic, &gl_dynamic_num);
586 graph_read_config ();
588 status = fs_scan (/* callback = */ gl_register_file, /* user data = */ NULL);
590 if (host_list_len > 0)
591 qsort (host_list, host_list_len, sizeof (*host_list),
592 gl_compare_hosts);
594 gl_last_update = now;
596 for (i = 0; i < gl_active_num; i++)
597 graph_sort_instances (gl_active[i]);
599 gl_dump ();
601 return (status);
602 } /* }}} int gl_update */
604 /* vim: set sw=2 sts=2 et fdm=marker : */