e7d193266e4d38622ff6ad35a659102cb605be50
[collection4.git] / src / graph_ident.c
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  **/
23
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>
33
34 #include "graph_ident.h"
35 #include "common.h"
36 #include "filesystem.h"
37 #include "utils_cgi.h"
38
39 #include <fcgiapp.h>
40 #include <fcgi_stdio.h>
41
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 */
53
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);
62
63   if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
64     return (NULL);
65
66   if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
67     return (NULL);
68
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   }
78
79   if (IS_ALL (selector))
80   {
81     if (flags & IDENT_FLAG_REPLACE_ALL)
82       return (strdup (part));
83     else
84       return (strdup (selector));
85   }
86
87   if (strcmp (selector, part) != 0)
88     return (NULL);
89
90   /* Otherwise (no replacement), return a copy of the selector. */
91   return (strdup (selector));
92 } /* }}} char *part_copy_with_selector */
93
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
101
102   if (selector == NULL) /* && (part != NULL) */
103     return (0);
104
105   if (IS_ANY(selector) || IS_ALL(selector))
106     return (1);
107
108   if (part == NULL) /* && (selector != NULL) */
109     return (0);
110
111   if (strcmp (selector, part) == 0)
112     return (1);
113
114   return (0);
115 } /* }}} _Bool part_matches */
116
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;
125
126   if ((host == NULL)
127       || (plugin == NULL) || (plugin_instance == NULL)
128       || (type == NULL) || (type_instance == NULL))
129     return (NULL);
130
131   ret = malloc (sizeof (*ret));
132   if (ret == NULL)
133     return (NULL);
134   memset (ret, 0, sizeof (*ret));
135
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;
142
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)
156
157   COPY_PART(host);
158   COPY_PART(plugin);
159   COPY_PART(plugin_instance);
160   COPY_PART(type);
161   COPY_PART(type_instance);
162
163 #undef COPY_PART
164
165   return (ret);
166 } /* }}} graph_ident_t *ident_create */
167
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 */
174
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;
179
180   if ((selector == NULL) || (ident == NULL))
181     return (NULL);
182
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;
192
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)
205
206   COPY_PART (host);
207   COPY_PART (plugin);
208   COPY_PART (plugin_instance);
209   COPY_PART (type);
210   COPY_PART (type_instance);
211
212 #undef COPY_PART
213
214   return (ret);
215 } /* }}} graph_ident_t *ident_copy_with_selector */
216
217 void ident_destroy (graph_ident_t *ident) /* {{{ */
218 {
219   if (ident == NULL)
220     return;
221
222   free (ident->host);
223   free (ident->plugin);
224   free (ident->plugin_instance);
225   free (ident->type);
226   free (ident->type_instance);
227
228   free (ident);
229 } /* }}} void ident_destroy */
230
231 /* ident_get_* methods {{{ */
232 const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
233 {
234   if (ident == NULL)
235     return (NULL);
236
237   return (ident->host);
238 } /* }}} char *ident_get_host */
239
240 const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
241 {
242   if (ident == NULL)
243     return (NULL);
244
245   return (ident->plugin);
246 } /* }}} char *ident_get_plugin */
247
248 const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
249 {
250   if (ident == NULL)
251     return (NULL);
252
253   return (ident->plugin_instance);
254 } /* }}} char *ident_get_plugin_instance */
255
256 const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
257 {
258   if (ident == NULL)
259     return (NULL);
260
261   return (ident->type);
262 } /* }}} char *ident_get_type */
263
264 const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
265 {
266   if (ident == NULL)
267     return (NULL);
268
269   return (ident->type_instance);
270 } /* }}} char *ident_get_type_instance */
271
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);
277
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 */
292
293 /* ident_set_* methods {{{ */
294 int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
295 {
296   char *tmp;
297
298   if ((ident == NULL) || (host == NULL))
299     return (EINVAL);
300
301   tmp = strdup (host);
302   if (tmp == NULL)
303     return (ENOMEM);
304
305   free (ident->host);
306   ident->host = tmp;
307
308   return (0);
309 } /* }}} int ident_set_host */
310
311 int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
312 {
313   char *tmp;
314
315   if ((ident == NULL) || (plugin == NULL))
316     return (EINVAL);
317
318   tmp = strdup (plugin);
319   if (tmp == NULL)
320     return (ENOMEM);
321
322   free (ident->plugin);
323   ident->plugin = tmp;
324
325   return (0);
326 } /* }}} int ident_set_plugin */
327
328 int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
329 {
330   char *tmp;
331
332   if ((ident == NULL) || (plugin_instance == NULL))
333     return (EINVAL);
334
335   tmp = strdup (plugin_instance);
336   if (tmp == NULL)
337     return (ENOMEM);
338
339   free (ident->plugin_instance);
340   ident->plugin_instance = tmp;
341
342   return (0);
343 } /* }}} int ident_set_plugin_instance */
344
345 int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
346 {
347   char *tmp;
348
349   if ((ident == NULL) || (type == NULL))
350     return (EINVAL);
351
352   tmp = strdup (type);
353   if (tmp == NULL)
354     return (ENOMEM);
355
356   free (ident->type);
357   ident->type = tmp;
358
359   return (0);
360 } /* }}} int ident_set_type */
361
362 int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
363 {
364   char *tmp;
365
366   if ((ident == NULL) || (type_instance == NULL))
367     return (EINVAL);
368
369   tmp = strdup (type_instance);
370   if (tmp == NULL)
371     return (ENOMEM);
372
373   free (ident->type_instance);
374   ident->type_instance = tmp;
375
376   return (0);
377 } /* }}} int ident_set_type_instance */
378
379 /* }}} ident_set_* methods */
380
381 int ident_compare (const graph_ident_t *i0, /* {{{ */
382     const graph_ident_t *i1)
383 {
384   int status;
385
386 #define COMPARE_PART(p) do {       \
387   status = strcmp (i0->p, i1->p);  \
388   if (status != 0)                 \
389     return (status);               \
390 } while (0)
391
392   COMPARE_PART (host);
393   COMPARE_PART (plugin);
394   COMPARE_PART (plugin_instance);
395   COMPARE_PART (type);
396   COMPARE_PART (type_instance);
397
398 #undef COMPARE_PART
399
400   return (0);
401 } /* }}} int ident_compare */
402
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
410
411   if (!part_matches (selector->host, ident->host))
412     return (0);
413
414   if (!part_matches (selector->plugin, ident->plugin))
415     return (0);
416
417   if (!part_matches (selector->plugin_instance, ident->plugin_instance))
418     return (0);
419
420   if (!part_matches (selector->type, ident->type))
421     return (0);
422
423   if (!part_matches (selector->type_instance, ident->type_instance))
424     return (0);
425
426   return (1);
427 } /* }}} _Bool ident_matches */
428
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)
438
439   INTERSECT_PART (host);
440   INTERSECT_PART (plugin);
441   INTERSECT_PART (plugin_instance);
442   INTERSECT_PART (type);
443   INTERSECT_PART (type_instance);
444
445 #undef INTERSECT_PART
446
447   return (1);
448 } /* }}} _Bool ident_intersect */
449
450 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
451 {
452   char buffer[PATH_MAX];
453
454   buffer[0] = 0;
455
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   }
471
472   return (strdup (buffer));
473 } /* }}} char *ident_to_string */
474
475 char *ident_to_file (const graph_ident_t *ident) /* {{{ */
476 {
477   char buffer[PATH_MAX];
478
479   buffer[0] = 0;
480
481   strlcat (buffer, DATA_DIR, sizeof (buffer));
482   strlcat (buffer, "/", sizeof (buffer));
483
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   }
499
500   strlcat (buffer, ".rrd", sizeof (buffer));
501
502   return (strdup (buffer));
503 } /* }}} char *ident_to_file */
504
505 int ident_to_json (const graph_ident_t *ident, /* {{{ */
506     yajl_gen handler)
507 {
508   yajl_gen_status status;
509
510   if ((ident == NULL) || (handler == NULL))
511     return (EINVAL);
512
513 #define ADD_STRING(str) do {                              \
514   status = yajl_gen_string (handler,                      \
515       (unsigned char *) (str),                            \
516       (unsigned int) strlen (str));                       \
517   if (status != yajl_gen_status_ok)                       \
518     return ((int) status);                                \
519 } while (0)
520
521   yajl_gen_map_open (handler);
522   ADD_STRING ("host");
523   ADD_STRING (ident->host);
524   ADD_STRING ("plugin");
525   ADD_STRING (ident->plugin);
526   ADD_STRING ("plugin_instance");
527   ADD_STRING (ident->plugin_instance);
528   ADD_STRING ("type");
529   ADD_STRING (ident->type);
530   ADD_STRING ("type_instance");
531   ADD_STRING (ident->type_instance);
532   yajl_gen_map_close (handler);
533
534 #undef ADD_FIELD
535
536   return (0);
537 } /* }}} char *ident_to_json */
538
539 int ident_describe (const graph_ident_t *ident, /* {{{ */
540     const graph_ident_t *selector,
541     char *buffer, size_t buffer_size)
542 {
543   if ((ident == NULL) || (selector == NULL)
544       || (buffer == NULL) || (buffer_size < 2))
545     return (EINVAL);
546
547   buffer[0] = 0;
548
549 #define CHECK_FIELD(field) do {                                              \
550   if (strcasecmp (selector->field, ident->field) != 0)                       \
551   {                                                                          \
552     if (buffer[0] != 0)                                                      \
553       strlcat (buffer, "/", buffer_size);                                    \
554     strlcat (buffer, ident->field, buffer_size);                             \
555   }                                                                          \
556 } while (0)
557
558   CHECK_FIELD (host);
559   CHECK_FIELD (plugin);
560   CHECK_FIELD (plugin_instance);
561   CHECK_FIELD (type);
562   CHECK_FIELD (type_instance);
563
564 #undef CHECK_FIELD
565
566   if (buffer[0] == 0)
567     strlcat (buffer, "default", buffer_size);
568
569   return (0);
570 } /* }}} int ident_describe */
571
572 time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
573 {
574   char *file;
575   struct stat statbuf;
576   int status;
577
578   if (ident == NULL)
579     return (0);
580
581   file = ident_to_file (ident);
582   if (file == NULL)
583     return (0);
584
585   memset (&statbuf, 0, sizeof (statbuf));
586   status = stat (file, &statbuf);
587   if (status != 0)
588   {
589     fprintf (stderr, "ident_get_mtime: stat'ing file \"%s\" failed: %s\n",
590         file, strerror (errno));
591     return (0);
592   }
593
594   free (file);
595   return (statbuf.st_mtime);
596 } /* }}} time_t ident_get_mtime */
597
598 /* vim: set sw=2 sts=2 et fdm=marker : */
599