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 "filesystem.h"
37 #include "utils_cgi.h"
39 #include <fcgiapp.h>
40 #include <fcgi_stdio.h>
42 /*
43 * Data types
44 */
45 struct graph_ident_s /* {{{ */
46 {
47 char *host;
48 char *plugin;
49 char *plugin_instance;
50 char *type;
51 char *type_instance;
52 }; /* }}} struct graph_ident_s */
54 /*
55 * Private functions
56 */
57 static char *part_copy_with_selector (const char *selector, /* {{{ */
58 const char *part, unsigned int flags)
59 {
60 if ((selector == NULL) || (part == NULL))
61 return (NULL);
63 if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
64 return (NULL);
66 if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
67 return (NULL);
69 /* Replace the ANY and ALL flags if requested and if the selecter actually
70 * *is* that flag. */
71 if (IS_ANY (selector))
72 {
73 if (flags & IDENT_FLAG_REPLACE_ANY)
74 return (strdup (part));
75 else
76 return (strdup (selector));
77 }
79 if (IS_ALL (selector))
80 {
81 if (flags & IDENT_FLAG_REPLACE_ALL)
82 return (strdup (part));
83 else
84 return (strdup (selector));
85 }
87 if (strcmp (selector, part) != 0)
88 return (NULL);
90 /* Otherwise (no replacement), return a copy of the selector. */
91 return (strdup (selector));
92 } /* }}} char *part_copy_with_selector */
94 static _Bool part_matches (const char *selector, /* {{{ */
95 const char *part)
96 {
97 #if C4_DEBUG
98 if ((selector == NULL) && (part == NULL))
99 return (1);
100 #endif
102 if (selector == NULL) /* && (part != NULL) */
103 return (0);
105 if (IS_ANY(selector) || IS_ALL(selector))
106 return (1);
108 if (part == NULL) /* && (selector != NULL) */
109 return (0);
111 if (strcmp (selector, part) == 0)
112 return (1);
114 return (0);
115 } /* }}} _Bool part_matches */
117 /*
118 * Public functions
119 */
120 graph_ident_t *ident_create (const char *host, /* {{{ */
121 const char *plugin, const char *plugin_instance,
122 const char *type, const char *type_instance)
123 {
124 graph_ident_t *ret;
126 if ((host == NULL)
127 || (plugin == NULL) || (plugin_instance == NULL)
128 || (type == NULL) || (type_instance == NULL))
129 return (NULL);
131 ret = malloc (sizeof (*ret));
132 if (ret == NULL)
133 return (NULL);
134 memset (ret, 0, sizeof (*ret));
136 ret->host = NULL;
137 ret->host = NULL;
138 ret->plugin = NULL;
139 ret->plugin_instance = NULL;
140 ret->type = NULL;
141 ret->type_instance = NULL;
143 #define COPY_PART(p) do { \
144 ret->p = strdup (p); \
145 if (ret->p == NULL) \
146 { \
147 free (ret->host); \
148 free (ret->plugin); \
149 free (ret->plugin_instance); \
150 free (ret->type); \
151 free (ret->type_instance); \
152 free (ret); \
153 return (NULL); \
154 } \
155 } while (0)
157 COPY_PART(host);
158 COPY_PART(plugin);
159 COPY_PART(plugin_instance);
160 COPY_PART(type);
161 COPY_PART(type_instance);
163 #undef COPY_PART
165 return (ret);
166 } /* }}} graph_ident_t *ident_create */
168 graph_ident_t *ident_clone (const graph_ident_t *ident) /* {{{ */
169 {
170 return (ident_create (ident->host,
171 ident->plugin, ident->plugin_instance,
172 ident->type, ident->type_instance));
173 } /* }}} graph_ident_t *ident_clone */
175 graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector, /* {{{ */
176 const graph_ident_t *ident, unsigned int flags)
177 {
178 graph_ident_t *ret;
180 if ((selector == NULL) || (ident == NULL))
181 return (NULL);
183 ret = malloc (sizeof (*ret));
184 if (ret == NULL)
185 return (NULL);
186 memset (ret, 0, sizeof (*ret));
187 ret->host = NULL;
188 ret->plugin = NULL;
189 ret->plugin_instance = NULL;
190 ret->type = NULL;
191 ret->type_instance = NULL;
193 #define COPY_PART(p) do { \
194 ret->p = part_copy_with_selector (selector->p, ident->p, flags); \
195 if (ret->p == NULL) \
196 { \
197 free (ret->host); \
198 free (ret->plugin); \
199 free (ret->plugin_instance); \
200 free (ret->type); \
201 free (ret->type_instance); \
202 return (NULL); \
203 } \
204 } while (0)
206 COPY_PART (host);
207 COPY_PART (plugin);
208 COPY_PART (plugin_instance);
209 COPY_PART (type);
210 COPY_PART (type_instance);
212 #undef COPY_PART
214 return (ret);
215 } /* }}} graph_ident_t *ident_copy_with_selector */
217 void ident_destroy (graph_ident_t *ident) /* {{{ */
218 {
219 if (ident == NULL)
220 return;
222 free (ident->host);
223 free (ident->plugin);
224 free (ident->plugin_instance);
225 free (ident->type);
226 free (ident->type_instance);
228 free (ident);
229 } /* }}} void ident_destroy */
231 /* ident_get_* methods {{{ */
232 const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
233 {
234 if (ident == NULL)
235 return (NULL);
237 return (ident->host);
238 } /* }}} char *ident_get_host */
240 const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
241 {
242 if (ident == NULL)
243 return (NULL);
245 return (ident->plugin);
246 } /* }}} char *ident_get_plugin */
248 const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
249 {
250 if (ident == NULL)
251 return (NULL);
253 return (ident->plugin_instance);
254 } /* }}} char *ident_get_plugin_instance */
256 const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
257 {
258 if (ident == NULL)
259 return (NULL);
261 return (ident->type);
262 } /* }}} char *ident_get_type */
264 const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
265 {
266 if (ident == NULL)
267 return (NULL);
269 return (ident->type_instance);
270 } /* }}} char *ident_get_type_instance */
272 const char *ident_get_field (const graph_ident_t *ident, /* {{{ */
273 graph_ident_field_t field)
274 {
275 if ((ident == NULL) || (field >= _GIF_LAST))
276 return (NULL);
278 if (field == GIF_HOST)
279 return (ident->host);
280 else if (field == GIF_PLUGIN)
281 return (ident->plugin);
282 else if (field == GIF_PLUGIN_INSTANCE)
283 return (ident->plugin_instance);
284 else if (field == GIF_TYPE)
285 return (ident->type);
286 else if (field == GIF_TYPE_INSTANCE)
287 return (ident->type_instance);
288 else
289 return (NULL); /* never reached */
290 } /* }}} const char *ident_get_field */
291 /* }}} ident_get_* methods */
293 /* ident_set_* methods {{{ */
294 int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
295 {
296 char *tmp;
298 if ((ident == NULL) || (host == NULL))
299 return (EINVAL);
301 tmp = strdup (host);
302 if (tmp == NULL)
303 return (ENOMEM);
305 free (ident->host);
306 ident->host = tmp;
308 return (0);
309 } /* }}} int ident_set_host */
311 int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
312 {
313 char *tmp;
315 if ((ident == NULL) || (plugin == NULL))
316 return (EINVAL);
318 tmp = strdup (plugin);
319 if (tmp == NULL)
320 return (ENOMEM);
322 free (ident->plugin);
323 ident->plugin = tmp;
325 return (0);
326 } /* }}} int ident_set_plugin */
328 int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
329 {
330 char *tmp;
332 if ((ident == NULL) || (plugin_instance == NULL))
333 return (EINVAL);
335 tmp = strdup (plugin_instance);
336 if (tmp == NULL)
337 return (ENOMEM);
339 free (ident->plugin_instance);
340 ident->plugin_instance = tmp;
342 return (0);
343 } /* }}} int ident_set_plugin_instance */
345 int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
346 {
347 char *tmp;
349 if ((ident == NULL) || (type == NULL))
350 return (EINVAL);
352 tmp = strdup (type);
353 if (tmp == NULL)
354 return (ENOMEM);
356 free (ident->type);
357 ident->type = tmp;
359 return (0);
360 } /* }}} int ident_set_type */
362 int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
363 {
364 char *tmp;
366 if ((ident == NULL) || (type_instance == NULL))
367 return (EINVAL);
369 tmp = strdup (type_instance);
370 if (tmp == NULL)
371 return (ENOMEM);
373 free (ident->type_instance);
374 ident->type_instance = tmp;
376 return (0);
377 } /* }}} int ident_set_type_instance */
379 /* }}} ident_set_* methods */
381 int ident_compare (const graph_ident_t *i0, /* {{{ */
382 const graph_ident_t *i1)
383 {
384 int status;
386 #define COMPARE_PART(p) do { \
387 status = strcmp (i0->p, i1->p); \
388 if (status != 0) \
389 return (status); \
390 } while (0)
392 COMPARE_PART (host);
393 COMPARE_PART (plugin);
394 COMPARE_PART (plugin_instance);
395 COMPARE_PART (type);
396 COMPARE_PART (type_instance);
398 #undef COMPARE_PART
400 return (0);
401 } /* }}} int ident_compare */
403 _Bool ident_matches (const graph_ident_t *selector, /* {{{ */
404 const graph_ident_t *ident)
405 {
406 #if C4_DEBUG
407 if ((selector == NULL) || (ident == NULL))
408 return (0);
409 #endif
411 if (!part_matches (selector->host, ident->host))
412 return (0);
414 if (!part_matches (selector->plugin, ident->plugin))
415 return (0);
417 if (!part_matches (selector->plugin_instance, ident->plugin_instance))
418 return (0);
420 if (!part_matches (selector->type, ident->type))
421 return (0);
423 if (!part_matches (selector->type_instance, ident->type_instance))
424 return (0);
426 return (1);
427 } /* }}} _Bool ident_matches */
429 _Bool ident_intersect (const graph_ident_t *s0, /* {{{ */
430 const graph_ident_t *s1)
431 {
432 #define INTERSECT_PART(p) do { \
433 if (!IS_ANY (s0->p) && !IS_ALL (s0->p) \
434 && !IS_ANY (s1->p) && !IS_ALL (s1->p) \
435 && (strcmp (s0->p, s1->p) != 0)) \
436 return (0); \
437 } while (0)
439 INTERSECT_PART (host);
440 INTERSECT_PART (plugin);
441 INTERSECT_PART (plugin_instance);
442 INTERSECT_PART (type);
443 INTERSECT_PART (type_instance);
445 #undef INTERSECT_PART
447 return (1);
448 } /* }}} _Bool ident_intersect */
450 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
451 {
452 char buffer[PATH_MAX];
454 buffer[0] = 0;
456 strlcat (buffer, ident->host, sizeof (buffer));
457 strlcat (buffer, "/", sizeof (buffer));
458 strlcat (buffer, ident->plugin, sizeof (buffer));
459 if (ident->plugin_instance[0] != 0)
460 {
461 strlcat (buffer, "-", sizeof (buffer));
462 strlcat (buffer, ident->plugin_instance, sizeof (buffer));
463 }
464 strlcat (buffer, "/", sizeof (buffer));
465 strlcat (buffer, ident->type, sizeof (buffer));
466 if (ident->type_instance[0] != 0)
467 {
468 strlcat (buffer, "-", sizeof (buffer));
469 strlcat (buffer, ident->type_instance, sizeof (buffer));
470 }
472 return (strdup (buffer));
473 } /* }}} char *ident_to_string */
475 char *ident_to_file (const graph_ident_t *ident) /* {{{ */
476 {
477 char buffer[PATH_MAX];
479 buffer[0] = 0;
481 strlcat (buffer, DATA_DIR, sizeof (buffer));
482 strlcat (buffer, "/", sizeof (buffer));
484 strlcat (buffer, ident->host, sizeof (buffer));
485 strlcat (buffer, "/", sizeof (buffer));
486 strlcat (buffer, ident->plugin, sizeof (buffer));
487 if (ident->plugin_instance[0] != 0)
488 {
489 strlcat (buffer, "-", sizeof (buffer));
490 strlcat (buffer, ident->plugin_instance, sizeof (buffer));
491 }
492 strlcat (buffer, "/", sizeof (buffer));
493 strlcat (buffer, ident->type, sizeof (buffer));
494 if (ident->type_instance[0] != 0)
495 {
496 strlcat (buffer, "-", sizeof (buffer));
497 strlcat (buffer, ident->type_instance, sizeof (buffer));
498 }
500 strlcat (buffer, ".rrd", sizeof (buffer));
502 return (strdup (buffer));
503 } /* }}} char *ident_to_file */
505 #define ADD_FIELD(field) do { \
506 char json[1024]; \
507 json_escape_copy (json, ident->field, sizeof (json)); \
508 strlcat (buffer, json, sizeof (buffer)); \
509 } while (0)
511 char *ident_to_json (const graph_ident_t *ident) /* {{{ */
512 {
513 char buffer[4096];
515 buffer[0] = 0;
517 strlcat (buffer, "{\"host\":\"", sizeof (buffer));
518 ADD_FIELD (host);
519 strlcat (buffer, "\",\"plugin\":\"", sizeof (buffer));
520 ADD_FIELD (plugin);
521 strlcat (buffer, "\",\"plugin_instance\":\"", sizeof (buffer));
522 ADD_FIELD (plugin_instance);
523 strlcat (buffer, "\",\"type\":\"", sizeof (buffer));
524 ADD_FIELD (type);
525 strlcat (buffer, "\",\"type_instance\":\"", sizeof (buffer));
526 ADD_FIELD (type_instance);
527 strlcat (buffer, "\"}", sizeof (buffer));
529 return (strdup (buffer));
530 } /* }}} char *ident_to_json */
532 #undef ADD_FIELD
534 int ident_describe (const graph_ident_t *ident, /* {{{ */
535 const graph_ident_t *selector,
536 char *buffer, size_t buffer_size)
537 {
538 if ((ident == NULL) || (selector == NULL)
539 || (buffer == NULL) || (buffer_size < 2))
540 return (EINVAL);
542 buffer[0] = 0;
544 #define CHECK_FIELD(field) do { \
545 if (strcasecmp (selector->field, ident->field) != 0) \
546 { \
547 if (buffer[0] != 0) \
548 strlcat (buffer, "/", buffer_size); \
549 strlcat (buffer, ident->field, buffer_size); \
550 } \
551 } while (0)
553 CHECK_FIELD (host);
554 CHECK_FIELD (plugin);
555 CHECK_FIELD (plugin_instance);
556 CHECK_FIELD (type);
557 CHECK_FIELD (type_instance);
559 #undef CHECK_FIELD
561 if (buffer[0] == 0)
562 strlcat (buffer, "default", buffer_size);
564 return (0);
565 } /* }}} int ident_describe */
567 time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
568 {
569 char *file;
570 struct stat statbuf;
571 int status;
573 if (ident == NULL)
574 return (0);
576 file = ident_to_file (ident);
577 if (file == NULL)
578 return (0);
580 memset (&statbuf, 0, sizeof (statbuf));
581 status = stat (file, &statbuf);
582 if (status != 0)
583 {
584 fprintf (stderr, "ident_get_mtime: stat'ing file \"%s\" failed: %s\n",
585 file, strerror (errno));
586 return (0);
587 }
589 free (file);
590 return (statbuf.st_mtime);
591 } /* }}} time_t ident_get_mtime */
593 /* vim: set sw=2 sts=2 et fdm=marker : */