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 #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
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;
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 };
58 struct meta_data_s
59 {
60 meta_entry_t *head;
61 pthread_mutex_t lock;
62 };
64 /*
65 * Private functions
66 */
67 static char *md_strdup (const char *orig) /* {{{ */
68 {
69 size_t sz;
70 char *dest;
72 if (orig == NULL)
73 return (NULL);
75 sz = strlen (orig) + 1;
76 dest = (char *) malloc (sz);
77 if (dest == NULL)
78 return (NULL);
80 memcpy (dest, orig, sz);
82 return (dest);
83 } /* }}} char *md_strdup */
85 static meta_entry_t *md_entry_alloc (const char *key) /* {{{ */
86 {
87 meta_entry_t *e;
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));
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 }
105 e->type = 0;
106 e->next = NULL;
108 return (e);
109 } /* }}} meta_entry_t *md_entry_alloc */
111 static void md_entry_free (meta_entry_t *e) /* {{{ */
112 {
113 if (e == NULL)
114 return;
116 free (e->key);
118 if (e->type == MD_TYPE_STRING)
119 free (e->value.mv_string);
121 if (e->next != NULL)
122 md_entry_free (e->next);
124 free (e);
125 } /* }}} void md_entry_free */
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;
132 if ((md == NULL) || (e == NULL))
133 return (-EINVAL);
135 pthread_mutex_lock (&md->lock);
137 prev = NULL;
138 this = md->head;
139 while (this != NULL)
140 {
141 if (strcasecmp (e->key, this->key) == 0)
142 break;
144 prev = this;
145 this = this->next;
146 }
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 }
159 e->next = NULL;
160 }
161 else /* (this != NULL) */
162 {
163 if (prev == NULL)
164 md->head = e;
165 else
166 prev->next = e;
168 e->next = this->next;
169 }
171 pthread_mutex_unlock (&md->lock);
173 if (this != NULL)
174 {
175 this->next = NULL;
176 md_entry_free (this);
177 }
179 return (0);
180 } /* }}} int md_entry_insert */
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;
188 if ((md == NULL) || (key == NULL))
189 return (NULL);
191 for (e = md->head; e != NULL; e = e->next)
192 if (strcasecmp (key, e->key) == 0)
193 break;
195 return (e);
196 } /* }}} meta_entry_t *md_entry_lookup */
198 /*
199 * Public functions
200 */
201 meta_data_t *meta_data_create (void) /* {{{ */
202 {
203 meta_data_t *md;
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));
213 md->head = NULL;
214 pthread_mutex_init (&md->lock, /* attr = */ NULL);
216 return (md);
217 } /* }}} meta_data_t *meta_data_create */
219 void meta_data_destroy (meta_data_t *md) /* {{{ */
220 {
221 if (md == NULL)
222 return;
224 md_entry_free (md->head);
225 free (md);
226 } /* }}} void meta_data_destroy */
228 int meta_data_exists (meta_data_t *md, const char *key) /* {{{ */
229 {
230 meta_entry_t *e;
232 if ((md == NULL) || (key == NULL))
233 return (-EINVAL);
235 pthread_mutex_lock (&md->lock);
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 }
246 pthread_mutex_unlock (&md->lock);
247 return (0);
248 } /* }}} int meta_data_exists */
250 int meta_data_delete (meta_data_t *md, const char *key) /* {{{ */
251 {
252 meta_entry_t *this;
253 meta_entry_t *prev;
255 if ((md == NULL) || (key == NULL))
256 return (-EINVAL);
258 pthread_mutex_lock (&md->lock);
260 prev = NULL;
261 this = md->head;
262 while (this != NULL)
263 {
264 if (strcasecmp (key, this->key) == 0)
265 break;
267 prev = this;
268 this = this->next;
269 }
271 if (this == NULL)
272 {
273 pthread_mutex_unlock (&md->lock);
274 return (-ENOENT);
275 }
277 if (prev == NULL)
278 md->head = this->next;
279 else
280 prev->next = this->next;
282 pthread_mutex_unlock (&md->lock);
284 this->next = NULL;
285 md_entry_free (this);
287 return (0);
288 } /* }}} int meta_data_delete */
290 int meta_data_add_string (meta_data_t *md, /* {{{ */
291 const char *key, const char *value)
292 {
293 meta_entry_t *e;
295 if ((md == NULL) || (key == NULL) || (value == NULL))
296 return (-EINVAL);
298 e = md_entry_alloc (key);
299 if (e == NULL)
300 return (-ENOMEM);
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;
311 return (md_entry_insert (md, e));
312 } /* }}} int meta_data_add_string */
314 int meta_data_add_signed_int (meta_data_t *md, /* {{{ */
315 const char *key, int64_t value)
316 {
317 meta_entry_t *e;
319 if ((md == NULL) || (key == NULL))
320 return (-EINVAL);
322 e = md_entry_alloc (key);
323 if (e == NULL)
324 return (-ENOMEM);
326 e->value.mv_signed_int = value;
327 e->type = MD_TYPE_SIGNED_INT;
329 return (md_entry_insert (md, e));
330 } /* }}} int meta_data_add_signed_int */
332 int meta_data_add_unsigned_int (meta_data_t *md, /* {{{ */
333 const char *key, uint64_t value)
334 {
335 meta_entry_t *e;
337 if ((md == NULL) || (key == NULL))
338 return (-EINVAL);
340 e = md_entry_alloc (key);
341 if (e == NULL)
342 return (-ENOMEM);
344 e->value.mv_unsigned_int = value;
345 e->type = MD_TYPE_UNSIGNED_INT;
347 return (md_entry_insert (md, e));
348 } /* }}} int meta_data_add_unsigned_int */
350 int meta_data_add_double (meta_data_t *md, /* {{{ */
351 const char *key, double value)
352 {
353 meta_entry_t *e;
355 if ((md == NULL) || (key == NULL))
356 return (-EINVAL);
358 e = md_entry_alloc (key);
359 if (e == NULL)
360 return (-ENOMEM);
362 e->value.mv_double = value;
363 e->type = MD_TYPE_DOUBLE;
365 return (md_entry_insert (md, e));
366 } /* }}} int meta_data_add_double */
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;
374 if ((md == NULL) || (key == NULL) || (value == NULL))
375 return (-EINVAL);
377 pthread_mutex_lock (&md->lock);
379 e = md_entry_lookup (md, key);
380 if (e == NULL)
381 {
382 pthread_mutex_unlock (&md->lock);
383 return (-ENOENT);
384 }
386 if (e->type != MD_TYPE_STRING)
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 }
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 }
401 pthread_mutex_unlock (&md->lock);
403 *value = temp;
405 return (0);
406 } /* }}} int meta_data_get_string */
408 int meta_data_get_signed_int (meta_data_t *md, /* {{{ */
409 const char *key, int64_t *value)
410 {
411 meta_entry_t *e;
413 if ((md == NULL) || (key == NULL) || (value == NULL))
414 return (-EINVAL);
416 pthread_mutex_lock (&md->lock);
418 e = md_entry_lookup (md, key);
419 if (e == NULL)
420 {
421 pthread_mutex_unlock (&md->lock);
422 return (-ENOENT);
423 }
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 }
432 *value = e->value.mv_signed_int;
434 pthread_mutex_unlock (&md->lock);
435 return (0);
436 } /* }}} int meta_data_get_signed_int */
438 int meta_data_get_unsigned_int (meta_data_t *md, /* {{{ */
439 const char *key, uint64_t *value)
440 {
441 meta_entry_t *e;
443 if ((md == NULL) || (key == NULL) || (value == NULL))
444 return (-EINVAL);
446 pthread_mutex_lock (&md->lock);
448 e = md_entry_lookup (md, key);
449 if (e == NULL)
450 {
451 pthread_mutex_unlock (&md->lock);
452 return (-ENOENT);
453 }
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 }
462 *value = e->value.mv_unsigned_int;
464 pthread_mutex_unlock (&md->lock);
465 return (0);
466 } /* }}} int meta_data_get_unsigned_int */
468 int meta_data_get_double (meta_data_t *md, /* {{{ */
469 const char *key, double *value)
470 {
471 meta_entry_t *e;
473 if ((md == NULL) || (key == NULL) || (value == NULL))
474 return (-EINVAL);
476 pthread_mutex_lock (&md->lock);
478 e = md_entry_lookup (md, key);
479 if (e == NULL)
480 {
481 pthread_mutex_unlock (&md->lock);
482 return (-ENOENT);
483 }
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 }
492 *value = e->value.mv_double;
494 pthread_mutex_unlock (&md->lock);
495 return (0);
496 } /* }}} int meta_data_get_double */
498 /* vim: set sw=2 sts=2 et fdm=marker : */