/*
* Copyright (c) 2008-2010 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Configuration file loading.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "pathnames.h"
struct cnc_config *
cnc_config_open(const char *file)
{
char path[FILENAME_MAX];
struct cnc_config *cf;
char *data, *s, *line;
size_t len, nRead;
ssize_t rv;
int fd;
if (file == NULL) {
strlcpy(path, _PATH_CNC_CONF, sizeof(path));
} else {
strlcpy(path, file, sizeof(path));
}
if ((fd = open(path, O_RDONLY)) == -1) {
cnc_set_error("%s: %s", path, strerror(errno));
return (NULL);
}
if ((len = (size_t)lseek(fd, 0, SEEK_END)) == 0) {
if ((cf = malloc(sizeof(struct cnc_config))) == NULL) {
cnc_set_error("Out of memory");
close(fd);
return (NULL);
}
cf->keys = NULL;
cf->vals = NULL;
cf->nvals = 0;
return (cf);
}
lseek(fd, 0, SEEK_SET);
if ((data = malloc(len)) == NULL) {
close(fd);
return (NULL);
}
for (nRead = 0; nRead < len; ) {
rv = read(fd, &data[nRead], len-nRead);
if (rv == -1) {
if (errno == EINTR) { continue; }
goto fail_read;
} else if (rv == 0) {
goto fail_read;
}
nRead += rv;
}
close(fd);
if ((cf = malloc(sizeof(struct cnc_config))) == NULL) {
goto outofmem;
}
if ((cf->keys = malloc(sizeof(char **))) == NULL) {
free(cf);
goto outofmem;
}
if ((cf->vals = malloc(sizeof(char **))) == NULL) {
free(cf->keys);
free(cf);
goto outofmem;
}
cf->nvals = 0;
s = data;
while ((line = strsep(&s, "\n")) != NULL) {
char *c = &line[0], *cKey, *cVal;
while (isspace(*c)) {
c++;
}
if (*c == '#')
continue;
cKey = strsep(&c, "=");
cVal = strsep(&c, "=");
if (cKey == NULL || cVal == NULL)
continue;
while (isspace(*cKey)) { cKey++; }
while (isspace(*cVal)) { cVal++; }
len = strlen(cKey)-1;
for (;;) {
if (!isspace(cKey[len])) {
break;
}
cKey[len] = '\0';
len--;
}
cf->keys = realloc(cf->keys, (cf->nvals+1)*sizeof(char *));
cf->vals = realloc(cf->vals, (cf->nvals+1)*sizeof(char *));
if (cf->keys == NULL || cf->vals == NULL) {
goto outofmem;
}
if ((cf->keys[cf->nvals] = strdup(cKey)) == NULL) {
goto outofmem;
}
if ((cf->vals[cf->nvals] = strdup(cVal)) == NULL) {
goto outofmem;
}
cf->nvals++;
}
free(data);
return (cf);
fail_read:
cnc_set_error("Read error");
close(fd);
free(data);
return (NULL);
outofmem:
cnc_set_error("Out of memory");
free(data);
return (NULL);
}
void
cnc_config_close(struct cnc_config *cf)
{
free(cf->keys);
free(cf->vals);
free(cf);
}
void
cnc_config_int(struct cnc_config *cf, const char *key, int *pVal, int dVal)
{
u_int i;
char *val;
for (i = 0; i < cf->nvals; i++) {
if (!strcasecmp(cf->keys[i], key)) {
val = cf->vals[i];
if (!strcasecmp(val, "true") ||
!strcasecmp(val, "yes") ||
!strcasecmp(val, "on")) {
*pVal = 1;
} else if (!strcasecmp(val, "false") ||
!strcasecmp(val, "no") ||
!strcasecmp(val, "off")) {
*pVal = 0;
} else {
*pVal = (int)strtol(cf->vals[i], NULL, 10);
}
return;
}
}
*pVal = dVal;
}
void
cnc_config_uint(struct cnc_config *cf, const char *key, u_int *pVal, u_int dVal)
{
u_int i;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
*pVal = (u_int)strtoul(cf->vals[i], NULL, 10);
return;
}
}
*pVal = dVal;
}
void
cnc_config_long(struct cnc_config *cf, const char *key, long *pVal, long dVal)
{
u_int i;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
*pVal = (long)strtoul(cf->vals[i], NULL, 10);
return;
}
}
*pVal = dVal;
}
void
cnc_config_ulong(struct cnc_config *cf, const char *key, u_long *pVal, u_long dVal)
{
u_int i;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
*pVal = strtoul(cf->vals[i], NULL, 10);
return;
}
}
*pVal = dVal;
}
void
cnc_config_flt(struct cnc_config *cf, const char *key, float *pVal, float dVal)
{
u_int i;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
*pVal = (float)strtod(cf->vals[i], NULL);
return;
}
}
*pVal = (float)dVal;
}
void
cnc_config_dbl(struct cnc_config *cf, const char *key, double *pVal, double dVal)
{
u_int i;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
*pVal = strtod(cf->vals[i], NULL);
return;
}
}
*pVal = dVal;
}
void
cnc_config_string(struct cnc_config *cf, const char *key, char **pVal,
const char *dVal)
{
u_int i;
size_t len;
char *s;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
if ((s = strdup(cf->vals[i])) == NULL) {
cnc_set_error("Out of memory");
*pVal = NULL;
return;
}
if (*s == '"' || *s == '\'') { s++; }
len = strlen(s);
if (s[len-1] == '"' || s[len-1] == '\'') {
s[len-1] = '\0';
}
*pVal = s;
return;
}
}
if ((*pVal = strdup(dVal)) == NULL) {
cnc_set_error("Out of memory");
*pVal = NULL;
}
}
void
cnc_config_strlcpy(struct cnc_config *cf, const char *key, char *dst,
size_t len, const char *dVal)
{
u_int i;
size_t sLen;
for (i = 0; i < cf->nvals; i++) {
if (strcasecmp(cf->keys[i], key) == 0) {
char *s = cf->vals[i];
if (*s == '"' || *s == '\'') { s++; }
strlcpy(dst, s, len);
sLen = strlen(dst);
if (dst[sLen-1] == '"' || dst[sLen-1] == '\'') {
dst[sLen-1] = '\0';
}
return;
}
}
strlcpy(dst, dVal, len);
}