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>
31 #include <assert.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #include <yajl/yajl_parse.h>
39 #include "graph_list.h"
40 #include "common.h"
41 #include "data_provider.h"
42 #include "filesystem.h"
43 #include "graph.h"
44 #include "graph_config.h"
45 #include "graph_def.h"
46 #include "graph_ident.h"
47 #include "graph_instance.h"
48 #include "utils_cgi.h"
49 #include "utils_search.h"
51 #include <fcgiapp.h>
52 #include <fcgi_stdio.h>
54 /*
55 * Defines
56 */
57 #define UPDATE_INTERVAL 900
59 /*
60 * Global variables
61 */
62 static graph_config_t **gl_active = NULL;
63 static size_t gl_active_num = 0;
65 static graph_config_t **gl_staging = NULL;
66 static size_t gl_staging_num = 0;
68 /* Graphs created on-the-fly for files which don't match any existing graph
69 * definition. */
70 static graph_config_t **gl_dynamic = NULL;
71 static size_t gl_dynamic_num = 0;
73 static char **host_list = NULL;
74 static size_t host_list_len = 0;
76 static time_t gl_last_update = 0;
78 /*
79 * Private functions
80 */
81 static int gl_add_graph_internal (graph_config_t *cfg, /* {{{ */
82 graph_config_t ***gl_array, size_t *gl_array_num)
83 {
84 graph_config_t **tmp;
86 #define ARRAY_PTR (*gl_array)
87 #define ARRAY_SIZE (*gl_array_num)
89 if (cfg == NULL)
90 return (EINVAL);
92 tmp = realloc (ARRAY_PTR, sizeof (*ARRAY_PTR) * (ARRAY_SIZE + 1));
93 if (tmp == NULL)
94 return (ENOMEM);
95 ARRAY_PTR = tmp;
97 ARRAY_PTR[ARRAY_SIZE] = cfg;
98 ARRAY_SIZE++;
100 #undef ARRAY_SIZE
101 #undef ARRAY_PTR
103 return (0);
104 } /* }}} int gl_add_graph_internal */
106 static void gl_destroy (graph_config_t ***gl_array, /* {{{ */
107 size_t *gl_array_num)
108 {
109 size_t i;
111 if ((gl_array == NULL) || (gl_array_num == NULL))
112 return;
114 #define ARRAY_PTR (*gl_array)
115 #define ARRAY_SIZE (*gl_array_num)
117 for (i = 0; i < ARRAY_SIZE; i++)
118 {
119 graph_destroy (ARRAY_PTR[i]);
120 ARRAY_PTR[i] = NULL;
121 }
122 free (ARRAY_PTR);
123 ARRAY_PTR = NULL;
124 ARRAY_SIZE = 0;
126 #undef ARRAY_SIZE
127 #undef ARRAY_PTR
128 } /* }}} void gl_destroy */
130 static int gl_register_host (const char *host) /* {{{ */
131 {
132 char **tmp;
133 size_t i;
135 if (host == NULL)
136 return (EINVAL);
138 for (i = 0; i < host_list_len; i++)
139 if (strcmp (host_list[i], host) == 0)
140 return (0);
142 tmp = realloc (host_list, sizeof (*host_list) * (host_list_len + 1));
143 if (tmp == NULL)
144 return (ENOMEM);
145 host_list = tmp;
147 host_list[host_list_len] = strdup (host);
148 if (host_list[host_list_len] == NULL)
149 return (ENOMEM);
151 host_list_len++;
152 return (0);
153 } /* }}} int gl_register_host */
155 static int gl_clear_hosts (void) /* {{{ */
156 {
157 size_t i;
159 for (i = 0; i < host_list_len; i++)
160 free (host_list[i]);
161 free (host_list);
163 host_list = NULL;
164 host_list_len = 0;
166 return (0);
167 } /* }}} int gl_clear_hosts */
169 static int gl_compare_hosts (const void *v0, const void *v1) /* {{{ */
170 {
171 return (strcmp (*(char * const *) v0, *(char * const *) v1));
172 } /* }}} int gl_compare_hosts */
174 static int gl_register_file (const graph_ident_t *file, /* {{{ */
175 __attribute__((unused)) void *user_data)
176 {
177 graph_config_t *cfg;
178 int num_graphs = 0;
179 size_t i;
181 for (i = 0; i < gl_active_num; i++)
182 {
183 graph_config_t *cfg = gl_active[i];
184 int status;
186 if (!graph_ident_matches (cfg, file))
187 continue;
189 status = graph_add_file (cfg, file);
190 if (status != 0)
191 {
192 /* report error */;
193 }
194 else
195 {
196 num_graphs++;
197 }
198 }
200 if (num_graphs == 0)
201 {
202 cfg = graph_create (file);
203 gl_add_graph_internal (cfg, &gl_dynamic, &gl_dynamic_num);
204 graph_add_file (cfg, file);
205 }
207 gl_register_host (ident_get_host (file));
209 return (0);
210 } /* }}} int gl_register_file */
212 static int gl_register_ident (graph_ident_t *ident, /* {{{ */
213 __attribute__((unused)) void *user_data)
214 {
215 /* TODO: Check for duplicates if multiple data providers are used. */
217 return (gl_register_file (ident, user_data));
218 } /* }}} int gl_register_ident */
220 static const char *get_part_from_param (const char *prim_key, /* {{{ */
221 const char *sec_key)
222 {
223 const char *val;
225 val = param (prim_key);
226 if (val != NULL)
227 return (val);
229 return (param (sec_key));
230 } /* }}} const char *get_part_from_param */
232 static int gl_clear_instances (void) /* {{{ */
233 {
234 size_t i;
236 for (i = 0; i < gl_active_num; i++)
237 graph_clear_instances (gl_active[i]);
239 return (0);
240 } /* }}} int gl_clear_instances */
242 static void gl_dump_cb (void *ctx, /* {{{ */
243 const char *str, unsigned int len)
244 {
245 int fd = *((int *) ctx);
246 const char *buffer;
247 size_t buffer_size;
248 ssize_t status;
250 buffer = str;
251 buffer_size = (size_t) len;
252 while (buffer_size > 0)
253 {
254 status = write (fd, buffer, buffer_size);
255 if (status < 0)
256 {
257 fprintf (stderr, "write(2) failed with status %i\n", errno);
258 return;
259 }
261 buffer += status;
262 buffer_size -= status;
263 }
264 } /* }}} void gl_dump_cb */
266 static int gl_update_cache (void) /* {{{ */
267 {
268 int fd;
269 yajl_gen handler;
270 yajl_gen_config handler_config = { /* pretty = */ 1, /* indent = */ " " };
271 const char *cache_file = graph_config_get_cache_file ();
272 struct flock lock;
273 struct stat statbuf;
274 int status;
275 size_t i;
277 memset (&statbuf, 0, sizeof (statbuf));
278 status = stat (cache_file, &statbuf);
279 if (status == 0)
280 {
281 if (statbuf.st_mtime >= gl_last_update)
282 /* Not writing to cache because it's at least as new as our internal data */
283 return (0);
284 }
285 else
286 {
287 status = errno;
288 fprintf (stderr, "gl_update_cache: stat(2) failed with status %i\n",
289 status);
290 /* Continue writing the file if possible. */
291 }
293 fd = open (cache_file, O_WRONLY | O_TRUNC | O_CREAT,
294 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
295 if (fd < 0)
296 {
297 status = errno;
298 fprintf (stderr, "gl_update_cache: open(2) failed with status %i\n",
299 status);
300 return (status);
301 }
303 memset (&lock, 0, sizeof (lock));
304 lock.l_type = F_WRLCK;
305 lock.l_whence = SEEK_SET;
306 lock.l_start = 0;
307 lock.l_len = 0; /* lock everything */
309 while (42)
310 {
311 status = fcntl (fd, F_SETLKW, &lock);
312 if (status == 0)
313 break;
315 if (errno == EINTR)
316 continue;
318 fprintf (stderr, "gl_update_cache: fcntl(2) failed with status %i\n", errno);
319 close (fd);
320 return (errno);
321 }
323 handler = yajl_gen_alloc2 (gl_dump_cb, &handler_config,
324 /* alloc funcs = */ NULL, /* ctx = */ &fd);
325 if (handler == NULL)
326 {
327 close (fd);
328 return (-1);
329 }
331 fprintf (stderr, "gl_update_cache: Start writing data\n");
332 fflush (stderr);
334 yajl_gen_array_open (handler);
336 for (i = 0; i < gl_active_num; i++)
337 graph_to_json (gl_active[i], handler);
339 for (i = 0; i < gl_dynamic_num; i++)
340 graph_to_json (gl_dynamic[i], handler);
342 yajl_gen_array_close (handler);
344 yajl_gen_free (handler);
345 close (fd);
347 fprintf (stderr, "gl_update_cache: Finished writing data\n");
348 fflush (stderr);
350 return (0);
351 } /* }}} int gl_update_cache */
353 /*
354 * JSON parsing functions
355 */
356 #define CTX_MASK 0xff000000
357 #define CTX_GRAPH 0x01000000
358 #define CTX_GRAPH_SELECT 0x02000000
359 #define CTX_INST 0x03000000
360 #define CTX_INST_SELECT 0x04000000
361 #define CTX_INST_FILE 0x05000000
363 #define CTX_IDENT_MASK 0x00ff0000
364 #define CTX_IDENT_HOST 0x00010000
365 #define CTX_IDENT_PLUGIN 0x00020000
366 #define CTX_IDENT_PLUGIN_INSTANCE 0x00030000
367 #define CTX_IDENT_TYPE 0x00040000
368 #define CTX_IDENT_TYPE_INSTANCE 0x00050000
370 struct gl_json_context_s
371 {
372 uint32_t state;
374 graph_config_t *cfg;
375 graph_instance_t *inst;
376 graph_ident_t *ident;
378 _Bool dynamic_graph;
379 };
380 typedef struct gl_json_context_s gl_json_context_t;
382 static void set_state (gl_json_context_t *ctx, /* {{{ */
383 uint32_t new_state, uint32_t mask)
384 {
385 uint32_t old_state = ctx->state;
386 ctx->state = (old_state & ~mask) | (new_state & mask);
387 } /* }}} void set_state */
389 static int gl_json_string (void *user_data, /* {{{ */
390 const unsigned char *str,
391 unsigned int str_length)
392 {
393 gl_json_context_t *ctx = user_data;
394 char buffer[str_length + 1];
396 memcpy (buffer, str, str_length);
397 buffer[str_length] = 0;
399 if (((ctx->state & CTX_MASK) == CTX_GRAPH_SELECT)
400 || ((ctx->state & CTX_MASK) == CTX_INST_SELECT)
401 || ((ctx->state & CTX_MASK) == CTX_INST_FILE))
402 {
403 switch (ctx->state & CTX_IDENT_MASK)
404 {
405 case CTX_IDENT_HOST:
406 ident_set_host (ctx->ident, buffer);
407 break;
408 case CTX_IDENT_PLUGIN:
409 ident_set_plugin (ctx->ident, buffer);
410 break;
411 case CTX_IDENT_PLUGIN_INSTANCE:
412 ident_set_plugin_instance (ctx->ident, buffer);
413 break;
414 case CTX_IDENT_TYPE:
415 ident_set_type (ctx->ident, buffer);
416 break;
417 case CTX_IDENT_TYPE_INSTANCE:
418 ident_set_type_instance (ctx->ident, buffer);
419 break;
420 }
421 }
423 return (1);
424 } /* }}} int gl_json_string */
426 static int gl_json_start_map (void *user_data) /* {{{ */
427 {
428 gl_json_context_t *ctx = user_data;
430 if (((ctx->state & CTX_MASK) == CTX_GRAPH_SELECT)
431 || ((ctx->state & CTX_MASK) == CTX_INST_SELECT)
432 || ((ctx->state & CTX_MASK) == CTX_INST_FILE))
433 {
434 assert (ctx->ident == NULL);
435 ctx->ident = ident_create (ANY_TOKEN,
436 ANY_TOKEN, ANY_TOKEN,
437 ANY_TOKEN, ANY_TOKEN);
438 }
440 return (1);
441 } /* }}} int gl_json_start_map */
443 static int gl_json_end_map (void *user_data) /* {{{ */
444 {
445 gl_json_context_t *ctx = user_data;
447 if ((ctx->state & CTX_MASK) == CTX_GRAPH_SELECT)
448 {
449 size_t i;
451 /* ctx->ident should now hold the valid selector */
452 assert (ctx->cfg == NULL);
453 assert (ctx->inst == NULL);
454 assert (ctx->ident != NULL);
456 for (i = 0; i < gl_active_num; i++)
457 {
458 if (graph_compare (gl_active[i], ctx->ident) != 0)
459 continue;
461 ctx->cfg = gl_active[i];
462 ctx->dynamic_graph = 0;
463 break;
464 }
466 if (ctx->cfg == NULL)
467 {
468 ctx->cfg = graph_create (ctx->ident);
469 ctx->dynamic_graph = 1;
470 }
472 ident_destroy (ctx->ident);
473 ctx->ident = NULL;
475 set_state (ctx, CTX_GRAPH, CTX_MASK);
476 }
477 else if ((ctx->state & CTX_MASK) == CTX_INST_SELECT)
478 {
479 /* ctx->ident should now hold the valid selector */
480 assert (ctx->cfg != NULL);
481 assert (ctx->inst == NULL);
482 assert (ctx->ident != NULL);
484 ctx->inst = inst_create (ctx->cfg, ctx->ident);
485 ident_destroy (ctx->ident);
486 ctx->ident = NULL;
488 set_state (ctx, CTX_INST, CTX_MASK);
489 }
490 else if ((ctx->state & CTX_MASK) == CTX_INST_FILE)
491 {
492 /* ctx->ident should now hold the valid file */
493 assert (ctx->cfg != NULL);
494 assert (ctx->inst != NULL);
495 assert (ctx->ident != NULL);
497 inst_add_file (ctx->inst, ctx->ident);
498 ident_destroy (ctx->ident);
499 ctx->ident = NULL;
501 /* Don't reset the state here, files are in an array. */
502 }
503 else if ((ctx->state & CTX_MASK) == CTX_INST)
504 {
505 /* ctx->inst should now hold a complete instance */
506 assert (ctx->cfg != NULL);
507 assert (ctx->inst != NULL);
508 assert (ctx->ident == NULL);
510 graph_add_inst (ctx->cfg, ctx->inst);
511 /* don't destroy / free ctx->inst */
512 ctx->inst = NULL;
514 /* Don't reset the state here, instances are in an array. */
515 }
516 else if ((ctx->state & CTX_MASK) == CTX_GRAPH)
517 {
518 /* ctx->cfg should now hold a complete graph */
519 assert (ctx->cfg != NULL);
520 assert (ctx->inst == NULL);
521 assert (ctx->ident == NULL);
523 if (ctx->dynamic_graph)
524 gl_add_graph_internal (ctx->cfg, &gl_dynamic, &gl_dynamic_num);
525 /* else: already contained in gl_active */
526 ctx->cfg = NULL;
528 /* Don't reset the state here, graphs are in an array. */
529 }
531 return (1);
532 } /* }}} int gl_json_end_map */
534 static int gl_json_end_array (void *user_data) /* {{{ */
535 {
536 gl_json_context_t *ctx = user_data;
538 if ((ctx->state & CTX_MASK) == CTX_INST_FILE)
539 set_state (ctx, CTX_INST, CTX_MASK);
540 else if ((ctx->state & CTX_MASK) == CTX_INST)
541 set_state (ctx, CTX_GRAPH, CTX_MASK);
542 else if ((ctx->state & CTX_MASK) == CTX_GRAPH)
543 {
544 /* We're done */
545 }
547 return (1);
548 } /* }}} int gl_json_end_array */
550 static int gl_json_key (void *user_data, /* {{{ */
551 const unsigned char *str,
552 unsigned int str_length)
553 {
554 gl_json_context_t *ctx = user_data;
555 char buffer[str_length + 1];
557 memcpy (buffer, str, str_length);
558 buffer[str_length] = 0;
560 if ((ctx->state & CTX_MASK) == CTX_GRAPH)
561 {
562 if (strcasecmp ("select", buffer) == 0)
563 set_state (ctx, CTX_GRAPH_SELECT, CTX_MASK);
564 else if (strcasecmp ("instances", buffer) == 0)
565 set_state (ctx, CTX_INST, CTX_MASK);
566 }
567 else if ((ctx->state & CTX_MASK) == CTX_INST)
568 {
569 if (strcasecmp ("select", buffer) == 0)
570 set_state (ctx, CTX_INST_SELECT, CTX_MASK);
571 else if (strcasecmp ("files", buffer) == 0)
572 set_state (ctx, CTX_INST_FILE, CTX_MASK);
573 }
574 else if (((ctx->state & CTX_MASK) == CTX_GRAPH_SELECT)
575 || ((ctx->state & CTX_MASK) == CTX_INST_SELECT)
576 || ((ctx->state & CTX_MASK) == CTX_INST_FILE))
577 {
578 assert (ctx->ident != NULL);
580 if (strcasecmp ("host", buffer) == 0)
581 set_state (ctx, CTX_IDENT_HOST, CTX_IDENT_MASK);
582 else if (strcasecmp ("plugin", buffer) == 0)
583 set_state (ctx, CTX_IDENT_PLUGIN, CTX_IDENT_MASK);
584 else if (strcasecmp ("plugin_instance", buffer) == 0)
585 set_state (ctx, CTX_IDENT_PLUGIN_INSTANCE, CTX_IDENT_MASK);
586 else if (strcasecmp ("type", buffer) == 0)
587 set_state (ctx, CTX_IDENT_TYPE, CTX_IDENT_MASK);
588 else if (strcasecmp ("type_instance", buffer) == 0)
589 set_state (ctx, CTX_IDENT_TYPE_INSTANCE, CTX_IDENT_MASK);
590 }
592 return (1);
593 } /* }}} int gl_json_key */
595 yajl_callbacks gl_json_callbacks =
596 {
597 /* null = */ NULL,
598 /* boolean = */ NULL,
599 /* integer = */ NULL,
600 /* double = */ NULL,
601 /* number = */ NULL,
602 /* string = */ gl_json_string,
603 /* start_map = */ gl_json_start_map,
604 /* map_key = */ gl_json_key,
605 /* end_map = */ gl_json_end_map,
606 /* start_array = */ NULL,
607 /* end_array = */ gl_json_end_array
608 };
610 static int gl_read_cache (_Bool block) /* {{{ */
611 {
612 yajl_handle handle;
613 gl_json_context_t context;
614 yajl_parser_config handle_config = { /* comments = */ 0, /* check UTF-8 */ 0 };
616 int fd;
617 int cmd;
618 struct stat statbuf;
619 struct flock lock;
620 int status;
621 time_t now;
623 fd = open (graph_config_get_cache_file (), O_RDONLY);
624 if (fd < 0)
625 {
626 fprintf (stderr, "gl_read_cache: open(2) failed with status %i\n", errno);
627 return (errno);
628 }
630 if (block)
631 cmd = F_SETLKW;
632 else
633 cmd = F_SETLK;
635 memset (&lock, 0, sizeof (lock));
636 lock.l_type = F_RDLCK;
637 lock.l_whence = SEEK_SET;
638 lock.l_start = 0;
639 lock.l_len = 0; /* lock everything */
641 while (42)
642 {
643 status = fcntl (fd, cmd, &lock);
644 if (status == 0)
645 break;
647 if (!block && ((errno == EACCES) || (errno == EAGAIN)))
648 {
649 close (fd);
650 return (0);
651 }
653 if (errno == EINTR)
654 continue;
656 status = errno;
657 fprintf (stderr, "gl_read_cache: fcntl(2) failed with status %i\n",
658 status);
659 close (fd);
660 return (status);
661 }
663 fprintf (stderr, "gl_read_cache: Opening and locking "
664 "cache file successful\n");
666 memset (&statbuf, 0, sizeof (statbuf));
667 status = fstat (fd, &statbuf);
668 if (status != 0)
669 {
670 status = errno;
671 fprintf (stderr, "gl_read_cache: fstat(2) failed with status %i\n",
672 status);
673 close (fd);
674 return (status);
675 }
677 now = time (NULL);
679 if (block)
680 {
681 /* Read the file. No excuses. */
682 }
683 else if (statbuf.st_mtime <= gl_last_update)
684 {
685 /* Our current data is at least as new as the cache. Return. */
686 fprintf (stderr, "gl_read_cache: Not using cache because "
687 "the internal data is newer\n");
688 fflush (stderr);
689 close (fd);
690 return (0);
691 }
692 else if ((statbuf.st_mtime + UPDATE_INTERVAL) < now)
693 {
694 /* We'll scan the directory anyway, so there is no need to parse the cache
695 * here. */
696 fprintf (stderr, "gl_read_cache: Not using cache because it's too old\n");
697 fflush (stderr);
698 close (fd);
699 return (0);
700 }
702 memset (&context, 0, sizeof (context));
703 context.state = CTX_GRAPH;
704 context.cfg = NULL;
705 context.inst = NULL;
706 context.ident = NULL;
708 handle = yajl_alloc (&gl_json_callbacks,
709 &handle_config,
710 /* alloc funcs = */ NULL,
711 &context);
713 fprintf (stderr, "gl_read_cache: Start parsing data\n");
714 fflush (stderr);
716 while (42)
717 {
718 ssize_t rd_status;
719 char buffer[1024*1024];
721 rd_status = read (fd, buffer, sizeof (buffer));
722 if (rd_status < 0)
723 {
724 if ((errno == EINTR) || (errno == EAGAIN))
725 continue;
727 status = errno;
728 fprintf (stderr, "gl_read_cache: read(2) failed with status %i\n",
729 status);
730 close (fd);
731 return (status);
732 }
733 else if (rd_status == 0)
734 {
735 yajl_parse_complete (handle);
736 break;
737 }
738 else
739 {
740 yajl_parse (handle,
741 (unsigned char *) &buffer[0],
742 (unsigned int) rd_status);
743 }
744 }
746 yajl_free (handle);
748 gl_last_update = statbuf.st_mtime;
749 close (fd);
751 fprintf (stderr, "gl_read_cache: Finished parsing data\n");
752 fflush (stderr);
754 return (0);
755 } /* }}} int gl_read_cache */
757 /*
758 * Global functions
759 */
760 int gl_add_graph (graph_config_t *cfg) /* {{{ */
761 {
762 return (gl_add_graph_internal (cfg, &gl_staging, &gl_staging_num));
763 } /* }}} int gl_add_graph */
765 int gl_config_submit (void) /* {{{ */
766 {
767 graph_config_t **old;
768 size_t old_num;
770 old = gl_active;
771 old_num = gl_active_num;
773 gl_active = gl_staging;
774 gl_active_num = gl_staging_num;
776 gl_staging = NULL;
777 gl_staging_num = 0;
779 gl_destroy (&old, &old_num);
781 return (0);
782 } /* }}} int graph_config_submit */
784 int gl_graph_get_all (_Bool include_dynamic, /* {{{ */
785 graph_callback_t callback, void *user_data)
786 {
787 size_t i;
789 if (callback == NULL)
790 return (EINVAL);
792 gl_update (/* request served = */ 0);
794 for (i = 0; i < gl_active_num; i++)
795 {
796 int status;
798 status = (*callback) (gl_active[i], user_data);
799 if (status != 0)
800 return (status);
801 }
803 if (!include_dynamic)
804 return (0);
806 for (i = 0; i < gl_dynamic_num; i++)
807 {
808 int status;
810 status = (*callback) (gl_dynamic[i], user_data);
811 if (status != 0)
812 return (status);
813 }
815 return (0);
816 } /* }}} int gl_graph_get_all */
818 graph_config_t *gl_graph_get_selected (void) /* {{{ */
819 {
820 const char *host = get_part_from_param ("graph_host", "host");
821 const char *plugin = get_part_from_param ("graph_plugin", "plugin");
822 const char *plugin_instance = get_part_from_param ("graph_plugin_instance", "plugin_instance");
823 const char *type = get_part_from_param ("graph_type", "type");
824 const char *type_instance = get_part_from_param ("graph_type_instance", "type_instance");
825 graph_ident_t *ident;
826 size_t i;
828 if ((host == NULL)
829 || (plugin == NULL) || (plugin_instance == NULL)
830 || (type == NULL) || (type_instance == NULL))
831 return (NULL);
833 ident = ident_create (host, plugin, plugin_instance, type, type_instance);
835 gl_update (/* request served = */ 0);
837 for (i = 0; i < gl_active_num; i++)
838 {
839 if (graph_compare (gl_active[i], ident) != 0)
840 continue;
842 ident_destroy (ident);
843 return (gl_active[i]);
844 }
846 for (i = 0; i < gl_dynamic_num; i++)
847 {
848 if (graph_compare (gl_dynamic[i], ident) != 0)
849 continue;
851 ident_destroy (ident);
852 return (gl_dynamic[i]);
853 }
855 ident_destroy (ident);
856 return (NULL);
857 } /* }}} graph_config_t *gl_graph_get_selected */
859 /* gl_instance_get_all, gl_graph_instance_get_all {{{ */
860 struct gl_inst_callback_data /* {{{ */
861 {
862 graph_config_t *cfg;
863 graph_inst_callback_t callback;
864 void *user_data;
865 }; /* }}} struct gl_inst_callback_data */
867 static int gl_inst_callback_handler (graph_instance_t *inst, /* {{{ */
868 void *user_data)
869 {
870 struct gl_inst_callback_data *data = user_data;
872 return ((*data->callback) (data->cfg, inst, data->user_data));
873 } /* }}} int gl_inst_callback_handler */
875 int gl_graph_instance_get_all (graph_config_t *cfg, /* {{{ */
876 graph_inst_callback_t callback, void *user_data)
877 {
878 struct gl_inst_callback_data data =
879 {
880 cfg,
881 callback,
882 user_data
883 };
885 if ((cfg == NULL) || (callback == NULL))
886 return (EINVAL);
888 return (graph_inst_foreach (cfg, gl_inst_callback_handler, &data));
889 } /* }}} int gl_graph_instance_get_all */
891 int gl_instance_get_all (graph_inst_callback_t callback, /* {{{ */
892 void *user_data)
893 {
894 size_t i;
896 gl_update (/* request served = */ 0);
898 for (i = 0; i < gl_active_num; i++)
899 {
900 int status;
902 status = gl_graph_instance_get_all (gl_active[i], callback, user_data);
903 if (status != 0)
904 return (status);
905 }
907 for (i = 0; i < gl_dynamic_num; i++)
908 {
909 int status;
911 status = gl_graph_instance_get_all (gl_dynamic[i], callback, user_data);
912 if (status != 0)
913 return (status);
914 }
916 return (0);
917 } /* }}} int gl_instance_get_all */
918 /* }}} gl_instance_get_all, gl_graph_instance_get_all */
920 int gl_search (search_info_t *si, /* {{{ */
921 graph_inst_callback_t callback, void *user_data)
922 {
923 size_t i;
924 graph_ident_t *ident;
926 if ((si == NULL) || (callback == NULL))
927 return (EINVAL);
929 if (search_has_selector (si))
930 {
931 ident = search_to_ident (si);
932 if (ident == NULL)
933 {
934 fprintf (stderr, "gl_search: search_to_ident failed\n");
935 return (-1);
936 }
937 }
938 else
939 {
940 ident = NULL;
941 }
943 for (i = 0; i < gl_active_num; i++)
944 {
945 int status;
947 if ((ident != NULL) && !graph_ident_intersect (gl_active[i], ident))
948 continue;
950 status = graph_search_inst (gl_active[i], si,
951 /* callback = */ callback,
952 /* user data = */ user_data);
953 if (status != 0)
954 return (status);
955 }
957 for (i = 0; i < gl_dynamic_num; i++)
958 {
959 int status;
961 if ((ident != NULL) && !graph_ident_intersect (gl_dynamic[i], ident))
962 continue;
964 status = graph_search_inst (gl_dynamic[i], si,
965 /* callback = */ callback,
966 /* user data = */ user_data);
967 if (status != 0)
968 return (status);
969 }
971 return (0);
972 } /* }}} int gl_search */
974 int gl_search_string (const char *term, graph_inst_callback_t callback, /* {{{ */
975 void *user_data)
976 {
977 size_t i;
979 for (i = 0; i < gl_active_num; i++)
980 {
981 int status;
983 status = graph_search_inst_string (gl_active[i], term,
984 /* callback = */ callback,
985 /* user data = */ user_data);
986 if (status != 0)
987 return (status);
988 }
990 for (i = 0; i < gl_dynamic_num; i++)
991 {
992 int status;
994 status = graph_search_inst_string (gl_dynamic[i], term,
995 /* callback = */ callback,
996 /* user data = */ user_data);
997 if (status != 0)
998 return (status);
999 }
1001 return (0);
1002 } /* }}} int gl_search_string */
1004 int gl_search_field (graph_ident_field_t field, /* {{{ */
1005 const char *field_value,
1006 graph_inst_callback_t callback, void *user_data)
1007 {
1008 size_t i;
1010 if ((field_value == NULL) || (callback == NULL))
1011 return (EINVAL);
1013 for (i = 0; i < gl_active_num; i++)
1014 {
1015 int status;
1017 status = graph_inst_search_field (gl_active[i],
1018 field, field_value,
1019 /* callback = */ callback,
1020 /* user data = */ user_data);
1021 if (status != 0)
1022 return (status);
1023 }
1025 for (i = 0; i < gl_dynamic_num; i++)
1026 {
1027 int status;
1029 status = graph_inst_search_field (gl_dynamic[i],
1030 field, field_value,
1031 /* callback = */ callback,
1032 /* user data = */ user_data);
1033 if (status != 0)
1034 return (status);
1035 }
1037 return (0);
1038 } /* }}} int gl_search_field */
1040 int gl_foreach_host (int (*callback) (const char *host, void *user_data), /* {{{ */
1041 void *user_data)
1042 {
1043 int status;
1044 size_t i;
1046 for (i = 0; i < host_list_len; i++)
1047 {
1048 status = (*callback) (host_list[i], user_data);
1049 if (status != 0)
1050 return (status);
1051 }
1053 return (0);
1054 } /* }}} int gl_foreach_host */
1056 int gl_update (_Bool request_served) /* {{{ */
1057 {
1058 time_t now;
1059 int status;
1060 size_t i;
1062 if (!request_served && (gl_last_update > 0))
1063 return (0);
1065 now = time (NULL);
1067 if ((gl_last_update + UPDATE_INTERVAL) >= now)
1068 {
1069 /* Write data to cache if appropriate */
1070 if (request_served)
1071 gl_update_cache ();
1072 return (0);
1073 }
1075 /* Clear state */
1076 gl_clear_instances ();
1077 gl_clear_hosts ();
1078 gl_destroy (&gl_dynamic, &gl_dynamic_num);
1080 graph_read_config ();
1082 status = gl_read_cache (/* block = */ 1);
1083 /* We have *something* to work with. Even if it's outdated, just get on with
1084 * handling the request and take care of re-reading data later on. */
1085 if ((status == 0) && !request_served)
1086 return (0);
1088 if ((status != 0)
1089 || ((gl_last_update + UPDATE_INTERVAL) < now))
1090 {
1091 /* Clear state */
1092 gl_clear_instances ();
1093 gl_clear_hosts ();
1094 gl_destroy (&gl_dynamic, &gl_dynamic_num);
1096 data_provider_get_idents (gl_register_ident, /* user data = */ NULL);
1098 gl_last_update = now;
1099 }
1101 if (host_list_len > 0)
1102 qsort (host_list, host_list_len, sizeof (*host_list),
1103 gl_compare_hosts);
1105 for (i = 0; i < gl_active_num; i++)
1106 graph_sort_instances (gl_active[i]);
1108 if (request_served)
1109 gl_update_cache ();
1111 return (status);
1112 } /* }}} int gl_update */
1114 /* vim: set sw=2 sts=2 et fdm=marker : */