Merge branch 'collectd-5.4' into 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  **/
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 = (char *) 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 = (meta_entry_t *) malloc (sizeof (*e));
88   if (e == NULL)
89   {
90     ERROR ("md_entry_alloc: malloc failed.");
91     return (NULL);
92   }
93   memset (e, 0, sizeof (*e));
94
95   e->key = md_strdup (key);
96   if (e->key == NULL)
97   {
98     free (e);
99     ERROR ("md_entry_alloc: md_strdup failed.");
100     return (NULL);
101   }
102
103   e->type = 0;
104   e->next = NULL;
105
106   return (e);
107 } /* }}} meta_entry_t *md_entry_alloc */
108
109 static meta_entry_t *md_entry_clone (const meta_entry_t *orig) /* {{{ */
110 {
111   meta_entry_t *copy;
112
113   if (orig == NULL)
114     return (NULL);
115
116   copy = md_entry_alloc (orig->key);
117   if (copy == NULL)
118     return (NULL);
119   copy->type = orig->type;
120   if (copy->type == MD_TYPE_STRING)
121     copy->value.mv_string = strdup (orig->value.mv_string);
122   else
123     copy->value = orig->value;
124
125   copy->next = md_entry_clone (orig->next);
126   return (copy);
127 } /* }}} meta_entry_t *md_entry_clone */
128
129 static void md_entry_free (meta_entry_t *e) /* {{{ */
130 {
131   if (e == NULL)
132     return;
133
134   free (e->key);
135
136   if (e->type == MD_TYPE_STRING)
137     free (e->value.mv_string);
138
139   if (e->next != NULL)
140     md_entry_free (e->next);
141
142   free (e);
143 } /* }}} void md_entry_free */
144
145 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
146 {
147   meta_entry_t *this;
148   meta_entry_t *prev;
149
150   if ((md == NULL) || (e == NULL))
151     return (-EINVAL);
152
153   pthread_mutex_lock (&md->lock);
154
155   prev = NULL;
156   this = md->head;
157   while (this != NULL)
158   {
159     if (strcasecmp (e->key, this->key) == 0)
160       break;
161
162     prev = this;
163     this = this->next;
164   }
165
166   if (this == NULL)
167   {
168     /* This key does not exist yet. */
169     if (md->head == NULL)
170       md->head = e;
171     else
172     {
173       assert (prev != NULL);
174       prev->next = e;
175     }
176
177     e->next = NULL;
178   }
179   else /* (this != NULL) */
180   {
181     if (prev == NULL)
182       md->head = e;
183     else
184       prev->next = e;
185
186     e->next = this->next;
187   }
188
189   pthread_mutex_unlock (&md->lock);
190
191   if (this != NULL)
192   {
193     this->next = NULL;
194     md_entry_free (this);
195   }
196
197   return (0);
198 } /* }}} int md_entry_insert */
199
200 /* XXX: The lock on md must be held while calling this function! */
201 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
202     const char *key)
203 {
204   meta_entry_t *e;
205
206   if ((md == NULL) || (key == NULL))
207     return (NULL);
208
209   for (e = md->head; e != NULL; e = e->next)
210     if (strcasecmp (key, e->key) == 0)
211       break;
212
213   return (e);
214 } /* }}} meta_entry_t *md_entry_lookup */
215
216 /*
217  * Public functions
218  */
219 meta_data_t *meta_data_create (void) /* {{{ */
220 {
221   meta_data_t *md;
222
223   md = (meta_data_t *) malloc (sizeof (*md));
224   if (md == NULL)
225   {
226     ERROR ("meta_data_create: malloc failed.");
227     return (NULL);
228   }
229   memset (md, 0, sizeof (*md));
230
231   md->head = NULL;
232   pthread_mutex_init (&md->lock, /* attr = */ NULL);
233
234   return (md);
235 } /* }}} meta_data_t *meta_data_create */
236
237 meta_data_t *meta_data_clone (meta_data_t *orig) /* {{{ */
238 {
239   meta_data_t *copy;
240
241   if (orig == NULL)
242     return (NULL);
243
244   copy = meta_data_create ();
245   if (copy == NULL)
246     return (NULL);
247
248   pthread_mutex_lock (&orig->lock);
249   copy->head = md_entry_clone (orig->head);
250   pthread_mutex_unlock (&orig->lock);
251
252   return (copy);
253 } /* }}} meta_data_t *meta_data_clone */
254
255 void meta_data_destroy (meta_data_t *md) /* {{{ */
256 {
257   if (md == NULL)
258     return;
259
260   md_entry_free (md->head);
261   pthread_mutex_destroy (&md->lock);
262   free (md);
263 } /* }}} void meta_data_destroy */
264
265 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
266 {
267   meta_entry_t *e;
268
269   if ((md == NULL) || (key == NULL))
270     return (-EINVAL);
271
272   pthread_mutex_lock (&md->lock);
273
274   for (e = md->head; e != NULL; e = e->next)
275   {
276     if (strcasecmp (key, e->key) == 0)
277     {
278       pthread_mutex_unlock (&md->lock);
279       return (1);
280     }
281   }
282
283   pthread_mutex_unlock (&md->lock);
284   return (0);
285 } /* }}} int meta_data_exists */
286
287 int meta_data_type (meta_data_t *md, const char *key) /* {{{ */
288 {
289   meta_entry_t *e;
290
291   if ((md == NULL) || (key == NULL))
292     return -EINVAL;
293
294   pthread_mutex_lock (&md->lock);
295
296   for (e = md->head; e != NULL; e = e->next)
297   {
298     if (strcasecmp (key, e->key) == 0)
299     {
300       pthread_mutex_unlock (&md->lock);
301       return e->type;
302     }
303   }
304
305   pthread_mutex_unlock (&md->lock);
306   return 0;
307 } /* }}} int meta_data_type */
308
309 int meta_data_toc (meta_data_t *md, char ***toc) /* {{{ */
310 {
311   int i = 0, count = 0;
312   meta_entry_t *e;
313
314   if ((md == NULL) || (toc == NULL))
315     return -EINVAL;
316
317   pthread_mutex_lock (&md->lock);
318
319   for (e = md->head; e != NULL; e = e->next)
320     ++count;    
321
322   if (count == 0)
323   {
324     pthread_mutex_unlock (&md->lock);
325     return (count);
326   }
327
328   *toc = calloc(count, sizeof(**toc));
329   for (e = md->head; e != NULL; e = e->next)
330     (*toc)[i++] = strdup(e->key);
331   
332   pthread_mutex_unlock (&md->lock);
333   return count;
334 } /* }}} int meta_data_toc */
335
336 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
337 {
338   meta_entry_t *this;
339   meta_entry_t *prev;
340
341   if ((md == NULL) || (key == NULL))
342     return (-EINVAL);
343
344   pthread_mutex_lock (&md->lock);
345
346   prev = NULL;
347   this = md->head;
348   while (this != NULL)
349   {
350     if (strcasecmp (key, this->key) == 0)
351       break;
352
353     prev = this;
354     this = this->next;
355   }
356
357   if (this == NULL)
358   {
359     pthread_mutex_unlock (&md->lock);
360     return (-ENOENT);
361   }
362
363   if (prev == NULL)
364     md->head = this->next;
365   else
366     prev->next = this->next;
367
368   pthread_mutex_unlock (&md->lock);
369
370   this->next = NULL;
371   md_entry_free (this);
372
373   return (0);
374 } /* }}} int meta_data_delete */
375
376 /*
377  * Add functions
378  */
379 int meta_data_add_string (meta_data_t *md, /* {{{ */
380     const char *key, const char *value)
381 {
382   meta_entry_t *e;
383
384   if ((md == NULL) || (key == NULL) || (value == NULL))
385     return (-EINVAL);
386
387   e = md_entry_alloc (key);
388   if (e == NULL)
389     return (-ENOMEM);
390
391   e->value.mv_string = md_strdup (value);
392   if (e->value.mv_string == NULL)
393   {
394     ERROR ("meta_data_add_string: md_strdup failed.");
395     md_entry_free (e);
396     return (-ENOMEM);
397   }
398   e->type = MD_TYPE_STRING;
399
400   return (md_entry_insert (md, e));
401 } /* }}} int meta_data_add_string */
402
403 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
404     const char *key, int64_t value)
405 {
406   meta_entry_t *e;
407
408   if ((md == NULL) || (key == NULL))
409     return (-EINVAL);
410
411   e = md_entry_alloc (key);
412   if (e == NULL)
413     return (-ENOMEM);
414
415   e->value.mv_signed_int = value;
416   e->type = MD_TYPE_SIGNED_INT;
417
418   return (md_entry_insert (md, e));
419 } /* }}} int meta_data_add_signed_int */
420
421 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
422     const char *key, uint64_t value)
423 {
424   meta_entry_t *e;
425
426   if ((md == NULL) || (key == NULL))
427     return (-EINVAL);
428
429   e = md_entry_alloc (key);
430   if (e == NULL)
431     return (-ENOMEM);
432
433   e->value.mv_unsigned_int = value;
434   e->type = MD_TYPE_UNSIGNED_INT;
435
436   return (md_entry_insert (md, e));
437 } /* }}} int meta_data_add_unsigned_int */
438
439 int meta_data_add_double (meta_data_t *md, /* {{{ */
440     const char *key, double value)
441 {
442   meta_entry_t *e;
443
444   if ((md == NULL) || (key == NULL))
445     return (-EINVAL);
446
447   e = md_entry_alloc (key);
448   if (e == NULL)
449     return (-ENOMEM);
450
451   e->value.mv_double = value;
452   e->type = MD_TYPE_DOUBLE;
453
454   return (md_entry_insert (md, e));
455 } /* }}} int meta_data_add_double */
456
457 int meta_data_add_boolean (meta_data_t *md, /* {{{ */
458     const char *key, _Bool value)
459 {
460   meta_entry_t *e;
461
462   if ((md == NULL) || (key == NULL))
463     return (-EINVAL);
464
465   e = md_entry_alloc (key);
466   if (e == NULL)
467     return (-ENOMEM);
468
469   e->value.mv_boolean = value;
470   e->type = MD_TYPE_BOOLEAN;
471
472   return (md_entry_insert (md, e));
473 } /* }}} int meta_data_add_boolean */
474
475 /*
476  * Get functions
477  */
478 int meta_data_get_string (meta_data_t *md, /* {{{ */
479     const char *key, char **value)
480 {
481   meta_entry_t *e;
482   char *temp;
483
484   if ((md == NULL) || (key == NULL) || (value == NULL))
485     return (-EINVAL);
486
487   pthread_mutex_lock (&md->lock);
488
489   e = md_entry_lookup (md, key);
490   if (e == NULL)
491   {
492     pthread_mutex_unlock (&md->lock);
493     return (-ENOENT);
494   }
495
496   if (e->type != MD_TYPE_STRING)
497   {
498     ERROR ("meta_data_get_string: Type mismatch for key `%s'", e->key);
499     pthread_mutex_unlock (&md->lock);
500     return (-ENOENT);
501   }
502
503   temp = md_strdup (e->value.mv_string);
504   if (temp == NULL)
505   {
506     pthread_mutex_unlock (&md->lock);
507     ERROR ("meta_data_get_string: md_strdup failed.");
508     return (-ENOMEM);
509   }
510  
511   pthread_mutex_unlock (&md->lock);
512
513   *value = temp;
514
515   return (0);
516 } /* }}} int meta_data_get_string */
517
518 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
519     const char *key, int64_t *value)
520 {
521   meta_entry_t *e;
522
523   if ((md == NULL) || (key == NULL) || (value == NULL))
524     return (-EINVAL);
525
526   pthread_mutex_lock (&md->lock);
527
528   e = md_entry_lookup (md, key);
529   if (e == NULL)
530   {
531     pthread_mutex_unlock (&md->lock);
532     return (-ENOENT);
533   }
534
535   if (e->type != MD_TYPE_SIGNED_INT)
536   {
537     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
538     pthread_mutex_unlock (&md->lock);
539     return (-ENOENT);
540   }
541
542   *value = e->value.mv_signed_int;
543
544   pthread_mutex_unlock (&md->lock);
545   return (0);
546 } /* }}} int meta_data_get_signed_int */
547
548 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
549     const char *key, uint64_t *value)
550 {
551   meta_entry_t *e;
552
553   if ((md == NULL) || (key == NULL) || (value == NULL))
554     return (-EINVAL);
555
556   pthread_mutex_lock (&md->lock);
557
558   e = md_entry_lookup (md, key);
559   if (e == NULL)
560   {
561     pthread_mutex_unlock (&md->lock);
562     return (-ENOENT);
563   }
564
565   if (e->type != MD_TYPE_UNSIGNED_INT)
566   {
567     ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
568     pthread_mutex_unlock (&md->lock);
569     return (-ENOENT);
570   }
571
572   *value = e->value.mv_unsigned_int;
573
574   pthread_mutex_unlock (&md->lock);
575   return (0);
576 } /* }}} int meta_data_get_unsigned_int */
577
578 int meta_data_get_double (meta_data_t *md, /* {{{ */
579     const char *key, double *value)
580 {
581   meta_entry_t *e;
582
583   if ((md == NULL) || (key == NULL) || (value == NULL))
584     return (-EINVAL);
585
586   pthread_mutex_lock (&md->lock);
587
588   e = md_entry_lookup (md, key);
589   if (e == NULL)
590   {
591     pthread_mutex_unlock (&md->lock);
592     return (-ENOENT);
593   }
594
595   if (e->type != MD_TYPE_DOUBLE)
596   {
597     ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
598     pthread_mutex_unlock (&md->lock);
599     return (-ENOENT);
600   }
601
602   *value = e->value.mv_double;
603
604   pthread_mutex_unlock (&md->lock);
605   return (0);
606 } /* }}} int meta_data_get_double */
607
608 int meta_data_get_boolean (meta_data_t *md, /* {{{ */
609     const char *key, _Bool *value)
610 {
611   meta_entry_t *e;
612
613   if ((md == NULL) || (key == NULL) || (value == NULL))
614     return (-EINVAL);
615
616   pthread_mutex_lock (&md->lock);
617
618   e = md_entry_lookup (md, key);
619   if (e == NULL)
620   {
621     pthread_mutex_unlock (&md->lock);
622     return (-ENOENT);
623   }
624
625   if (e->type != MD_TYPE_BOOLEAN)
626   {
627     ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
628     pthread_mutex_unlock (&md->lock);
629     return (-ENOENT);
630   }
631
632   *value = e->value.mv_boolean;
633
634   pthread_mutex_unlock (&md->lock);
635   return (0);
636 } /* }}} int meta_data_get_boolean */
637
638 /* vim: set sw=2 sts=2 et fdm=marker : */