Code

Merge branch 'collectd-5.5'
[collectd.git] / src / daemon / meta_data.c
1 /**
2  * collectd - src/meta_data.c
3  * Copyright (C) 2008-2011  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
27 #include "collectd.h"
28 #include "plugin.h"
29 #include "meta_data.h"
31 #include <pthread.h>
33 /*
34  * Data types
35  */
36 union meta_value_u
37 {
38   char    *mv_string;
39   int64_t  mv_signed_int;
40   uint64_t mv_unsigned_int;
41   double   mv_double;
42   _Bool    mv_boolean;
43 };
44 typedef union meta_value_u meta_value_t;
46 struct meta_entry_s;
47 typedef struct meta_entry_s meta_entry_t;
48 struct meta_entry_s
49 {
50   char         *key;
51   meta_value_t  value;
52   int           type;
53   meta_entry_t *next;
54 };
56 struct meta_data_s
57 {
58   meta_entry_t   *head;
59   pthread_mutex_t lock;
60 };
62 /*
63  * Private functions
64  */
65 static char *md_strdup (const char *orig) /* {{{ */
66 {
67   size_t sz;
68   char *dest;
70   if (orig == NULL)
71     return (NULL);
73   sz = strlen (orig) + 1;
74   dest = malloc (sz);
75   if (dest == NULL)
76     return (NULL);
78   memcpy (dest, orig, sz);
80   return (dest);
81 } /* }}} char *md_strdup */
83 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
84 {
85   meta_entry_t *e;
87   e = calloc (1, sizeof (*e));
88   if (e == NULL)
89   {
90     ERROR ("md_entry_alloc: calloc failed.");
91     return (NULL);
92   }
94   e->key = md_strdup (key);
95   if (e->key == NULL)
96   {
97     free (e);
98     ERROR ("md_entry_alloc: md_strdup failed.");
99     return (NULL);
100   }
102   e->type = 0;
103   e->next = NULL;
105   return (e);
106 } /* }}} meta_entry_t *md_entry_alloc */
108 /* XXX: The lock on md must be held while calling this function! */
109 static meta_entry_t *md_entry_clone_contents (const meta_entry_t *orig) /* {{{ */
111   meta_entry_t *copy;
113   /* WARNINGS :
114    *  - we do not check that orig != NULL here. You should have done it before.
115    *  - we do not set copy->next. DO NOT FORGET TO SET copy->next IN YOUR FUNCTION
116    */
118   copy = md_entry_alloc (orig->key);
119   if (copy == NULL)
120     return (NULL);
121   copy->type = orig->type;
122   if (copy->type == MD_TYPE_STRING)
123     copy->value.mv_string = strdup (orig->value.mv_string);
124   else
125     copy->value = orig->value;
127   return (copy);
128 } /* }}} meta_entry_t *md_entry_clone_contents */
130 static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
132   meta_entry_t *copy;
134   if (orig == NULL)
135     return (NULL);
137   copy = md_entry_clone_contents(orig);
139   copy->next = md_entry_clone (orig->next);
140   return (copy);
141 } /* }}} meta_entry_t *md_entry_clone */
143 static void md_entry_free (meta_entry_t *e) /* {{{ */
145   if (e == NULL)
146     return;
148   free (e->key);
150   if (e->type == MD_TYPE_STRING)
151     free (e->value.mv_string);
153   if (e->next != NULL)
154     md_entry_free (e->next);
156   free (e);
157 } /* }}} void md_entry_free */
159 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
161   meta_entry_t *this;
162   meta_entry_t *prev;
164   if ((md == NULL) || (e == NULL))
165     return (-EINVAL);
167   pthread_mutex_lock (&md->lock);
169   prev = NULL;
170   this = md->head;
171   while (this != NULL)
172   {
173     if (strcasecmp (e->key, this->key) == 0)
174       break;
176     prev = this;
177     this = this->next;
178   }
180   if (this == NULL)
181   {
182     /* This key does not exist yet. */
183     if (md->head == NULL)
184       md->head = e;
185     else
186     {
187       assert (prev != NULL);
188       prev->next = e;
189     }
191     e->next = NULL;
192   }
193   else /* (this != NULL) */
194   {
195     if (prev == NULL)
196       md->head = e;
197     else
198       prev->next = e;
200     e->next = this->next;
201   }
203   pthread_mutex_unlock (&md->lock);
205   if (this != NULL)
206   {
207     this->next = NULL;
208     md_entry_free (this);
209   }
211   return (0);
212 } /* }}} int md_entry_insert */
214 /* XXX: The lock on md must be held while calling this function! */
215 static int md_entry_insert_clone (meta_data_t *md, meta_entry_t *orig) /* {{{ */
217   meta_entry_t *e;
218   meta_entry_t *this;
219   meta_entry_t *prev;
221   /* WARNINGS :
222    *  - we do not check that md and e != NULL here. You should have done it before.
223    *  - we do not use the lock. You should have set it before.
224    */
226   e = md_entry_clone_contents(orig);
228   prev = NULL;
229   this = md->head;
230   while (this != NULL)
231   {
232     if (strcasecmp (e->key, this->key) == 0)
233       break;
235     prev = this;
236     this = this->next;
237   }
239   if (this == NULL)
240   {
241     /* This key does not exist yet. */
242     if (md->head == NULL)
243       md->head = e;
244     else
245     {
246       assert (prev != NULL);
247       prev->next = e;
248     }
250     e->next = NULL;
251   }
252   else /* (this != NULL) */
253   {
254     if (prev == NULL)
255       md->head = e;
256     else
257       prev->next = e;
259     e->next = this->next;
260   }
262   if (this != NULL)
263   {
264     this->next = NULL;
265     md_entry_free (this);
266   }
268   return (0);
269 } /* }}} int md_entry_insert_clone */
271 /* XXX: The lock on md must be held while calling this function! */
272 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
273     const char *key)
275   meta_entry_t *e;
277   if ((md == NULL) || (key == NULL))
278     return (NULL);
280   for (e = md->head; e != NULL; e = e->next)
281     if (strcasecmp (key, e->key) == 0)
282       break;
284   return (e);
285 } /* }}} meta_entry_t *md_entry_lookup */
287 /*
288  * Public functions
289  */
290 meta_data_t *meta_data_create (void) /* {{{ */
292   meta_data_t *md;
294   md = calloc (1, sizeof (*md));
295   if (md == NULL)
296   {
297     ERROR ("meta_data_create: calloc failed.");
298     return (NULL);
299   }
301   pthread_mutex_init (&md->lock, /* attr = */ NULL);
303   return (md);
304 } /* }}} meta_data_t *meta_data_create */
306 meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
308   meta_data_t *copy;
310   if (orig == NULL)
311     return (NULL);
313   copy = meta_data_create ();
314   if (copy == NULL)
315     return (NULL);
317   pthread_mutex_lock (&orig->lock);
318   copy->head = md_entry_clone (orig->head);
319   pthread_mutex_unlock (&orig->lock);
321   return (copy);
322 } /* }}} meta_data_t *meta_data_clone */
324 int meta_data_clone_merge (meta_data_t **dest, meta_data_t *orig) /* {{{ */
326   meta_entry_t *e;
328   if (orig == NULL)
329     return (0);
331   if (*dest == NULL) {
332     *dest = meta_data_clone(orig);
333     return(0);
334   }
336   pthread_mutex_lock (&orig->lock);
337   for (e=orig->head; e != NULL; e = e->next)
338   {
339     md_entry_insert_clone((*dest), e);
340   }
341   pthread_mutex_unlock (&orig->lock);
343   return (0);
344 } /* }}} int meta_data_clone_merge */
346 void meta_data_destroy (meta_data_t *md) /* {{{ */
348   if (md == NULL)
349     return;
351   md_entry_free (md->head);
352   pthread_mutex_destroy (&md->lock);
353   free (md);
354 } /* }}} void meta_data_destroy */
356 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
358   meta_entry_t *e;
360   if ((md == NULL) || (key == NULL))
361     return (-EINVAL);
363   pthread_mutex_lock (&md->lock);
365   for (e = md->head; e != NULL; e = e->next)
366   {
367     if (strcasecmp (key, e->key) == 0)
368     {
369       pthread_mutex_unlock (&md->lock);
370       return (1);
371     }
372   }
374   pthread_mutex_unlock (&md->lock);
375   return (0);
376 } /* }}} int meta_data_exists */
378 int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
380   meta_entry_t *e;
382   if ((md == NULL) || (key == NULL))
383     return -EINVAL;
385   pthread_mutex_lock (&md->lock);
387   for (e = md->head; e != NULL; e = e->next)
388   {
389     if (strcasecmp (key, e->key) == 0)
390     {
391       pthread_mutex_unlock (&md->lock);
392       return e->type;
393     }
394   }
396   pthread_mutex_unlock (&md->lock);
397   return 0;
398 } /* }}} int meta_data_type */
400 int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
402   int i = 0, count = 0;
403   meta_entry_t *e;
405   if ((md == NULL) || (toc == NULL))
406     return -EINVAL;
408   pthread_mutex_lock (&md->lock);
410   for (e = md->head; e != NULL; e = e->next)
411     ++count;
413   if (count == 0)
414   {
415     pthread_mutex_unlock (&md->lock);
416     return (count);
417   }
419   *toc = calloc(count, sizeof(**toc));
420   for (e = md->head; e != NULL; e = e->next)
421     (*toc)[i++] = strdup(e->key);
423   pthread_mutex_unlock (&md->lock);
424   return count;
425 } /* }}} int meta_data_toc */
427 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
429   meta_entry_t *this;
430   meta_entry_t *prev;
432   if ((md == NULL) || (key == NULL))
433     return (-EINVAL);
435   pthread_mutex_lock (&md->lock);
437   prev = NULL;
438   this = md->head;
439   while (this != NULL)
440   {
441     if (strcasecmp (key, this->key) == 0)
442       break;
444     prev = this;
445     this = this->next;
446   }
448   if (this == NULL)
449   {
450     pthread_mutex_unlock (&md->lock);
451     return (-ENOENT);
452   }
454   if (prev == NULL)
455     md->head = this->next;
456   else
457     prev->next = this->next;
459   pthread_mutex_unlock (&md->lock);
461   this->next = NULL;
462   md_entry_free (this);
464   return (0);
465 } /* }}} int meta_data_delete */
467 /*
468  * Add functions
469  */
470 int meta_data_add_string (meta_data_t *md, /* {{{ */
471     const char *key, const char *value)
473   meta_entry_t *e;
475   if ((md == NULL) || (key == NULL) || (value == NULL))
476     return (-EINVAL);
478   e = md_entry_alloc (key);
479   if (e == NULL)
480     return (-ENOMEM);
482   e->value.mv_string = md_strdup (value);
483   if (e->value.mv_string == NULL)
484   {
485     ERROR ("meta_data_add_string: md_strdup failed.");
486     md_entry_free (e);
487     return (-ENOMEM);
488   }
489   e->type = MD_TYPE_STRING;
491   return (md_entry_insert (md, e));
492 } /* }}} int meta_data_add_string */
494 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
495     const char *key, int64_t value)
497   meta_entry_t *e;
499   if ((md == NULL) || (key == NULL))
500     return (-EINVAL);
502   e = md_entry_alloc (key);
503   if (e == NULL)
504     return (-ENOMEM);
506   e->value.mv_signed_int = value;
507   e->type = MD_TYPE_SIGNED_INT;
509   return (md_entry_insert (md, e));
510 } /* }}} int meta_data_add_signed_int */
512 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
513     const char *key, uint64_t value)
515   meta_entry_t *e;
517   if ((md == NULL) || (key == NULL))
518     return (-EINVAL);
520   e = md_entry_alloc (key);
521   if (e == NULL)
522     return (-ENOMEM);
524   e->value.mv_unsigned_int = value;
525   e->type = MD_TYPE_UNSIGNED_INT;
527   return (md_entry_insert (md, e));
528 } /* }}} int meta_data_add_unsigned_int */
530 int meta_data_add_double (meta_data_t *md, /* {{{ */
531     const char *key, double value)
533   meta_entry_t *e;
535   if ((md == NULL) || (key == NULL))
536     return (-EINVAL);
538   e = md_entry_alloc (key);
539   if (e == NULL)
540     return (-ENOMEM);
542   e->value.mv_double = value;
543   e->type = MD_TYPE_DOUBLE;
545   return (md_entry_insert (md, e));
546 } /* }}} int meta_data_add_double */
548 int meta_data_add_boolean (meta_data_t *md, /* {{{ */
549     const char *key, _Bool value)
551   meta_entry_t *e;
553   if ((md == NULL) || (key == NULL))
554     return (-EINVAL);
556   e = md_entry_alloc (key);
557   if (e == NULL)
558     return (-ENOMEM);
560   e->value.mv_boolean = value;
561   e->type = MD_TYPE_BOOLEAN;
563   return (md_entry_insert (md, e));
564 } /* }}} int meta_data_add_boolean */
566 /*
567  * Get functions
568  */
569 int meta_data_get_string (meta_data_t *md, /* {{{ */
570     const char *key, char **value)
572   meta_entry_t *e;
573   char *temp;
575   if ((md == NULL) || (key == NULL) || (value == NULL))
576     return (-EINVAL);
578   pthread_mutex_lock (&md->lock);
580   e = md_entry_lookup (md, key);
581   if (e == NULL)
582   {
583     pthread_mutex_unlock (&md->lock);
584     return (-ENOENT);
585   }
587   if (e->type != MD_TYPE_STRING)
588   {
589     ERROR ("meta_data_get_string: Type mismatch for key `%s'", e->key);
590     pthread_mutex_unlock (&md->lock);
591     return (-ENOENT);
592   }
594   temp = md_strdup (e->value.mv_string);
595   if (temp == NULL)
596   {
597     pthread_mutex_unlock (&md->lock);
598     ERROR ("meta_data_get_string: md_strdup failed.");
599     return (-ENOMEM);
600   }
602   pthread_mutex_unlock (&md->lock);
604   *value = temp;
606   return (0);
607 } /* }}} int meta_data_get_string */
609 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
610     const char *key, int64_t *value)
612   meta_entry_t *e;
614   if ((md == NULL) || (key == NULL) || (value == NULL))
615     return (-EINVAL);
617   pthread_mutex_lock (&md->lock);
619   e = md_entry_lookup (md, key);
620   if (e == NULL)
621   {
622     pthread_mutex_unlock (&md->lock);
623     return (-ENOENT);
624   }
626   if (e->type != MD_TYPE_SIGNED_INT)
627   {
628     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
629     pthread_mutex_unlock (&md->lock);
630     return (-ENOENT);
631   }
633   *value = e->value.mv_signed_int;
635   pthread_mutex_unlock (&md->lock);
636   return (0);
637 } /* }}} int meta_data_get_signed_int */
639 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
640     const char *key, uint64_t *value)
642   meta_entry_t *e;
644   if ((md == NULL) || (key == NULL) || (value == NULL))
645     return (-EINVAL);
647   pthread_mutex_lock (&md->lock);
649   e = md_entry_lookup (md, key);
650   if (e == NULL)
651   {
652     pthread_mutex_unlock (&md->lock);
653     return (-ENOENT);
654   }
656   if (e->type != MD_TYPE_UNSIGNED_INT)
657   {
658     ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
659     pthread_mutex_unlock (&md->lock);
660     return (-ENOENT);
661   }
663   *value = e->value.mv_unsigned_int;
665   pthread_mutex_unlock (&md->lock);
666   return (0);
667 } /* }}} int meta_data_get_unsigned_int */
669 int meta_data_get_double (meta_data_t *md, /* {{{ */
670     const char *key, double *value)
672   meta_entry_t *e;
674   if ((md == NULL) || (key == NULL) || (value == NULL))
675     return (-EINVAL);
677   pthread_mutex_lock (&md->lock);
679   e = md_entry_lookup (md, key);
680   if (e == NULL)
681   {
682     pthread_mutex_unlock (&md->lock);
683     return (-ENOENT);
684   }
686   if (e->type != MD_TYPE_DOUBLE)
687   {
688     ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
689     pthread_mutex_unlock (&md->lock);
690     return (-ENOENT);
691   }
693   *value = e->value.mv_double;
695   pthread_mutex_unlock (&md->lock);
696   return (0);
697 } /* }}} int meta_data_get_double */
699 int meta_data_get_boolean (meta_data_t *md, /* {{{ */
700     const char *key, _Bool *value)
702   meta_entry_t *e;
704   if ((md == NULL) || (key == NULL) || (value == NULL))
705     return (-EINVAL);
707   pthread_mutex_lock (&md->lock);
709   e = md_entry_lookup (md, key);
710   if (e == NULL)
711   {
712     pthread_mutex_unlock (&md->lock);
713     return (-ENOENT);
714   }
716   if (e->type != MD_TYPE_BOOLEAN)
717   {
718     ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
719     pthread_mutex_unlock (&md->lock);
720     return (-ENOENT);
721   }
723   *value = e->value.mv_boolean;
725   pthread_mutex_unlock (&md->lock);
726   return (0);
727 } /* }}} int meta_data_get_boolean */
729 /* vim: set sw=2 sts=2 et fdm=marker : */