1 /**
2 * collectd - src/meta_data.c
3 * Copyright (C) 2008,2009 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 **/
22 #include "collectd.h"
23 #include "plugin.h"
24 #include "meta_data.h"
26 #include <pthread.h>
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 #define MD_TYPE_BOOLEAN 5
37 /*
38 * Data types
39 */
40 union meta_value_u
41 {
42 char *mv_string;
43 int64_t mv_signed_int;
44 uint64_t mv_unsigned_int;
45 double mv_double;
46 _Bool mv_boolean;
47 };
48 typedef union meta_value_u meta_value_t;
50 struct meta_entry_s;
51 typedef struct meta_entry_s meta_entry_t;
52 struct meta_entry_s
53 {
54 char *key;
55 meta_value_t value;
56 int type;
57 meta_entry_t *next;
58 };
60 struct meta_data_s
61 {
62 meta_entry_t *head;
63 pthread_mutex_t lock;
64 };
66 /*
67 * Private functions
68 */
69 static char *md_strdup (const char *orig) /* {{{ */
70 {
71 size_t sz;
72 char *dest;
74 if (orig == NULL)
75 return (NULL);
77 sz = strlen (orig) + 1;
78 dest = (char *) malloc (sz);
79 if (dest == NULL)
80 return (NULL);
82 memcpy (dest, orig, sz);
84 return (dest);
85 } /* }}} char *md_strdup */
87 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
88 {
89 meta_entry_t *e;
91 e = (meta_entry_t *) malloc (sizeof (*e));
92 if (e == NULL)
93 {
94 ERROR ("md_entry_alloc: malloc failed.");
95 return (NULL);
96 }
97 memset (e, 0, sizeof (*e));
99 e->key = md_strdup (key);
100 if (e->key == NULL)
101 {
102 free (e);
103 ERROR ("md_entry_alloc: md_strdup failed.");
104 return (NULL);
105 }
107 e->type = 0;
108 e->next = NULL;
110 return (e);
111 } /* }}} meta_entry_t *md_entry_alloc */
113 static void md_entry_free (meta_entry_t *e) /* {{{ */
114 {
115 if (e == NULL)
116 return;
118 free (e->key);
120 if (e->type == MD_TYPE_STRING)
121 free (e->value.mv_string);
123 if (e->next != NULL)
124 md_entry_free (e->next);
126 free (e);
127 } /* }}} void md_entry_free */
129 static int md_entry_insert (meta_data_t *md, meta_entry_t *e) /* {{{ */
130 {
131 meta_entry_t *this;
132 meta_entry_t *prev;
134 if ((md == NULL) || (e == NULL))
135 return (-EINVAL);
137 pthread_mutex_lock (&md->lock);
139 prev = NULL;
140 this = md->head;
141 while (this != NULL)
142 {
143 if (strcasecmp (e->key, this->key) == 0)
144 break;
146 prev = this;
147 this = this->next;
148 }
150 if (this == NULL)
151 {
152 /* This key does not exist yet. */
153 if (md->head == NULL)
154 md->head = e;
155 else
156 {
157 assert (prev != NULL);
158 prev->next = e;
159 }
161 e->next = NULL;
162 }
163 else /* (this != NULL) */
164 {
165 if (prev == NULL)
166 md->head = e;
167 else
168 prev->next = e;
170 e->next = this->next;
171 }
173 pthread_mutex_unlock (&md->lock);
175 if (this != NULL)
176 {
177 this->next = NULL;
178 md_entry_free (this);
179 }
181 return (0);
182 } /* }}} int md_entry_insert */
184 /* XXX: The lock on md must be held while calling this function! */
185 static meta_entry_t *md_entry_lookup (meta_data_t *md, /* {{{ */
186 const char *key)
187 {
188 meta_entry_t *e;
190 if ((md == NULL) || (key == NULL))
191 return (NULL);
193 for (e = md->head; e != NULL; e = e->next)
194 if (strcasecmp (key, e->key) == 0)
195 break;
197 return (e);
198 } /* }}} meta_entry_t *md_entry_lookup */
200 /*
201 * Public functions
202 */
203 meta_data_t *meta_data_create (void) /* {{{ */
204 {
205 meta_data_t *md;
207 md = (meta_data_t *) malloc (sizeof (*md));
208 if (md == NULL)
209 {
210 ERROR ("meta_data_create: malloc failed.");
211 return (NULL);
212 }
213 memset (md, 0, sizeof (*md));
215 md->head = NULL;
216 pthread_mutex_init (&md->lock, /* attr = */ NULL);
218 return (md);
219 } /* }}} meta_data_t *meta_data_create */
221 void meta_data_destroy (meta_data_t *md) /* {{{ */
222 {
223 if (md == NULL)
224 return;
226 md_entry_free (md->head);
227 free (md);
228 } /* }}} void meta_data_destroy */
230 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
231 {
232 meta_entry_t *e;
234 if ((md == NULL) || (key == NULL))
235 return (-EINVAL);
237 pthread_mutex_lock (&md->lock);
239 for (e = md->head; e != NULL; e = e->next)
240 {
241 if (strcasecmp (key, e->key) == 0)
242 {
243 pthread_mutex_unlock (&md->lock);
244 return (1);
245 }
246 }
248 pthread_mutex_unlock (&md->lock);
249 return (0);
250 } /* }}} int meta_data_exists */
252 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
253 {
254 meta_entry_t *this;
255 meta_entry_t *prev;
257 if ((md == NULL) || (key == NULL))
258 return (-EINVAL);
260 pthread_mutex_lock (&md->lock);
262 prev = NULL;
263 this = md->head;
264 while (this != NULL)
265 {
266 if (strcasecmp (key, this->key) == 0)
267 break;
269 prev = this;
270 this = this->next;
271 }
273 if (this == NULL)
274 {
275 pthread_mutex_unlock (&md->lock);
276 return (-ENOENT);
277 }
279 if (prev == NULL)
280 md->head = this->next;
281 else
282 prev->next = this->next;
284 pthread_mutex_unlock (&md->lock);
286 this->next = NULL;
287 md_entry_free (this);
289 return (0);
290 } /* }}} int meta_data_delete */
292 /*
293 * Add functions
294 */
295 int meta_data_add_string (meta_data_t *md, /* {{{ */
296 const char *key, const char *value)
297 {
298 meta_entry_t *e;
300 if ((md == NULL) || (key == NULL) || (value == NULL))
301 return (-EINVAL);
303 e = md_entry_alloc (key);
304 if (e == NULL)
305 return (-ENOMEM);
307 e->value.mv_string = md_strdup (value);
308 if (e->value.mv_string == NULL)
309 {
310 ERROR ("meta_data_add_string: md_strdup failed.");
311 md_entry_free (e);
312 return (-ENOMEM);
313 }
314 e->type = MD_TYPE_STRING;
316 return (md_entry_insert (md, e));
317 } /* }}} int meta_data_add_string */
319 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
320 const char *key, int64_t value)
321 {
322 meta_entry_t *e;
324 if ((md == NULL) || (key == NULL))
325 return (-EINVAL);
327 e = md_entry_alloc (key);
328 if (e == NULL)
329 return (-ENOMEM);
331 e->value.mv_signed_int = value;
332 e->type = MD_TYPE_SIGNED_INT;
334 return (md_entry_insert (md, e));
335 } /* }}} int meta_data_add_signed_int */
337 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
338 const char *key, uint64_t value)
339 {
340 meta_entry_t *e;
342 if ((md == NULL) || (key == NULL))
343 return (-EINVAL);
345 e = md_entry_alloc (key);
346 if (e == NULL)
347 return (-ENOMEM);
349 e->value.mv_unsigned_int = value;
350 e->type = MD_TYPE_UNSIGNED_INT;
352 return (md_entry_insert (md, e));
353 } /* }}} int meta_data_add_unsigned_int */
355 int meta_data_add_double (meta_data_t *md, /* {{{ */
356 const char *key, double value)
357 {
358 meta_entry_t *e;
360 if ((md == NULL) || (key == NULL))
361 return (-EINVAL);
363 e = md_entry_alloc (key);
364 if (e == NULL)
365 return (-ENOMEM);
367 e->value.mv_double = value;
368 e->type = MD_TYPE_DOUBLE;
370 return (md_entry_insert (md, e));
371 } /* }}} int meta_data_add_double */
373 int meta_data_add_boolean (meta_data_t *md, /* {{{ */
374 const char *key, _Bool value)
375 {
376 meta_entry_t *e;
378 if ((md == NULL) || (key == NULL))
379 return (-EINVAL);
381 e = md_entry_alloc (key);
382 if (e == NULL)
383 return (-ENOMEM);
385 e->value.mv_boolean = value;
386 e->type = MD_TYPE_BOOLEAN;
388 return (md_entry_insert (md, e));
389 } /* }}} int meta_data_add_boolean */
391 /*
392 * Get functions
393 */
394 int meta_data_get_string (meta_data_t *md, /* {{{ */
395 const char *key, char **value)
396 {
397 meta_entry_t *e;
398 char *temp;
400 if ((md == NULL) || (key == NULL) || (value == NULL))
401 return (-EINVAL);
403 pthread_mutex_lock (&md->lock);
405 e = md_entry_lookup (md, key);
406 if (e == NULL)
407 {
408 pthread_mutex_unlock (&md->lock);
409 return (-ENOENT);
410 }
412 if (e->type != MD_TYPE_SIGNED_INT)
413 {
414 ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
415 pthread_mutex_unlock (&md->lock);
416 return (-ENOENT);
417 }
419 temp = md_strdup (e->value.mv_string);
420 if (temp == NULL)
421 {
422 pthread_mutex_unlock (&md->lock);
423 ERROR ("meta_data_get_string: md_strdup failed.");
424 return (-ENOMEM);
425 }
427 pthread_mutex_unlock (&md->lock);
429 *value = temp;
431 return (0);
432 } /* }}} int meta_data_get_string */
434 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
435 const char *key, int64_t *value)
436 {
437 meta_entry_t *e;
439 if ((md == NULL) || (key == NULL) || (value == NULL))
440 return (-EINVAL);
442 pthread_mutex_lock (&md->lock);
444 e = md_entry_lookup (md, key);
445 if (e == NULL)
446 {
447 pthread_mutex_unlock (&md->lock);
448 return (-ENOENT);
449 }
451 if (e->type != MD_TYPE_SIGNED_INT)
452 {
453 ERROR ("meta_data_get_signed_int: Type mismatch for key `%s'", e->key);
454 pthread_mutex_unlock (&md->lock);
455 return (-ENOENT);
456 }
458 *value = e->value.mv_signed_int;
460 pthread_mutex_unlock (&md->lock);
461 return (0);
462 } /* }}} int meta_data_get_signed_int */
464 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
465 const char *key, uint64_t *value)
466 {
467 meta_entry_t *e;
469 if ((md == NULL) || (key == NULL) || (value == NULL))
470 return (-EINVAL);
472 pthread_mutex_lock (&md->lock);
474 e = md_entry_lookup (md, key);
475 if (e == NULL)
476 {
477 pthread_mutex_unlock (&md->lock);
478 return (-ENOENT);
479 }
481 if (e->type != MD_TYPE_UNSIGNED_INT)
482 {
483 ERROR ("meta_data_get_unsigned_int: Type mismatch for key `%s'", e->key);
484 pthread_mutex_unlock (&md->lock);
485 return (-ENOENT);
486 }
488 *value = e->value.mv_unsigned_int;
490 pthread_mutex_unlock (&md->lock);
491 return (0);
492 } /* }}} int meta_data_get_unsigned_int */
494 int meta_data_get_double (meta_data_t *md, /* {{{ */
495 const char *key, double *value)
496 {
497 meta_entry_t *e;
499 if ((md == NULL) || (key == NULL) || (value == NULL))
500 return (-EINVAL);
502 pthread_mutex_lock (&md->lock);
504 e = md_entry_lookup (md, key);
505 if (e == NULL)
506 {
507 pthread_mutex_unlock (&md->lock);
508 return (-ENOENT);
509 }
511 if (e->type != MD_TYPE_DOUBLE)
512 {
513 ERROR ("meta_data_get_double: Type mismatch for key `%s'", e->key);
514 pthread_mutex_unlock (&md->lock);
515 return (-ENOENT);
516 }
518 *value = e->value.mv_double;
520 pthread_mutex_unlock (&md->lock);
521 return (0);
522 } /* }}} int meta_data_get_double */
524 int meta_data_get_boolean (meta_data_t *md, /* {{{ */
525 const char *key, _Bool *value)
526 {
527 meta_entry_t *e;
529 if ((md == NULL) || (key == NULL) || (value == NULL))
530 return (-EINVAL);
532 pthread_mutex_lock (&md->lock);
534 e = md_entry_lookup (md, key);
535 if (e == NULL)
536 {
537 pthread_mutex_unlock (&md->lock);
538 return (-ENOENT);
539 }
541 if (e->type != MD_TYPE_BOOLEAN)
542 {
543 ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
544 pthread_mutex_unlock (&md->lock);
545 return (-ENOENT);
546 }
548 *value = e->value.mv_boolean;
550 pthread_mutex_unlock (&md->lock);
551 return (0);
552 } /* }}} int meta_data_get_boolean */
554 /* vim: set sw=2 sts=2 et fdm=marker : */