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 **/
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
30 #ifndef _ISOC99_SOURCE
31 # define _ISOC99_SOURCE
32 #endif
34 #ifdef _POSIX_C_SOURCE
35 # undef _POSIX_C_SOURCE
36 #endif
37 #define _POSIX_C_SOURCE 200112L
39 #ifdef _XOPEN_SOURCE
40 # undef _XOPEN_SOURCE
41 #endif
42 #define _XOPEN_SOURCE 600
44 #ifndef _REENTRANT
45 # define _REENTRANT
46 #endif
48 #ifndef _THREAD_SAFE
49 # define _THREAD_SAFE
50 #endif
52 #ifdef _GNU_SOURCE
53 # undef _GNU_SOURCE
54 #endif
55 /* }}} */
57 #include "collectd.h"
58 #include "plugin.h"
59 #include "meta_data.h"
61 #include <pthread.h>
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
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;
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 };
93 struct meta_data_s
94 {
95 meta_entry_t *head;
96 pthread_mutex_t lock;
97 };
99 /*
100 * Private functions
101 */
102 static char *md_strdup (const char *orig) /* {{{ */
103 {
104 size_t sz;
105 char *dest;
107 if (orig == NULL)
108 return (NULL);
110 sz = strlen (orig) + 1;
111 dest = (char *) malloc (sz);
112 if (dest == NULL)
113 return (NULL);
115 memcpy (dest, orig, sz);
117 return (dest);
118 } /* }}} char *md_strdup */
120 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
121 {
122 meta_entry_t *e;
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));
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 }
140 e->type = 0;
141 e->next = NULL;
143 return (e);
144 } /* }}} meta_entry_t *md_entry_alloc */
146 static void md_entry_free (meta_entry_t *e) /* {{{ */
147 {
148 if (e == NULL)
149 return;
151 free (e->key);
153 if (e->type == MD_TYPE_STRING)
154 free (e->value.mv_string);
156 if (e->next != NULL)
157 md_entry_free (e->next);
159 free (e);
160 } /* }}} void md_entry_free */
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;
167 if ((md == NULL) || (e == NULL))
168 return (-EINVAL);
170 pthread_mutex_lock (&md->lock);
172 prev = NULL;
173 this = md->head;
174 while (this != NULL)
175 {
176 if (strcasecmp (e->key, this->key) == 0)
177 break;
179 prev = this;
180 this = this->next;
181 }
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 }
194 e->next = NULL;
195 }
196 else /* (this != NULL) */
197 {
198 if (prev == NULL)
199 md->head = e;
200 else
201 prev->next = e;
203 e->next = this->next;
204 }
206 pthread_mutex_unlock (&md->lock);
208 if (this != NULL)
209 {
210 this->next = NULL;
211 md_entry_free (this);
212 }
214 return (0);
215 } /* }}} int md_entry_insert */
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;
223 if ((md == NULL) || (key == NULL))
224 return (NULL);
226 for (e = md->head; e != NULL; e = e->next)
227 if (strcasecmp (key, e->key) == 0)
228 break;
230 return (e);
231 } /* }}} meta_entry_t *md_entry_lookup */
233 /*
234 * Public functions
235 */
236 meta_data_t *meta_data_create (void) /* {{{ */
237 {
238 meta_data_t *md;
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));
248 md->head = NULL;
249 pthread_mutex_init (&md->lock, /* attr = */ NULL);
251 return (md);
252 } /* }}} meta_data_t *meta_data_create */
254 void meta_data_destroy (meta_data_t *md) /* {{{ */
255 {
256 if (md == NULL)
257 return;
259 md_entry_free (md->head);
260 free (md);
261 } /* }}} void meta_data_destroy */
263 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
264 {
265 meta_entry_t *e;
267 if ((md == NULL) || (key == NULL))
268 return (-EINVAL);
270 pthread_mutex_lock (&md->lock);
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 }
281 pthread_mutex_unlock (&md->lock);
282 return (0);
283 } /* }}} int meta_data_exists */
285 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
286 {
287 meta_entry_t *this;
288 meta_entry_t *prev;
290 if ((md == NULL) || (key == NULL))
291 return (-EINVAL);
293 pthread_mutex_lock (&md->lock);
295 prev = NULL;
296 this = md->head;
297 while (this != NULL)
298 {
299 if (strcasecmp (key, this->key) == 0)
300 break;
302 prev = this;
303 this = this->next;
304 }
306 if (this == NULL)
307 {
308 pthread_mutex_unlock (&md->lock);
309 return (-ENOENT);
310 }
312 if (prev == NULL)
313 md->head = this->next;
314 else
315 prev->next = this->next;
317 pthread_mutex_unlock (&md->lock);
319 this->next = NULL;
320 md_entry_free (this);
322 return (0);
323 } /* }}} int meta_data_delete */
325 int meta_data_add_string (meta_data_t *md, /* {{{ */
326 const char *key, const char *value)
327 {
328 meta_entry_t *e;
330 if ((md == NULL) || (key == NULL) || (value == NULL))
331 return (-EINVAL);
333 e = md_entry_alloc (key);
334 if (e == NULL)
335 return (-ENOMEM);
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;
346 return (md_entry_insert (md, e));
347 } /* }}} int meta_data_add_string */
349 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
350 const char *key, int64_t value)
351 {
352 meta_entry_t *e;
354 if ((md == NULL) || (key == NULL))
355 return (-EINVAL);
357 e = md_entry_alloc (key);
358 if (e == NULL)
359 return (-ENOMEM);
361 e->value.mv_signed_int = value;
362 e->type = MD_TYPE_SIGNED_INT;
364 return (md_entry_insert (md, e));
365 } /* }}} int meta_data_add_signed_int */
367 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
368 const char *key, uint64_t value)
369 {
370 meta_entry_t *e;
372 if ((md == NULL) || (key == NULL))
373 return (-EINVAL);
375 e = md_entry_alloc (key);
376 if (e == NULL)
377 return (-ENOMEM);
379 e->value.mv_unsigned_int = value;
380 e->type = MD_TYPE_UNSIGNED_INT;
382 return (md_entry_insert (md, e));
383 } /* }}} int meta_data_add_unsigned_int */
385 int meta_data_add_double (meta_data_t *md, /* {{{ */
386 const char *key, double value)
387 {
388 meta_entry_t *e;
390 if ((md == NULL) || (key == NULL))
391 return (-EINVAL);
393 e = md_entry_alloc (key);
394 if (e == NULL)
395 return (-ENOMEM);
397 e->value.mv_double = value;
398 e->type = MD_TYPE_DOUBLE;
400 return (md_entry_insert (md, e));
401 } /* }}} int meta_data_add_double */
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;
409 if ((md == NULL) || (key == NULL) || (value == NULL))
410 return (-EINVAL);
412 pthread_mutex_lock (&md->lock);
414 e = md_entry_lookup (md, key);
415 if (e == NULL)
416 {
417 pthread_mutex_unlock (&md->lock);
418 return (-ENOENT);
419 }
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 }
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 }
436 pthread_mutex_unlock (&md->lock);
438 *value = temp;
440 return (0);
441 } /* }}} int meta_data_get_string */
443 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
444 const char *key, int64_t *value)
445 {
446 meta_entry_t *e;
448 if ((md == NULL) || (key == NULL) || (value == NULL))
449 return (-EINVAL);
451 pthread_mutex_lock (&md->lock);
453 e = md_entry_lookup (md, key);
454 if (e == NULL)
455 {
456 pthread_mutex_unlock (&md->lock);
457 return (-ENOENT);
458 }
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 }
467 *value = e->value.mv_signed_int;
469 pthread_mutex_unlock (&md->lock);
470 return (0);
471 } /* }}} int meta_data_get_signed_int */
473 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
474 const char *key, uint64_t *value)
475 {
476 meta_entry_t *e;
478 if ((md == NULL) || (key == NULL) || (value == NULL))
479 return (-EINVAL);
481 pthread_mutex_lock (&md->lock);
483 e = md_entry_lookup (md, key);
484 if (e == NULL)
485 {
486 pthread_mutex_unlock (&md->lock);
487 return (-ENOENT);
488 }
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 }
497 *value = e->value.mv_unsigned_int;
499 pthread_mutex_unlock (&md->lock);
500 return (0);
501 } /* }}} int meta_data_get_unsigned_int */
503 int meta_data_get_double (meta_data_t *md, /* {{{ */
504 const char *key, double *value)
505 {
506 meta_entry_t *e;
508 if ((md == NULL) || (key == NULL) || (value == NULL))
509 return (-EINVAL);
511 pthread_mutex_lock (&md->lock);
513 e = md_entry_lookup (md, key);
514 if (e == NULL)
515 {
516 pthread_mutex_unlock (&md->lock);
517 return (-ENOENT);
518 }
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 }
527 *value = e->value.mv_double;
529 pthread_mutex_unlock (&md->lock);
530 return (0);
531 } /* }}} int meta_data_get_double */
533 /* vim: set sw=2 sts=2 et fdm=marker : */