src/graph_ident.c: ident_to_json: Escape strings before adding them to the buffer.
[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 ((selector == NULL) && (part == NULL))
98     return (1);
99
100   if (selector == NULL) /* && (part != NULL) */
101     return (0);
102
103   if (IS_ANY(selector) || IS_ALL(selector))
104     return (1);
105
106   if (part == NULL) /* && (selector != NULL) */
107     return (0);
108
109   if (strcmp (selector, part) == 0)
110     return (1);
111
112   return (0);
113 } /* }}} _Bool part_matches */
114
115 /*
116  * Public functions
117  */
118 graph_ident_t *ident_create (const char *host, /* {{{ */
119     const char *plugin, const char *plugin_instance,
120     const char *type, const char *type_instance)
121 {
122   graph_ident_t *ret;
123
124   if ((host == NULL)
125       || (plugin == NULL) || (plugin_instance == NULL)
126       || (type == NULL) || (type_instance == NULL))
127     return (NULL);
128
129   ret = malloc (sizeof (*ret));
130   if (ret == NULL)
131     return (NULL);
132   memset (ret, 0, sizeof (*ret));
133
134   ret->host = NULL;
135   ret->host = NULL;
136   ret->plugin = NULL;
137   ret->plugin_instance = NULL;
138   ret->type = NULL;
139   ret->type_instance = NULL;
140
141 #define COPY_PART(p) do {        \
142   ret->p = strdup (p);           \
143   if (ret->p == NULL)            \
144   {                              \
145     free (ret->host);            \
146     free (ret->plugin);          \
147     free (ret->plugin_instance); \
148     free (ret->type);            \
149     free (ret->type_instance);   \
150     free (ret);                  \
151     return (NULL);               \
152   }                              \
153 } while (0)
154
155   COPY_PART(host);
156   COPY_PART(plugin);
157   COPY_PART(plugin_instance);
158   COPY_PART(type);
159   COPY_PART(type_instance);
160
161 #undef COPY_PART
162
163   return (ret);
164 } /* }}} graph_ident_t *ident_create */
165
166 graph_ident_t *ident_clone (const graph_ident_t *ident) /* {{{ */
167 {
168   return (ident_create (ident->host,
169         ident->plugin, ident->plugin_instance,
170         ident->type, ident->type_instance));
171 } /* }}} graph_ident_t *ident_clone */
172
173 graph_ident_t *ident_copy_with_selector (const graph_ident_t *selector, /* {{{ */
174     const graph_ident_t *ident, unsigned int flags)
175 {
176   graph_ident_t *ret;
177
178   if ((selector == NULL) || (ident == NULL))
179     return (NULL);
180
181   ret = malloc (sizeof (*ret));
182   if (ret == NULL)
183     return (NULL);
184   memset (ret, 0, sizeof (*ret));
185   ret->host = NULL;
186   ret->plugin = NULL;
187   ret->plugin_instance = NULL;
188   ret->type = NULL;
189   ret->type_instance = NULL;
190
191 #define COPY_PART(p) do {                                  \
192   ret->p = part_copy_with_selector (selector->p, ident->p, flags); \
193   if (ret->p == NULL)                                      \
194   {                                                        \
195     free (ret->host);                                      \
196     free (ret->plugin);                                    \
197     free (ret->plugin_instance);                           \
198     free (ret->type);                                      \
199     free (ret->type_instance);                             \
200     return (NULL);                                         \
201   }                                                        \
202 } while (0)
203
204   COPY_PART (host);
205   COPY_PART (plugin);
206   COPY_PART (plugin_instance);
207   COPY_PART (type);
208   COPY_PART (type_instance);
209
210 #undef COPY_PART
211
212   return (ret);
213 } /* }}} graph_ident_t *ident_copy_with_selector */
214
215 void ident_destroy (graph_ident_t *ident) /* {{{ */
216 {
217   if (ident == NULL)
218     return;
219
220   free (ident->host);
221   free (ident->plugin);
222   free (ident->plugin_instance);
223   free (ident->type);
224   free (ident->type_instance);
225
226   free (ident);
227 } /* }}} void ident_destroy */
228
229 /* ident_get_* methods {{{ */
230 const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
231 {
232   if (ident == NULL)
233     return (NULL);
234
235   return (ident->host);
236 } /* }}} char *ident_get_host */
237
238 const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
239 {
240   if (ident == NULL)
241     return (NULL);
242
243   return (ident->plugin);
244 } /* }}} char *ident_get_plugin */
245
246 const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
247 {
248   if (ident == NULL)
249     return (NULL);
250
251   return (ident->plugin_instance);
252 } /* }}} char *ident_get_plugin_instance */
253
254 const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
255 {
256   if (ident == NULL)
257     return (NULL);
258
259   return (ident->type);
260 } /* }}} char *ident_get_type */
261
262 const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
263 {
264   if (ident == NULL)
265     return (NULL);
266
267   return (ident->type_instance);
268 } /* }}} char *ident_get_type_instance */
269
270 const char *ident_get_field (const graph_ident_t *ident, /* {{{ */
271     graph_ident_field_t field)
272 {
273   if ((ident == NULL) || (field >= _GIF_LAST))
274     return (NULL);
275
276   if (field == GIF_HOST)
277     return (ident->host);
278   else if (field == GIF_PLUGIN)
279     return (ident->plugin);
280   else if (field == GIF_PLUGIN_INSTANCE)
281     return (ident->plugin_instance);
282   else if (field == GIF_TYPE)
283     return (ident->type);
284   else if (field == GIF_TYPE_INSTANCE)
285     return (ident->type_instance);
286   else
287     return (NULL); /* never reached */
288 } /* }}} const char *ident_get_field */
289 /* }}} ident_get_* methods */
290
291 /* ident_set_* methods {{{ */
292 int ident_set_host (graph_ident_t *ident, const char *host) /* {{{ */
293 {
294   char *tmp;
295
296   if ((ident == NULL) || (host == NULL))
297     return (EINVAL);
298
299   tmp = strdup (host);
300   if (tmp == NULL)
301     return (ENOMEM);
302
303   free (ident->host);
304   ident->host = tmp;
305
306   return (0);
307 } /* }}} int ident_set_host */
308
309 int ident_set_plugin (graph_ident_t *ident, const char *plugin) /* {{{ */
310 {
311   char *tmp;
312
313   if ((ident == NULL) || (plugin == NULL))
314     return (EINVAL);
315
316   tmp = strdup (plugin);
317   if (tmp == NULL)
318     return (ENOMEM);
319
320   free (ident->plugin);
321   ident->plugin = tmp;
322
323   return (0);
324 } /* }}} int ident_set_plugin */
325
326 int ident_set_plugin_instance (graph_ident_t *ident, const char *plugin_instance) /* {{{ */
327 {
328   char *tmp;
329
330   if ((ident == NULL) || (plugin_instance == NULL))
331     return (EINVAL);
332
333   tmp = strdup (plugin_instance);
334   if (tmp == NULL)
335     return (ENOMEM);
336
337   free (ident->plugin_instance);
338   ident->plugin_instance = tmp;
339
340   return (0);
341 } /* }}} int ident_set_plugin_instance */
342
343 int ident_set_type (graph_ident_t *ident, const char *type) /* {{{ */
344 {
345   char *tmp;
346
347   if ((ident == NULL) || (type == NULL))
348     return (EINVAL);
349
350   tmp = strdup (type);
351   if (tmp == NULL)
352     return (ENOMEM);
353
354   free (ident->type);
355   ident->type = tmp;
356
357   return (0);
358 } /* }}} int ident_set_type */
359
360 int ident_set_type_instance (graph_ident_t *ident, const char *type_instance) /* {{{ */
361 {
362   char *tmp;
363
364   if ((ident == NULL) || (type_instance == NULL))
365     return (EINVAL);
366
367   tmp = strdup (type_instance);
368   if (tmp == NULL)
369     return (ENOMEM);
370
371   free (ident->type_instance);
372   ident->type_instance = tmp;
373
374   return (0);
375 } /* }}} int ident_set_type_instance */
376
377 /* }}} ident_set_* methods */
378
379 int ident_compare (const graph_ident_t *i0, /* {{{ */
380     const graph_ident_t *i1)
381 {
382   int status;
383
384 #define COMPARE_PART(p) do {       \
385   status = strcmp (i0->p, i1->p);  \
386   if (status != 0)                 \
387     return (status);               \
388 } while (0)
389
390   COMPARE_PART (host);
391   COMPARE_PART (plugin);
392   COMPARE_PART (plugin_instance);
393   COMPARE_PART (type);
394   COMPARE_PART (type_instance);
395
396 #undef COMPARE_PART
397
398   return (0);
399 } /* }}} int ident_compare */
400
401 _Bool ident_matches (const graph_ident_t *selector, /* {{{ */
402     const graph_ident_t *ident)
403 {
404   if ((selector == NULL) || (ident == NULL))
405     return (0);
406
407   if (!part_matches (selector->host, ident->host))
408     return (0);
409
410   if (!part_matches (selector->plugin, ident->plugin))
411     return (0);
412
413   if (!part_matches (selector->plugin_instance, ident->plugin_instance))
414     return (0);
415
416   if (!part_matches (selector->type, ident->type))
417     return (0);
418
419   if (!part_matches (selector->type_instance, ident->type_instance))
420     return (0);
421
422   return (1);
423 } /* }}} _Bool ident_matches */
424
425 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
426 {
427   char buffer[PATH_MAX];
428
429   buffer[0] = 0;
430
431   strlcat (buffer, ident->host, sizeof (buffer));
432   strlcat (buffer, "/", sizeof (buffer));
433   strlcat (buffer, ident->plugin, sizeof (buffer));
434   if (ident->plugin_instance[0] != 0)
435   {
436     strlcat (buffer, "-", sizeof (buffer));
437     strlcat (buffer, ident->plugin_instance, sizeof (buffer));
438   }
439   strlcat (buffer, "/", sizeof (buffer));
440   strlcat (buffer, ident->type, sizeof (buffer));
441   if (ident->type_instance[0] != 0)
442   {
443     strlcat (buffer, "-", sizeof (buffer));
444     strlcat (buffer, ident->type_instance, sizeof (buffer));
445   }
446
447   return (strdup (buffer));
448 } /* }}} char *ident_to_string */
449
450 char *ident_to_file (const graph_ident_t *ident) /* {{{ */
451 {
452   char buffer[PATH_MAX];
453
454   buffer[0] = 0;
455
456   strlcat (buffer, DATA_DIR, sizeof (buffer));
457   strlcat (buffer, "/", sizeof (buffer));
458
459   strlcat (buffer, ident->host, sizeof (buffer));
460   strlcat (buffer, "/", sizeof (buffer));
461   strlcat (buffer, ident->plugin, sizeof (buffer));
462   if (ident->plugin_instance[0] != 0)
463   {
464     strlcat (buffer, "-", sizeof (buffer));
465     strlcat (buffer, ident->plugin_instance, sizeof (buffer));
466   }
467   strlcat (buffer, "/", sizeof (buffer));
468   strlcat (buffer, ident->type, sizeof (buffer));
469   if (ident->type_instance[0] != 0)
470   {
471     strlcat (buffer, "-", sizeof (buffer));
472     strlcat (buffer, ident->type_instance, sizeof (buffer));
473   }
474
475   strlcat (buffer, ".rrd", sizeof (buffer));
476
477   return (strdup (buffer));
478 } /* }}} char *ident_to_file */
479
480 #define ADD_FIELD(field) do {                              \
481   char json[1024];                                         \
482   json_escape_copy (json, ident->field, sizeof (json));    \
483   strlcat (buffer, json, sizeof (buffer));                 \
484 } while (0)
485
486 char *ident_to_json (const graph_ident_t *ident) /* {{{ */
487 {
488   char buffer[4096];
489
490   buffer[0] = 0;
491
492   strlcat (buffer, "{\"host\":\"", sizeof (buffer));
493   ADD_FIELD (host);
494   strlcat (buffer, "\",\"plugin\":\"", sizeof (buffer));
495   ADD_FIELD (plugin);
496   strlcat (buffer, "\",\"plugin_instance\":\"", sizeof (buffer));
497   ADD_FIELD (plugin_instance);
498   strlcat (buffer, "\",\"type\":\"", sizeof (buffer));
499   ADD_FIELD (type);
500   strlcat (buffer, "\",\"type_instance\":\"", sizeof (buffer));
501   ADD_FIELD (type_instance);
502   strlcat (buffer, "\"}", sizeof (buffer));
503
504   return (strdup (buffer));
505 } /* }}} char *ident_to_json */
506
507 #undef ADD_FIELD
508
509 time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
510 {
511   char *file;
512   struct stat statbuf;
513   int status;
514
515   if (ident == NULL)
516     return (0);
517
518   file = ident_to_file (ident);
519   if (file == NULL)
520     return (0);
521
522   memset (&statbuf, 0, sizeof (statbuf));
523   status = stat (file, &statbuf);
524   if (status != 0)
525   {
526     fprintf (stderr, "ident_get_mtime: stat'ing file \"%s\" failed: %s\n",
527         file, strerror (errno));
528     return (0);
529   }
530
531   free (file);
532   return (statbuf.st_mtime);
533 } /* }}} time_t ident_get_mtime */
534
535 /* vim: set sw=2 sts=2 et fdm=marker : */
536