Merge pull request #1710 from rpv-tomsk/perl-plugin-fixes
[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  **/
26
27 #include "collectd.h"
28 #include "plugin.h"
29 #include "meta_data.h"
30
31 #include <pthread.h>
32
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;
45
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 };
55
56 struct meta_data_s
57 {
58   meta_entry_t   *head;
59   pthread_mutex_t lock;
60 };
61
62 /*
63  * Private functions
64  */
65 static char *md_strdup (const char *orig) /* {{{ */
66 {
67   size_t sz;
68   char *dest;
69
70   if (orig == NULL)
71     return (NULL);
72
73   sz = strlen (orig) + 1;
74   dest = malloc (sz);
75   if (dest == NULL)
76     return (NULL);
77
78   memcpy (dest, orig, sz);
79
80   return (dest);
81 } /* }}} char *md_strdup */
82
83 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
84 {
85   meta_entry_t *e;
86
87   e = calloc (1, sizeof (*e));
88   if (e == NULL)
89   {
90     ERROR ("md_entry_alloc: calloc failed.");
91     return (NULL);
92   }
93
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   }
101
102   e->type = 0;
103   e->next = NULL;
104
105   return (e);
106 } /* }}} meta_entry_t *md_entry_alloc */
107
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) /* {{{ */
110 {
111   meta_entry_t *copy;
112
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    */
117
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;
126
127   return (copy);
128 } /* }}} meta_entry_t *md_entry_clone_contents */
129
130 static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
131 {
132   meta_entry_t *copy;
133
134   if (orig == NULL)
135     return (NULL);
136
137   copy = md_entry_clone_contents(orig);
138
139   copy->next = md_entry_clone (orig->next);
140   return (copy);
141 } /* }}} meta_entry_t *md_entry_clone */
142
143 static void md_entry_free (meta_entry_t *e) /* {{{ */
144 {
145   if (e == NULL)
146     return;
147
148   free (e->key);
149
150   if (e->type == MD_TYPE_STRING)
151     free (e->value.mv_string);
152
153   if (e->next != NULL)
154     md_entry_free (e->next);
155
156   free (e);
157 } /* }}} void md_entry_free */
158
159 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
160 {
161   meta_entry_t *this;
162   meta_entry_t *prev;
163
164   if ((md == NULL) || (e == NULL))
165     return (-EINVAL);
166
167   pthread_mutex_lock (&md->lock);
168
169   prev = NULL;
170   this = md->head;
171   while (this != NULL)
172   {
173     if (strcasecmp (e->key, this->key) == 0)
174       break;
175
176     prev = this;
177     this = this->next;
178   }
179
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     }
190
191     e->next = NULL;
192   }
193   else /* (this != NULL) */
194   {
195     if (prev == NULL)
196       md->head = e;
197     else
198       prev->next = e;
199
200     e->next = this->next;
201   }
202
203   pthread_mutex_unlock (&md->lock);
204
205   if (this != NULL)
206   {
207     this->next = NULL;
208     md_entry_free (this);
209   }
210
211   return (0);
212 } /* }}} int md_entry_insert */
213
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) /* {{{ */
216 {
217   meta_entry_t *e;
218   meta_entry_t *this;
219   meta_entry_t *prev;
220
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    */
225
226   e = md_entry_clone_contents(orig);
227
228   prev = NULL;
229   this = md->head;
230   while (this != NULL)
231   {
232     if (strcasecmp (e->key, this->key) == 0)
233       break;
234
235     prev = this;
236     this = this->next;
237   }
238
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     }
249
250     e->next = NULL;
251   }
252   else /* (this != NULL) */
253   {
254     if (prev == NULL)
255       md->head = e;
256     else
257       prev->next = e;
258
259     e->next = this->next;
260   }
261
262   if (this != NULL)
263   {
264     this->next = NULL;
265     md_entry_free (this);
266   }
267
268   return (0);
269 } /* }}} int md_entry_insert_clone */
270
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)
274 {
275   meta_entry_t *e;
276
277   if ((md == NULL) || (key == NULL))
278     return (NULL);
279
280   for (e = md->head; e != NULL; e = e->next)
281     if (strcasecmp (key, e->key) == 0)
282       break;
283
284   return (e);
285 } /* }}} meta_entry_t *md_entry_lookup */
286
287 /*
288  * Public functions
289  */
290 meta_data_t *meta_data_create (void) /* {{{ */
291 {
292   meta_data_t *md;
293
294   md = calloc (1, sizeof (*md));
295   if (md == NULL)
296   {
297     ERROR ("meta_data_create: calloc failed.");
298     return (NULL);
299   }
300
301   pthread_mutex_init (&md->lock, /* attr = */ NULL);
302
303   return (md);
304 } /* }}} meta_data_t *meta_data_create */
305
306 meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
307 {
308   meta_data_t *copy;
309
310   if (orig == NULL)
311     return (NULL);
312
313   copy = meta_data_create ();
314   if (copy == NULL)
315     return (NULL);
316
317   pthread_mutex_lock (&orig->lock);
318   copy->head = md_entry_clone (orig->head);
319   pthread_mutex_unlock (&orig->lock);
320
321   return (copy);
322 } /* }}} meta_data_t *meta_data_clone */
323
324 int meta_data_clone_merge (meta_data_t **dest, meta_data_t *orig) /* {{{ */
325 {
326   meta_entry_t *e;
327
328   if (orig == NULL)
329     return (0);
330
331   if (*dest == NULL) {
332     *dest = meta_data_clone(orig);
333     return(0);
334   }
335
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);
342
343   return (0);
344 } /* }}} int meta_data_clone_merge */
345
346 void meta_data_destroy (meta_data_t *md) /* {{{ */
347 {
348   if (md == NULL)
349     return;
350
351   md_entry_free (md->head);
352   pthread_mutex_destroy (&md->lock);
353   free (md);
354 } /* }}} void meta_data_destroy */
355
356 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
357 {
358   meta_entry_t *e;
359
360   if ((md == NULL) || (key == NULL))
361     return (-EINVAL);
362
363   pthread_mutex_lock (&md->lock);
364
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   }
373
374   pthread_mutex_unlock (&md->lock);
375   return (0);
376 } /* }}} int meta_data_exists */
377
378 int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
379 {
380   meta_entry_t *e;
381
382   if ((md == NULL) || (key == NULL))
383     return -EINVAL;
384
385   pthread_mutex_lock (&md->lock);
386
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   }
395
396   pthread_mutex_unlock (&md->lock);
397   return 0;
398 } /* }}} int meta_data_type */
399
400 int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
401 {
402   int i = 0, count = 0;
403   meta_entry_t *e;
404
405   if ((md == NULL) || (toc == NULL))
406     return -EINVAL;
407
408   pthread_mutex_lock (&md->lock);
409
410   for (e = md->head; e != NULL; e = e->next)
411     ++count;
412
413   if (count == 0)
414   {
415     pthread_mutex_unlock (&md->lock);
416     return (count);
417   }
418
419   *toc = calloc(count, sizeof(**toc));
420   for (e = md->head; e != NULL; e = e->next)
421     (*toc)[i++] = strdup(e->key);
422
423   pthread_mutex_unlock (&md->lock);
424   return count;
425 } /* }}} int meta_data_toc */
426
427 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
428 {
429   meta_entry_t *this;
430   meta_entry_t *prev;
431
432   if ((md == NULL) || (key == NULL))
433     return (-EINVAL);
434
435   pthread_mutex_lock (&md->lock);
436
437   prev = NULL;
438   this = md->head;
439   while (this != NULL)
440   {
441     if (strcasecmp (key, this->key) == 0)
442       break;
443
444     prev = this;
445     this = this->next;
446   }
447
448   if (this == NULL)
449   {
450     pthread_mutex_unlock (&md->lock);
451     return (-ENOENT);
452   }
453
454   if (prev == NULL)
455     md->head = this->next;
456   else
457     prev->next = this->next;
458
459   pthread_mutex_unlock (&md->lock);
460
461   this->next = NULL;
462   md_entry_free (this);
463
464   return (0);
465 } /* }}} int meta_data_delete */
466
467 /*
468  * Add functions
469  */
470 int meta_data_add_string (meta_data_t *md, /* {{{ */
471     const char *key, const char *value)
472 {
473   meta_entry_t *e;
474
475   if ((md == NULL) || (key == NULL) || (value == NULL))
476     return (-EINVAL);
477
478   e = md_entry_alloc (key);
479   if (e == NULL)
480     return (-ENOMEM);
481
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;
490
491   return (md_entry_insert (md, e));
492 } /* }}} int meta_data_add_string */
493
494 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
495     const char *key, int64_t value)
496 {
497   meta_entry_t *e;
498
499   if ((md == NULL) || (key == NULL))
500     return (-EINVAL);
501
502   e = md_entry_alloc (key);
503   if (e == NULL)
504     return (-ENOMEM);
505
506   e->value.mv_signed_int = value;
507   e->type = MD_TYPE_SIGNED_INT;
508
509   return (md_entry_insert (md, e));
510 } /* }}} int meta_data_add_signed_int */
511
512 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
513     const char *key, uint64_t value)
514 {
515   meta_entry_t *e;
516
517   if ((md == NULL) || (key == NULL))
518     return (-EINVAL);
519
520   e = md_entry_alloc (key);
521   if (e == NULL)
522     return (-ENOMEM);
523
524   e->value.mv_unsigned_int = value;
525   e->type = MD_TYPE_UNSIGNED_INT;
526
527   return (md_entry_insert (md, e));
528 } /* }}} int meta_data_add_unsigned_int */
529
530 int meta_data_add_double (meta_data_t *md, /* {{{ */
531     const char *key, double value)
532 {
533   meta_entry_t *e;
534
535   if ((md == NULL) || (key == NULL))
536     return (-EINVAL);
537
538   e = md_entry_alloc (key);
539   if (e == NULL)
540     return (-ENOMEM);
541
542   e->value.mv_double = value;
543   e->type = MD_TYPE_DOUBLE;
544
545   return (md_entry_insert (md, e));
546 } /* }}} int meta_data_add_double */
547
548 int meta_data_add_boolean (meta_data_t *md, /* {{{ */
549     const char *key, _Bool value)
550 {
551   meta_entry_t *e;
552
553   if ((md == NULL) || (key == NULL))
554     return (-EINVAL);
555
556   e = md_entry_alloc (key);
557   if (e == NULL)
558     return (-ENOMEM);
559
560   e->value.mv_boolean = value;
561   e->type = MD_TYPE_BOOLEAN;
562
563   return (md_entry_insert (md, e));
564 } /* }}} int meta_data_add_boolean */
565
566 /*
567  * Get functions
568  */
569 int meta_data_get_string (meta_data_t *md, /* {{{ */
570     const char *key, char **value)
571 {
572   meta_entry_t *e;
573   char *temp;
574
575   if ((md == NULL) || (key == NULL) || (value == NULL))
576     return (-EINVAL);
577
578   pthread_mutex_lock (&md->lock);
579
580   e = md_entry_lookup (md, key);
581   if (e == NULL)
582   {
583     pthread_mutex_unlock (&md->lock);
584     return (-ENOENT);
585   }
586
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   }
593
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   }
601
602   pthread_mutex_unlock (&md->lock);
603
604   *value = temp;
605
606   return (0);
607 } /* }}} int meta_data_get_string */
608
609 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
610     const char *key, int64_t *value)
611 {
612   meta_entry_t *e;
613
614   if ((md == NULL) || (key == NULL) || (value == NULL))
615     return (-EINVAL);
616
617   pthread_mutex_lock (&md->lock);
618
619   e = md_entry_lookup (md, key);
620   if (e == NULL)
621   {
622     pthread_mutex_unlock (&md->lock);
623     return (-ENOENT);
624   }
625
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   }
632
633   *value = e->value.mv_signed_int;
634
635   pthread_mutex_unlock (&md->lock);
636   return (0);
637 } /* }}} int meta_data_get_signed_int */
638
639 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
640     const char *key, uint64_t *value)
641 {
642   meta_entry_t *e;
643
644   if ((md == NULL) || (key == NULL) || (value == NULL))
645     return (-EINVAL);
646
647   pthread_mutex_lock (&md->lock);
648
649   e = md_entry_lookup (md, key);
650   if (e == NULL)
651   {
652     pthread_mutex_unlock (&md->lock);
653     return (-ENOENT);
654   }
655
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   }
662
663   *value = e->value.mv_unsigned_int;
664
665   pthread_mutex_unlock (&md->lock);
666   return (0);
667 } /* }}} int meta_data_get_unsigned_int */
668
669 int meta_data_get_double (meta_data_t *md, /* {{{ */
670     const char *key, double *value)
671 {
672   meta_entry_t *e;
673
674   if ((md == NULL) || (key == NULL) || (value == NULL))
675     return (-EINVAL);
676
677   pthread_mutex_lock (&md->lock);
678
679   e = md_entry_lookup (md, key);
680   if (e == NULL)
681   {
682     pthread_mutex_unlock (&md->lock);
683     return (-ENOENT);
684   }
685
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   }
692
693   *value = e->value.mv_double;
694
695   pthread_mutex_unlock (&md->lock);
696   return (0);
697 } /* }}} int meta_data_get_double */
698
699 int meta_data_get_boolean (meta_data_t *md, /* {{{ */
700     const char *key, _Bool *value)
701 {
702   meta_entry_t *e;
703
704   if ((md == NULL) || (key == NULL) || (value == NULL))
705     return (-EINVAL);
706
707   pthread_mutex_lock (&md->lock);
708
709   e = md_entry_lookup (md, key);
710   if (e == NULL)
711   {
712     pthread_mutex_unlock (&md->lock);
713     return (-ENOENT);
714   }
715
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   }
722
723   *value = e->value.mv_boolean;
724
725   pthread_mutex_unlock (&md->lock);
726   return (0);
727 } /* }}} int meta_data_get_boolean */
728
729 /* vim: set sw=2 sts=2 et fdm=marker : */