/*
* NVRAM WakeUp
* Copyright (C) 2001-2004, Sergei Haller.
*
* $Id: readconf.c 926 2010-01-24 11:53:49Z tiber $
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define CVSREV_readconf_c \
"$Id: readconf.c 926 2010-01-24 11:53:49Z tiber $"
/*
*
* The syntax of the configuration file is the following:
*
* - lines containing no non-space characters are comments.
*
* - If there's a '#' somewhere on the line, the rest of the line
* is a comment.
*
* - lines of the form VARIABLE = VALUE with optional following
* comment are interpreted as a definition of the variable
* VARIABLE to the value VALUE.
*
* Read `man nvram-wakeup.conf(5)' for the list on allowed variable
* names
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include "nvram-wakeup.h"
struct biosinfo lnrs; /* store line numbers for different variables */
void deprecated(char * old, char * new) {
nvprintf(LOG_WARNING, "Use of \"%s\" is deprecated. Use \"%s\" instead.\n", old, new);
}
int assign(int lnr, struct biosinfo * b, int * ptr, char * val, int allow_symbolic) {
char * tail;
/*
* now is the tricky part:
* pointer to the member of lnrs corresponding
* to the member pointed by ptr in *b
* I love C
*/
int * prev = (int *)((int)(&lnrs) + ((int)ptr - (int)b));
if (*prev) {
return *prev;
}
else {
*prev = lnr;
switch (allow_symbolic) {
case 0: /* no symbolic assignments allowed */
break;
case 1: /* only ON/OFF allowed */
if (!strcmp(val, "ON" )) {*ptr = ON ; return 0;}
else if (!strcmp(val, "OFF" )) {*ptr = OFF ; return 0;}
break;
case 2: /* ON_STAT and stuff like this */
if (!strcmp(val, "ALWAYS" )) {*ptr = ALWAYS ; deprecated("ALWAYS", "ON_ANY_CHANGE"); return 0;}
else if (!strcmp(val, "ON_ANY_CHANGE" )) {*ptr = ON_ANY_CHANGE ; return 0;}
else if (!strcmp(val, "ON_STAT" )) {*ptr = ON_STAT ; return 0;}
else if (!strcmp(val, "ON_MON" )) {*ptr = ON_MON ; return 0;}
else if (!strcmp(val, "ON_DAY" )) {*ptr = ON_DAY ; return 0;}
else if (!strcmp(val, "ON_WDAYS" )) {*ptr = ON_WDAYS ; return 0;}
else if (!strcmp(val, "ON_HOUR" )) {*ptr = ON_HOUR ; return 0;}
else if (!strcmp(val, "ON_MIN" )) {*ptr = ON_MIN ; return 0;}
else if (!strcmp(val, "ON_SEC" )) {*ptr = ON_SEC ; return 0;}
else if (!strcmp(val, "OFF" )) {*ptr = OFF ; return 0;}
/* ... more to come ??? ... */
break;
case 3: /* upper methods */
if (!strcmp(val, "OFF" )) {*ptr = OFF ; return 0;}
else if (!strcmp(val, "INTEL" )) {*ptr = INTEL ; return 0;}
else if (!strcmp(val, "DS1685" )) {*ptr = DS1685 ; return 0;}
else if (!strcmp(val, "VT82Cxxx" )) {*ptr = VT82Cxxx ; return 0;}
else if (!strcmp(val, "VT8235_37" )) {*ptr = VT8235_37 ; return 0;}
/* ... more to come ??? ... */
break;
case 4: /* checksum algorithms */
if (!strcmp(val, "DELL" )) {*ptr = DELL ; return 0;}
else if (!strcmp(val, "FSC" )) {*ptr = FSC ; return 0;}
/* ... more to come ??? ... */
break;
}
errno = 0;
*ptr = strtol(val, &tail, 0);
if (*tail != 0) return -2; /* val is not a number */
if (errno) return -3; /* overflow (number too large/too small) */
return 0; /* ok */
}
}
int readconf(struct biosinfo *b, const char * filename) {
char * line=NULL;
char * rest=NULL;
char * comment=NULL;
char * name=NULL;
char * val=NULL;
size_t n = 0;
int lnr = 0; /* number of the line */
ssize_t got;
FILE * fd_conf;
if (!set_biosinfo_defaults(b)) {
nvprintf(LOG_ERR, "Can't set biosinfo defaults\n");
return 0;
}
nvprintf(LOG_DEBUG, "Opening %s in 'r' mode...\n", filename);
if ((fd_conf = fopen(filename, "r")) == NULL) {
nvprintf(LOG_ERR, "%s: %m\n", filename);
return 0;
}
/* read the next line */
while ((got = getline(&line,&n,fd_conf)) > -1) {
lnr++;
/*
* printf("got %d characters\n",got);
*/
/* copy contents of the line to be used with strsep */
comment = strdupa(line);
/* release space allocated by getline and reset n */
free(line);
n=0;
/* everything after a # is a comment */
rest = strip(strsep(&comment, "#"));
/* remove trailing line break */
if (comment && comment[strlen(comment)-1] == '\n')
comment[strlen(comment)-1] = 0;
if (comment)
nvprintf(LOG_DEBUG, "%s: %d: comment: #%s\n", filename, lnr, comment);
if (rest && *rest) {
/* split the rest into a pair of name and value */
name = strip(strsep(&rest, "="));
val = strip(rest);
nvprintf(LOG_DEBUG, "%s: %d: name : %s\n", filename, lnr, name );
nvprintf(LOG_DEBUG, "%s: %d: value : %s\n", filename, lnr, val );
if (name && *name && val && *val) {
int ret;
/* now assign values */
if (!strcmp(name, "need_reboot" )) ret = assign(lnr, b, &(b->need_reboot ), val, 2);
else if (!strcmp(name, "addr_chk_h" )) ret = assign(lnr, b, &(b->addr_chk_h ), val, 0);
else if (!strcmp(name, "addr_chk_l" )) ret = assign(lnr, b, &(b->addr_chk_l ), val, 0);
else if (!strcmp(name, "addr_chk_h2" )) ret = assign(lnr, b, &(b->addr_chk_h2 ), val, 0);
else if (!strcmp(name, "addr_chk_l2" )) ret = assign(lnr, b, &(b->addr_chk_l2 ), val, 0);
else if (!strcmp(name, "addr_stat" )) ret = assign(lnr, b, &(b->addr_stat ), val, 0);
else if (!strcmp(name, "addr_mon" )) ret = assign(lnr, b, &(b->addr_mon ), val, 0);
else if (!strcmp(name, "addr_day" )) ret = assign(lnr, b, &(b->addr_day ), val, 0);
else if (!strcmp(name, "addr_wdays" )) ret = assign(lnr, b, &(b->addr_wdays ), val, 0);
else if (!strcmp(name, "addr_hour" )) ret = assign(lnr, b, &(b->addr_hour ), val, 0);
else if (!strcmp(name, "addr_min" )) ret = assign(lnr, b, &(b->addr_min ), val, 0);
else if (!strcmp(name, "addr_sec" )) ret = assign(lnr, b, &(b->addr_sec ), val, 0);
else if (!strcmp(name, "shift_stat" )) ret = assign(lnr, b, &(b->shift_stat ), val, 0);
else if (!strcmp(name, "shift_mon" )) ret = assign(lnr, b, &(b->shift_mon ), val, 0);
else if (!strcmp(name, "shift_day" )) ret = assign(lnr, b, &(b->shift_day ), val, 0);
else if (!strcmp(name, "shift_wdays" )) ret = assign(lnr, b, &(b->shift_wdays ), val, 0);
else if (!strcmp(name, "shift_hour" )) ret = assign(lnr, b, &(b->shift_hour ), val, 0);
else if (!strcmp(name, "shift_min" )) ret = assign(lnr, b, &(b->shift_min ), val, 0);
else if (!strcmp(name, "shift_sec" )) ret = assign(lnr, b, &(b->shift_sec ), val, 0);
else if (!strcmp(name, "rtc_time" )) ret = assign(lnr, b, &(b->rtc_time ), val, 1);
else if (!strcmp(name, "rtc_day" )) ret = assign(lnr, b, &(b->rtc_day ), val, 0);
else if (!strcmp(name, "rtc_mon" )) ret = assign(lnr, b, &(b->rtc_mon ), val, 0);
else if (!strcmp(name, "rtc_day_0_is_c0" )) ret = assign(lnr, b, &(b->rtc_day_0_is_c0 ), val, 1);
else if (!strcmp(name, "rtc_mon_0_is_c0" )) ret = assign(lnr, b, &(b->rtc_mon_0_is_c0 ), val, 1);
else if (!strcmp(name, "reset_day" )) ret = assign(lnr, b, &(b->reset_day ), val, 1);
else if (!strcmp(name, "reset_mon" )) ret = assign(lnr, b, &(b->reset_mon ), val, 1);
else if (!strcmp(name, "nr_stat" )) ret = assign(lnr, b, &(b->nr_stat ), val, 0);
else if (!strcmp(name, "nr_mon" )) ret = assign(lnr, b, &(b->nr_mon ), val, 0);
else if (!strcmp(name, "nr_day" )) ret = assign(lnr, b, &(b->nr_day ), val, 0);
else if (!strcmp(name, "nr_hour" )) ret = assign(lnr, b, &(b->nr_hour ), val, 0);
else if (!strcmp(name, "nr_min" )) ret = assign(lnr, b, &(b->nr_min ), val, 0);
else if (!strcmp(name, "nr_sec" )) ret = assign(lnr, b, &(b->nr_sec ), val, 0);
else if (!strcmp(name, "nr_rtc_day" )) ret = assign(lnr, b, &(b->nr_rtc_day ), val, 0);
else if (!strcmp(name, "nr_rtc_mon" )) ret = assign(lnr, b, &(b->nr_rtc_mon ), val, 0);
else if (!strcmp(name, "nr_wdays" )) ret = assign(lnr, b, &(b->nr_wdays ), val, 0);
else if (!strcmp(name, "bcd" )) ret = assign(lnr, b, &(b->bcd ), val, 1);
else if (!strcmp(name, "day_no_bcd" )) ret = assign(lnr, b, &(b->day_no_bcd ), val, 1);
else if (!strcmp(name, "day_hack" )) ret = assign(lnr, b, &(b->day_hack ), val, 0);
else if (!strcmp(name, "upper_method" )) ret = assign(lnr, b, &(b->upper_method ), val, 3);
else if (!strcmp(name, "chk_method" )) ret = assign(lnr, b, &(b->chk_method ), val, 4);
else if (!strcmp(name, "addr_date" )) { deprecated("addr_date", "addr_day" );
ret = assign(lnr, b, &(b->addr_day ), val, 0); }
else if (!strcmp(name, "shift_date" )) { deprecated("shift_date", "shift_day" );
ret = assign(lnr, b, &(b->shift_day ), val, 0); }
else if (!strcmp(name, "rtc_date" )) { deprecated("rtc_date", "rtc_day" );
ret = assign(lnr, b, &(b->rtc_day ), val, 0); }
else if (!strcmp(name, "rtc_date_0_is_c0")) { deprecated("rtc_date_0_is_c0", "rtc_day_0_is_c0" );
ret = assign(lnr, b, &(b->rtc_day_0_is_c0 ), val, 1); }
else if (!strcmp(name, "reset_date" )) { deprecated("reset_date", "reset_day" );
ret = assign(lnr, b, &(b->reset_day ), val, 1); }
else if (!strcmp(name, "nr_date" )) { deprecated("nr_date", "nr_day" );
ret = assign(lnr, b, &(b->nr_day ), val, 0); }
else if (!strcmp(name, "nr_rtc_date" )) { deprecated("nr_rtc_date", "nr_rtc_day" );
ret = assign(lnr, b, &(b->nr_rtc_day ), val, 0); }
else if (!strcmp(name, "date_hack" )) { deprecated("date_hack", "day_hack" );
ret = assign(lnr, b, &(b->day_hack ), val, 0); }
else ret = -1;
switch(ret) {
case -1: nvprintf(LOG_ERR, "%s: %d: Syntax error: unknown variable name\n", filename, lnr);
fclose(fd_conf);
return 0;
case -2: nvprintf(LOG_ERR, "%s: %d: Syntax error: value is not a number\n", filename, lnr);
fclose(fd_conf);
return 0;
case -3: nvprintf(LOG_ERR, "%s: %d: Syntax error: value too large/too small\n", filename, lnr);
fclose(fd_conf);
return 0;
case 0: break;
default : if (ret>0) {
nvprintf(LOG_ERR, "%s: %d: Previous definition of variable `%s': first definition in line %d\n",
filename, lnr, name, ret);
fclose(fd_conf);
return 0;
}
/* should have no negative numbers here */
}
}
else {
nvprintf(LOG_ERR, "%s: %d: Syntax error: no value\n", filename, lnr);
fclose(fd_conf);
return 0;
}
}
}
nvprintf(LOG_DEBUG, "Closing %s ...\n", filename);
fclose(fd_conf);
return 1;
}