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