Merge branch 'collectd-4.6'
[collectd.git] / src / meta_data.c
1 /**
2  * collectd - src/meta_data.c
3  * Copyright (C) 2008  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 /*
23  * First tell the compiler to stick to the C99 and POSIX standards as close as
24  * possible.
25  */
26 #ifndef __STRICT_ANSI__ /* {{{ */
27 # define __STRICT_ANSI__
28 #endif
29
30 #ifndef _ISOC99_SOURCE
31 # define _ISOC99_SOURCE
32 #endif
33
34 #ifdef _POSIX_C_SOURCE
35 # undef _POSIX_C_SOURCE
36 #endif
37 #define _POSIX_C_SOURCE 200112L
38
39 #ifdef _XOPEN_SOURCE
40 # undef _XOPEN_SOURCE
41 #endif
42 #define _XOPEN_SOURCE 600
43
44 #ifndef _REENTRANT
45 # define _REENTRANT
46 #endif
47
48 #ifndef _THREAD_SAFE
49 # define _THREAD_SAFE
50 #endif
51
52 #ifdef _GNU_SOURCE
53 # undef _GNU_SOURCE
54 #endif
55 /* }}} */
56
57 #include "collectd.h"
58 #include "plugin.h"
59 #include "meta_data.h"
60
61 #include <pthread.h>
62
63 /*
64  * Defines
65  */
66 #define MD_TYPE_STRING       1
67 #define MD_TYPE_SIGNED_INT   2
68 #define MD_TYPE_UNSIGNED_INT 3
69 #define MD_TYPE_DOUBLE       4
70
71 /*
72  * Data types
73  */
74 union meta_value_u
75 {
76   char    *mv_string;
77   int64_t  mv_signed_int;
78   uint64_t mv_unsigned_int;
79   double   mv_double;
80 };
81 typedef union meta_value_u meta_value_t;
82
83 struct meta_entry_s;
84 typedef struct meta_entry_s meta_entry_t;
85 struct meta_entry_s
86 {
87   char         *key;
88   meta_value_t  value;
89   int           type;
90   meta_entry_t *next;
91 };
92
93 struct meta_data_s
94 {
95   meta_entry_t   *head;
96   pthread_mutex_t lock;
97 };
98
99 /*
100  * Private functions
101  */
102 static char *md_strdup (const char *orig) /* {{{ */
103 {
104   size_t sz;
105   char *dest;
106
107   if (orig == NULL)
108     return (NULL);
109
110   sz = strlen (orig) + 1;
111   dest = (char *) malloc (sz);
112   if (dest == NULL)
113     return (NULL);
114
115   memcpy (dest, orig, sz);
116
117   return (dest);
118 } /* }}} char *md_strdup */
119
120 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
121 {
122   meta_entry_t *e;
123
124   e = (meta_entry_t *) malloc (sizeof (*e));
125   if (e == NULL)
126   {
127     ERROR ("md_entry_alloc: malloc failed.");
128     return (NULL);
129   }
130   memset (e, 0, sizeof (*e));
131
132   e->key = md_strdup (key);
133   if (e->key == NULL)
134   {
135     free (e);
136     ERROR ("md_entry_alloc: md_strdup failed.");
137     return (NULL);
138   }
139
140   e->type = 0;
141   e->next = NULL;
142
143   return (e);
144 } /* }}} meta_entry_t *md_entry_alloc */
145
146 static void md_entry_free (meta_entry_t *e) /* {{{ */
147 {
148   if (e == NULL)
149     return;
150
151   free (e->key);
152
153   if (e->type == MD_TYPE_STRING)
154     free (e->value.mv_string);
155
156   if (e->next != NULL)
157     md_entry_free (e->next);
158
159   free (e);
160 } /* }}} void md_entry_free */
161
162 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
163 {
164   meta_entry_t *this;
165   meta_entry_t *prev;
166
167   if ((md == NULL) || (e == NULL))
168     return (-EINVAL);
169
170   pthread_mutex_lock (&md->lock);
171
172   prev = NULL;
173   this = md->head;
174   while (this != NULL)
175   {
176     if (strcasecmp (e->key, this->key) == 0)
177       break;
178
179     prev = this;
180     this = this->next;
181   }
182
183   if (this == NULL)
184   {
185     /* This key does not exist yet. */
186     if (md->head == NULL)
187       md->head = e;
188     else
189     {
190       assert (prev != NULL);
191       prev->next = e;
192     }
193
194     e->next = NULL;
195   }
196   else /* (this != NULL) */
197   {
198     if (prev == NULL)
199       md->head = e;
200     else
201       prev->next = e;
202
203     e->next = this->next;
204   }
205
206   pthread_mutex_unlock (&md->lock);
207
208   if (this != NULL)
209   {
210     this->next = NULL;
211     md_entry_free (this);
212   }
213
214   return (0);
215 } /* }}} int md_entry_insert */
216
217 /* XXX: The lock on md must be held while calling this function! */
218 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
219     const char *key)
220 {
221   meta_entry_t *e;
222
223   if ((md == NULL) || (key == NULL))
224     return (NULL);
225
226   for (e = md->head; e != NULL; e = e->next)
227     if (strcasecmp (key, e->key) == 0)
228       break;
229
230   return (e);
231 } /* }}} meta_entry_t *md_entry_lookup */
232
233 /*
234  * Public functions
235  */
236 meta_data_t *meta_data_create (void) /* {{{ */
237 {
238   meta_data_t *md;
239
240   md = (meta_data_t *) malloc (sizeof (*md));
241   if (md == NULL)
242   {
243     ERROR ("meta_data_create: malloc failed.");
244     return (NULL);
245   }
246   memset (md, 0, sizeof (*md));
247
248   md->head = NULL;
249   pthread_mutex_init (&md->lock, /* attr = */ NULL);
250
251   return (md);
252 } /* }}} meta_data_t *meta_data_create */
253
254 void meta_data_destroy (meta_data_t *md) /* {{{ */
255 {
256   if (md == NULL)
257     return;
258
259   md_entry_free (md->head);
260   free (md);
261 } /* }}} void meta_data_destroy */
262
263 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
264 {
265   meta_entry_t *e;
266
267   if ((md == NULL) || (key == NULL))
268     return (-EINVAL);
269
270   pthread_mutex_lock (&md->lock);
271
272   for (e = md->head; e != NULL; e = e->next)
273   {
274     if (strcasecmp (key, e->key) == 0)
275     {
276       pthread_mutex_unlock (&md->lock);
277       return (1);
278     }
279   }
280
281   pthread_mutex_unlock (&md->lock);
282   return (0);
283 } /* }}} int meta_data_exists */
284
285 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
286 {
287   meta_entry_t *this;
288   meta_entry_t *prev;
289
290   if ((md == NULL) || (key == NULL))
291     return (-EINVAL);
292
293   pthread_mutex_lock (&md->lock);
294
295   prev = NULL;
296   this = md->head;
297   while (this != NULL)
298   {
299     if (strcasecmp (key, this->key) == 0)
300       break;
301
302     prev = this;
303     this = this->next;
304   }
305
306   if (this == NULL)
307   {
308     pthread_mutex_unlock (&md->lock);
309     return (-ENOENT);
310   }
311
312   if (prev == NULL)
313     md->head = this->next;
314   else
315     prev->next = this->next;
316
317   pthread_mutex_unlock (&md->lock);
318
319   this->next = NULL;
320   md_entry_free (this);
321
322   return (0);
323 } /* }}} int meta_data_delete */
324
325 int meta_data_add_string (meta_data_t *md, /* {{{ */
326     const char *key, const char *value)
327 {
328   meta_entry_t *e;
329
330   if ((md == NULL) || (key == NULL) || (value == NULL))
331     return (-EINVAL);
332
333   e = md_entry_alloc (key);
334   if (e == NULL)
335     return (-ENOMEM);
336
337   e->value.mv_string = md_strdup (value);
338   if (e->value.mv_string == NULL)
339   {
340     ERROR ("meta_data_add_string: md_strdup failed.");
341     md_entry_free (e);
342     return (-ENOMEM);
343   }
344   e->type = MD_TYPE_STRING;
345
346   return (md_entry_insert (md, e));
347 } /* }}} int meta_data_add_string */
348
349 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
350     const char *key, int64_t value)
351 {
352   meta_entry_t *e;
353
354   if ((md == NULL) || (key == NULL))
355     return (-EINVAL);
356
357   e = md_entry_alloc (key);
358   if (e == NULL)
359     return (-ENOMEM);
360
361   e->value.mv_signed_int = value;
362   e->type = MD_TYPE_SIGNED_INT;
363
364   return (md_entry_insert (md, e));
365 } /* }}} int meta_data_add_signed_int */
366
367 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
368     const char *key, uint64_t value)
369 {
370   meta_entry_t *e;
371
372   if ((md == NULL) || (key == NULL))
373     return (-EINVAL);
374
375   e = md_entry_alloc (key);
376   if (e == NULL)
377     return (-ENOMEM);
378
379   e->value.mv_unsigned_int = value;
380   e->type = MD_TYPE_UNSIGNED_INT;
381
382   return (md_entry_insert (md, e));
383 } /* }}} int meta_data_add_unsigned_int */
384
385 int meta_data_add_double (meta_data_t *md, /* {{{ */
386     const char *key, double value)
387 {
388   meta_entry_t *e;
389
390   if ((md == NULL) || (key == NULL))
391     return (-EINVAL);
392
393   e = md_entry_alloc (key);
394   if (e == NULL)
395     return (-ENOMEM);
396
397   e->value.mv_double = value;
398   e->type = MD_TYPE_DOUBLE;
399
400   return (md_entry_insert (md, e));
401 } /* }}} int meta_data_add_double */
402
403 int meta_data_get_string (meta_data_t *md, /* {{{ */
404     const char *key, char **value)
405 {
406   meta_entry_t *e;
407   char *temp;
408
409   if ((md == NULL) || (key == NULL) || (value == NULL))
410     return (-EINVAL);
411
412   pthread_mutex_lock (&md->lock);
413
414   e = md_entry_lookup (md, key);
415   if (e == NULL)
416   {
417     pthread_mutex_unlock (&md->lock);
418     return (-ENOENT);
419   }
420
421   if (e->type != MD_TYPE_SIGNED_INT)
422   {
423     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
424     pthread_mutex_unlock (&md->lock);
425     return (-ENOENT);
426   }
427
428   temp = md_strdup (e->value.mv_string);
429   if (temp == NULL)
430   {
431     pthread_mutex_unlock (&md->lock);
432     ERROR ("meta_data_get_string: md_strdup failed.");
433     return (-ENOMEM);
434   }
435  
436   pthread_mutex_unlock (&md->lock);
437
438   *value = temp;
439
440   return (0);
441 } /* }}} int meta_data_get_string */
442
443 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
444     const char *key, int64_t *value)
445 {
446   meta_entry_t *e;
447
448   if ((md == NULL) || (key == NULL) || (value == NULL))
449     return (-EINVAL);
450
451   pthread_mutex_lock (&md->lock);
452
453   e = md_entry_lookup (md, key);
454   if (e == NULL)
455   {
456     pthread_mutex_unlock (&md->lock);
457     return (-ENOENT);
458   }
459
460   if (e->type != MD_TYPE_SIGNED_INT)
461   {
462     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
463     pthread_mutex_unlock (&md->lock);
464     return (-ENOENT);
465   }
466
467   *value = e->value.mv_signed_int;
468
469   pthread_mutex_unlock (&md->lock);
470   return (0);
471 } /* }}} int meta_data_get_signed_int */
472
473 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
474     const char *key, uint64_t *value)
475 {
476   meta_entry_t *e;
477
478   if ((md == NULL) || (key == NULL) || (value == NULL))
479     return (-EINVAL);
480
481   pthread_mutex_lock (&md->lock);
482
483   e = md_entry_lookup (md, key);
484   if (e == NULL)
485   {
486     pthread_mutex_unlock (&md->lock);
487     return (-ENOENT);
488   }
489
490   if (e->type != MD_TYPE_UNSIGNED_INT)
491   {
492     ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
493     pthread_mutex_unlock (&md->lock);
494     return (-ENOENT);
495   }
496
497   *value = e->value.mv_unsigned_int;
498
499   pthread_mutex_unlock (&md->lock);
500   return (0);
501 } /* }}} int meta_data_get_unsigned_int */
502
503 int meta_data_get_double (meta_data_t *md, /* {{{ */
504     const char *key, double *value)
505 {
506   meta_entry_t *e;
507
508   if ((md == NULL) || (key == NULL) || (value == NULL))
509     return (-EINVAL);
510
511   pthread_mutex_lock (&md->lock);
512
513   e = md_entry_lookup (md, key);
514   if (e == NULL)
515   {
516     pthread_mutex_unlock (&md->lock);
517     return (-ENOENT);
518   }
519
520   if (e->type != MD_TYPE_DOUBLE)
521   {
522     ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
523     pthread_mutex_unlock (&md->lock);
524     return (-ENOENT);
525   }
526
527   *value = e->value.mv_double;
528
529   pthread_mutex_unlock (&md->lock);
530   return (0);
531 } /* }}} int meta_data_get_double */
532
533 /* vim: set sw=2 sts=2 et fdm=marker : */