1 /**
2 * collection4 - graph_ident.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 <unistd.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <errno.h>
30 #include <limits.h> /* PATH_MAX */
31 #include <sys/types.h>
32 #include <sys/stat.h>
34 #include "graph_ident.h"
35 #include "common.h"
36 #include "data_provider.h"
37 #include "filesystem.h"
38 #include "utils_cgi.h"
40 #include <fcgiapp.h>
41 #include <fcgi_stdio.h>
43 /*
44 * Data types
45 */
46 struct graph_ident_s /* {{{ */
47 {
48 char *host;
49 char *plugin;
50 char *plugin_instance;
51 char *type;
52 char *type_instance;
53 }; /* }}} struct graph_ident_s */
55 /*
56 * Private functions
57 */
58 static char *part_copy_with_selector (const char *selector, /* {{{ */
59 const char *part, unsigned int flags)
60 {
61 if ((selector == NULL) || (part == NULL))
62 return (NULL);
64 if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
65 return (NULL);
67 if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
68 return (NULL);
70 /* Replace the ANY and ALL flags if requested and if the selecter actually
71 * *is* that flag. */
72 if (IS_ANY (selector))
73 {
74 if (flags & IDENT_FLAG_REPLACE_ANY)
75 return (strdup (part));
76 else
77 return (strdup (selector));
78 }
80 if (IS_ALL (selector))
81 {
82 if (flags & IDENT_FLAG_REPLACE_ALL)
83 return (strdup (part));
84 else
85 return (strdup (selector));
86 }
88 if (strcmp (selector, part) != 0)
89 return (NULL);
91 /* Otherwise (no replacement), return a copy of the selector. */
92 return (strdup (selector));
93 } /* }}} char *part_copy_with_selector */
95 static _Bool part_matches (const char *selector, /* {{{ */
96 const char *part)
97 {
98 #if C4_DEBUG
99 if ((selector == NULL) && (part == NULL))
100 return (1);
101 #endif
103 if (selector == NULL) /* && (part != NULL) */
104 return (0);
106 if (IS_ANY(selector) || IS_ALL(selector))
107 return (1);
109 if (part == NULL) /* && (selector != NULL) */
110 return (0);
112 if (strcmp (selector, part) == 0)
113 return (1);
115 return (0);
116 } /* }}} _Bool part_matches */
118 /*
119 * Public functions
120 */
121 graph_ident_t *ident_create (const char *host, /* {{{ */
122 const char *plugin, const char *plugin_instance,
123 const char *type, const char *type_instance)
124 {
125 graph_ident_t *ret;
127 if ((host == NULL)
128 || (plugin == NULL) || (plugin_instance == NULL)
129 || (type == NULL) || (type_instance == NULL))
130 return (NULL);
132 ret = malloc (sizeof (*ret));
133 if (ret == NULL)
134 return (NULL);
135 memset (ret, 0, sizeof (*ret));
137 ret->host = NULL;
138 ret->host = NULL;
139 ret->plugin = NULL;
140 ret->plugin_instance = NULL;
141 ret->type = NULL;
142 ret->type_instance = NULL;
144 #define COPY_PART(p) do { \
145 ret->p = strdup (p); \
146 if (ret->p == NULL) \
147 { \
148 free (ret->host); \
149 free (ret->plugin); \
150 free (ret->plugin_instance); \
151 free (ret->type); \
152 free (ret->type_instance); \
153 free (ret); \
154 return (NULL); \
155 } \
156 } while (0)
158 COPY_PART(host);
159 COPY_PART(plugin);
160 COPY_PART(plugin_instance);
161 COPY_PART(type);
162 COPY_PART(type_instance);
164 #undef COPY_PART
166 return (ret);
167 } /* }}} graph_ident_t *ident_create */
169 graph_ident_t *ident_clone (const graph_ident_t *ident) /* {{{ */
170 {
171 return (ident_create (ident->host,
172 ident->plugin, ident->plugin_instance,
173 ident->type, ident->type_instance));
174 } /* }}} graph_ident_t *ident_clone */
176 graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector, /* {{{ */
177 const graph_ident_t *ident, unsigned int flags)
178 {
179 graph_ident_t *ret;
181 if ((selector == NULL) || (ident == NULL))
182 return (NULL);
184 ret = malloc (sizeof (*ret));
185 if (ret == NULL)
186 return (NULL);
187 memset (ret, 0, sizeof (*ret));
188 ret->host = NULL;
189 ret->plugin = NULL;
190 ret->plugin_instance = NULL;
191 ret->type = NULL;
192 ret->type_instance = NULL;
194 #define COPY_PART(p) do { \
195 ret->p = part_copy_with_selector (selector->p, ident->p, flags); \
196 if (ret->p == NULL) \
197 { \
198 free (ret->host); \
199 free (ret->plugin); \
200 free (ret->plugin_instance); \
201 free (ret->type); \
202 free (ret->type_instance); \
203 return (NULL); \
204 } \
205 } while (0)
207 COPY_PART (host);
208 COPY_PART (plugin);
209 COPY_PART (plugin_instance);
210 COPY_PART (type);
211 COPY_PART (type_instance);
213 #undef COPY_PART
215 return (ret);
216 } /* }}} graph_ident_t *ident_copy_with_selector */
218 void ident_destroy (graph_ident_t *ident) /* {{{ */
219 {
220 if (ident == NULL)
221 return;
223 free (ident->host);
224 free (ident->plugin);
225 free (ident->plugin_instance);
226 free (ident->type);
227 free (ident->type_instance);
229 free (ident);
230 } /* }}} void ident_destroy */
232 /* ident_get_* methods {{{ */
233 const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
234 {
235 if (ident == NULL)
236 return (NULL);
238 return (ident->host);
239 } /* }}} char *ident_get_host */
241 const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
242 {
243 if (ident == NULL)
244 return (NULL);
246 return (ident->plugin);
247 } /* }}} char *ident_get_plugin */
249 const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
250 {
251 if (ident == NULL)
252 return (NULL);
254 return (ident->plugin_instance);
255 } /* }}} char *ident_get_plugin_instance */
257 const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
258 {
259 if (ident == NULL)
260 return (NULL);
262 return (ident->type);
263 } /* }}} char *ident_get_type */
265 const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
266 {
267 if (ident == NULL)
268 return (NULL);
270 return (ident->type_instance);
271 } /* }}} char *ident_get_type_instance */
273 const char *ident_get_field (const graph_ident_t *ident, /* {{{ */
274 graph_ident_field_t field)
275 {
276 if ((ident == NULL) || (field >= _GIF_LAST))
277 return (NULL);
279 if (field == GIF_HOST)
280 return (ident->host);
281 else if (field == GIF_PLUGIN)
282 return (ident->plugin);
283 else if (field == GIF_PLUGIN_INSTANCE)
284 return (ident->plugin_instance);
285 else if (field == GIF_TYPE)
286 return (ident->type);
287 else if (field == GIF_TYPE_INSTANCE)
288 return (ident->type_instance);
289 else
290 return (NULL); /* never reached */
291 } /* }}} const char *ident_get_field */
292 /* }}} ident_get_* methods */
294 /* ident_set_* methods {{{ */
295 int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
296 {
297 char *tmp;
299 if ((ident == NULL) || (host == NULL))
300 return (EINVAL);
302 tmp = strdup (host);
303 if (tmp == NULL)
304 return (ENOMEM);
306 free (ident->host);
307 ident->host = tmp;
309 return (0);
310 } /* }}} int ident_set_host */
312 int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
313 {
314 char *tmp;
316 if ((ident == NULL) || (plugin == NULL))
317 return (EINVAL);
319 tmp = strdup (plugin);
320 if (tmp == NULL)
321 return (ENOMEM);
323 free (ident->plugin);
324 ident->plugin = tmp;
326 return (0);
327 } /* }}} int ident_set_plugin */
329 int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
330 {
331 char *tmp;
333 if ((ident == NULL) || (plugin_instance == NULL))
334 return (EINVAL);
336 tmp = strdup (plugin_instance);
337 if (tmp == NULL)
338 return (ENOMEM);
340 free (ident->plugin_instance);
341 ident->plugin_instance = tmp;
343 return (0);
344 } /* }}} int ident_set_plugin_instance */
346 int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
347 {
348 char *tmp;
350 if ((ident == NULL) || (type == NULL))
351 return (EINVAL);
353 tmp = strdup (type);
354 if (tmp == NULL)
355 return (ENOMEM);
357 free (ident->type);
358 ident->type = tmp;
360 return (0);
361 } /* }}} int ident_set_type */
363 int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
364 {
365 char *tmp;
367 if ((ident == NULL) || (type_instance == NULL))
368 return (EINVAL);
370 tmp = strdup (type_instance);
371 if (tmp == NULL)
372 return (ENOMEM);
374 free (ident->type_instance);
375 ident->type_instance = tmp;
377 return (0);
378 } /* }}} int ident_set_type_instance */
380 /* }}} ident_set_* methods */
382 int ident_compare (const graph_ident_t *i0, /* {{{ */
383 const graph_ident_t *i1)
384 {
385 int status;
387 #define COMPARE_PART(p) do { \
388 status = strcmp (i0->p, i1->p); \
389 if (status != 0) \
390 return (status); \
391 } while (0)
393 COMPARE_PART (host);
394 COMPARE_PART (plugin);
395 COMPARE_PART (plugin_instance);
396 COMPARE_PART (type);
397 COMPARE_PART (type_instance);
399 #undef COMPARE_PART
401 return (0);
402 } /* }}} int ident_compare */
404 _Bool ident_matches (const graph_ident_t *selector, /* {{{ */
405 const graph_ident_t *ident)
406 {
407 #if C4_DEBUG
408 if ((selector == NULL) || (ident == NULL))
409 return (0);
410 #endif
412 if (!part_matches (selector->host, ident->host))
413 return (0);
415 if (!part_matches (selector->plugin, ident->plugin))
416 return (0);
418 if (!part_matches (selector->plugin_instance, ident->plugin_instance))
419 return (0);
421 if (!part_matches (selector->type, ident->type))
422 return (0);
424 if (!part_matches (selector->type_instance, ident->type_instance))
425 return (0);
427 return (1);
428 } /* }}} _Bool ident_matches */
430 _Bool ident_intersect (const graph_ident_t *s0, /* {{{ */
431 const graph_ident_t *s1)
432 {
433 #define INTERSECT_PART(p) do { \
434 if (!IS_ANY (s0->p) && !IS_ALL (s0->p) \
435 && !IS_ANY (s1->p) && !IS_ALL (s1->p) \
436 && (strcmp (s0->p, s1->p) != 0)) \
437 return (0); \
438 } while (0)
440 INTERSECT_PART (host);
441 INTERSECT_PART (plugin);
442 INTERSECT_PART (plugin_instance);
443 INTERSECT_PART (type);
444 INTERSECT_PART (type_instance);
446 #undef INTERSECT_PART
448 return (1);
449 } /* }}} _Bool ident_intersect */
451 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
452 {
453 char buffer[PATH_MAX];
455 buffer[0] = 0;
457 strlcat (buffer, ident->host, sizeof (buffer));
458 strlcat (buffer, "/", sizeof (buffer));
459 strlcat (buffer, ident->plugin, sizeof (buffer));
460 if (ident->plugin_instance[0] != 0)
461 {
462 strlcat (buffer, "-", sizeof (buffer));
463 strlcat (buffer, ident->plugin_instance, sizeof (buffer));
464 }
465 strlcat (buffer, "/", sizeof (buffer));
466 strlcat (buffer, ident->type, sizeof (buffer));
467 if (ident->type_instance[0] != 0)
468 {
469 strlcat (buffer, "-", sizeof (buffer));
470 strlcat (buffer, ident->type_instance, sizeof (buffer));
471 }
473 return (strdup (buffer));
474 } /* }}} char *ident_to_string */
476 char *ident_to_file (const graph_ident_t *ident) /* {{{ */
477 {
478 char buffer[PATH_MAX];
480 buffer[0] = 0;
482 strlcat (buffer, DATA_DIR, sizeof (buffer));
483 strlcat (buffer, "/", sizeof (buffer));
485 strlcat (buffer, ident->host, sizeof (buffer));
486 strlcat (buffer, "/", sizeof (buffer));
487 strlcat (buffer, ident->plugin, sizeof (buffer));
488 if (ident->plugin_instance[0] != 0)
489 {
490 strlcat (buffer, "-", sizeof (buffer));
491 strlcat (buffer, ident->plugin_instance, sizeof (buffer));
492 }
493 strlcat (buffer, "/", sizeof (buffer));
494 strlcat (buffer, ident->type, sizeof (buffer));
495 if (ident->type_instance[0] != 0)
496 {
497 strlcat (buffer, "-", sizeof (buffer));
498 strlcat (buffer, ident->type_instance, sizeof (buffer));
499 }
501 strlcat (buffer, ".rrd", sizeof (buffer));
503 return (strdup (buffer));
504 } /* }}} char *ident_to_file */
506 int ident_to_json (const graph_ident_t *ident, /* {{{ */
507 yajl_gen handler)
508 {
509 yajl_gen_status status;
511 if ((ident == NULL) || (handler == NULL))
512 return (EINVAL);
514 #define ADD_STRING(str) do { \
515 status = yajl_gen_string (handler, \
516 (unsigned char *) (str), \
517 (unsigned int) strlen (str)); \
518 if (status != yajl_gen_status_ok) \
519 return ((int) status); \
520 } while (0)
522 yajl_gen_map_open (handler);
523 ADD_STRING ("host");
524 ADD_STRING (ident->host);
525 ADD_STRING ("plugin");
526 ADD_STRING (ident->plugin);
527 ADD_STRING ("plugin_instance");
528 ADD_STRING (ident->plugin_instance);
529 ADD_STRING ("type");
530 ADD_STRING (ident->type);
531 ADD_STRING ("type_instance");
532 ADD_STRING (ident->type_instance);
533 yajl_gen_map_close (handler);
535 #undef ADD_FIELD
537 return (0);
538 } /* }}} char *ident_to_json */
540 /* {{{ ident_data_to_json */
541 struct ident_data_to_json__data_s
542 {
543 dp_time_t begin;
544 dp_time_t end;
545 yajl_gen handler;
546 };
547 typedef struct ident_data_to_json__data_s ident_data_to_json__data_t;
549 #define yajl_gen_string_cast(h,s,l) \
550 yajl_gen_string (h, (unsigned char *) s, (unsigned int) l)
552 static int ident_data_to_json__get_ident_data (
553 __attribute__((unused)) graph_ident_t *ident, /* {{{ */
554 __attribute__((unused)) const char *ds_name,
555 const dp_data_point_t *dp, size_t dp_num,
556 void *user_data)
557 {
558 ident_data_to_json__data_t *data = user_data;
559 size_t i;
561 yajl_gen_map_open (data->handler);
563 for (i = 0; i < dp_num; i++)
564 {
565 yajl_gen_map_open (data->handler);
566 yajl_gen_integer (data->handler, (long) dp[i].time.tv_sec);
567 yajl_gen_double (data->handler, dp[i].value);
568 yajl_gen_map_close (data->handler);
569 }
571 yajl_gen_map_close (data->handler);
573 return (0);
574 } /* }}} int ident_data_to_json__get_ident_data */
576 /* Called for each DS name */
577 static int ident_data_to_json__get_ds_name (const graph_ident_t *ident, /* {{{ */
578 const char *ds_name, void *user_data)
579 {
580 ident_data_to_json__data_t *data = user_data;
581 int status;
583 yajl_gen_map_open (data->handler);
585 yajl_gen_string_cast (data->handler, "ds_name", strlen ("ds_name"));
586 yajl_gen_string_cast (data->handler, ds_name, strlen (ds_name));
588 yajl_gen_string_cast (data->handler, "data", strlen ("data"));
589 yajl_gen_array_open (data->handler);
591 status = data_provider_get_ident_data (ident, ds_name,
592 data->begin, data->end,
593 ident_data_to_json__get_ident_data,
594 data);
596 yajl_gen_array_close (data->handler);
597 yajl_gen_map_close (data->handler);
599 return (status);
600 } /* }}} int ident_data_to_json__get_ds_name */
602 int ident_data_to_json (const graph_ident_t *ident, /* {{{ */
603 dp_time_t begin, dp_time_t end,
604 yajl_gen handler)
605 {
606 ident_data_to_json__data_t data;
607 int status;
609 data.begin = begin;
610 data.end = end;
611 data.handler = handler;
613 /* Iterate over all DS names */
614 status = data_provider_get_ident_ds_names (ident,
615 ident_data_to_json__get_ds_name, &data);
616 if (status != 0)
617 fprintf (stderr, "ident_data_to_json: data_provider_get_ident_ds_names "
618 "failed with status %i\n", status);
620 return (status);
621 } /* }}} int ident_data_to_json */
622 /* }}} ident_data_to_json */
624 int ident_describe (const graph_ident_t *ident, /* {{{ */
625 const graph_ident_t *selector,
626 char *buffer, size_t buffer_size)
627 {
628 if ((ident == NULL) || (selector == NULL)
629 || (buffer == NULL) || (buffer_size < 2))
630 return (EINVAL);
632 buffer[0] = 0;
634 #define CHECK_FIELD(field) do { \
635 if (strcasecmp (selector->field, ident->field) != 0) \
636 { \
637 if (buffer[0] != 0) \
638 strlcat (buffer, "/", buffer_size); \
639 strlcat (buffer, ident->field, buffer_size); \
640 } \
641 } while (0)
643 CHECK_FIELD (host);
644 CHECK_FIELD (plugin);
645 CHECK_FIELD (plugin_instance);
646 CHECK_FIELD (type);
647 CHECK_FIELD (type_instance);
649 #undef CHECK_FIELD
651 if (buffer[0] == 0)
652 strlcat (buffer, "default", buffer_size);
654 return (0);
655 } /* }}} int ident_describe */
657 time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
658 {
659 char *file;
660 struct stat statbuf;
661 int status;
663 if (ident == NULL)
664 return (0);
666 file = ident_to_file (ident);
667 if (file == NULL)
668 return (0);
670 memset (&statbuf, 0, sizeof (statbuf));
671 status = stat (file, &statbuf);
672 if (status != 0)
673 {
674 fprintf (stderr, "ident_get_mtime: stat'ing file \"%s\" failed: %s\n",
675 file, strerror (errno));
676 return (0);
677 }
679 free (file);
680 return (statbuf.st_mtime);
681 } /* }}} time_t ident_get_mtime */
683 /* vim: set sw=2 sts=2 et fdm=marker : */