Code

Added `configfile.[ch]' to configfile-branch (forgot that yesterday)
authorocto <octo>
Wed, 14 Dec 2005 08:56:37 +0000 (08:56 +0000)
committerocto <octo>
Wed, 14 Dec 2005 08:56:37 +0000 (08:56 +0000)
Added a call to `cf_register' to `ping.c' to test everything

src/configfile.c [new file with mode: 0644]
src/configfile.h [new file with mode: 0644]
src/ping.c
src/plugin.h

diff --git a/src/configfile.c b/src/configfile.c
new file mode 100644 (file)
index 0000000..f93eda0
--- /dev/null
@@ -0,0 +1,358 @@
+/**
+ * collectd - src/configfile.c
+ * Copyright (C) 2005  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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 <octo at verplant.org>
+ **/
+
+/*
+ * FIXME:
+ * - remove all (I mean *ALL*) calls to `fprintf': `stderr' will have been
+ *   closed.
+ */
+
+#include "collectd.h"
+
+#include "libconfig/libconfig.h"
+
+#include "configfile.h"
+#include "utils_debug.h"
+
+#define SHORTOPT_NONE 0
+
+#define ERR_NOT_NESTED "Sections cannot be nested.\n"
+#define ERR_SECTION_ONLY "`%s' can only be used as section.\n"
+#define ERR_NEEDS_ARG "Section `%s' needs an argument.\n"
+#define ERR_NEEDS_SECTION "`%s' can only be used within a section.\n"
+
+typedef struct cf_callback
+{
+       char  *type;
+       int  (*callback) (char *, char *);
+       char **keys;
+       int    keys_num;
+       struct cf_callback *next;
+} cf_callback_t;
+
+static cf_callback_t *first_callback = NULL;
+
+static int nesting_depth = 0;
+static char *current_module = NULL;
+
+/* cf_register needs this prototype */
+int cf_callback_general (const char *, const char *, const char *,
+               const char *, lc_flags_t, void *);
+
+/*
+ * Functions to handle register/unregister, search, ...
+ */
+cf_callback_t *cf_search (char *type)
+{
+       cf_callback_t *cf_cb;
+
+       if (type == NULL)
+               return (NULL);
+
+       for (cf_cb = first_callback; cf_cb != NULL; cf_cb = cf_cb->next)
+               if (strcasecmp (cf_cb->type, type) == 0)
+                       break;
+
+       return (cf_cb);
+}
+
+int cf_dispatch (char *type, const char *orig_key, const char *orig_value)
+{
+       cf_callback_t *cf_cb;
+       char *key;
+       char *value;
+       int ret;
+       int i;
+
+       if ((cf_cb = cf_search (type)) == NULL)
+       {
+               fprintf (stderr, "Plugin `%s' did not register a callback.\n", type);
+               return (-1);
+       }
+
+       if ((key = strdup (orig_key)) == NULL)
+               return (1);
+       if ((value = strdup (orig_value)) == NULL)
+       {
+               free (key);
+               return (2);
+       }
+
+       ret = -1;
+
+       for (i = 0; i < cf_cb->keys_num; i++)
+       {
+               if (strcasecmp (cf_cb->keys[i], key) == 0)
+                       ret = (*cf_cb->callback) (key, value);
+       }
+
+       if (i >= cf_cb->keys_num)
+               fprintf (stderr, "Plugin `%s' did not register for value `%s'.\n", type, key);
+
+       free (key);
+       free (value);
+
+       return (ret);
+}
+
+void cf_unregister (char *type)
+{
+       cf_callback_t *this, *prev;
+
+       for (prev = NULL, this = first_callback;
+                       this != NULL;
+                       prev = this, this = this->next)
+               if (strcasecmp (this->type, type) == 0)
+               {
+                       if (prev == NULL)
+                               first_callback = this->next;
+                       else
+                               prev->next = this->next;
+
+                       free (this);
+                       break;
+               }
+}
+
+void cf_register (char *type,
+               int (*callback) (char *, char *),
+               char **keys, int keys_num)
+{
+       cf_callback_t *cf_cb;
+       char buf[64];
+       int i;
+
+       /* Remove this module from the list, if it already exists */
+       cf_unregister (type);
+
+       /* This pointer will be free'd in `cf_unregister' */
+       if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
+               return;
+
+       cf_cb->type     = type;
+       cf_cb->callback = callback;
+       cf_cb->keys     = keys;
+       cf_cb->keys_num = keys_num;
+
+       cf_cb->next = first_callback;
+       first_callback = cf_cb;
+
+       for (i = 0; i < keys_num; i++)
+       {
+               if (snprintf (buf, 64, "Module.%s", keys[i]) < 64)
+               {
+                       /* This may be called multiple times for the same
+                        * `key', but apparently `lc_register_*' can handle
+                        * it.. */
+                       lc_register_callback (buf, SHORTOPT_NONE,
+                                       LC_VAR_STRING, cf_callback_general,
+                                       NULL);
+               }
+               else
+               {
+                       DBG ("Key was truncated: `%s'", keys[i]);
+               }
+       }
+}
+
+/* 
+ * Functions for the actual parsing
+ */
+int cf_callback_general (const char *shortvar, const char *var,
+               const char *arguments, const char *value, lc_flags_t flags,
+               void *extra)
+{
+       DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
+                       shortvar, var, arguments, value);
+
+       if ((nesting_depth == 0) || (current_module == NULL))
+       {
+               fprintf (stderr, ERR_NEEDS_SECTION, shortvar);
+               return (LC_CBRET_ERROR);
+       }
+
+       /* Send the data to the plugin */
+       if (cf_dispatch (current_module, shortvar, value) < 0)
+               return (LC_CBRET_ERROR);
+
+       return (LC_CBRET_OKAY);
+}
+
+int cf_callback_section_mode (const char *shortvar, const char *var,
+               const char *arguments, const char *value, lc_flags_t flags,
+               void *extra)
+{
+       DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
+                       shortvar, var, arguments, value);
+
+       if (flags == LC_FLAGS_SECTIONSTART)
+       {
+               if (nesting_depth != 0)
+               {
+                       fprintf (stderr, ERR_NOT_NESTED);
+                       return (LC_CBRET_ERROR);
+               }
+
+               if (arguments == NULL)
+               {
+                       fprintf (stderr, ERR_NEEDS_ARG, shortvar);
+                       return (LC_CBRET_ERROR);
+               }
+
+               nesting_depth++;
+
+               if (((operating_mode == MODE_CLIENT)
+                                       && (strcasecmp (arguments, "Client") == 0))
+                               || ((operating_mode == MODE_SERVER)
+                                       && (strcasecmp (arguments, "Server") == 0))
+                               || ((operating_mode == MODE_LOCAL)
+                                       && (strcasecmp (arguments, "Local") == 0)))
+               {
+                       return (LC_CBRET_OKAY);
+               }
+               else
+               {
+                       return (LC_CBRET_IGNORESECTION);
+               }
+       }
+       else if (flags == LC_FLAGS_SECTIONEND)
+       {
+               nesting_depth--;
+
+               return (LC_CBRET_OKAY);
+       }
+       else
+       {
+               fprintf (stderr, ERR_SECTION_ONLY, shortvar);
+               return (LC_CBRET_ERROR);
+       }
+
+}
+
+int cf_callback_section_module (const char *shortvar, const char *var,
+               const char *arguments, const char *value, lc_flags_t flags,
+               void *extra)
+{
+       DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
+                       shortvar, var, arguments, value);
+
+       if (flags == LC_FLAGS_SECTIONSTART)
+       {
+               if (nesting_depth != 0)
+               {
+                       fprintf (stderr, ERR_NOT_NESTED);
+                       return (LC_CBRET_ERROR);
+               }
+
+               if (arguments == NULL)
+               {
+                       fprintf (stderr, ERR_NEEDS_ARG, shortvar);
+                       return (LC_CBRET_ERROR);
+               }
+
+               if ((current_module = strdup (arguments)) == NULL)
+               {
+                       perror ("strdup");
+                       return (LC_CBRET_ERROR);
+               }
+
+               nesting_depth++;
+
+               if (cf_search (current_module) != NULL)
+                       return (LC_CBRET_OKAY);
+               else
+                       return (LC_CBRET_IGNORESECTION);
+       }
+       else if (flags == LC_FLAGS_SECTIONEND)
+       {
+               if (current_module != NULL)
+               {
+                       free (current_module);
+                       current_module == NULL;
+               }
+
+               nesting_depth--;
+
+               return (LC_CBRET_OKAY);
+       }
+       else
+       {
+               fprintf (stderr, ERR_SECTION_ONLY, shortvar);
+               return (LC_CBRET_ERROR);
+       }
+}
+
+int cf_callback_loadmodule (const char *shortvar, const char *var,
+               const char *arguments, const char *value, lc_flags_t flags,
+               void *extra)
+{
+       DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
+                       shortvar, var, arguments, value);
+
+       if (nesting_depth == 0)
+       {
+               fprintf (stderr, ERR_NEEDS_SECTION, shortvar);
+               return (LC_CBRET_ERROR);
+       }
+
+       /*
+        * TODO:
+        * - Write wrapper around `plugin_load' to resolve path/filename
+        * - Call this new, public function here
+        */
+       DBG ("Implement me, idiot!");
+
+       return (LC_CBRET_OKAY);
+}
+
+int cf_read (char *filename)
+{
+       if (filename == NULL)
+               filename = CONFIGFILE;
+
+       lc_register_callback ("Mode", SHORTOPT_NONE, LC_VAR_SECTION,
+                       cf_callback_section_mode, NULL);
+       lc_register_callback ("Module", SHORTOPT_NONE, LC_VAR_SECTION,
+                       cf_callback_section_module, NULL);
+
+       /*
+        * TODO:
+        * - Add more directives, such as `DefaultMode', `DataDir', `PIDFile', ...
+        */
+
+       lc_register_callback ("Mode.LoadModule", SHORTOPT_NONE,
+                       LC_VAR_STRING, cf_callback_loadmodule,
+                       NULL);
+
+       if (lc_process_file ("collectd", filename, LC_CONF_APACHE))
+       {
+               /* FIXME: Use syslog here */
+               fprintf (stderr, "Error loading config file `%s': %s\n",
+                               filename, lc_geterrstr ());
+               return (-1);
+       }
+
+       /* free memory and stuff */
+       lc_cleanup ();
+
+       return (0);
+}
diff --git a/src/configfile.h b/src/configfile.h
new file mode 100644 (file)
index 0000000..0802ba5
--- /dev/null
@@ -0,0 +1,76 @@
+/**
+ * collectd - src/configfile.h
+ * Copyright (C) 2005  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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 <octo at verplant.org>
+ **/
+
+#ifndef CONFIGFILE_H
+#define CONFIGFILE_H
+
+/*
+ * DESCRIPTION
+ *  Remove a registered plugin from the internal data structures.
+ * 
+ * PARAMETERS
+ *  `type'      Name of the plugin (must be the same as passed to
+ *              `plugin_register'
+ */
+void cf_unregister (char *type);
+
+/*
+ * DESCRIPTION
+ *  `cf_register' is called by plugins that wish to receive config keys. The
+ *  plugin will then receive all keys it registered for if they're found in a
+ *  `<Moudle $type>' section.
+ *
+ * PARAMETERS
+ *  `type'      Name of the plugin (must be the same as passed to
+ *              `plugin_register'
+ *  `callback'  Pointer to the callback function. The callback must return zero
+ *              upon success, a value smaller than zero if it doesn't know how
+ *              to handle the `key' passed to it (the first argument) or a
+ *              value greater than zero if it knows how to handle the key but
+ *              failed.
+ *  `keys'      Array of key values this plugin wished to receive. The last
+ *              element must be a NULL-pointer.
+ *  `keys_num'  Number of elements in the array (not counting the last NULL-
+ *              pointer.
+ *
+ * NOTES
+ *  `cf_unregister' will be called for `type' to make sure only one record
+ *  exists for each `type' at any time. This means that `cf_register' may be
+ *  called multiple times, but only the last call will have an effect.
+ */
+void cf_register (char *type,
+               int (*callback) (char *, char *),
+               char **keys, int keys_num);
+
+/*
+ * DESCRIPTION
+ *  `cf_read' reads the config file `filename' and dispatches the read
+ *  information to functions/variables. Most important: Is calls `plugin_load'
+ *  to load specific plugins, depending on the current mode of operation.
+ *
+ * RETURN VALUE
+ *  Returns zero upon success and non-zero otherwise. A error-message will have
+ *  been printed in this case.
+ */
+int cf_read (char *filename);
+
+#endif /* defined(CONFIGFILE_H) */
index eb35360b5464b9f55f378b5bd18b21b840829a12..9c318ceecf98178130b8a2bf45194e1bfd23b823 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "plugin.h"
 #include "common.h"
+#include "configfile.h"
 
 #include <netinet/in.h>
 #include "libping/ping.h"
@@ -44,6 +45,13 @@ static char *ds_def[] =
 };
 static int ds_num = 1;
 
+static char *config_keys[] =
+{
+       "Host",
+       NULL
+};
+static int config_keys_num = 1;
+
 extern time_t curtime;
 
 void ping_init (void)
@@ -56,6 +64,28 @@ void ping_init (void)
        return;
 }
 
+int ping_config (char *key, char *value)
+{
+       if (strcasecmp (key, "host"))
+       {
+               return (-1);
+       }
+       else if (num_pinghosts >= MAX_PINGHOSTS)
+       {
+               return (1);
+       }
+       else if ((pinghosts[num_pinghosts] = strdup (value)) == NULL)
+       {
+               return (2);
+       }
+       else
+       {
+               pingerrors[num_pinghosts] = 0;
+               num_pinghosts++;
+               return (0);
+       }
+}
+
 void ping_write (char *host, char *inst, char *val)
 {
        char file[512];
@@ -131,6 +161,7 @@ void ping_read (void)
 void module_register (void)
 {
        plugin_register (MODULE_NAME, ping_init, ping_read, ping_write);
+       cf_register (MODULE_NAME, ping_config, config_keys, config_keys_num);
 }
 
 #undef MODULE_NAME
index 8dd56ae31a1f6202fd6a082641454e04e32801e6..5bf5de67160991dd525bb75100b2b4a3226ada71 100644 (file)
@@ -32,6 +32,7 @@ void plugin_register (char *type,
                void (*init) (void),
                void (*read) (void),
                void (*write) (char *, char *, char *));
+
 #ifdef HAVE_LIBRRD
 void plugin_write    (char *host, char *type, char *inst, char *val);
 #endif /* HAVE_LIBRRD */