/* * 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 #include #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; }