src/graph_ident.c: Fix minor issues.
[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 "data_provider.h"
37 #include "filesystem.h"
38 #include "utils_cgi.h"
39
40 #include <fcgiapp.h>
41 #include <fcgi_stdio.h>
42
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 */
54
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);
63
64   if ((flags & IDENT_FLAG_REPLACE_ANY) && IS_ANY (part))
65     return (NULL);
66
67   if ((flags & IDENT_FLAG_REPLACE_ALL) && IS_ALL (part))
68     return (NULL);
69
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   }
79
80   if (IS_ALL (selector))
81   {
82     if (flags & IDENT_FLAG_REPLACE_ALL)
83       return (strdup (part));
84     else
85       return (strdup (selector));
86   }
87
88   if (strcmp (selector, part) != 0)
89     return (NULL);
90
91   /* Otherwise (no replacement), return a copy of the selector. */
92   return (strdup (selector));
93 } /* }}} char *part_copy_with_selector */
94
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
102
103   if (selector == NULL) /* && (part != NULL) */
104     return (0);
105
106   if (IS_ANY(selector) || IS_ALL(selector))
107     return (1);
108
109   if (part == NULL) /* && (selector != NULL) */
110     return (0);
111
112   if (strcmp (selector, part) == 0)
113     return (1);
114
115   return (0);
116 } /* }}} _Bool part_matches */
117
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;
126
127   if ((host == NULL)
128       || (plugin == NULL) || (plugin_instance == NULL)
129       || (type == NULL) || (type_instance == NULL))
130     return (NULL);
131
132   ret = malloc (sizeof (*ret));
133   if (ret == NULL)
134     return (NULL);
135   memset (ret, 0, sizeof (*ret));
136
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;
143
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)
157
158   COPY_PART(host);
159   COPY_PART(plugin);
160   COPY_PART(plugin_instance);
161   COPY_PART(type);
162   COPY_PART(type_instance);
163
164 #undef COPY_PART
165
166   return (ret);
167 } /* }}} graph_ident_t *ident_create */
168
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 */
175
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;
180
181   if ((selector == NULL) || (ident == NULL))
182     return (NULL);
183
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;
193
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)
206
207   COPY_PART (host);
208   COPY_PART (plugin);
209   COPY_PART (plugin_instance);
210   COPY_PART (type);
211   COPY_PART (type_instance);
212
213 #undef COPY_PART
214
215   return (ret);
216 } /* }}} graph_ident_t *ident_copy_with_selector */
217
218 void ident_destroy (graph_ident_t *ident) /* {{{ */
219 {
220   if (ident == NULL)
221     return;
222
223   free (ident->host);
224   free (ident->plugin);
225   free (ident->plugin_instance);
226   free (ident->type);
227   free (ident->type_instance);
228
229   free (ident);
230 } /* }}} void ident_destroy */
231
232 /* ident_get_* methods {{{ */
233 const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
234 {
235   if (ident == NULL)
236     return (NULL);
237
238   return (ident->host);
239 } /* }}} char *ident_get_host */
240
241 const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
242 {
243   if (ident == NULL)
244     return (NULL);
245
246   return (ident->plugin);
247 } /* }}} char *ident_get_plugin */
248
249 const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
250 {
251   if (ident == NULL)
252     return (NULL);
253
254   return (ident->plugin_instance);
255 } /* }}} char *ident_get_plugin_instance */
256
257 const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
258 {
259   if (ident == NULL)
260     return (NULL);
261
262   return (ident->type);
263 } /* }}} char *ident_get_type */
264
265 const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
266 {
267   if (ident == NULL)
268     return (NULL);
269
270   return (ident->type_instance);
271 } /* }}} char *ident_get_type_instance */
272
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);
278
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 */
293
294 /* ident_set_* methods {{{ */
295 int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
296 {
297   char *tmp;
298
299   if ((ident == NULL) || (host == NULL))
300     return (EINVAL);
301
302   tmp = strdup (host);
303   if (tmp == NULL)
304     return (ENOMEM);
305
306   free (ident->host);
307   ident->host = tmp;
308
309   return (0);
310 } /* }}} int ident_set_host */
311
312 int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
313 {
314   char *tmp;
315
316   if ((ident == NULL) || (plugin == NULL))
317     return (EINVAL);
318
319   tmp = strdup (plugin);
320   if (tmp == NULL)
321     return (ENOMEM);
322
323   free (ident->plugin);
324   ident->plugin = tmp;
325
326   return (0);
327 } /* }}} int ident_set_plugin */
328
329 int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
330 {
331   char *tmp;
332
333   if ((ident == NULL) || (plugin_instance == NULL))
334     return (EINVAL);
335
336   tmp = strdup (plugin_instance);
337   if (tmp == NULL)
338     return (ENOMEM);
339
340   free (ident->plugin_instance);
341   ident->plugin_instance = tmp;
342
343   return (0);
344 } /* }}} int ident_set_plugin_instance */
345
346 int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
347 {
348   char *tmp;
349
350   if ((ident == NULL) || (type == NULL))
351     return (EINVAL);
352
353   tmp = strdup (type);
354   if (tmp == NULL)
355     return (ENOMEM);
356
357   free (ident->type);
358   ident->type = tmp;
359
360   return (0);
361 } /* }}} int ident_set_type */
362
363 int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
364 {
365   char *tmp;
366
367   if ((ident == NULL) || (type_instance == NULL))
368     return (EINVAL);
369
370   tmp = strdup (type_instance);
371   if (tmp == NULL)
372     return (ENOMEM);
373
374   free (ident->type_instance);
375   ident->type_instance = tmp;
376
377   return (0);
378 } /* }}} int ident_set_type_instance */
379
380 /* }}} ident_set_* methods */
381
382 int ident_compare (const graph_ident_t *i0, /* {{{ */
383     const graph_ident_t *i1)
384 {
385   int status;
386
387 #define COMPARE_PART(p) do {       \
388   status = strcmp (i0->p, i1->p);  \
389   if (status != 0)                 \
390     return (status);               \
391 } while (0)
392
393   COMPARE_PART (host);
394   COMPARE_PART (plugin);
395   COMPARE_PART (plugin_instance);
396   COMPARE_PART (type);
397   COMPARE_PART (type_instance);
398
399 #undef COMPARE_PART
400
401   return (0);
402 } /* }}} int ident_compare */
403
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
411
412   if (!part_matches (selector->host, ident->host))
413     return (0);
414
415   if (!part_matches (selector->plugin, ident->plugin))
416     return (0);
417
418   if (!part_matches (selector->plugin_instance, ident->plugin_instance))
419     return (0);
420
421   if (!part_matches (selector->type, ident->type))
422     return (0);
423
424   if (!part_matches (selector->type_instance, ident->type_instance))
425     return (0);
426
427   return (1);
428 } /* }}} _Bool ident_matches */
429
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)
439
440   INTERSECT_PART (host);
441   INTERSECT_PART (plugin);
442   INTERSECT_PART (plugin_instance);
443   INTERSECT_PART (type);
444   INTERSECT_PART (type_instance);
445
446 #undef INTERSECT_PART
447
448   return (1);
449 } /* }}} _Bool ident_intersect */
450
451 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
452 {
453   char buffer[PATH_MAX];
454
455   buffer[0] = 0;
456
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   }
472
473   return (strdup (buffer));
474 } /* }}} char *ident_to_string */
475
476 char *ident_to_file (const graph_ident_t *ident) /* {{{ */
477 {
478   char buffer[PATH_MAX];
479
480   buffer[0] = 0;
481
482   strlcat (buffer, DATA_DIR, sizeof (buffer));
483   strlcat (buffer, "/", sizeof (buffer));
484
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   }
500
501   strlcat (buffer, ".rrd", sizeof (buffer));
502
503   return (strdup (buffer));
504 } /* }}} char *ident_to_file */
505
506 int ident_to_json (const graph_ident_t *ident, /* {{{ */
507     yajl_gen handler)
508 {
509   yajl_gen_status status;
510
511   if ((ident == NULL) || (handler == NULL))
512     return (EINVAL);
513
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)
521
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);
534
535 #undef ADD_FIELD
536
537   return (0);
538 } /* }}} char *ident_to_json */
539
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;
548
549 #define yajl_gen_string_cast(h,s,l) \
550   yajl_gen_string (h, (unsigned char *) s, (unsigned int) l)
551
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;
560
561   yajl_gen_map_open (data->handler);
562
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   }
570
571   yajl_gen_map_close (data->handler);
572
573   return (0);
574 } /* }}} int ident_data_to_json__get_ident_data */
575
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;
582
583   yajl_gen_map_open (data->handler);
584
585   yajl_gen_string_cast (data->handler, "ds_name", strlen ("ds_name"));
586   yajl_gen_string_cast (data->handler, ds_name, strlen (ds_name));
587
588   yajl_gen_string_cast (data->handler, "data", strlen ("data"));
589   yajl_gen_array_open (data->handler);
590
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);
595
596   yajl_gen_array_close (data->handler);
597   yajl_gen_map_close (data->handler);
598
599   return (status);
600 } /* }}} int ident_data_to_json__get_ds_name */
601
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;
608
609   data.begin = begin;
610   data.end = end;
611   data.handler = handler;
612
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);
619
620   return (status);
621 } /* }}} int ident_data_to_json */
622 /* }}} ident_data_to_json */
623
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);
631
632   buffer[0] = 0;
633
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)
642
643   CHECK_FIELD (host);
644   CHECK_FIELD (plugin);
645   CHECK_FIELD (plugin_instance);
646   CHECK_FIELD (type);
647   CHECK_FIELD (type_instance);
648
649 #undef CHECK_FIELD
650
651   if (buffer[0] == 0)
652     strlcat (buffer, "default", buffer_size);
653
654   return (0);
655 } /* }}} int ident_describe */
656
657 time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
658 {
659   char *file;
660   struct stat statbuf;
661   int status;
662
663   if (ident == NULL)
664     return (0);
665
666   file = ident_to_file (ident);
667   if (file == NULL)
668     return (0);
669
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   }
678
679   free (file);
680   return (statbuf.st_mtime);
681 } /* }}} time_t ident_get_mtime */
682
683 /* vim: set sw=2 sts=2 et fdm=marker : */
684