mbusd/src/cfg.c

338 lines
7.9 KiB
C

/*
* OpenMODBUS/TCP to RS-232/485 MODBUS RTU gateway
*
* cfg.c - configuration related procedures
*
* Copyright (c) 2002-2003, 2013, Victor Antonovich (v.antonovich@gmail.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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 REGENTS 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.
*
* $Id: cfg.c,v 1.3 2015/02/25 10:33:57 kapyar Exp $
*/
#include "cfg.h"
#include <stdlib.h>
#include <string.h>
#include "util.h"
#define CFG_MAX_LINE_LENGTH 200
#define CFG_NAME_MATCH(n) strcmp(n, name) == 0
#define CFG_VALUE_MATCH(n) strcasecmp(n, value) == 0
#define CFG_VALUE_BOOL() (strcasecmp("y", value) == 0 || strcasecmp("yes", value) == 0)
/* Global configuration storage variable */
cfg_t cfg;
/* Configuration error message */
char cfg_err[INTBUFSIZE + 1];
#define CFG_ERR(s, v) snprintf(cfg_err, INTBUFSIZE, s, v)
/*
* Setting up config defaults
*/
void
cfg_init(void)
{
#ifdef LOG
cfg.dbglvl = 2;
strncpy(cfg.logname, LOGNAME, INTBUFSIZE);
#endif
strncpy(cfg.ttyport, DEFAULT_PORT, INTBUFSIZE);
cfg.ttyspeed = DEFAULT_SPEED;
strncpy(cfg.ttymode, DEFAULT_MODE, INTBUFSIZE);
#ifdef HAVE_TIOCRS485
cfg.rs485 = FALSE;
#endif
#ifdef TRXCTL
cfg.trxcntl = TRX_ADDC;
*cfg.trxcntl_file = '\0';
#endif
strncpy(cfg.serveraddr, DEFAULT_SERVERADDR, INTBUFSIZE);
cfg.serverport = DEFAULT_SERVERPORT;
cfg.maxconn = DEFAULT_MAXCONN;
cfg.maxtry = DEFAULT_MAXTRY;
cfg.rqstpause = DEFAULT_RQSTPAUSE;
cfg.respwait = DEFAULT_RESPWAIT;
cfg.conntimeout = DEFAULT_CONNTIMEOUT;
cfg.replyonbroadcast=0;
}
int
cfg_handle_param(char *name, char *value)
{
if (CFG_NAME_MATCH("device"))
{
strncpy(cfg.ttyport, value, INTBUFSIZE);
}
else if (CFG_NAME_MATCH("speed"))
{
char *end;
cfg.ttyspeed = strtoul(value, &end, 0);
if (!cfg.ttyspeed || value == end || '\0' != *end)
{
CFG_ERR("invalid serial port speed: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("mode"))
{
int mode_invalid;
if (strlen(value) != 3)
mode_invalid = 1;
else
{
char parity = toupper(value[1]);
mode_invalid = value[0] != '8' || (value[2] != '1' && value[2] != '2') ||
(parity != 'N' && parity != 'E' && parity != 'O');
}
if (mode_invalid)
{
CFG_ERR("invalid device mode: %s", value);
return 0;
}
strncpy(cfg.ttymode, value, INTBUFSIZE);
}
else if (CFG_NAME_MATCH("address"))
{
strncpy(cfg.serveraddr, value, INTBUFSIZE);
}
else if (CFG_NAME_MATCH("port"))
{
cfg.serverport = strtoul(value, NULL, 0);
}
else if (CFG_NAME_MATCH("maxconn"))
{
cfg.maxconn = strtoul(value, NULL, 0);
if (cfg.maxconn < 1 || cfg.maxconn > MAX_MAXCONN)
{
CFG_ERR("invalid maxconn value: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("retries"))
{
cfg.maxtry = strtoul(value, NULL, 0);
if (cfg.maxtry > MAX_MAXTRY)
{
CFG_ERR("invalid retries value: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("pause"))
{
cfg.rqstpause = strtoul(value, NULL, 0);
if (cfg.rqstpause < 1 || cfg.rqstpause > MAX_RQSTPAUSE)
{
CFG_ERR("invalid pause value: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("wait"))
{
cfg.respwait = strtoul(value, NULL, 0);
if (cfg.respwait < 1 || cfg.respwait > MAX_RESPWAIT)
{
CFG_ERR("invalid wait value: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("replyonbroadcast"))
{
cfg.replyonbroadcast = CFG_VALUE_BOOL();
}
else if (CFG_NAME_MATCH("timeout"))
{
cfg.conntimeout = strtoul(value, NULL, 0);
if (cfg.conntimeout > MAX_CONNTIMEOUT)
return 0;
#ifdef HAVE_TIOCRS485
}
else if (CFG_NAME_MATCH("enable_rs485"))
{
cfg.rs485 = CFG_VALUE_BOOL();
#endif
#ifdef TRXCTL
}
else if (CFG_NAME_MATCH("trx_control"))
{
if (CFG_VALUE_MATCH("addc"))
{
cfg.trxcntl = TRX_ADDC;
}
else if (CFG_VALUE_MATCH("rts") || CFG_VALUE_MATCH("rts_1"))
{
cfg.trxcntl = TRX_RTS_1;
}
else if (CFG_VALUE_MATCH("rts_0"))
{
cfg.trxcntl = TRX_RTS_0;
}
else if (CFG_VALUE_MATCH("sysfs_0"))
{
cfg.trxcntl = TRX_SYSFS_0;
}
else if (CFG_VALUE_MATCH("sysfs_1"))
{
cfg.trxcntl = TRX_SYSFS_1;
}
else
{
/* Unknown TRX control mode */
CFG_ERR("unknown trx control mode: %s", value);
return 0;
}
}
else if (CFG_NAME_MATCH("trx_sysfile"))
{
strncpy(cfg.trxcntl_file, value, INTBUFSIZE);
#endif
#ifdef LOG
}
else if (CFG_NAME_MATCH("loglevel"))
{
cfg.dbglvl = (char)strtol(value, NULL, 0);
# ifdef DEBUG
if (!(isdigit(*value)) || cfg.dbglvl < 0 || cfg.dbglvl > 9)
{ /* report about invalid log level */
CFG_ERR("invalid loglevel value: %s (must be 0-9)", value);
# else
if (!(isdigit(*value)) || cfg.dbglvl < 0 || cfg.dbglvl > 2)
{ /* report about invalid log level */
CFG_ERR("invalid loglevel value: %s (must be 0-2)", value);
# endif
return 0;
}
}
else if (CFG_NAME_MATCH("logfile"))
{
if (!strlen(value))
{
CFG_ERR("missing logfile value", value);
return 0;
}
else if (*value != '/')
{
if (*value == '-')
{
/* logging to file disabled */
*cfg.logname = '\0';
}
else
{ /* concatenate given log file name with default path */
strncpy(cfg.logname, LOGPATH, INTBUFSIZE);
strncat(cfg.logname, value, INTBUFSIZE - strlen(cfg.logname));
}
}
else strncpy(cfg.logname, value, INTBUFSIZE);
#endif
}
else {
/* Unknown parameter name */
CFG_ERR("unknown parameter: %s", name);
return 0;
}
return 1;
}
int
cfg_parse_file(void *file)
{
char *line;
char *start;
char *end;
char *name;
char *value;
int lineno = 0;
int error = 0;
*cfg_err = '\0';
line = (char *) malloc(CFG_MAX_LINE_LENGTH);
if (!line)
{
return -1;
}
while (fgets(line, CFG_MAX_LINE_LENGTH, file) != NULL)
{
lineno++;
start = util_trim(line);
if (*start == '#')
{
/* skip comment */
continue;
}
else if (*start)
{
/* parse `name=value` pair */
for (end = start; *end && *end != '='; end++);
if (*end == '=')
{
*end = '\0';
name = util_rtrim(start);
value = util_trim(end + 1);
/* handle name/value pair */
if (!cfg_handle_param(name, value))
{
error = lineno;
break;
}
}
else
{
/* no '=' found on config line */
error = lineno;
CFG_ERR("can't parse line: %s", start);
break;
}
}
}
free(line);
return error;
}
int
cfg_read_file(const char *filename)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = cfg_parse_file(file);
fclose(file);
return error;
}