aboutsummaryrefslogtreecommitdiff
path: root/sftp_server/libconfig/libconfig.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp_server/libconfig/libconfig.c')
-rw-r--r--sftp_server/libconfig/libconfig.c954
1 files changed, 954 insertions, 0 deletions
diff --git a/sftp_server/libconfig/libconfig.c b/sftp_server/libconfig/libconfig.c
new file mode 100644
index 00000000..3069708f
--- /dev/null
+++ b/sftp_server/libconfig/libconfig.c
@@ -0,0 +1,954 @@
+#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;
+int lc_optind = 0;
+
+extern char **environ;
+
+static int lc_process_var_string(void *data, const char *value) {
+ char **dataval;
+
+ dataval = data;
+ *dataval = strdup(value);
+
+ return(0);
+}
+
+static int lc_process_var_cidr(void *data, const char *value) {
+ return(0);
+}
+
+static int lc_process_var_ip(void *data, const char *value) {
+ uint32_t *dataval = NULL, retval = 0;
+ const char *dotptr = NULL;
+ int tmpval = -1;
+
+ 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;
+
+ return(0);
+}
+
+static int lc_process_var_longlong(void *data, const char *value) {
+ long long *dataval;
+
+ dataval = data;
+ *dataval = strtoll(value, NULL, 10);
+
+ return(0);
+}
+
+static int lc_process_var_long(void *data, const char *value) {
+ long *dataval;
+
+ dataval = data;
+ *dataval = strtoll(value, NULL, 10);
+
+ return(0);
+}
+
+static int lc_process_var_int(void *data, const char *value) {
+ int *dataval;
+
+ dataval = data;
+ *dataval = strtoll(value, NULL, 10);
+
+ return(0);
+}
+
+static int lc_process_var_short(void *data, const char *value) {
+ short *dataval;
+
+ dataval = data;
+ *dataval = strtoll(value, NULL, 10);
+
+ return(0);
+}
+
+static int lc_process_var_bool_byexistance(void *data, const char *value) {
+ int *dataval;
+
+ dataval = data;
+
+ *dataval = 1;
+
+ return(0);
+}
+
+static int lc_process_var_bool(void *data, const char *value) {
+ int *dataval;
+
+ dataval = data;
+
+ *dataval = -1;
+
+ if (strcasecmp(value, "enable") == 0 ||
+ strcasecmp(value, "true") == 0 ||
+ strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "on") == 0 ||
+ strcasecmp(value, "y") == 0 ||
+ strcasecmp(value, "1") == 0) {
+ *dataval = 1;
+ return(0);
+ } else if (strcasecmp(value, "disable") == 0 ||
+ strcasecmp(value, "false") == 0 ||
+ strcasecmp(value, "off") == 0 ||
+ strcasecmp(value, "no") == 0 ||
+ strcasecmp(value, "n") == 0 ||
+ strcasecmp(value, "0") == 0) {
+ *dataval = 0;
+ return(0);
+ }
+
+ lc_errno = LC_ERR_BADFORMAT;
+ return(-1);
+}
+
+static long long lc_process_size(const char *value) {
+ long long retval = -1;
+ 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) {
+ long long *dataval;
+
+ dataval = data;
+ *dataval = lc_process_size(value);
+
+ return(0);
+}
+
+static int lc_process_var_sizelong(void *data, const char *value) {
+ long *dataval;
+
+ dataval = data;
+ *dataval = lc_process_size(value);
+
+ return(0);
+}
+
+static int lc_process_var_sizeint(void *data, const char *value) {
+ int *dataval;
+
+ dataval = data;
+ *dataval = lc_process_size(value);
+
+ return(0);
+}
+
+static int lc_process_var_sizeshort(void *data, const char *value) {
+ short *dataval;
+
+ dataval = data;
+ *dataval = lc_process_size(value);
+
+ return(0);
+}
+
+static int lc_process_var_sizesizet(void *data, const char *value) {
+ size_t *dataval;
+
+ dataval = data;
+ *dataval = lc_process_size(value);
+
+ return(0);
+}
+
+
+static int lc_handle_type(lc_var_type_t type, const char *value, void *data) {
+ switch (type) {
+ case LC_VAR_STRING:
+ return(lc_process_var_string(data, value));
+ break;
+ case LC_VAR_LONG_LONG:
+ return(lc_process_var_longlong(data, value));
+ break;
+ case LC_VAR_LONG:
+ return(lc_process_var_long(data, value));
+ break;
+ case LC_VAR_INT:
+ return(lc_process_var_int(data, value));
+ break;
+ case LC_VAR_SHORT:
+ return(lc_process_var_short(data, value));
+ break;
+ case LC_VAR_BOOL:
+ return(lc_process_var_bool(data, value));
+ break;
+ case LC_VAR_SIZE_LONG_LONG:
+ return(lc_process_var_sizelonglong(data, value));
+ break;
+ case LC_VAR_SIZE_LONG:
+ return(lc_process_var_sizelong(data, value));
+ break;
+ case LC_VAR_SIZE_INT:
+ return(lc_process_var_sizeint(data, value));
+ break;
+ case LC_VAR_SIZE_SHORT:
+ return(lc_process_var_sizeshort(data, value));
+ break;
+ case LC_VAR_BOOL_BY_EXISTANCE:
+ return(lc_process_var_bool_byexistance(data, value));
+ break;
+ case LC_VAR_SIZE_SIZE_T:
+ return(lc_process_var_sizesizet(data, value));
+ break;
+ case LC_VAR_IP:
+ return(lc_process_var_ip(data, value));
+ break;
+ case LC_VAR_CIDR:
+ return(lc_process_var_cidr(data, value));
+ 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;
+
+ /* 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);
+ }
+
+ /* Allocate and create our uppercase appname. */
+ ucase_appname = strdup(appname);
+ if (ucase_appname == NULL) {
+ 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;
+
+ /* Allocate "argc + 1" (+1 for the NULL terminator) elements. */
+ newargv = malloc((argc + 1) * sizeof(*newargv));
+ if (newargv == NULL) {
+ 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_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, abort. */
+ 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_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_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_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: -%c\n", ch);
+ 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;
+ }
+
+ 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) {
+ char *retval = NULL;
+
+ switch (lc_errno) {
+ case LC_ERR_NONE:
+ retval = "Success";
+ break;
+ case LC_ERR_INVCMD:
+ retval = "Invalid command";
+ break;
+ case LC_ERR_INVSECTION:
+ retval = "Invalid section";
+ break;
+ case LC_ERR_INVDATA:
+ retval = "Invalid application data (internal error)";
+ break;
+ case LC_ERR_BADFORMAT:
+ retval = "Bad data specified or incorrect format.";
+ break;
+ case LC_ERR_CANTOPEN:
+ retval = "Can't open file.";
+ break;
+ case LC_ERR_CALLBACK:
+ retval = "Error return from application handler.";
+ break;
+ case LC_ERR_ENOMEM:
+ retval = "Insuffcient memory.";
+ break;
+ }
+
+ lc_errno = LC_ERR_NONE;
+
+ if (retval != NULL) {
+ return(retval);
+ }
+ return("Unknown error");
+}