From 69362465fa6074dd1ef8460723a1e4fc793ac8ad Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Sat, 25 Apr 2009 15:16:01 +0200 Subject: [PATCH] src/utils_fbhash.c: Implementation of a file-backed hash. This is going to be used for password files on the server. --- src/utils_fbhash.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils_fbhash.h | 47 ++++++++++ 2 files changed, 317 insertions(+) create mode 100644 src/utils_fbhash.c create mode 100644 src/utils_fbhash.h diff --git a/src/utils_fbhash.c b/src/utils_fbhash.c new file mode 100644 index 00000000..d20b7e39 --- /dev/null +++ b/src/utils_fbhash.c @@ -0,0 +1,270 @@ +/** + * collectd - src/utils_fbhash.c + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include "collectd.h" +#include "plugin.h" + +#include + +#include "utils_fbhash.h" +#include "utils_avltree.h" + +struct fbhash_s +{ + char *filename; + time_t mtime; + + pthread_mutex_t lock; + c_avl_tree_t *tree; +}; + +/* + * Private functions + */ +static void fbh_free_tree (c_avl_tree_t *tree) /* {{{ */ +{ + int status; + + if (tree == NULL) + return; + + while (42) + { + char *key = NULL; + char *value = NULL; + + status = c_avl_pick (tree, (void *) &key, (void *) &value); + if (status != 0) + break; + + free (key); + free (value); + } + + c_avl_destroy (tree); +} /* }}} void fbh_free_tree */ + +static int fbh_read_file (fbhash_t *h) /* {{{ */ +{ + FILE *fh; + char buffer[4096]; + struct flock fl; + c_avl_tree_t *tree; + int status; + + fh = fopen (h->filename, "r"); + if (fh == NULL) + return (-1); + + memset (&fl, 0, sizeof (fl)); + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; /* == entire file */ + /* TODO: Lock file? -> fcntl */ + + status = fcntl (fileno (fh), F_SETLK, &fl); + if (status != 0) + { + fclose (fh); + return (-1); + } + + tree = c_avl_create ((void *) strcmp); + if (tree == NULL) + { + fclose (fh); + return (-1); + } + + /* Read `fh' into `tree' */ + while (fgets (buffer, sizeof (buffer), fh) != NULL) /* {{{ */ + { + size_t len; + char *key; + char *value; + + char *key_copy; + char *value_copy; + + buffer[sizeof (buffer) - 1] = 0; + len = strlen (buffer); + + /* Remove trailing newline characters. */ + while ((len > 0) + && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r'))) + { + len--; + buffer[len] = 0; + } + + /* Seek first non-space character */ + key = buffer; + while ((*key != 0) && isspace ((int) *key)) + key++; + + /* Skip empty lines and comments */ + if ((key[0] == 0) || (key[0] == '#')) + continue; + + /* Seek first colon */ + value = strchr (key, ':'); + if (value == NULL) + continue; + + /* Null-terminate `key'. */ + *value = 0; + value++; + + /* Skip leading whitespace */ + while ((*value != 0) && isspace ((int) *value)) + value++; + + /* Skip lines without value */ + if (value[0] == 0) + continue; + + key_copy = strdup (key); + value_copy = strdup (value); + + if ((key_copy == NULL) || (value_copy == NULL)) + { + free (key_copy); + free (value_copy); + continue; + } + + status = c_avl_insert (tree, key_copy, value_copy); + if (status != 0) + { + free (key_copy); + free (value_copy); + continue; + } + + DEBUG ("utils_fbhash: fbh_read_file: key = %s; value = %s;", + key, value); + } /* }}} while (fgets) */ + + fclose (fh); + + fbh_free_tree (h->tree); + h->tree = tree; + + return (0); +} /* }}} int fbh_read_file */ + +static int fbh_check_file (fbhash_t *h) /* {{{ */ +{ + struct stat statbuf; + int status; + + memset (&statbuf, 0, sizeof (statbuf)); + + status = stat (h->filename, &statbuf); + if (status != 0) + return (-1); + + if (h->mtime >= statbuf.st_mtime) + return (0); + + status = fbh_read_file (h); + if (status == 0) + h->mtime = statbuf.st_mtime; + + return (status); +} /* }}} int fbh_check_file */ + +/* + * Public functions + */ +fbhash_t *fbh_create (const char *file) /* {{{ */ +{ + fbhash_t *h; + int status; + + if (file == NULL) + return (NULL); + + h = malloc (sizeof (*h)); + if (h == NULL) + return (NULL); + memset (h, 0, sizeof (*h)); + + h->filename = strdup (file); + if (h->filename == NULL) + { + free (h); + return (NULL); + } + + h->mtime = 0; + pthread_mutex_init (&h->lock, /* attr = */ NULL); + + status = fbh_check_file (h); + if (status != 0) + { + fbh_destroy (h); + return (NULL); + } + + return (h); +} /* }}} fbhash_t *fbh_create */ + +void fbh_destroy (fbhash_t *h) /* {{{ */ +{ + if (h == NULL) + return; + + free (h->filename); + fbh_free_tree (h->tree); +} /* }}} void fbh_destroy */ + +char *fbh_get (fbhash_t *h, const char *key) /* {{{ */ +{ + char *value; + char *value_copy; + int status; + + if ((h == NULL) || (key == NULL)) + return (NULL); + + value = NULL; + value_copy = NULL; + + pthread_mutex_lock (&h->lock); + + /* TODO: Checking this everytime may be a bit much..? */ + fbh_check_file (h); + + status = c_avl_get (h->tree, key, (void *) &value); + if (status == 0) + { + assert (value != NULL); + value_copy = strdup (value); + } + + pthread_mutex_unlock (&h->lock); + + return (value_copy); +} /* }}} char *fbh_get */ + +/* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/src/utils_fbhash.h b/src/utils_fbhash.h new file mode 100644 index 00000000..0a0305ed --- /dev/null +++ b/src/utils_fbhash.h @@ -0,0 +1,47 @@ +/** + * collectd - src/utils_fbhash.h + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#ifndef UTILS_FBHASH_H +#define UTILS_FBHASH_H 1 + +/* + * File-backed hash + * + * This module reads a file of the form + * key: value + * into a hash, which can then be queried. The file is given to `fbh_create', + * the hash is queried using `fbh_get'. If the file is changed during runtime, + * it will automatically be re-read. + */ + +struct fbhash_s; +typedef struct fbhash_s fbhash_t; + +fbhash_t *fbh_create (const char *file); +void fbh_destroy (fbhash_t *h); + +/* Returns the value as a newly allocated `char *'. It's the caller's + * responsibility to free this memory. */ +char *fbh_get (fbhash_t *h, const char *key); + +#endif /* UTILS_FBHASH_H */ + +/* vim: set sw=2 sts=2 et fdm=marker : */ -- 2.11.0