Merged branch configfile to trunk
authorocto <octo>
Sat, 17 Dec 2005 09:23:52 +0000 (09:23 +0000)
committerocto <octo>
Sat, 17 Dec 2005 09:23:52 +0000 (09:23 +0000)
33 files changed:
Makefile.am
configure.in
src/Makefile.am
src/collectd.c
src/common.c
src/configfile.c [new file with mode: 0644]
src/configfile.h [new file with mode: 0644]
src/libconfig/AUTHORS [new file with mode: 0644]
src/libconfig/LICENSE [new file with mode: 0644]
src/libconfig/Makefile.am [new file with mode: 0644]
src/libconfig/README [new file with mode: 0644]
src/libconfig/TODO [new file with mode: 0644]
src/libconfig/compat.h [new file with mode: 0644]
src/libconfig/conf_apache.c [new file with mode: 0644]
src/libconfig/conf_apache.h [new file with mode: 0644]
src/libconfig/conf_colon.c [new file with mode: 0644]
src/libconfig/conf_colon.h [new file with mode: 0644]
src/libconfig/conf_equal.c [new file with mode: 0644]
src/libconfig/conf_equal.h [new file with mode: 0644]
src/libconfig/conf_section.c [new file with mode: 0644]
src/libconfig/conf_section.h [new file with mode: 0644]
src/libconfig/conf_space.c [new file with mode: 0644]
src/libconfig/conf_space.h [new file with mode: 0644]
src/libconfig/conf_xml.c [new file with mode: 0644]
src/libconfig/conf_xml.h [new file with mode: 0644]
src/libconfig/libconfig.c [new file with mode: 0644]
src/libconfig/libconfig.h [new file with mode: 0644]
src/libconfig/libconfig_private.h [new file with mode: 0644]
src/libconfig/test-lc.c [new file with mode: 0644]
src/libconfig/win32.h [new file with mode: 0644]
src/ping.c
src/plugin.c
src/plugin.h

index a465d3c..30beb63 100644 (file)
@@ -7,5 +7,6 @@ dist-hook:
        find $(distdir) -type d -name '.svn' | xargs rm -rf
 
 install-exec-hook:
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
        $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run
        $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE_NAME)
index b68e94b..e5cf5cb 100644 (file)
@@ -24,7 +24,7 @@ AC_SUBST(LIBLTDL)
 AC_LIBTOOL_DLOPEN
 AC_PROG_LIBTOOL
 #AC_PROG_RANLIB
-AC_CONFIG_SUBDIRS(libltdl)
+AC_CONFIG_SUBDIRS(libltdl src/libconfig)
 
 #
 # Checks for header files.
@@ -89,6 +89,7 @@ AC_CHECK_LIB(m, ext)
 AC_C_CONST
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
+AC_TYPE_UID_T
 AC_HEADER_TIME
 
 #
@@ -657,7 +658,7 @@ AM_CONDITIONAL(BUILD_MODULE_TRAFFIC, test "x$enable_traffic" = "xyes")
 
 AC_COLLECTD([users],     [disable], [module], [user count statistics])
 
-AC_OUTPUT(Makefile src/libping/Makefile src/Makefile)
+AC_OUTPUT(Makefile src/libconfig/Makefile src/libping/Makefile src/Makefile)
 
 cat <<EOF;
 
index 6b85c03..11e34a9 100644 (file)
@@ -1,5 +1,6 @@
+SUBDIRS = libconfig
 if BUILD_MODULE_PING
-SUBDIRS = libping .
+SUBDIRS += libping
 endif
 
 sbin_PROGRAMS = collectd
@@ -9,7 +10,8 @@ collectd_SOURCES = collectd.c collectd.h \
                   utils_mount.c utils_mount.h \
                   common.c common.h \
                   multicast.c multicast.h \
-                  plugin.c plugin.h
+                  plugin.c plugin.h \
+                  configfile.c configfile.h
 #collectd_CFLAGS = -DPLUGINDIR='"$(pkglibdir)"'
 collectd_CPPFLAGS = $(LTDLINCL)
 collectd_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
@@ -22,9 +24,9 @@ if BUILD_FEATURE_DEBUG
 collectd_CPPFLAGS += -DLOGFILE='"${localstatedir}/log/${PACKAGE_NAME}/collectd.log"'
 endif
 collectd_LDFLAGS = -export-dynamic
-collectd_CFLAGS = -Werror
-collectd_LDADD = $(LIBLTDL) "-dlopen" self
-collectd_DEPENDENCIES = $(LIBLTDL)
+collectd_CFLAGS = -Wall -Werror
+collectd_LDADD = $(LIBLTDL) libconfig/libconfig.la "-dlopen" self
+collectd_DEPENDENCIES = $(LIBLTDL) libconfig/libconfig.la
 
 pkglib_LTLIBRARIES = 
 
@@ -158,7 +160,7 @@ if BUILD_MODULE_USERS
 pkglib_LTLIBRARIES += users.la
 users_la_SOURCES = users.c users.h
 users_la_LDFLAGS = -module -avoid-version
-users_la_CFLAGS = -Werror
+users_la_CFLAGS = -Wall -Werror
 collectd_LDADD += "-dlopen" users.la
 collectd_DEPENDENCIES += users.la
 endif
index 76c62d9..c86a678 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "multicast.h"
 #include "plugin.h"
+#include "configfile.h"
 
 #include "ping.h"
 
@@ -70,12 +71,12 @@ static int change_basedir (char *dir)
                {
                        if (mkdir (dir, 0755) == -1)
                        {
-                               syslog (LOG_ERR, "mkdir: %s", strerror (errno));
+                               syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
                                return (-1);
                        }
                        else if (chdir (dir) == -1)
                        {
-                               syslog (LOG_ERR, "chdir: %s", strerror (errno));
+                               syslog (LOG_ERR, "chdir (%s): %s", dir, strerror (errno));
                                return (-1);
                        }
                }
@@ -352,15 +353,21 @@ int main (int argc, char **argv)
        DBG_STARTFILE(logfile, "debug file opened.");
 
        /*
-        * Load plugins and change to output directory
-        * Loading plugins is done first so relative paths work as expected..
+        * Read the config file. This will load any modules automagically.
         */
-       if (plugin_load_all (plugindir) < 1)
+       plugin_set_dir (plugindir);
+
+       if (cf_read (configfile))
        {
-               fprintf (stderr, "Error: No plugins found.\n");
+               fprintf (stderr, "Error: Reading the config file failed!\n"
+                               "Read the syslog for details.\n");
                return (1);
        }
 
+       /*
+        * Change directory. We do this _after_ reading the config and loading
+        * modules to relative paths work as expected.
+        */
        if (change_basedir (datadir))
        {
                fprintf (stderr, "Error: Unable to change to directory `%s'.\n", datadir);
index d946cfb..1eec286 100644 (file)
@@ -105,13 +105,13 @@ int check_create_dir (char *dir)
                {
                        if (mkdir (dir, 0755) == -1)
                        {
-                               syslog (LOG_ERR, "mkdir %s: %s", dir, strerror (errno));
+                               syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
                                return (-1);
                        }
                }
                else
                {
-                       syslog (LOG_ERR, "stat %s: %s", dir, strerror (errno));
+                       syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
                        return (-1);
                }
        }
diff --git a/src/configfile.c b/src/configfile.c
new file mode 100644 (file)
index 0000000..cbe2de9
--- /dev/null
@@ -0,0 +1,364 @@
+/**
+ * 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 "plugin.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"
+
+#ifdef HAVE_LIBRRD
+extern int operating_mode;
+#else
+static int operating_mode = MODE_LOCAL;
+#endif
+
+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);
+                       break;
+               }
+       }
+
+       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, "Plugin.%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);
+       }
+
+       if (plugin_load (value))
+               syslog (LOG_ERR, "plugin_load (%s): failed to load plugin", shortvar);
+
+       /* Return `okay' even if there was an error, because it's not a syntax
+        * problem.. */
+       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 ("Plugin", SHORTOPT_NONE, LC_VAR_SECTION,
+                       cf_callback_section_module, NULL);
+
+       /*
+        * TODO:
+        * - Add more directives, such as `DefaultMode', `DataDir', `PIDFile', ...
+        */
+
+       lc_register_callback ("Mode.LoadPlugin", SHORTOPT_NONE,
+                       LC_VAR_STRING, cf_callback_loadmodule,
+                       NULL);
+
+       if (lc_process_file ("collectd", filename, LC_CONF_APACHE))
+       {
+               syslog (LOG_ERR, "lc_process_file (%s): %s", 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) */
diff --git a/src/libconfig/AUTHORS b/src/libconfig/AUTHORS
new file mode 100644 (file)
index 0000000..53f27bf
--- /dev/null
@@ -0,0 +1,17 @@
+                                libconfig 0.1.21
+
+Release information:
+  pkg:  libconfig version 0.1.21
+  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
+  web:  http://www.rkeene.org/oss/libconfig/
+  date: Tue Oct 18 16:03:55 CDT 2005
+  mail: libconfig@rkeene.org
+--------------------------------------------------------------------------
+
+Primary Authors:
+  * Roy Keene <libconfig@rkeene.org>
+    Primary maintainer.
+
+People who have submitted patches:
+  * Mirko Buffoni <mirko.buffoni@synthesys.it>
+    Fixed installation issues and corrected mistakes in RPM spec file.
diff --git a/src/libconfig/LICENSE b/src/libconfig/LICENSE
new file mode 100644 (file)
index 0000000..4af06fb
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2004  Roy Keene, Keene Enterprises
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/libconfig/Makefile.am b/src/libconfig/Makefile.am
new file mode 100644 (file)
index 0000000..187d563
--- /dev/null
@@ -0,0 +1,14 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+noinst_LTLIBRARIES = libconfig.la
+
+libconfig_la_CFLAGS =
+libconfig_la_LDFLAGS = -avoid-version
+libconfig_la_SOURCES = \
+       libconfig.c libconfig.h \
+       conf_apache.c conf_apache.h \
+       conf_colon.c conf_colon.h \
+       conf_equal.c conf_equal.h \
+       conf_section.c conf_section.h \
+       conf_space.c conf_space.h \
+       conf_xml.c conf_xml.h
diff --git a/src/libconfig/README b/src/libconfig/README
new file mode 100644 (file)
index 0000000..7274223
--- /dev/null
@@ -0,0 +1,19 @@
+                                libconfig 0.1.21
+
+Release information:
+  pkg:  libconfig version 0.1.21
+  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
+  web:  http://www.rkeene.org/oss/libconfig/
+  date: Tue Oct 18 16:03:55 CDT 2005
+  mail: libconfig@rkeene.org
+--------------------------------------------------------------------------
+
+Tested platforms:
+  Mac OS X 10.1
+  HP-UX 11.11
+  NetBSD 1.6.1
+  FreeBSD 4.8
+  OpenBSD 3.4
+  SunOS 5.9
+  Linux (Slackware, RedHat, Fedora Core, Debian)
+  IRIX 6.5
diff --git a/src/libconfig/TODO b/src/libconfig/TODO
new file mode 100644 (file)
index 0000000..6ba4ed3
--- /dev/null
@@ -0,0 +1,11 @@
+                                libconfig 0.1.21
+
+Release information:
+  pkg:  libconfig version 0.1.21
+  url:  http://www.rkeene.org/files/oss/libconfig/devel/libconfig-0.1.21.tar.gz
+  web:  http://www.rkeene.org/oss/libconfig/
+  date: Tue Oct 18 16:03:55 CDT 2005
+  mail: libconfig@rkeene.org
+--------------------------------------------------------------------------
+
+  More manual pages.
diff --git a/src/libconfig/compat.h b/src/libconfig/compat.h
new file mode 100644 (file)
index 0000000..48d0b07
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef RSK_COMPAT_H
+#define RSK_COMPAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef __WIN32__
+#include "win32.h"
+#endif
+
+#ifndef LC_LINEBUF_LEN
+#define LC_LINEBUF_LEN 1024
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_OPENNET_H
+#include <opennet.h>
+#endif
+#ifdef HAVE_LIBOPENNET
+#define lc_fopen(path, mode) fopen_net(path, mode)
+#define lc_fgets(buf, size, stream) fgets_net(buf, size, stream)
+#define lc_feof(stream) feof_net(stream)
+#define lc_fclose(stream) fclose_net(stream)
+#define LC_FILE NETFILE
+#else
+#define lc_fopen(path, mode) fopen(path, mode)
+#define lc_fgets(buf, size, stream) fgets(buf, size, stream)
+#define lc_feof(stream) feof(stream)
+#define lc_fclose(stream) fclose(stream)
+#define LC_FILE FILE
+#endif
+
+#endif
diff --git a/src/libconfig/conf_apache.c b/src/libconfig/conf_apache.c
new file mode 100644 (file)
index 0000000..1497d1e
--- /dev/null
@@ -0,0 +1,371 @@
+#include "compat.h"
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_apache.h"
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
+static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix);
+
+static int lc_process_conf_apache_include(const char *pathname, const char *pathprefix) {
+       struct stat pathinfo;
+       struct dirent *dinfo = NULL;
+       char includepath[LC_LINEBUF_LEN] = {0};
+       DIR *dh = NULL;
+       int statret = -1, lcpcafret = -1;
+       int retval = 0;
+
+       statret = stat(pathname, &pathinfo);
+       if (statret < 0) {
+               return(-1);
+       }
+
+       if (S_ISDIR(pathinfo.st_mode)) {
+               dh = opendir(pathname);
+               if (dh == NULL) {
+                       return(-1);
+               }
+
+               while (1) {
+                       dinfo = readdir(dh);
+                       if (dinfo == NULL) {
+                               break;
+                       }
+
+                       /* Skip files that begin with a dot ('.') */
+                       if (dinfo->d_name[0] == '.') continue;
+
+                       snprintf(includepath, sizeof(includepath) - 1, "%s/%s", pathname, dinfo->d_name);
+                       lcpcafret = lc_process_conf_apache_include(includepath, pathprefix);
+                       if (lcpcafret < 0) {
+                               retval = -1;
+                               /* XXX: should we break here (abort further including of files from a directory if one fails ?) */
+                       }
+               }
+
+               closedir(dh);
+       } else {
+               lcpcafret = lc_process_conf_apache_file(pathname, pathprefix);
+               if (lcpcafret < 0) {
+                       retval = -1;
+               }
+       }
+
+       return(retval);
+}
+
+static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix) {
+       LC_FILE *configfp = NULL;
+       const char *local_lc_errfile;
+       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL, *tmp_ptr = NULL;
+       char *lastsection = NULL;
+       char qualifbuf[LC_LINEBUF_LEN] = {0};
+       char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL;
+       char *fgetsret = NULL;
+       int lcpvret = -1, lpcafret = -1;
+       int invalid_section = 0, ignore_section = 0;
+       int local_lc_errline;
+       int retval = 0;
+       lc_err_t save_lc_errno = LC_ERR_NONE;
+
+       if (pathprefix != NULL) {
+               /* Copy the prefix, if specified. */
+               strncpy(qualifbuf, pathprefix, sizeof(qualifbuf) - 1);
+       }
+
+       local_lc_errfile = configfile;
+       local_lc_errline = 0;
+
+       if (configfile == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_INVDATA;
+               return(-1);
+       }
+
+       configfp = lc_fopen(configfile, "r");
+
+       if (configfp == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_CANTOPEN;
+               return(-1);
+       }
+
+       while (1) {
+               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
+               if (fgetsret == NULL) {
+                       break;
+               }
+               if (lc_feof(configfp)) {
+                       break;
+               }
+
+               local_lc_errline++;
+
+               /* Remove trailing crap (but not spaces). */
+               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
+               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
+                       *linebuf_ptr = '\0';
+                       linebuf_ptr--;
+               }
+
+               /* Remove leading spaces. */
+               linebuf_ptr = &linebuf[0];
+               while (*linebuf_ptr == ' ' || *linebuf_ptr == '\t') {
+                       linebuf_ptr++;
+               }
+
+               /* Handle section header. */
+               if (linebuf_ptr[0] == '<' && linebuf_ptr[strlen(linebuf_ptr) - 1] == '>') {
+                       /* Remove < and > from around the data. */
+                       linebuf_ptr[strlen(linebuf_ptr) - 1] = '\0';
+                       linebuf_ptr++;
+
+                       /* Lowercase the command part of the section. */
+                       tmp_ptr = linebuf_ptr;
+                       while (*tmp_ptr != '\0' && *tmp_ptr != ' ') {
+                               *tmp_ptr = tolower(*tmp_ptr);
+                               tmp_ptr++;
+                       }
+
+                       /* If this is a close section command, handle it */
+                       if (linebuf_ptr[0] == '/') {
+                               linebuf_ptr++;
+                               cmd = linebuf_ptr; 
+
+                               /* Find the last section closed. */
+                               tmp_ptr = strrchr(qualifbuf, '.');
+                               if (tmp_ptr == NULL) {
+                                       lastsection = qualifbuf;
+                                       tmp_ptr = qualifbuf;
+                               } else {
+                                       lastsection = tmp_ptr + 1;
+                               }
+
+                               if (strcmp(cmd, lastsection) != 0) {
+#ifdef DEBUG
+                                       fprintf(stderr, "Section closing does not match last opened section.\n");
+                                       fprintf(stderr, "Last opened = \"%s\", Closing = \"%s\"\n", lastsection, cmd);
+#endif
+                                       retval = -1;
+                                       lc_errfile = local_lc_errfile;
+                                       lc_errline = local_lc_errline;
+                                       lc_errno = LC_ERR_BADFORMAT;
+
+                                       /* For this error, we abort immediately. */
+                                       break;
+                               }
+
+                               lcpvret = lc_process_var(qualifbuf, NULL, NULL, LC_FLAGS_SECTIONEND);
+                               if (lcpvret < 0) {
+#ifdef DEBUG
+                                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", qualifbuf);
+#endif
+                               }
+
+                               /* Remove the "lastsection" part.. */
+                               *tmp_ptr = '\0';
+
+                               /* We just sucessfully closed the last section opened,
+                                  we must be in a valid section now since we only open
+                                  sections from within valid sections. */
+                               invalid_section = 0;
+                               ignore_section = 0;
+
+                               continue;
+                       }
+                       /* Otherwise, open a new section. */
+
+                       /* Don't open a section from an invalid section. */
+                       if (invalid_section == 1 || ignore_section == 1) {
+                               continue;
+                       }
+
+                       /* Parse out any argument passed. */
+                       sep = strpbrk(linebuf_ptr, " \t");
+
+                       if (sep != NULL) {
+                               cmdend = sep;
+                               /* Delete space at the end of the command. */
+                               cmdend--; /* It currently derefs to the seperator.. */
+                               while (*cmdend <= ' ') {
+                                       *cmdend = '\0';
+                                       cmdend--;
+                               }
+
+                               /* Delete the seperator char and any leading space. */
+                               *sep = '\0';
+                               sep++;
+                               while (*sep == ' ' || *sep == '\t') {
+                                       sep++;
+                               }
+                               value = sep;
+                       } else {
+                               /* XXX: should this be "" or NULL ? */
+                               value = "";
+                       }
+
+                       cmd = linebuf_ptr;
+
+                       if (qualifbuf[0] != '\0') {
+                               strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
+                       }
+                       strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
+
+                       lcpvret = lc_process_var(qualifbuf, value, NULL, LC_FLAGS_SECTIONSTART);
+                       if (lcpvret < 0) {
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid section: \"%s\"\n", qualifbuf);
+#endif
+                               invalid_section = 1;
+                               lc_errfile = local_lc_errfile;
+                               lc_errline = local_lc_errline;
+                               lc_errno = LC_ERR_INVSECTION;
+                               retval = -1;
+                       }
+                       if (lcpvret == LC_CBRET_IGNORESECTION) {
+                               ignore_section = 1;
+                       }
+                       continue;
+               }
+
+               /* Drop comments and blank lines. */
+               if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') {
+                       continue;
+               }
+
+               /* Don't handle things for a section that doesn't exist. */
+               if (invalid_section == 1) {
+#ifdef DEBUG
+                       fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf);
+#endif
+                       continue;
+               }
+               if (ignore_section == 1) {
+#ifdef DEBUG
+                       fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf);
+#endif
+                       continue;
+               }
+
+               /* Find the command and the data in the line. */
+               sep = strpbrk(linebuf_ptr, " \t");
+               if (sep != NULL) {
+                       cmdend = sep;
+
+                       /* Delete space at the end of the command. */
+                       cmdend--; /* It currently derefs to the seperator.. */
+                       while (*cmdend <= ' ') {
+                               *cmdend = '\0';
+                               cmdend--;
+                       }
+
+                       /* Delete the seperator char and any leading space. */
+                       *sep = '\0';
+                       sep++;
+                       while (*sep == ' ' || *sep == '\t') {
+                               sep++;
+                       }
+                       value = sep;
+               } else {
+                       value = NULL;
+               }
+
+               cmd = linebuf_ptr;
+
+               /* Handle special commands. */
+               if (strcasecmp(cmd, "include") == 0) {
+                       if (value == NULL) {
+                               lc_errfile = local_lc_errfile;
+                               lc_errline = local_lc_errline;
+                               lc_errno = LC_ERR_BADFORMAT;
+                               retval = -1;
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid include command.\n");
+#endif
+                               continue;
+                       }
+
+                       lpcafret = lc_process_conf_apache_include(value, qualifbuf);
+                       if (lpcafret < 0) {
+#ifdef DEBUG
+                               fprintf(stderr, "Error in included file.\n");
+#endif
+                               retval = -1;
+                       }
+                       continue;
+               }
+
+               /* Create the fully qualified variable name. */
+               if (qualifbuf[0] != '\0') {
+                       strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1);
+               }
+               strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1);
+
+               /* Call the parent and tell them we have data. */
+               save_lc_errno = lc_errno;
+               lc_errno = LC_ERR_NONE;
+               lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR);
+               if (lcpvret < 0) {
+                       if (lc_errno == LC_ERR_NONE) {
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
+#endif
+                               lc_errfile = local_lc_errfile;
+                               lc_errline = local_lc_errline;
+                               lc_errno = LC_ERR_INVCMD;
+                       } else {
+#ifdef DEBUG
+                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
+#endif
+                       }
+                       lc_errfile = local_lc_errfile;
+                       lc_errline = local_lc_errline;
+                       retval = -1;
+               } else {
+                       lc_errno = save_lc_errno;
+               }
+
+               /* Remove the "cmd" part of the buffer. */
+               tmp_ptr = strrchr(qualifbuf, '.');
+               if (tmp_ptr == NULL) {
+                       tmp_ptr = qualifbuf;
+               }
+               *tmp_ptr = '\0';
+       }
+
+       lc_fclose(configfp);
+
+       return(retval);
+}
+
+int lc_process_conf_apache(const char *appname, const char *configfile) {
+       return(lc_process_conf_apache_file(configfile, NULL));
+}
diff --git a/src/libconfig/conf_apache.h b/src/libconfig/conf_apache.h
new file mode 100644 (file)
index 0000000..36c556e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_APACHE_H
+#define LC_CONF_APACHE_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_apache(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/conf_colon.c b/src/libconfig/conf_colon.c
new file mode 100644 (file)
index 0000000..f184309
--- /dev/null
@@ -0,0 +1,7 @@
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_colon.h"
+
+int lc_process_conf_colon(const char *appname, const char *configfile) {
+       return(-1);
+}
diff --git a/src/libconfig/conf_colon.h b/src/libconfig/conf_colon.h
new file mode 100644 (file)
index 0000000..7d2323c
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_COLON_H
+#define LC_CONF_COLON_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_colon(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/conf_equal.c b/src/libconfig/conf_equal.c
new file mode 100644 (file)
index 0000000..a214330
--- /dev/null
@@ -0,0 +1,7 @@
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_equal.h"
+
+int lc_process_conf_equal(const char *appname, const char *configfile) {
+       return(-1);
+}
diff --git a/src/libconfig/conf_equal.h b/src/libconfig/conf_equal.h
new file mode 100644 (file)
index 0000000..82e0f04
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_EQUAL_H
+#define LC_CONF_EQUAL_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_equal(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/conf_section.c b/src/libconfig/conf_section.c
new file mode 100644 (file)
index 0000000..fb948c1
--- /dev/null
@@ -0,0 +1,201 @@
+#include "compat.h"
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_section.h"
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+int lc_process_conf_section(const char *appname, const char *configfile) {
+       LC_FILE *configfp = NULL;
+       const char *local_lc_errfile;
+       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL;
+       char qualifbuf[LC_LINEBUF_LEN] = {0};
+       char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL;
+       char *currsection = NULL;
+       char *fgetsret = NULL;
+       int lcpvret = -1;
+       int invalid_section = 1, ignore_section = 0;
+       int local_lc_errline;
+       int retval = 0;
+       lc_err_t save_lc_errno = LC_ERR_NONE;
+
+       local_lc_errfile = configfile;
+       local_lc_errline = 0;
+
+       if (appname == NULL || configfile == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_INVDATA;
+               return(-1);
+       }
+
+       configfp = lc_fopen(configfile, "r");
+
+       if (configfp == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_CANTOPEN;
+               return(-1);
+       }
+
+       while (1) {
+               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
+               if (fgetsret == NULL) {
+                       break;
+               }
+               if (lc_feof(configfp)) {
+                       break;
+               }
+
+               local_lc_errline++;
+
+               /* Remove trailing crap (but not spaces). */
+               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
+               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
+                       *linebuf_ptr = '\0';
+                       linebuf_ptr--;
+               }
+
+               /* Handle section header. */
+               if (linebuf[0] == '[' && linebuf[strlen(linebuf) - 1] == ']') {
+                       linebuf[strlen(linebuf) - 1] = '\0';
+                       linebuf_ptr = &linebuf[1];
+
+                       /* If a section was open, close it. */
+                       if (currsection != NULL) {
+                               lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONEND);
+                               if (lcpvret < 0) {
+#ifdef DEBUG
+                                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", currsection);
+#endif
+                               }
+                               free(currsection);
+                       }
+
+                       /* Open new section. */
+                       currsection = strdup(linebuf_ptr);
+                       lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONSTART);
+                       if (lcpvret < 0) {
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid section: \"%s\"\n", currsection);
+#endif
+                               invalid_section = 1;
+                               lc_errfile = local_lc_errfile;
+                               lc_errline = local_lc_errline;
+                               lc_errno = LC_ERR_INVSECTION;
+                               retval = -1;
+                       } else {
+                               invalid_section = 0;
+                               ignore_section = 0;
+                       }
+
+                       if (lcpvret == LC_CBRET_IGNORESECTION) {
+                               ignore_section = 1;
+                       }
+                       continue;
+               }
+
+               /* Remove leading spaces. */
+               linebuf_ptr = &linebuf[0];
+               while (*linebuf_ptr == ' ') {
+                       linebuf_ptr++;
+               }
+
+               /* Drop comments and blank lines. */
+               if (*linebuf_ptr == ';' || *linebuf_ptr == '\0') {
+                       continue;
+               }
+
+               /* Don't handle things for a section that doesn't exist. */
+               if (invalid_section == 1) {
+#ifdef DEBUG
+                       fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf);
+#endif
+                       continue;
+               }
+
+               /* Don't process commands if this section is specifically ignored. */
+               if (ignore_section == 1) {
+#ifdef DEBUG
+                       fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf);
+#endif
+                       continue;
+               }
+
+               /* Find the command and the data in the line. */
+               cmdend = sep = strpbrk(linebuf_ptr, "=");
+               if (sep == NULL) {
+#ifdef DEBUG
+                       fprintf(stderr, "Invalid line: \"%s\"\n", linebuf);
+#endif
+                       continue;
+               }
+
+               /* Delete space at the end of the command. */
+               cmdend--; /* It currently derefs to the seperator.. */
+               while (*cmdend <= ' ') {
+                       *cmdend = '\0';
+                       cmdend--;
+               }
+
+               cmd = linebuf_ptr;
+
+               /* Delete the seperator char and any leading space. */
+               *sep = '\0';
+               sep++;
+               while (*sep == ' ' || *sep == '\t') {
+                       sep++;
+               }
+               value = sep;
+
+               /* Create the fully qualified variable name. */
+               if (currsection == NULL) {
+                       strncpy(qualifbuf, cmd, sizeof(qualifbuf) - 1);
+               } else {
+                       snprintf(qualifbuf, sizeof(qualifbuf) - 1, "%s.%s", currsection, cmd);
+               }
+
+               /* Call the parent and tell them we have data. */
+               save_lc_errno = lc_errno;
+               lc_errno = LC_ERR_NONE;
+               lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR);
+               if (lcpvret < 0) {
+                       if (lc_errno == LC_ERR_NONE) {
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
+#endif
+                               lc_errno = LC_ERR_INVCMD;
+                       } else {
+#ifdef DEBUG
+                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
+#endif
+                       }
+                       lc_errfile = local_lc_errfile;
+                       lc_errline = local_lc_errline;
+                       retval = -1;
+               } else {
+                       lc_errno = save_lc_errno;
+               }
+       }
+
+       /* Close any open section, and clean-up. */
+       if (currsection != NULL) {
+               lcpvret = lc_process_var(currsection, NULL, NULL, LC_FLAGS_SECTIONEND);
+               if (lcpvret < 0) {
+#ifdef DEBUG
+                       fprintf(stderr, "Invalid section terminating: \"%s\"\n", currsection);
+#endif
+               }
+               free(currsection);
+       }
+
+       lc_fclose(configfp);
+
+       return(retval);
+}
diff --git a/src/libconfig/conf_section.h b/src/libconfig/conf_section.h
new file mode 100644 (file)
index 0000000..1d1a94c
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_SECTION_H
+#define LC_CONF_SECTION_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_section(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/conf_space.c b/src/libconfig/conf_space.c
new file mode 100644 (file)
index 0000000..50a9b23
--- /dev/null
@@ -0,0 +1,109 @@
+#include "compat.h"
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_space.h"
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+int lc_process_conf_space(const char *appname, const char *configfile) {
+       LC_FILE *configfp = NULL;
+       const char *local_lc_errfile;
+       char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL;
+       char *cmd = NULL, *value = NULL, *sep = NULL;
+       char *fgetsret = NULL;
+       int local_lc_errline;
+       int lcpvret = -1;
+       int retval = 0;
+       lc_err_t save_lc_errno = LC_ERR_NONE;
+
+       local_lc_errfile = configfile;
+       local_lc_errline = 0;
+
+       if (appname == NULL || configfile == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_INVDATA;
+               return(-1);
+       }
+
+       configfp = lc_fopen(configfile, "r");
+
+       if (configfp == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_CANTOPEN;
+               return(-1);
+       }
+
+       while (1) {
+               fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp);
+               if (fgetsret == NULL) {
+                       break;
+               }
+               if (lc_feof(configfp)) {
+                       break;
+               }
+
+               local_lc_errline++;
+
+               linebuf_ptr = &linebuf[strlen(linebuf) - 1];
+               while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) {
+                       *linebuf_ptr = '\0';
+                       linebuf_ptr--;
+               }
+
+               linebuf_ptr = &linebuf[0];
+               while (*linebuf_ptr == ' ') {
+                       linebuf_ptr++;
+               }
+
+               if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') {
+                       continue;
+               }
+
+
+               sep = strpbrk(linebuf_ptr, " \t");
+               cmd = linebuf_ptr;
+               if (sep != NULL) {
+                       *sep = '\0';
+                       sep++;
+                       while (*sep == ' ' || *sep == '\t') {
+                               sep++;
+                       }
+                       value = sep;
+               } else {
+                       value = NULL;
+               }
+
+               save_lc_errno = lc_errno;
+               lc_errno = LC_ERR_NONE;
+               lcpvret = lc_process_var(cmd, NULL, value, LC_FLAGS_VAR);
+               if (lcpvret < 0) {
+                       if (lc_errno == LC_ERR_NONE) {
+#ifdef DEBUG
+                               fprintf(stderr, "Invalid command: \"%s\"\n", cmd);
+#endif
+                               lc_errno = LC_ERR_INVCMD;
+                       } else {
+#ifdef DEBUG
+                               fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n");
+#endif
+                       }
+                       lc_errfile = local_lc_errfile;
+                       lc_errline = local_lc_errline;
+                       retval = -1;
+               } else {
+                       lc_errno = save_lc_errno;
+               }
+       }
+
+       lc_fclose(configfp);
+
+       return(retval);
+}
diff --git a/src/libconfig/conf_space.h b/src/libconfig/conf_space.h
new file mode 100644 (file)
index 0000000..6cf0462
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_SPACE_H
+#define LC_CONF_SPACE_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_space(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/conf_xml.c b/src/libconfig/conf_xml.c
new file mode 100644 (file)
index 0000000..85edd51
--- /dev/null
@@ -0,0 +1,7 @@
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_xml.h"
+
+int lc_process_conf_xml(const char *appname, const char *configfile) {
+       return(-1);
+}
diff --git a/src/libconfig/conf_xml.h b/src/libconfig/conf_xml.h
new file mode 100644 (file)
index 0000000..f0deffb
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef LC_CONF_XML_H
+#define LC_CONF_XML_H
+#include "libconfig.h"
+#include "libconfig_private.h"
+
+int lc_process_conf_xml(const char *appname, const char *configfile);
+
+#endif
diff --git a/src/libconfig/libconfig.c b/src/libconfig/libconfig.c
new file mode 100644 (file)
index 0000000..9f80a76
--- /dev/null
@@ -0,0 +1,1073 @@
+#include "compat.h"
+#include "libconfig.h"
+#include "libconfig_private.h"
+#include "conf_section.h"
+#include "conf_apache.h"
+#include "conf_colon.h"
+#include "conf_equal.h"
+#include "conf_space.h"
+#include "conf_xml.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+struct lc_varhandler_st *varhandlers = NULL;
+lc_err_t lc_errno = LC_ERR_NONE;
+const char *lc_errfile = NULL;
+int lc_optind = 0;
+int lc_errline = 0;
+
+extern char **environ;
+
+static int lc_process_var_string(void *data, const char *value, const char **endptr) {
+       char **dataval;
+
+       dataval = data;
+       *dataval = strdup(value);
+
+       *endptr = NULL;
+
+       return(0);
+}
+
+static int lc_process_var_cidr(void *data, const char *value, const char **endptr) {
+       return(-1);
+}
+
+static int lc_process_var_hostname6(void *data, const char *value, const char **endptr) {
+       return(-1);
+}
+
+static int lc_process_var_hostname4(void *data, const char *value, const char **endptr) {
+       return(-1);
+}
+
+static int lc_process_var_ip6(void *data, const char *value, const char **endptr) {
+       return(-1);
+}
+
+static int lc_process_var_ip4(void *data, const char *value, const char **endptr) {
+       uint32_t *dataval, retval = 0;
+       const char *dotptr = NULL;
+       int tmpval = -1;
+//     int dotcount
+
+       dataval = data;
+
+       dotptr = value;
+
+       while (1) {
+               tmpval = atoi(dotptr);
+               if (tmpval < 0) {
+                       break;
+               }
+
+               retval <<= 8;
+               retval |= tmpval;
+
+               dotptr = strpbrk(dotptr, "./ \t");
+               if (dotptr == NULL) {
+                       break;
+               }
+               if (*dotptr != '.') {
+                       break;
+               }
+               dotptr++;
+       }
+
+       *dataval = retval;
+
+       *endptr = (char *) dotptr;
+
+       return(0);
+}
+
+static int lc_process_var_longlong(void *data, const char *value, const char **endptr) {
+       long long *dataval;
+
+       dataval = data;
+       *dataval = strtoll(value, (char **) endptr, 10);
+
+       return(0);
+}
+
+static int lc_process_var_long(void *data, const char *value, const char **endptr) {
+       long *dataval;
+
+       dataval = data;
+       *dataval = strtoll(value, (char **) endptr, 10);
+
+       return(0);
+}
+
+static int lc_process_var_int(void *data, const char *value, const char **endptr) {
+       int *dataval;
+
+       dataval = data;
+       *dataval = strtoll(value, (char **) endptr, 10);
+
+       return(0);
+}
+
+static int lc_process_var_short(void *data, const char *value, const char **endptr) {
+       short *dataval;
+
+       dataval = data;
+       *dataval = strtoll(value, (char **) endptr, 10);
+
+       return(0);
+}
+
+static int lc_process_var_bool_byexistance(void *data, const char *value, const char **endptr) {
+       int *dataval;
+
+       dataval = data;
+
+       *dataval = 1;
+
+       *endptr = NULL;
+
+       return(0);
+}
+
+static int lc_process_var_bool(void *data, const char *value, const char **endptr) {
+       char *trueval[] = {"enable", "true", "yes", "on", "y", "1"};
+       char *falseval[] = {"disable", "false", "no", "off", "n", "0"};
+       size_t chkvallen, vallen;
+       int *dataval;
+       int i;
+
+       dataval = data;
+
+       *dataval = -1;
+
+       vallen = strlen(value);
+
+       for (i = 0; i < (sizeof(trueval) / sizeof(*trueval)); i++) {
+               chkvallen = strlen(trueval[i]);
+
+               /*
+                * Skip if there's no way we could find a match here.
+                */
+               if (chkvallen > vallen) {
+                       continue;
+               }
+
+               /*
+                * Skip if there is no partial match.
+                */
+               if (strncasecmp(value, trueval[i], chkvallen) != 0) {
+                       continue;
+               }
+
+               if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \
+                   value[chkvallen] == ' ') {
+                       /* Declare a winner and set the next token. */
+                       *endptr = value + chkvallen;
+                       *dataval = 1;
+                       return(0);
+               }
+       }
+
+       for (i = 0; i < (sizeof(falseval) / sizeof(*falseval)); i++) {
+               chkvallen = strlen(falseval[i]);
+
+               /*
+                * Skip if there's no way we could find a match here.
+                */
+               if (chkvallen > vallen) {
+                       continue;
+               }
+
+               /*
+                * Skip if there is no partial match.
+                */
+               if (strncasecmp(value, falseval[i], chkvallen) != 0) {
+                       continue;
+               }
+
+               if (value[chkvallen] == '\0' || value[chkvallen] == ',' || \
+                   value[chkvallen] == ' ') {
+                       /* Declare a winner and set the next token. */
+                       *endptr = value + chkvallen;
+                       *dataval = 0;
+                       return(0);
+               }
+       }
+
+       lc_errno = LC_ERR_BADFORMAT;
+       return(-1);
+}
+
+static unsigned long long lc_process_size(const char *value, const char **endptr) {
+       unsigned long long retval = 0;
+       char *mult = NULL;
+
+       retval = strtoll(value, &mult, 10);
+       if (mult != NULL) {
+               switch (tolower(mult[0])) {
+                       case 'p':
+                               retval *= 1125899906842624LLU;
+                               break;
+                       case 't':
+                               retval *= 1958505086976LLU;
+                               break;
+                       case 'g':
+                               retval *= 1073741824;
+                               break;
+                       case 'm':
+                               retval *= 1048576;
+                               break;
+                       case 'k':
+                               retval *= 1024;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       return(retval);
+}
+
+static int lc_process_var_sizelonglong(void *data, const char *value, const char **endptr) {
+       long long *dataval;
+
+       dataval = data;
+       *dataval = lc_process_size(value, endptr);
+
+       return(0);
+}
+
+static int lc_process_var_sizelong(void *data, const char *value, const char **endptr) {
+       long *dataval;
+
+       dataval = data;
+       *dataval = lc_process_size(value, endptr);
+
+       return(0);
+}
+
+static int lc_process_var_sizeint(void *data, const char *value, const char **endptr) {
+       int *dataval;
+
+       dataval = data;
+       *dataval = lc_process_size(value, endptr);
+
+       return(0);
+}
+
+static int lc_process_var_sizeshort(void *data, const char *value, const char **endptr) {
+       short *dataval;
+
+       dataval = data;
+       *dataval = lc_process_size(value, endptr);
+
+       return(0);
+}
+
+static int lc_process_var_sizesizet(void *data, const char *value, const char **endptr) {
+       size_t *dataval;
+
+       dataval = data;
+       *dataval = lc_process_size(value, endptr);
+
+       return(0);
+}
+
+
+static int lc_handle_type(lc_var_type_t type, const char *value, void *data) {
+       const char *next;
+       int is_list;
+
+       is_list = type & LC_VAR_LIST;
+
+       if (is_list == LC_VAR_LIST) {
+       }
+
+       switch (type) {
+               case LC_VAR_STRING:
+                       return(lc_process_var_string(data, value, &next));
+                       break;
+               case LC_VAR_LONG_LONG:
+                       return(lc_process_var_longlong(data, value, &next));
+                       break;
+               case LC_VAR_LONG:
+                       return(lc_process_var_long(data, value, &next));
+                       break;
+               case LC_VAR_INT:
+                       return(lc_process_var_int(data, value, &next));
+                       break;
+               case LC_VAR_SHORT:
+                       return(lc_process_var_short(data, value, &next));
+                       break;
+               case LC_VAR_BOOL:
+                       return(lc_process_var_bool(data, value, &next));
+                       break;
+               case LC_VAR_SIZE_LONG_LONG:
+                       return(lc_process_var_sizelonglong(data, value, &next));
+                       break;
+               case LC_VAR_SIZE_LONG:
+                       return(lc_process_var_sizelong(data, value, &next));
+                       break;
+               case LC_VAR_SIZE_INT:
+                       return(lc_process_var_sizeint(data, value, &next));
+                       break;
+               case LC_VAR_SIZE_SHORT:
+                       return(lc_process_var_sizeshort(data, value, &next));
+                       break;
+               case LC_VAR_BOOL_BY_EXISTANCE:
+                       return(lc_process_var_bool_byexistance(data, value, &next));
+                       break;
+               case LC_VAR_SIZE_SIZE_T:
+                       return(lc_process_var_sizesizet(data, value, &next));
+                       break;
+               case LC_VAR_IP:
+               case LC_VAR_IP4:
+                       return(lc_process_var_ip4(data, value, &next));
+                       break;
+               case LC_VAR_IP6:
+                       return(lc_process_var_ip6(data, value, &next));
+                       break;
+               case LC_VAR_HOSTNAME4:
+                       return(lc_process_var_hostname4(data, value, &next));
+                       break;
+               case LC_VAR_HOSTNAME6:
+                       return(lc_process_var_hostname6(data, value, &next));
+                       break;
+               case LC_VAR_CIDR:
+                       return(lc_process_var_cidr(data, value, &next));
+                       break;
+               case LC_VAR_TIME:
+               case LC_VAR_DATE:
+               case LC_VAR_FILENAME:
+               case LC_VAR_DIRECTORY:
+#ifdef DEBUG
+                       fprintf(stderr, "Not implemented yet!\n");
+#endif
+                       return(-1);
+               case LC_VAR_NONE:
+               case LC_VAR_UNKNOWN:
+               case LC_VAR_SECTION:
+               case LC_VAR_SECTIONSTART:
+               case LC_VAR_SECTIONEND:
+                       return(0);
+                       break;
+       }
+
+       return(-1);
+}
+
+static int lc_handle(struct lc_varhandler_st *handler, const char *var, const char *varargs, const char *value, lc_flags_t flags) {
+       const char *localvar = NULL;
+       int retval;
+
+       if (var != NULL) {
+               localvar = strrchr(var, '.');
+               if (localvar == NULL) {
+                       localvar = var;
+               } else {
+                       localvar++;
+               }
+       } else {
+               localvar = NULL;
+       }
+
+       switch (handler->mode) {
+               case LC_MODE_CALLBACK:
+                       if (handler->callback != NULL) {
+                               retval = handler->callback(localvar, var, varargs, value, flags, handler->extra);
+                               if (retval < 0) {
+                                       lc_errno = LC_ERR_CALLBACK;
+                               }
+                               return(retval);
+                       }
+                       break;
+               case LC_MODE_VAR:
+                       return(lc_handle_type(handler->type, value, handler->data));
+                       break;
+       }
+
+       return(-1);
+}
+
+static int lc_process_environment(const char *appname) {
+#ifndef ENABLE_SMALL
+       struct lc_varhandler_st *handler = NULL;
+       size_t appnamelen = 0;
+       char varnamebuf[128] = {0};
+       char **currvar;
+       char *sep = NULL, *value = NULL, *cmd = NULL;
+       char *ucase_appname = NULL, *ucase_appname_itr = NULL;
+       char *lastcomponent_handler = NULL;
+       int varnamelen = 0;
+       char *local_lc_errfile;
+       int local_lc_errline;
+
+       /* Make sure we have an environment to screw with, if not,
+          no arguments were found to be in error */
+       if (environ == NULL || appname == NULL) {
+               return(0);
+       }
+
+       local_lc_errfile = "<environment>";
+       local_lc_errline = 0;
+
+       /* Allocate and create our uppercase appname. */
+       ucase_appname = strdup(appname);
+       if (ucase_appname == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_ENOMEM;
+               return(-1);
+       }
+       for (ucase_appname_itr = ucase_appname; *ucase_appname_itr != '\0'; ucase_appname_itr++) {
+               *ucase_appname_itr = toupper(*ucase_appname_itr);
+       }
+
+       appnamelen = strlen(ucase_appname);
+
+       for (currvar = environ; *currvar != NULL; currvar++) {
+               /* If it doesn't begin with our appname ignore it completely. */
+               if (strncmp(*currvar, ucase_appname, appnamelen) != 0) {
+                       continue;
+               }
+
+               /* Find our seperator. */
+               sep = strchr(*currvar, '=');
+               if (sep == NULL) {
+                       continue;
+               }
+
+               varnamelen = sep - *currvar;
+
+               /* Skip variables that would overflow our buffer. */
+               if (varnamelen >= sizeof(varnamebuf)) {
+                       continue;
+               }
+
+               strncpy(varnamebuf, *currvar, varnamelen);
+
+               varnamebuf[varnamelen] = '\0';
+               value = sep + 1;
+
+               /* We ignore APPNAME by itself. */
+               if (strlen(varnamebuf) <= appnamelen) {
+                       continue;
+               }
+
+               /* Further it must be <APPNAME>_ */
+               if (varnamebuf[appnamelen] != '_') {
+                       continue;
+               }
+
+               cmd = varnamebuf + appnamelen + 1;
+
+               /* We don't allow section specifiers, for reasons see notes in
+                  the cmdline processor (below). */
+               if (strchr(cmd, '.') != NULL) {
+                       continue;
+               }
+
+               for (handler = varhandlers; handler != NULL; handler = handler->_next) {
+                       if (handler->var == NULL) {
+                               continue;
+                       }
+
+                       /* Skip handlers which don't agree with being
+                          processed outside a config file */
+                       if (handler->type == LC_VAR_SECTION ||
+                           handler->type == LC_VAR_SECTIONSTART ||
+                           handler->type == LC_VAR_SECTIONEND ||
+                           handler->type == LC_VAR_UNKNOWN) {
+                               continue;
+                       }
+
+                       /* Find the last part of the variable and compare it with 
+                          the option being processed, if a wildcard is given. */
+                       if (handler->var[0] == '*' && handler->var[1] == '.') {
+                               lastcomponent_handler = strrchr(handler->var, '.');
+                               if (lastcomponent_handler == NULL) {
+                                       lastcomponent_handler = handler->var;
+                               } else {
+                                       lastcomponent_handler++;
+                               }
+                       } else {
+                               lastcomponent_handler = handler->var;
+                       }
+
+                       /* Ignore this handler if they don't match. */
+                       if (strcasecmp(lastcomponent_handler, cmd) != 0) {
+                               continue;
+                       }
+
+                       if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
+                               value = NULL;
+                       }
+
+                       /* We ignore errors from the environment variables,
+                          they're mostly insignificant. */
+                       lc_handle(handler, cmd, NULL, value, LC_FLAGS_ENVIRON);
+
+                       break;
+               }
+       }
+
+       free(ucase_appname);
+
+#endif
+       return(0);
+}
+
+static int lc_process_cmdline(int argc, char **argv) {
+       struct lc_varhandler_st *handler = NULL;
+       char *cmdarg = NULL, *cmdoptarg = NULL;
+       char *lastcomponent_handler = NULL;
+       char **newargv = NULL;
+       char *usedargv = NULL;
+       int cmdargidx = 0;
+       int newargvidx = 0;
+       int retval = 0, chkretval = 0;
+       int ch = 0;
+       char *local_lc_errfile;
+       int local_lc_errline;
+
+       local_lc_errfile = "<cmdline>";
+       local_lc_errline = 0;
+
+       /* Allocate "argc + 1" (+1 for the NULL terminator) elements. */
+       newargv = malloc((argc + 1) * sizeof(*newargv));
+       if (newargv == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_ENOMEM;
+               return(-1);
+       }
+       newargv[newargvidx++] = argv[0];
+       newargv[argc] = NULL;
+
+       /* Allocate space to indicate which arguments have been used. */
+       usedargv = malloc(argc * sizeof(*usedargv));
+       if (usedargv == NULL) {
+               lc_errfile = local_lc_errfile;
+               lc_errline = local_lc_errline;
+               lc_errno = LC_ERR_ENOMEM;
+               free(newargv);
+               return(-1);
+       }
+       for (cmdargidx = 0; cmdargidx < argc; cmdargidx++) {
+               usedargv[cmdargidx] = 0;
+       }
+
+       for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
+               cmdarg = argv[cmdargidx];
+
+               /* Make sure we have an argument here. */
+               if (cmdarg == NULL) {
+                       break;
+               }
+
+               /* If the argument isn't an option, skip. */
+               if (cmdarg[0] != '-') {
+                       continue;
+               }
+
+               /* Setup a pointer in the new array for the actual argument. */
+               newargv[newargvidx++] = cmdarg;
+               usedargv[cmdargidx] = 1;
+
+               /* Then shift the argument past the '-' so we can ignore it. */
+               cmdarg++;
+
+               /* Handle long options. */
+               if (cmdarg[0] == '-') {
+                       cmdarg++;
+
+                       /* Don't process arguments after the '--' option. */
+                       if (cmdarg[0] == '\0') {
+                               break;
+                       }
+
+                       /* Look for a variable name that matches */
+                       for (handler = varhandlers; handler != NULL; handler = handler->_next) {
+                               /* Skip handlers with no variable name. */
+                               if (handler->var == NULL) {
+                                       continue;
+                               }
+                               /* Skip handlers which don't agree with being
+                                  processed on the command line. */
+                               if (handler->type == LC_VAR_SECTION ||
+                                   handler->type == LC_VAR_SECTIONSTART ||
+                                   handler->type == LC_VAR_SECTIONEND ||
+                                   handler->type == LC_VAR_UNKNOWN) {
+                                       continue;
+                               }
+
+                               /* Find the last part of the variable and compare it with 
+                                  the option being processed, if a wildcard is given. */
+                               if (handler->var[0] == '*' && handler->var[1] == '.') {
+                                       lastcomponent_handler = strrchr(handler->var, '.');
+                                       if (lastcomponent_handler == NULL) {
+                                               lastcomponent_handler = handler->var;
+                                       } else {
+                                               lastcomponent_handler++;
+                                       }
+                               } else {
+                                       /* Disallow use of the fully qualified name
+                                          since there was no sectionstart portion
+                                          we cannot allow it to handle children of it. */
+                                       if (strchr(cmdarg, '.') != NULL) {
+                                               continue;
+                                       }
+                                       lastcomponent_handler = handler->var;
+                               }
+
+                               /* Ignore this handler if they don't match. */
+                               if (strcasecmp(lastcomponent_handler, cmdarg) != 0) {
+                                       continue;
+                               }
+
+                               if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
+                                       cmdoptarg = NULL;
+                               } else {
+                                       cmdargidx++;
+                                       if (cmdargidx >= argc) {
+                                               fprintf(stderr, "Argument required.\n");
+                                               lc_errfile = local_lc_errfile;
+                                               lc_errline = local_lc_errline;
+                                               lc_errno = LC_ERR_BADFORMAT;
+                                               free(usedargv);
+                                               free(newargv);
+                                               return(-1);
+                                       }
+                                       cmdoptarg = argv[cmdargidx];
+                                       newargv[newargvidx++] = cmdoptarg;
+                                       usedargv[cmdargidx] = 1;
+                               }
+
+                               chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE);
+                               if (chkretval < 0) {
+                                       retval = -1;
+                               }
+
+                               break;
+                       }
+
+                       if (handler == NULL) {
+                               fprintf(stderr, "Unknown option: --%s\n", cmdarg);
+                               lc_errfile = local_lc_errfile;
+                               lc_errline = local_lc_errline;
+                               lc_errno = LC_ERR_INVCMD;
+                               free(usedargv);
+                               free(newargv);
+                               return(-1);
+                       }
+               } else {
+                       for (; *cmdarg != '\0'; cmdarg++) {
+                               ch = *cmdarg;
+
+                               for (handler = varhandlers; handler != NULL; handler = handler->_next) {
+                                       if (handler->opt != ch || handler->opt == '\0') {
+                                               continue;
+                                       }
+                                       /* Skip handlers which don't agree with being
+                                          processed on the command line. */
+                                       if (handler->type == LC_VAR_SECTION ||
+                                           handler->type == LC_VAR_SECTIONSTART ||
+                                           handler->type == LC_VAR_SECTIONEND ||
+                                           handler->type == LC_VAR_UNKNOWN) {
+                                               continue;
+                                       }
+
+                                       if (handler->type == LC_VAR_NONE || handler->type == LC_VAR_BOOL_BY_EXISTANCE) {
+                                               cmdoptarg = NULL;
+                                       } else {
+                                               cmdargidx++;
+                                               if (cmdargidx >= argc) {
+                                                       fprintf(stderr, "Argument required.\n");
+                                                       lc_errfile = local_lc_errfile;
+                                                       lc_errline = local_lc_errline;
+                                                       lc_errno = LC_ERR_BADFORMAT;
+                                                       free(usedargv);
+                                                       free(newargv);
+                                                       return(-1);
+                                               }
+                                               cmdoptarg = argv[cmdargidx];
+                                               newargv[newargvidx++] = cmdoptarg;
+                                               usedargv[cmdargidx] = 1;
+                                       }
+
+                                       chkretval = lc_handle(handler, handler->var, NULL, cmdoptarg, LC_FLAGS_CMDLINE);
+                                       if (chkretval < 0) {
+                                               lc_errfile = local_lc_errfile;
+                                               lc_errline = local_lc_errline;
+                                               retval = -1;
+                                       }
+
+                                       break;
+                               }
+
+                               if (handler == NULL) {
+                                       fprintf(stderr, "Unknown option: -%c\n", ch);
+                                       lc_errfile = local_lc_errfile;
+                                       lc_errline = local_lc_errline;
+                                       lc_errno = LC_ERR_INVCMD;
+                                       free(usedargv);
+                                       free(newargv);
+                                       return(-1);
+                               }
+                       }
+               }
+       }
+
+       if (retval >= 0) {
+               lc_optind = newargvidx;
+               for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
+                       if (usedargv[cmdargidx] != 0) {
+                               continue;
+                       }
+                       
+                       cmdarg = argv[cmdargidx];
+
+                       newargv[newargvidx++] = cmdarg;
+               }
+               for (cmdargidx = 1; cmdargidx < argc; cmdargidx++) {
+                       argv[cmdargidx] = newargv[cmdargidx];
+               }
+       }
+
+       free(usedargv);
+       free(newargv);
+
+       return(retval);
+}
+
+
+int lc_process_var(const char *var, const char *varargs, const char *value, lc_flags_t flags) {
+       struct lc_varhandler_st *handler = NULL;
+       const char *lastcomponent_handler = NULL, *lastcomponent_var = NULL;
+
+       lastcomponent_var = strrchr(var, '.');
+       if (lastcomponent_var == NULL) {
+               lastcomponent_var = var;
+       } else {
+               lastcomponent_var++;
+       }
+
+       for (handler = varhandlers; handler != NULL; handler = handler->_next) {
+               /* If either handler->var or var is NULL, skip, unless both are NULL. */
+               if (handler->var != var && (handler->var == NULL || var == NULL)) {
+                       continue;
+               }
+
+               /* If both are not-NULL, compare them. */
+               if (handler->var != NULL) {
+                       /* Wild-card-ish match. */
+                       if (handler->var[0] == '*' && handler->var[1] == '.') {
+                               /* Only compare the last components */
+
+                               lastcomponent_handler = strrchr(handler->var, '.') + 1; /* strrchr() won't return NULL, because we already checked it. */
+
+                               if (strcasecmp(lastcomponent_handler, lastcomponent_var) != 0) {
+                                       continue;
+                               }
+                       } else if (strcasecmp(handler->var, var) != 0) {
+                               /* Exact (case-insensitive comparison) failed. */
+                               continue;
+                       }
+               }
+
+               if (value == NULL &&
+                   handler->type != LC_VAR_NONE &&
+                   handler->type != LC_VAR_BOOL_BY_EXISTANCE &&
+                   handler->type != LC_VAR_SECTION &&
+                   handler->type != LC_VAR_SECTIONSTART &&
+                   handler->type != LC_VAR_SECTIONEND) {
+                       lc_errno = LC_ERR_BADFORMAT;
+                       break;
+               }
+
+               return(lc_handle(handler, var, varargs, value, flags));
+       }
+
+       return(-1);
+}
+
+int lc_register_callback(const char *var, char opt, lc_var_type_t type, int (*callback)(const char *, const char *, const char *, const char *, lc_flags_t, void *), void *extra) {
+       struct lc_varhandler_st *newhandler = NULL;
+
+       newhandler = malloc(sizeof(*newhandler));
+
+       if (newhandler == NULL) {
+               return(-1);
+       }
+
+       if (var == NULL) {
+               newhandler->var = NULL;
+       } else {
+               newhandler->var = strdup(var);
+       }
+       newhandler->mode = LC_MODE_CALLBACK;
+       newhandler->type = type;
+       newhandler->callback = callback;
+       newhandler->opt = opt;
+       newhandler->extra = extra;
+       newhandler->_next = varhandlers;
+
+       varhandlers = newhandler;
+
+       return(0);
+}
+
+int lc_register_var(const char *var, lc_var_type_t type, void *data, char opt) {
+       struct lc_varhandler_st *newhandler = NULL;
+
+       newhandler = malloc(sizeof(*newhandler));
+
+       if (newhandler == NULL) {
+               return(-1);
+       }
+
+       if (var == NULL) {
+               newhandler->var = NULL;
+       } else {
+               newhandler->var = strdup(var);
+       }
+       newhandler->mode = LC_MODE_VAR;
+       newhandler->type = type;
+       newhandler->data = data;
+       newhandler->opt = opt;
+       newhandler->extra = NULL;
+       newhandler->_next = varhandlers;
+
+       varhandlers = newhandler;
+
+       return(0);
+}
+
+int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type) {
+       int chkretval = 0;
+
+       switch (type) {
+               case LC_CONF_SECTION:
+                       chkretval = lc_process_conf_section(appname, pathname);
+                       break;
+               case LC_CONF_APACHE:
+                       chkretval = lc_process_conf_apache(appname, pathname);
+                       break;
+               case LC_CONF_COLON:
+                       chkretval = lc_process_conf_colon(appname, pathname);
+                       break;
+               case LC_CONF_EQUAL:
+                       chkretval = lc_process_conf_equal(appname, pathname);
+                       break;
+               case LC_CONF_SPACE:
+                       chkretval = lc_process_conf_space(appname, pathname);
+                       break;
+               case LC_CONF_XML:
+                       chkretval = lc_process_conf_xml(appname, pathname);
+                       break;
+               default:
+                       chkretval = -1;
+                       lc_errno = LC_ERR_INVDATA;
+                       break;
+       }
+
+       return(chkretval);
+}
+
+static int lc_process_files(const char *appname, lc_conf_type_t type, const char *extraconfig) {
+#ifdef HAVE_GETPWUID
+       struct passwd *pwinfo = NULL;
+#endif
+       char configfiles[3][13][512] = {{{0}}};
+       char *configfile = NULL;
+       char *homedir = NULL;
+       int configsetidx = 0, configidx = 0;
+       int chkretval = 0, retval = 0;
+
+       if (extraconfig != NULL) {
+               snprintf(configfiles[0][0], sizeof(**configfiles) - 1, "%s", extraconfig);
+       }
+       snprintf(configfiles[1][0], sizeof(**configfiles) - 1, "/etc/%s.cfg", appname);
+       snprintf(configfiles[1][1], sizeof(**configfiles) - 1, "/etc/%s.conf", appname);
+       snprintf(configfiles[1][2], sizeof(**configfiles) - 1, "/etc/%s/%s.cfg", appname, appname);
+       snprintf(configfiles[1][3], sizeof(**configfiles) - 1, "/etc/%s/%s.conf", appname, appname);
+       snprintf(configfiles[1][4], sizeof(**configfiles) - 1, "/usr/etc/%s.cfg", appname);
+       snprintf(configfiles[1][5], sizeof(**configfiles) - 1, "/usr/etc/%s.conf", appname);
+       snprintf(configfiles[1][6], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.cfg", appname, appname);
+       snprintf(configfiles[1][7], sizeof(**configfiles) - 1, "/usr/etc/%s/%s.conf", appname, appname);
+       snprintf(configfiles[1][8], sizeof(**configfiles) - 1, "/usr/local/etc/%s.cfg", appname);
+       snprintf(configfiles[1][9], sizeof(**configfiles) - 1, "/usr/local/etc/%s.conf", appname);
+       snprintf(configfiles[1][10], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.cfg", appname, appname);
+       snprintf(configfiles[1][11], sizeof(**configfiles) - 1, "/usr/local/etc/%s/%s.conf", appname, appname);
+       if (getuid() != 0) {
+               homedir = getenv("HOME");
+#ifdef HAVE_GETPWUID
+               if (homedir == NULL) {
+                       pwinfo = getpwuid(getuid());
+                       if (pwinfo != NULL) {
+                               homedir = pwinfo->pw_dir;
+                       }
+               }
+#endif
+               if (homedir != NULL) {
+                       if (strcmp(homedir, "/") != 0 && access(homedir, R_OK|W_OK|X_OK) == 0) {
+                               snprintf(configfiles[2][0], sizeof(**configfiles) - 1, "%s/.%src", homedir, appname);
+                               snprintf(configfiles[2][1], sizeof(**configfiles) - 1, "%s/.%s.cfg", homedir, appname);
+                               snprintf(configfiles[2][2], sizeof(**configfiles) - 1, "%s/.%s.conf", homedir, appname);
+                               snprintf(configfiles[2][3], sizeof(**configfiles) - 1, "%s/.%s/%s.cfg", homedir, appname, appname);
+                               snprintf(configfiles[2][4], sizeof(**configfiles) - 1, "%s/.%s/%s.conf", homedir, appname, appname);
+                               snprintf(configfiles[2][5], sizeof(**configfiles) - 1, "%s/.%s/config", homedir, appname);
+                       }
+               }
+       }
+
+       for (configsetidx = 0; configsetidx < 3; configsetidx++) {
+               for (configidx = 0; configidx < 13; configidx++) {
+                       configfile = configfiles[configsetidx][configidx];
+                       if (configfile[0] == '\0') {
+                               break;
+                       }
+                       if (access(configfile, R_OK) == 0) {
+                               chkretval = lc_process_file(appname, configfile, type);
+                               if (chkretval < 0) {
+                                       retval = -1;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       return(retval);
+}
+
+void lc_cleanup(void) {
+       struct lc_varhandler_st *handler = NULL, *next = NULL;
+
+       handler = varhandlers;
+       while (handler != NULL) {
+               if (handler->var != NULL) {
+                       free(handler->var);
+               }
+
+               next = handler->_next;
+
+               free(handler);
+
+               handler = next;
+       }
+
+       varhandlers = NULL;
+
+       return;
+}
+
+int lc_process(int argc, char **argv, const char *appname, lc_conf_type_t type, const char *extra) {
+       int retval = 0, chkretval = 0;
+
+       /* Handle config files. */
+       chkretval = lc_process_files(appname, type, extra);
+       if (chkretval < 0) {
+               retval = -1;
+       }
+
+       /* Handle environment variables.*/
+       chkretval = lc_process_environment(appname);
+       if (chkretval < 0) {
+               retval = -1;
+       }
+
+       /* Handle command line arguments */
+       chkretval = lc_process_cmdline(argc, argv);
+       if (chkretval < 0) {
+               retval = -1;
+       }
+
+       return(retval);
+}
+
+
+lc_err_t lc_geterrno(void) {
+       lc_err_t retval;
+
+       retval = lc_errno;
+
+       lc_errno = LC_ERR_NONE;
+
+       return(retval);
+}
+
+char *lc_geterrstr(void) {
+       static char retval[512];
+       char *errmsg = NULL;
+
+       switch (lc_errno) {
+               case LC_ERR_NONE:
+                       errmsg = "Success";
+                       break;
+               case LC_ERR_INVCMD:
+                       errmsg = "Invalid command or option";
+                       break;
+               case LC_ERR_INVSECTION:
+                       errmsg = "Invalid section";
+                       break;
+               case LC_ERR_INVDATA:
+                       errmsg = "Invalid application data (internal error)";
+                       break;
+               case LC_ERR_BADFORMAT:
+                       errmsg = "Bad data specified or incorrect format.";
+                       break;
+               case LC_ERR_CANTOPEN:
+                       errmsg = "Can't open file.";
+                       break;
+               case LC_ERR_CALLBACK:
+                       errmsg = "Error return from application handler.";
+                       break;
+               case LC_ERR_ENOMEM:
+                       errmsg = "Insuffcient memory.";
+                       break;
+       }
+
+       /*
+        * This is not part of the switch statement so we will get warnings
+        * about unhandled enum values.
+        */
+       if (errmsg == NULL) {
+               errmsg = "Unknown error";
+       }
+
+       if (lc_errfile == NULL) {
+               snprintf(retval, sizeof(retval), "%s:%i: %s", "<no file>", lc_errline, errmsg);
+       } else {
+               snprintf(retval, sizeof(retval), "%s:%i: %s", lc_errfile, lc_errline, errmsg);
+       }
+
+       retval[sizeof(retval) - 1] = '\0';
+
+       return(retval);
+}
diff --git a/src/libconfig/libconfig.h b/src/libconfig/libconfig.h
new file mode 100644 (file)
index 0000000..8c2f361
--- /dev/null
@@ -0,0 +1,84 @@
+#  ifndef _RSK_LIBCONFIG_H
+#  define _RSK_LIBCONFIG_H
+#  ifdef __cplusplus
+extern "C" {
+#  endif
+
+#  define LC_VAR_LIST 0x80
+
+typedef enum {
+        LC_CONF_SECTION,
+        LC_CONF_APACHE,
+        LC_CONF_COLON,
+        LC_CONF_EQUAL,
+        LC_CONF_SPACE,
+        LC_CONF_XML
+} lc_conf_type_t;
+
+typedef enum {
+        LC_VAR_UNKNOWN,
+        LC_VAR_NONE,
+        LC_VAR_STRING,
+        LC_VAR_LONG_LONG,
+        LC_VAR_LONG,
+        LC_VAR_INT,
+        LC_VAR_SHORT,
+        LC_VAR_BOOL,
+        LC_VAR_FILENAME,
+        LC_VAR_DIRECTORY,
+        LC_VAR_SIZE_LONG_LONG,
+        LC_VAR_SIZE_LONG,
+        LC_VAR_SIZE_INT,
+        LC_VAR_SIZE_SHORT,
+        LC_VAR_TIME,
+        LC_VAR_DATE,
+        LC_VAR_SECTION,
+        LC_VAR_SECTIONSTART,
+        LC_VAR_SECTIONEND,
+        LC_VAR_BOOL_BY_EXISTANCE,
+        LC_VAR_SIZE_SIZE_T,
+        LC_VAR_CIDR,
+        LC_VAR_IP,
+        LC_VAR_IP4,
+        LC_VAR_IP6,
+        LC_VAR_HOSTNAME4,
+        LC_VAR_HOSTNAME6,
+} lc_var_type_t;
+
+typedef enum {
+        LC_FLAGS_VAR,
+        LC_FLAGS_CMDLINE,
+        LC_FLAGS_ENVIRON,
+        LC_FLAGS_SECTIONSTART,
+        LC_FLAGS_SECTIONEND
+} lc_flags_t;
+
+typedef enum {
+        LC_ERR_NONE,
+        LC_ERR_INVCMD,
+        LC_ERR_INVSECTION,
+        LC_ERR_INVDATA,
+        LC_ERR_BADFORMAT,
+        LC_ERR_CANTOPEN,
+        LC_ERR_CALLBACK,
+        LC_ERR_ENOMEM
+} lc_err_t;
+
+int lc_process(int argc, char **argv, const char *appname, lc_conf_type_t type, const char *extra);
+int lc_register_callback(const char *var, char opt, lc_var_type_t type, int (*callback)(const char *, const char *, const char *, const char *, lc_flags_t, void *), void *extra);
+int lc_register_var(const char *var, lc_var_type_t type, void *data, char opt);
+lc_err_t lc_geterrno(void);
+char *lc_geterrstr(void);
+int lc_process_file(const char *appname, const char *pathname, lc_conf_type_t type);
+void lc_cleanup(void);
+
+#  define LC_CBRET_IGNORESECTION (255)
+#  define LC_CBRET_OKAY (0)
+#  define LC_CBRET_ERROR (-1)
+
+extern int lc_optind;
+
+#  ifdef __cplusplus
+}
+#  endif
+#  endif
diff --git a/src/libconfig/libconfig_private.h b/src/libconfig/libconfig_private.h
new file mode 100644 (file)
index 0000000..8310a85
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _RSK_LIBCONFIG_PRIVATE_H
+#define _RSK_LIBCONFIG_PRIVATE_H
+
+#include "libconfig.h"
+
+extern lc_err_t lc_errno;
+extern int lc_errline;
+extern const char *lc_errfile;
+
+int lc_process_var(const char *var, const char *varargs, const char *value, lc_flags_t flags);
+
+struct lc_varhandler_st;
+
+struct lc_varhandler_st {
+       struct lc_varhandler_st *_next;
+       char *var;
+       char opt;
+       lc_var_type_t type;
+       enum {
+               LC_MODE_CALLBACK,
+               LC_MODE_VAR
+       } mode;
+       int (*callback)();
+       void *data;
+       void *extra;
+};
+
+#endif
diff --git a/src/libconfig/test-lc.c b/src/libconfig/test-lc.c
new file mode 100644 (file)
index 0000000..ed492d8
--- /dev/null
@@ -0,0 +1,79 @@
+#include "compat.h"
+#include "libconfig.h"
+
+int help_cmd(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
+       printf("Usage info goes here\n");
+       printf("\n");
+
+       exit(EXIT_FAILURE);
+}
+int sally_cmd(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
+       fprintf(stderr, "%s sets value: \"%s\" (flags=%i)\n", arg, val, flags);
+       return(0);
+}
+
+int cmd_ifmodule(const char *partarg, const char *arg, const char *argarg, const char *val, lc_flags_t flags, void *extra) {
+       if (flags == LC_FLAGS_SECTIONEND) {
+               return(LC_CBRET_OKAY);
+       }
+       if (flags != LC_FLAGS_SECTIONSTART) {
+               fprintf(stderr, "IfModule can only be used as a section.\n");
+               return(LC_CBRET_ERROR);
+       }
+       if (argarg == NULL) {
+               fprintf(stderr, "You must specify an argument to IfModule.\n");
+               return(LC_CBRET_ERROR);
+       }
+
+       fprintf(stderr, "IfModule (%s)\n", argarg);
+       return(LC_CBRET_IGNORESECTION);
+}
+
+int main(int argc, char **argv) {
+       char *joeval = NULL;
+       size_t xval = -1;
+       int onoff = -1;
+       int lcpret = -1;
+       int i = 0;
+       int onoff2 = 0;
+       uint32_t ipaddr = 0;
+
+       lc_register_var("Section", LC_VAR_SECTION, NULL, 0);
+       lc_register_var("Somesection", LC_VAR_SECTION, NULL, 0);
+       lc_register_var("Section.Test", LC_VAR_STRING, &joeval, 'j');
+       lc_register_var("bob", LC_VAR_SIZE_SIZE_T, &xval, 's');
+       lc_register_var("Somesection.Free", LC_VAR_BOOL, &onoff, 0);
+       lc_register_var("long", LC_VAR_BOOL_BY_EXISTANCE, &onoff2, 'l');
+       lc_register_var("ipaddr", LC_VAR_IP, &ipaddr, 'i');
+       lc_register_callback("sally", 0, LC_VAR_STRING, sally_cmd, NULL);
+       lc_register_callback("HELP", 'h', LC_VAR_NONE, help_cmd, NULL);
+       lc_register_callback("*.ifmodule", 0, LC_VAR_NONE, cmd_ifmodule, NULL);
+       lcpret = lc_process_file("testapp", "build/test.conf", LC_CONF_APACHE);
+       if (lcpret < 0) {
+               fprintf(stderr, "Error processing config file: %s\n", lc_geterrstr());
+               return(EXIT_FAILURE);
+       }
+
+       lcpret = lc_process(argc, argv, "testapp", LC_CONF_APACHE, "test.cfg");
+       if (lcpret < 0) {
+               fprintf(stderr, "Error processing config file: %s\n", lc_geterrstr());
+               return(EXIT_FAILURE);
+       }
+
+       lc_cleanup();
+
+       if (joeval != NULL) {
+               fprintf(stderr, "joeval = \"%s\"\n", joeval);
+       } else {
+               fprintf(stderr, "joeval = \"(null)\"\n");
+       }
+       fprintf(stderr, "xval = %llu\n", (unsigned long long) xval);
+       fprintf(stderr, "onoff = %i\n", onoff);
+       fprintf(stderr, "long = %i\n", onoff2);
+       fprintf(stderr, "ip = %08lx\n", (unsigned long) ipaddr);
+       for (i = lc_optind; i < argc; i++) {
+               fprintf(stderr, "argv[%i] = \"%s\"\n", i, argv[i]);
+       }
+
+       return(0);
+}
diff --git a/src/libconfig/win32.h b/src/libconfig/win32.h
new file mode 100644 (file)
index 0000000..06f3a0d
--- /dev/null
@@ -0,0 +1,44 @@
+#if !defined(_LOCAL_WIN32_H) && defined(__WIN32__) && !defined(__CYGWIN__)
+#define _LOCAL_WIN32_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __MINGW32__
+     /* MingW32 specific stuff here. */
+#  if defined(HAVE_WINSOCK2_H) && defined(HAVE_LIBWSOCK32)
+     /* We have to override the detected configuration
+        because it can't detect the network libraries. */
+#    define HAVE_GETHOSTBYNAME 1
+#    define HAVE_INET_ADDR 1
+#    define HAVE_SOCKET 1
+#  endif
+#  define sleep(x) Sleep((x) * 1000)
+#else
+   /* MSVC++ configuration follows */
+#  undef HAVE_UNISTD_H
+#  define HAVE_STDLIB_H 1
+#  define HAVE_WINDOWS_H 1
+#  define HAVE_STDARG_H 1
+#  define HAVE_WINSVC_H 1
+#  define HAVE_WINSOCK2_H 1
+#  define HAVE_WINDOWSX_H 1
+#endif /* __MINGW32__ */
+
+#ifdef HAVE_WINDOWS_H
+#  include <windows.h>
+#endif
+#ifdef HAVE_WINDOWSX_H
+#  include <windowsx.h>
+#endif
+#ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+#endif
+#ifdef HAVE_WINSVC_H
+#  include <winsvc.h>
+#endif
+
+#define _USE_WIN32_ 1
+
+#endif /* _LOCAL_WIN32_H */
index d418232..e6456f8 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;
+
 void ping_init (void)
 {
        int i;
@@ -54,6 +62,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];
@@ -129,6 +159,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 a6792de..87668d7 100644 (file)
@@ -42,6 +42,27 @@ static plugin_t *first_plugin = NULL;
 extern int operating_mode;
 #endif
 
+static char *plugindir = NULL;
+
+char *plugin_get_dir (void)
+{
+       if (plugindir == NULL)
+               return (PLUGINDIR);
+       else
+               return (plugindir);
+}
+
+void plugin_set_dir (char *dir)
+{
+       if (plugindir != NULL)
+               free (plugindir);
+
+       if (dir == NULL)
+               plugindir = NULL;
+       else if ((plugindir = strdup (dir)) == NULL)
+               syslog (LOG_ERR, "strdup: %s", strerror (errno));
+}
+
 /*
  * Returns the number of plugins registered
  */
@@ -59,7 +80,7 @@ int plugin_count (void)
 /*
  * Returns the plugins with the type `type' or NULL if it's not found.
  */
-plugin_t *plugin_search (char *type)
+plugin_t *plugin_search (const char *type)
 {
        plugin_t *ret;
 
@@ -74,11 +95,23 @@ plugin_t *plugin_search (char *type)
 }
 
 /*
- * (Try to) load the shared object `name'. Won't complain if it isn't a shared
+ * Returns true if the plugin is loaded (i.e. `exists') and false otherwise.
+ * This is used in `configfile.c' to skip sections that are not needed..
+ */
+int plugin_exists (char *type)
+{
+       if (plugin_search (type) == NULL)
+               return (0);
+       else
+               return (1);
+}
+
+/*
+ * (Try to) load the shared object `file'. Won't complain if it isn't a shared
  * object, but it will bitch about a shared object not having a
  * ``module_register'' symbol..
  */
-void plugin_load (char *name)
+int plugin_load_file (char *file)
 {
        lt_dlhandle dlh;
        void (*reg_handle) (void);
@@ -86,24 +119,94 @@ void plugin_load (char *name)
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
 
-       if ((dlh = lt_dlopen (name)) == NULL)
-               return;
+       if ((dlh = lt_dlopen (file)) == NULL)
+               return (1);
 
        if ((reg_handle = lt_dlsym (dlh, "module_register")) == NULL)
        {
                syslog (LOG_WARNING, "Couldn't find symbol ``module_register'' in ``%s'': %s\n",
-                               name, lt_dlerror ());
+                               file, lt_dlerror ());
                lt_dlclose (dlh);
-               return;
+               return (-1);
        }
 
        (*reg_handle) ();
+
+       return (0);
+}
+
+#define BUFSIZE 512
+int plugin_load (const char *type)
+{
+       DIR  *dh;
+       char *dir;
+       char  filename[BUFSIZE];
+       char  typename[BUFSIZE];
+       int   typename_len;
+       int   ret;
+       struct stat    statbuf;
+       struct dirent *de;
+
+       dir = plugin_get_dir ();
+       ret = 1;
+
+       /* don't load twice */
+       if (plugin_search (type) != NULL)
+               return (0);
+
+       /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
+        * type when matching the filename */
+       if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
+       {
+               syslog (LOG_WARNING, "snprintf: truncated: `%s.so'", type);
+               return (-1);
+       }
+       typename_len = strlen (typename);
+
+       if ((dh = opendir (dir)) == NULL)
+       {
+               syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
+               return (-1);
+       }
+
+       while ((de = readdir (dh)) != NULL)
+       {
+               if (strncasecmp (de->d_name, typename, typename_len))
+                       continue;
+
+               if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
+               {
+                       syslog (LOG_WARNING, "snprintf: truncated: `%s/%s'", dir, de->d_name);
+                       continue;
+               }
+
+               if (lstat (filename, &statbuf) == -1)
+               {
+                       syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
+                       continue;
+               }
+               else if (!S_ISREG (statbuf.st_mode))
+               {
+                       /* don't follow symlinks */
+                       continue;
+               }
+
+               if (plugin_load_file (filename) == 0)
+               {
+                       /* success */
+                       ret = 0;
+                       break;
+               }
+       }
+
+       closedir (dh);
+
+       return (ret);
 }
 
 /*
  * (Try to) load all plugins in `dir'. Returns the number of loaded plugins..
  */
-#define BUFSIZE 512
 int plugin_load_all (char *dir)
 {
        DIR *dh;
@@ -112,18 +215,23 @@ int plugin_load_all (char *dir)
        struct stat statbuf;
 
        if (dir == NULL)
-               dir = PLUGINDIR;
+               dir = plugin_get_dir ();
+       else
+               plugin_set_dir (dir);
 
        if ((dh = opendir (dir)) == NULL)
        {
-               fprintf (stderr, "Error: Cannot read plugin directory `%s'\n", dir);
+               syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
                return (0);
        }
 
        while ((de = readdir (dh)) != NULL)
        {
                if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
+               {
+                       syslog (LOG_WARNING, "snprintf: truncated: %s/%s", dir, de->d_name);
                        continue;
+               }
 
                if (lstat (filename, &statbuf) == -1)
                {
@@ -135,7 +243,7 @@ int plugin_load_all (char *dir)
                        continue;
                }
 
-               plugin_load (filename);
+               plugin_load_file (filename);
        }
 
        closedir (dh);
index 4a8b7ad..8749327 100644 (file)
 #ifndef PLUGIN_H
 #define PLUGIN_H
 
+/*
+ * NAME
+ *  plugin_set_dir
+ *
+ * DESCRIPTION
+ *  Sets the current `plugindir'
+ *
+ * ARGUMENTS
+ *  `dir'       Path to the plugin directory
+ *
+ * NOTES
+ *  If `dir' is NULL the compiled in default `PLUGINDIR' is used.
+ */
+void plugin_set_dir (char *dir);
+
+/*
+ * NAME
+ *  plugin_count
+ *
+ * DESCRIPTION
+ *  trivial
+ *
+ * RETURN VALUE
+ *  The number of currently loaded plugins
+ */
+int plugin_count (void);
+
+/*
+ * NAME
+ *  plugin_exists
+ *
+ * DESCRIPTION
+ *  trivial
+ *
+ * ARGUMENTS
+ *  `type'      Name of the plugin.
+ *
+ * RETURN VALUE
+ *  Returns non-zero if a plugin with the name $type is found and zero
+ *  otherwise.
+ */
+int plugin_exists (char *type);
+
+/*
+ * NAME
+ *  plugin_load
+ *
+ * DESCRIPTION
+ *  Searches the current `plugindir' (see `plugin_set_dir') for the plugin
+ *  named $type and loads it. Afterwards the plugin's `module_register'
+ *  function is called, which then calls `plugin_register' to register callback
+ *  functions.
+ *
+ * ARGUMENTS
+ *  `type'      Name of the plugin to load.
+ *
+ * RETURN VALUE
+ *  Returns zero upon success, a value greater than zero if no plugin was found
+ *  and a value below zero if an error occurs.
+ *
+ * NOTES
+ *  No attempt is made to re-load an already loaded module.
+ */
+int  plugin_load (const char *type);
+
 int  plugin_load_all (char *dir);
 void plugin_init_all (void);
 void plugin_read_all (void);
@@ -31,6 +96,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 */