Merge branch 'collectd-4.5' into 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 #include "collectd.h"
23 #include "plugin.h"
24 #include "meta_data.h"
25
26 #include <pthread.h>
27
28 /*
29  * Defines
30  */
31 #define MD_TYPE_STRING       1
32 #define MD_TYPE_SIGNED_INT   2
33 #define MD_TYPE_UNSIGNED_INT 3
34 #define MD_TYPE_DOUBLE       4
35
36 /*
37  * Data types
38  */
39 union meta_value_u
40 {
41   char    *mv_string;
42   int64_t  mv_signed_int;
43   uint64_t mv_unsigned_int;
44   double   mv_double;
45 };
46 typedef union meta_value_u meta_value_t;
47
48 struct meta_entry_s;
49 typedef struct meta_entry_s meta_entry_t;
50 struct meta_entry_s
51 {
52   char         *key;
53   meta_value_t  value;
54   int           type;
55   meta_entry_t *next;
56 };
57
58 struct meta_data_s
59 {
60   meta_entry_t   *head;
61   pthread_mutex_t lock;
62 };
63
64 /*
65  * Private functions
66  */
67 static char *md_strdup (const char *orig) /* {{{ */
68 {
69   size_t sz;
70   char *dest;
71
72   if (orig == NULL)
73     return (NULL);
74
75   sz = strlen (orig) + 1;
76   dest = (char *) malloc (sz);
77   if (dest == NULL)
78     return (NULL);
79
80   memcpy (dest, orig, sz);
81
82   return (dest);
83 } /* }}} char *md_strdup */
84
85 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
86 {
87   meta_entry_t *e;
88
89   e = (meta_entry_t *) malloc (sizeof (*e));
90   if (e == NULL)
91   {
92     ERROR ("md_entry_alloc: malloc failed.");
93     return (NULL);
94   }
95   memset (e, 0, sizeof (*e));
96
97   e->key = md_strdup (key);
98   if (e->key == NULL)
99   {
100     free (e);
101     ERROR ("md_entry_alloc: md_strdup failed.");
102     return (NULL);
103   }
104
105   e->type = 0;
106   e->next = NULL;
107
108   return (e);
109 } /* }}} meta_entry_t *md_entry_alloc */
110
111 static void md_entry_free (meta_entry_t *e) /* {{{ */
112 {
113   if (e == NULL)
114     return;
115
116   free (e->key);
117
118   if (e->type == MD_TYPE_STRING)
119     free (e->value.mv_string);
120
121   if (e->next != NULL)
122     md_entry_free (e->next);
123
124   free (e);
125 } /* }}} void md_entry_free */
126
127 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
128 {
129   meta_entry_t *this;
130   meta_entry_t *prev;
131
132   if ((md == NULL) || (e == NULL))
133     return (-EINVAL);
134
135   pthread_mutex_lock (&md->lock);
136
137   prev = NULL;
138   this = md->head;
139   while (this != NULL)
140   {
141     if (strcasecmp (e->key, this->key) == 0)
142       break;
143
144     prev = this;
145     this = this->next;
146   }
147
148   if (this == NULL)
149   {
150     /* This key does not exist yet. */
151     if (md->head == NULL)
152       md->head = e;
153     else
154     {
155       assert (prev != NULL);
156       prev->next = e;
157     }
158
159     e->next = NULL;
160   }
161   else /* (this != NULL) */
162   {
163     if (prev == NULL)
164       md->head = e;
165     else
166       prev->next = e;
167
168     e->next = this->next;
169   }
170
171   pthread_mutex_unlock (&md->lock);
172
173   if (this != NULL)
174   {
175     this->next = NULL;
176     md_entry_free (this);
177   }
178
179   return (0);
180 } /* }}} int md_entry_insert */
181
182 /* XXX: The lock on md must be held while calling this function! */
183 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
184     const char *key)
185 {
186   meta_entry_t *e;
187
188   if ((md == NULL) || (key == NULL))
189     return (NULL);
190
191   for (e = md->head; e != NULL; e = e->next)
192     if (strcasecmp (key, e->key) == 0)
193       break;
194
195   return (e);
196 } /* }}} meta_entry_t *md_entry_lookup */
197
198 /*
199  * Public functions
200  */
201 meta_data_t *meta_data_create (void) /* {{{ */
202 {
203   meta_data_t *md;
204
205   md = (meta_data_t *) malloc (sizeof (*md));
206   if (md == NULL)
207   {
208     ERROR ("meta_data_create: malloc failed.");
209     return (NULL);
210   }
211   memset (md, 0, sizeof (*md));
212
213   md->head = NULL;
214   pthread_mutex_init (&md->lock, /* attr = */ NULL);
215
216   return (md);
217 } /* }}} meta_data_t *meta_data_create */
218
219 void meta_data_destroy (meta_data_t *md) /* {{{ */
220 {
221   if (md == NULL)
222     return;
223
224   md_entry_free (md->head);
225   free (md);
226 } /* }}} void meta_data_destroy */
227
228 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
229 {
230   meta_entry_t *e;
231
232   if ((md == NULL) || (key == NULL))
233     return (-EINVAL);
234
235   pthread_mutex_lock (&md->lock);
236
237   for (e = md->head; e != NULL; e = e->next)
238   {
239     if (strcasecmp (key, e->key) == 0)
240     {
241       pthread_mutex_unlock (&md->lock);
242       return (1);
243     }
244   }
245
246   pthread_mutex_unlock (&md->lock);
247   return (0);
248 } /* }}} int meta_data_exists */
249
250 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
251 {
252   meta_entry_t *this;
253   meta_entry_t *prev;
254
255   if ((md == NULL) || (key == NULL))
256     return (-EINVAL);
257
258   pthread_mutex_lock (&md->lock);
259
260   prev = NULL;
261   this = md->head;
262   while (this != NULL)
263   {
264     if (strcasecmp (key, this->key) == 0)
265       break;
266
267     prev = this;
268     this = this->next;
269   }
270
271   if (this == NULL)
272   {
273     pthread_mutex_unlock (&md->lock);
274     return (-ENOENT);
275   }
276
277   if (prev == NULL)
278     md->head = this->next;
279   else
280     prev->next = this->next;
281
282   pthread_mutex_unlock (&md->lock);
283
284   this->next = NULL;
285   md_entry_free (this);
286
287   return (0);
288 } /* }}} int meta_data_delete */
289
290 int meta_data_add_string (meta_data_t *md, /* {{{ */
291     const char *key, const char *value)
292 {
293   meta_entry_t *e;
294
295   if ((md == NULL) || (key == NULL) || (value == NULL))
296     return (-EINVAL);
297
298   e = md_entry_alloc (key);
299   if (e == NULL)
300     return (-ENOMEM);
301
302   e->value.mv_string = md_strdup (value);
303   if (e->value.mv_string == NULL)
304   {
305     ERROR ("meta_data_add_string: md_strdup failed.");
306     md_entry_free (e);
307     return (-ENOMEM);
308   }
309   e->type = MD_TYPE_STRING;
310
311   return (md_entry_insert (md, e));
312 } /* }}} int meta_data_add_string */
313
314 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
315     const char *key, int64_t value)
316 {
317   meta_entry_t *e;
318
319   if ((md == NULL) || (key == NULL))
320     return (-EINVAL);
321
322   e = md_entry_alloc (key);
323   if (e == NULL)
324     return (-ENOMEM);
325
326   e->value.mv_signed_int = value;
327   e->type = MD_TYPE_SIGNED_INT;
328
329   return (md_entry_insert (md, e));
330 } /* }}} int meta_data_add_signed_int */
331
332 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
333     const char *key, uint64_t value)
334 {
335   meta_entry_t *e;
336
337   if ((md == NULL) || (key == NULL))
338     return (-EINVAL);
339
340   e = md_entry_alloc (key);
341   if (e == NULL)
342     return (-ENOMEM);
343
344   e->value.mv_unsigned_int = value;
345   e->type = MD_TYPE_UNSIGNED_INT;
346
347   return (md_entry_insert (md, e));
348 } /* }}} int meta_data_add_unsigned_int */
349
350 int meta_data_add_double (meta_data_t *md, /* {{{ */
351     const char *key, double value)
352 {
353   meta_entry_t *e;
354
355   if ((md == NULL) || (key == NULL))
356     return (-EINVAL);
357
358   e = md_entry_alloc (key);
359   if (e == NULL)
360     return (-ENOMEM);
361
362   e->value.mv_double = value;
363   e->type = MD_TYPE_DOUBLE;
364
365   return (md_entry_insert (md, e));
366 } /* }}} int meta_data_add_double */
367
368 int meta_data_get_string (meta_data_t *md, /* {{{ */
369     const char *key, char **value)
370 {
371   meta_entry_t *e;
372   char *temp;
373
374   if ((md == NULL) || (key == NULL) || (value == NULL))
375     return (-EINVAL);
376
377   pthread_mutex_lock (&md->lock);
378
379   e = md_entry_lookup (md, key);
380   if (e == NULL)
381   {
382     pthread_mutex_unlock (&md->lock);
383     return (-ENOENT);
384   }
385
386   if (e->type != MD_TYPE_SIGNED_INT)
387   {
388     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
389     pthread_mutex_unlock (&md->lock);
390     return (-ENOENT);
391   }
392
393   temp = md_strdup (e->value.mv_string);
394   if (temp == NULL)
395   {
396     pthread_mutex_unlock (&md->lock);
397     ERROR ("meta_data_get_string: md_strdup failed.");
398     return (-ENOMEM);
399   }
400  
401   pthread_mutex_unlock (&md->lock);
402
403   *value = temp;
404
405   return (0);
406 } /* }}} int meta_data_get_string */
407
408 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
409     const char *key, int64_t *value)
410 {
411   meta_entry_t *e;
412
413   if ((md == NULL) || (key == NULL) || (value == NULL))
414     return (-EINVAL);
415
416   pthread_mutex_lock (&md->lock);
417
418   e = md_entry_lookup (md, key);
419   if (e == NULL)
420   {
421     pthread_mutex_unlock (&md->lock);
422     return (-ENOENT);
423   }
424
425   if (e->type != MD_TYPE_SIGNED_INT)
426   {
427     ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
428     pthread_mutex_unlock (&md->lock);
429     return (-ENOENT);
430   }
431
432   *value = e->value.mv_signed_int;
433
434   pthread_mutex_unlock (&md->lock);
435   return (0);
436 } /* }}} int meta_data_get_signed_int */
437
438 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
439     const char *key, uint64_t *value)
440 {
441   meta_entry_t *e;
442
443   if ((md == NULL) || (key == NULL) || (value == NULL))
444     return (-EINVAL);
445
446   pthread_mutex_lock (&md->lock);
447
448   e = md_entry_lookup (md, key);
449   if (e == NULL)
450   {
451     pthread_mutex_unlock (&md->lock);
452     return (-ENOENT);
453   }
454
455   if (e->type != MD_TYPE_UNSIGNED_INT)
456   {
457     ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
458     pthread_mutex_unlock (&md->lock);
459     return (-ENOENT);
460   }
461
462   *value = e->value.mv_unsigned_int;
463
464   pthread_mutex_unlock (&md->lock);
465   return (0);
466 } /* }}} int meta_data_get_unsigned_int */
467
468 int meta_data_get_double (meta_data_t *md, /* {{{ */
469     const char *key, double *value)
470 {
471   meta_entry_t *e;
472
473   if ((md == NULL) || (key == NULL) || (value == NULL))
474     return (-EINVAL);
475
476   pthread_mutex_lock (&md->lock);
477
478   e = md_entry_lookup (md, key);
479   if (e == NULL)
480   {
481     pthread_mutex_unlock (&md->lock);
482     return (-ENOENT);
483   }
484
485   if (e->type != MD_TYPE_DOUBLE)
486   {
487     ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
488     pthread_mutex_unlock (&md->lock);
489     return (-ENOENT);
490   }
491
492   *value = e->value.mv_double;
493
494   pthread_mutex_unlock (&md->lock);
495   return (0);
496 } /* }}} int meta_data_get_double */
497
498 /* vim: set sw=2 sts=2 et fdm=marker : */