|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm@clamav.net> |
|
|
|
|
* Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net> |
|
|
|
|
* |
|
|
|
|
* 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 |
|
|
|
@ -32,110 +32,122 @@ |
|
|
|
|
#include "memory.h" |
|
|
|
|
#include "misc.h" |
|
|
|
|
|
|
|
|
|
struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
|
|
|
|
static int regcfg(struct cfgstruct **copt, char *optname, char *strarg, int numarg, short multiple); |
|
|
|
|
|
|
|
|
|
struct cfgstruct *getcfg(const char *cfgfile, int verbose) |
|
|
|
|
{ |
|
|
|
|
char buff[LINE_LENGTH], *name, *arg; |
|
|
|
|
FILE *fs; |
|
|
|
|
int line = 0, i, found, ctype, calc; |
|
|
|
|
int line = 0, i, found, ctype, calc, val; |
|
|
|
|
struct cfgstruct *copt = NULL; |
|
|
|
|
struct cfgoption *pt; |
|
|
|
|
|
|
|
|
|
struct cfgoption cfg_options[] = { |
|
|
|
|
{"LogFile", OPT_STR}, |
|
|
|
|
{"LogFileUnlock", OPT_NOARG}, |
|
|
|
|
{"LogFileMaxSize", OPT_COMPSIZE}, |
|
|
|
|
{"LogTime", OPT_NOARG}, |
|
|
|
|
{"LogClean", OPT_NOARG}, |
|
|
|
|
{"LogVerbose", OPT_NOARG}, /* clamd + freshclam */ |
|
|
|
|
{"LogSyslog", OPT_NOARG}, |
|
|
|
|
{"LogFacility", OPT_STR}, |
|
|
|
|
{"PidFile", OPT_STR}, |
|
|
|
|
{"TemporaryDirectory", OPT_STR}, |
|
|
|
|
{"DisableDefaultScanOptions", OPT_NOARG}, |
|
|
|
|
{"ScanPE", OPT_NOARG}, |
|
|
|
|
{"DetectBrokenExecutables", OPT_NOARG}, |
|
|
|
|
{"ScanMail", OPT_NOARG}, |
|
|
|
|
{"MailFollowURLs", OPT_NOARG}, |
|
|
|
|
{"ScanHTML", OPT_NOARG}, |
|
|
|
|
{"ScanOLE2", OPT_NOARG}, |
|
|
|
|
{"ScanArchive", OPT_NOARG}, |
|
|
|
|
{"ScanRAR", OPT_NOARG}, |
|
|
|
|
{"ArchiveMaxFileSize", OPT_COMPSIZE}, |
|
|
|
|
{"ArchiveMaxRecursion", OPT_NUM}, |
|
|
|
|
{"ArchiveMaxFiles", OPT_NUM}, |
|
|
|
|
{"ArchiveMaxCompressionRatio", OPT_NUM}, |
|
|
|
|
{"ArchiveLimitMemoryUsage", OPT_NOARG}, |
|
|
|
|
{"ArchiveBlockEncrypted", OPT_NOARG}, |
|
|
|
|
{"ArchiveBlockMax", OPT_NOARG}, |
|
|
|
|
{"DataDirectory", OPT_STR}, /* obsolete */ |
|
|
|
|
{"DatabaseDirectory", OPT_STR}, /* clamd + freshclam */ |
|
|
|
|
{"TCPAddr", OPT_STR}, |
|
|
|
|
{"TCPSocket", OPT_NUM}, |
|
|
|
|
{"LocalSocket", OPT_STR}, |
|
|
|
|
{"MaxConnectionQueueLength", OPT_NUM}, |
|
|
|
|
{"StreamMaxLength", OPT_COMPSIZE}, |
|
|
|
|
{"StreamMinPort", OPT_NUM}, |
|
|
|
|
{"StreamMaxPort", OPT_NUM}, |
|
|
|
|
{"MaxThreads", OPT_NUM}, |
|
|
|
|
{"ReadTimeout", OPT_NUM}, |
|
|
|
|
{"IdleTimeout", OPT_NUM}, |
|
|
|
|
{"MaxDirectoryRecursion", OPT_NUM}, |
|
|
|
|
{"FollowDirectorySymlinks", OPT_NOARG}, |
|
|
|
|
{"FollowFileSymlinks", OPT_NOARG}, |
|
|
|
|
{"ExitOnOOM", OPT_NOARG}, |
|
|
|
|
{"Foreground", OPT_NOARG}, /* clamd + freshclam */ |
|
|
|
|
{"Debug", OPT_NOARG}, |
|
|
|
|
{"LeaveTemporaryFiles", OPT_NOARG}, |
|
|
|
|
{"FixStaleSocket", OPT_NOARG}, |
|
|
|
|
{"User", OPT_STR}, |
|
|
|
|
{"AllowSupplementaryGroups", OPT_NOARG}, |
|
|
|
|
{"SelfCheck", OPT_NUM}, |
|
|
|
|
{"VirusEvent", OPT_FULLSTR}, |
|
|
|
|
{"ClamukoScanOnLine", OPT_NOARG}, /* old name */ |
|
|
|
|
{"ClamukoScanOnAccess", OPT_NOARG}, |
|
|
|
|
{"ClamukoScanOnOpen", OPT_NOARG}, |
|
|
|
|
{"ClamukoScanOnClose", OPT_NOARG}, |
|
|
|
|
{"ClamukoScanOnExec", OPT_NOARG}, |
|
|
|
|
{"ClamukoIncludePath", OPT_STR}, |
|
|
|
|
{"ClamukoExcludePath", OPT_STR}, |
|
|
|
|
{"ClamukoMaxFileSize", OPT_COMPSIZE}, |
|
|
|
|
{"ClamukoScanArchive", OPT_NOARG}, |
|
|
|
|
{"DatabaseOwner", OPT_STR}, /* freshclam */ |
|
|
|
|
{"Checks", OPT_NUM}, /* freshclam */ |
|
|
|
|
{"UpdateLogFile", OPT_STR}, /* freshclam */ |
|
|
|
|
{"DNSDatabaseInfo", OPT_STR}, /* freshclam */ |
|
|
|
|
{"DatabaseMirror", OPT_STR}, /* freshclam */ |
|
|
|
|
{"MaxAttempts", OPT_NUM}, /* freshclam */ |
|
|
|
|
{"HTTPProxyServer", OPT_STR}, /* freshclam */ |
|
|
|
|
{"HTTPProxyPort", OPT_NUM}, /* freshclam */ |
|
|
|
|
{"HTTPProxyUsername", OPT_STR}, /* freshclam */ |
|
|
|
|
{"HTTPProxyPassword", OPT_STR}, /* freshclam */ |
|
|
|
|
{"NotifyClamd", OPT_OPTARG}, /* freshclam */ |
|
|
|
|
{"OnUpdateExecute", OPT_FULLSTR}, /* freshclam */ |
|
|
|
|
{"OnErrorExecute", OPT_FULLSTR}, /* freshclam */ |
|
|
|
|
{"LocalIPAddress", OPT_STR}, /* freshclam */ |
|
|
|
|
{"LogFile", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"LogFileUnlock", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"LogFileMaxSize", OPT_COMPSIZE, 1048576, NULL, 0}, |
|
|
|
|
{"LogTime", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"LogClean", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"LogVerbose", OPT_BOOL, 0, NULL, 0}, /* clamd + freshclam */ |
|
|
|
|
{"LogSyslog", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"LogFacility", OPT_STR, -1, "LOG_LOCAL6", 0}, |
|
|
|
|
{"PidFile", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"TemporaryDirectory", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"ScanPE", OPT_BOOL, 1, NULL, 0}, |
|
|
|
|
{"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ScanMail", OPT_BOOL, 1, NULL, 0}, |
|
|
|
|
{"MailFollowURLs", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ScanHTML", OPT_BOOL, 1, NULL, 0}, |
|
|
|
|
{"ScanOLE2", OPT_BOOL, 1, NULL, 0}, |
|
|
|
|
{"ScanArchive", OPT_BOOL, 1, NULL, 0}, |
|
|
|
|
{"ArchiveMaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0}, |
|
|
|
|
{"ArchiveMaxRecursion", OPT_NUM, 8, NULL, 0}, |
|
|
|
|
{"ArchiveMaxFiles", OPT_NUM, 1000, NULL, 0}, |
|
|
|
|
{"ArchiveMaxCompressionRatio", OPT_NUM, 250, NULL, 0}, |
|
|
|
|
{"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"DatabaseDirectory", OPT_STR, -1, DATADIR, 0}, /* clamd + freshclam */ |
|
|
|
|
{"TCPAddr", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"TCPSocket", OPT_NUM, -1, NULL, 0}, |
|
|
|
|
{"LocalSocket", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"MaxConnectionQueueLength", OPT_NUM, 15, NULL, 0}, |
|
|
|
|
{"StreamMaxLength", OPT_COMPSIZE, 10485760, NULL, 0}, |
|
|
|
|
{"StreamMinPort", OPT_NUM, 1024, NULL, 0}, |
|
|
|
|
{"StreamMaxPort", OPT_NUM, 2048, NULL, 0}, |
|
|
|
|
{"MaxThreads", OPT_NUM, 10, NULL, 0}, |
|
|
|
|
{"ReadTimeout", OPT_NUM, 120, NULL, 0}, |
|
|
|
|
{"IdleTimeout", OPT_NUM, 30, NULL, 0}, |
|
|
|
|
{"MaxDirectoryRecursion", OPT_NUM, 15, NULL, 0}, |
|
|
|
|
{"FollowDirectorySymlinks", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"FollowFileSymlinks", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ExitOnOOM", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"Foreground", OPT_BOOL, 0, NULL, 0}, /* clamd + freshclam */ |
|
|
|
|
{"Debug", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"LeaveTemporaryFiles", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"FixStaleSocket", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"User", OPT_STR, -1, NULL, 0}, |
|
|
|
|
{"AllowSupplementaryGroups", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"SelfCheck", OPT_NUM, 1800, NULL, 0}, |
|
|
|
|
{"VirusEvent", OPT_FULLSTR, -1, NULL, 0}, |
|
|
|
|
{"ClamukoScanOnAccess", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ClamukoScanOnOpen", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ClamukoScanOnClose", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ClamukoScanOnExec", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"ClamukoIncludePath", OPT_STR, 0, NULL, 0}, |
|
|
|
|
{"ClamukoExcludePath", OPT_STR, 0, NULL, 0}, |
|
|
|
|
{"ClamukoMaxFileSize", OPT_COMPSIZE, 5242880, NULL, 0}, |
|
|
|
|
{"ClamukoScanArchive", OPT_BOOL, 0, NULL, 0}, |
|
|
|
|
{"DatabaseOwner", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"Checks", OPT_NUM, 12, NULL, 0}, /* freshclam */ |
|
|
|
|
{"UpdateLogFile", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"DNSDatabaseInfo", OPT_STR, -1, "current.cvd.clamav.net", 0}, /* freshclam */ |
|
|
|
|
{"DatabaseMirror", OPT_STR, -1, NULL, 1}, /* freshclam */ |
|
|
|
|
{"MaxAttempts", OPT_NUM, 3, NULL, 0}, /* freshclam */ |
|
|
|
|
{"HTTPProxyServer", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"HTTPProxyPort", OPT_NUM, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"HTTPProxyUsername", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"HTTPProxyPassword", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"NotifyClamd", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"OnUpdateExecute", OPT_FULLSTR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"OnErrorExecute", OPT_FULLSTR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{"LocalIPAddress", OPT_STR, -1, NULL, 0}, /* freshclam */ |
|
|
|
|
{0, 0} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if((fs = fopen(cfgfile, "r")) == NULL) |
|
|
|
|
for(i = 0; ; i++) { |
|
|
|
|
pt = &cfg_options[i]; |
|
|
|
|
if(!pt->name) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
if(regcfg(&copt, strdup(pt->name), pt->strarg ? strdup(pt->strarg) : NULL, pt->numarg, pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if((fs = fopen(cfgfile, "r")) == NULL) { |
|
|
|
|
/* do not print error message here! */ |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while(fgets(buff, LINE_LENGTH, fs)) { |
|
|
|
|
|
|
|
|
|
line++; |
|
|
|
|
|
|
|
|
|
if(buff[0] == '#') |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if(!strncmp("Example", buff, 7)) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if((name = cli_strtok(buff, 0, " \r\n"))) { |
|
|
|
|
arg = cli_strtok(buff, 1, " \r\n"); |
|
|
|
|
found = 0; |
|
|
|
@ -147,41 +159,61 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
|
|
|
|
switch(pt->argtype) { |
|
|
|
|
case OPT_STR: |
|
|
|
|
if(!arg) { |
|
|
|
|
if(messages) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
if(regcfg(&copt, name, arg, -1, pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
copt = regcfg(copt, name, arg, 0); |
|
|
|
|
break; |
|
|
|
|
case OPT_FULLSTR: |
|
|
|
|
/* an ugly hack of the above case */ |
|
|
|
|
if(!arg) { |
|
|
|
|
if(messages) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
/* FIXME: this one is an ugly hack of the above case */ |
|
|
|
|
free(arg); |
|
|
|
|
arg = strstr(buff, " "); |
|
|
|
|
arg = strdup(++arg); |
|
|
|
|
copt = regcfg(copt, name, arg, 0); |
|
|
|
|
if(regcfg(&copt, name, arg, -1, pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case OPT_NUM: |
|
|
|
|
if(!arg || !isnumb(arg)) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
if(regcfg(&copt, name, NULL, atoi(arg), pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
free(arg); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
copt = regcfg(copt, name, NULL, atoi(arg)); |
|
|
|
|
free(arg); |
|
|
|
|
break; |
|
|
|
|
case OPT_COMPSIZE: |
|
|
|
|
if(!arg) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
ctype = tolower(arg[strlen(arg) - 1]); |
|
|
|
@ -189,9 +221,10 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
|
|
|
|
char *cpy = (char *) mcalloc(strlen(arg), sizeof(char)); |
|
|
|
|
strncpy(cpy, arg, strlen(arg) - 1); |
|
|
|
|
if(!isnumb(cpy)) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
if(ctype == 'm') |
|
|
|
@ -201,44 +234,69 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
|
|
|
|
free(cpy); |
|
|
|
|
} else { |
|
|
|
|
if(!isnumb(arg)) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
calc = atoi(arg); |
|
|
|
|
} |
|
|
|
|
copt = regcfg(copt, name, NULL, calc); |
|
|
|
|
free(arg); |
|
|
|
|
break; |
|
|
|
|
case OPT_NOARG: |
|
|
|
|
if(arg) { |
|
|
|
|
if(messages) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg); |
|
|
|
|
if(regcfg(&copt, name, NULL, calc, pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
copt = regcfg(copt, name, NULL, 0); |
|
|
|
|
break; |
|
|
|
|
case OPT_OPTARG: |
|
|
|
|
copt = regcfg(copt, name, arg, 0); |
|
|
|
|
case OPT_BOOL: |
|
|
|
|
|
|
|
|
|
if(!arg) { |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!strcasecmp(arg, "yes") || !strcmp(arg, "1") || !strcasecmp(arg, "true")) { |
|
|
|
|
val = 1; |
|
|
|
|
} else if(!strcasecmp(arg, "no") || !strcmp(arg, "0") || !strcasecmp(arg, "false")) { |
|
|
|
|
val = 0; |
|
|
|
|
} else { |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
free(arg); |
|
|
|
|
if(regcfg(&copt, name, NULL, val, pt->multiple) < 0) { |
|
|
|
|
fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n"); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype); |
|
|
|
|
free(name); |
|
|
|
|
free(arg); |
|
|
|
|
break; |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else |
|
|
|
|
break; |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(!found) { |
|
|
|
|
if(messages) |
|
|
|
|
if(verbose) |
|
|
|
|
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); |
|
|
|
|
fclose(fs); |
|
|
|
|
freecfg(copt); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -253,7 +311,7 @@ void freecfg(struct cfgstruct *copt) |
|
|
|
|
struct cfgstruct *handler; |
|
|
|
|
struct cfgstruct *arg; |
|
|
|
|
|
|
|
|
|
while (copt) { |
|
|
|
|
while(copt) { |
|
|
|
|
arg = copt->nextarg; |
|
|
|
|
while(arg) { |
|
|
|
|
if(arg->strarg) { |
|
|
|
@ -265,12 +323,12 @@ void freecfg(struct cfgstruct *copt) |
|
|
|
|
} else |
|
|
|
|
arg = arg->nextarg; |
|
|
|
|
} |
|
|
|
|
if(copt->optname) { |
|
|
|
|
if(copt->optname) |
|
|
|
|
free(copt->optname); |
|
|
|
|
} |
|
|
|
|
if(copt->strarg) { |
|
|
|
|
|
|
|
|
|
if(copt->strarg) |
|
|
|
|
free(copt->strarg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handler = copt; |
|
|
|
|
copt = copt->next; |
|
|
|
|
free(handler); |
|
|
|
@ -278,48 +336,79 @@ void freecfg(struct cfgstruct *copt) |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct cfgstruct *regcfg(struct cfgstruct *copt, char *optname, char *strarg, int numarg) |
|
|
|
|
struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname) |
|
|
|
|
{ |
|
|
|
|
struct cfgstruct *handler; |
|
|
|
|
|
|
|
|
|
handler = (struct cfgstruct *) copt; |
|
|
|
|
|
|
|
|
|
while(1) { |
|
|
|
|
if(handler) { |
|
|
|
|
if(handler->optname) |
|
|
|
|
if(!strcmp(handler->optname, optname)) |
|
|
|
|
return handler; |
|
|
|
|
} else break; |
|
|
|
|
handler = handler->next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int regcfg(struct cfgstruct **copt, char *optname, char *strarg, int numarg, short multiple) |
|
|
|
|
{ |
|
|
|
|
struct cfgstruct *newnode, *pt; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newnode = (struct cfgstruct *) mmalloc(sizeof(struct cfgstruct)); |
|
|
|
|
|
|
|
|
|
if(!newnode) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
newnode->optname = optname; |
|
|
|
|
newnode->nextarg = NULL; |
|
|
|
|
newnode->next = NULL; |
|
|
|
|
newnode->enabled = 0; |
|
|
|
|
newnode->multiple = multiple; |
|
|
|
|
|
|
|
|
|
if(strarg) |
|
|
|
|
if(strarg) { |
|
|
|
|
newnode->strarg = strarg; |
|
|
|
|
else { |
|
|
|
|
newnode->enabled = 1; |
|
|
|
|
} else { |
|
|
|
|
newnode->strarg = NULL; |
|
|
|
|
newnode->numarg = numarg; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if((pt = cfgopt(copt, optname))) { |
|
|
|
|
while(pt->nextarg) |
|
|
|
|
pt = pt->nextarg; |
|
|
|
|
newnode->numarg = numarg; |
|
|
|
|
if(numarg != -1 && numarg != 0) |
|
|
|
|
newnode->enabled = 1; |
|
|
|
|
|
|
|
|
|
pt->nextarg = newnode; |
|
|
|
|
return copt; |
|
|
|
|
} else { |
|
|
|
|
newnode->next = copt; |
|
|
|
|
return newnode; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if((pt = cfgopt(*copt, optname))) { |
|
|
|
|
if(pt->multiple) { |
|
|
|
|
|
|
|
|
|
struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname) |
|
|
|
|
{ |
|
|
|
|
struct cfgstruct *handler; |
|
|
|
|
if(pt->enabled) { |
|
|
|
|
while(pt->nextarg) |
|
|
|
|
pt = pt->nextarg; |
|
|
|
|
|
|
|
|
|
handler = (struct cfgstruct *) copt; |
|
|
|
|
pt->nextarg = newnode; |
|
|
|
|
} else { |
|
|
|
|
pt->strarg = newnode->strarg; |
|
|
|
|
pt->numarg = newnode->numarg; |
|
|
|
|
pt->enabled = newnode->enabled; |
|
|
|
|
free(newnode); |
|
|
|
|
} |
|
|
|
|
return 3; /* registered additional argument */ |
|
|
|
|
|
|
|
|
|
while(1) { |
|
|
|
|
if(handler) { |
|
|
|
|
if(handler->optname) |
|
|
|
|
if(!strcmp(handler->optname, optname)) |
|
|
|
|
return handler; |
|
|
|
|
} else break; |
|
|
|
|
handler = handler->next; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
pt->strarg = newnode->strarg; |
|
|
|
|
pt->numarg = newnode->numarg; |
|
|
|
|
pt->enabled = newnode->enabled; |
|
|
|
|
free(newnode); |
|
|
|
|
return 2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
} else { |
|
|
|
|
newnode->next = *copt; |
|
|
|
|
*copt = newnode; |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|