Browse code

initial version of the unified option parser (bb#1215)

git-svn: trunk@4565

Tomasz Kojm authored on 2008/12/18 06:42:54
Showing 23 changed files
... ...
@@ -1,3 +1,9 @@
1
+Wed Dec 17 22:43:54 CET 2008 (tk)
2
+---------------------------------
3
+ * shared/optparser.[ch]: initial version of the unified option parser (bb#1215)
4
+ * clamd: use the new option parser
5
+ * more to come
6
+
1 7
 Tue Dec 16 15:18:28 EET 2008 (edwin)
2 8
 ------------------------------------
3 9
  * libclamav/special.c: fix Swizzor detection: if no individual
... ...
@@ -294,7 +294,6 @@ DISTCLEANFILES = target.h
294 294
 @DISTCHECK_ENABLE_FLAGS_TRUE@DISTCHECK_CONFIGURE_FLAGS =  \
295 295
 @DISTCHECK_ENABLE_FLAGS_TRUE@	--enable-milter --disable-clamav \
296 296
 @DISTCHECK_ENABLE_FLAGS_TRUE@	CFLAGS="-Wno-pointer-sign \
297
-@DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=attributes \
298 297
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Werror-implicit-function-declaration \
299 298
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Werror -Wextra -Wall \
300 299
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Wbad-function-cast -Wcast-align \
... ...
@@ -324,8 +323,7 @@ DISTCLEANFILES = target.h
324 324
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=shadow \
325 325
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=uninitialized \
326 326
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-fdiagnostics-show-option \
327
-@DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-unused-parameter -Wpacked \
328
-@DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=packed \
327
+@DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-unused-parameter \
329 328
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=unreachable-code \
330 329
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Winvalid-pch \
331 330
 @DISTCHECK_ENABLE_FLAGS_TRUE@	-Wno-error=invalid-pch -O2 \
... ...
@@ -23,16 +23,14 @@ sbin_PROGRAMS = clamd
23 23
 clamd_SOURCES = \
24 24
     $(top_srcdir)/shared/output.c \
25 25
     $(top_srcdir)/shared/output.h \
26
-    $(top_srcdir)/shared/cfgparser.c \
27
-    $(top_srcdir)/shared/cfgparser.h \
26
+    $(top_srcdir)/shared/optparser.c \
27
+    $(top_srcdir)/shared/optparser.h \
28 28
     $(top_srcdir)/shared/getopt.c \
29 29
     $(top_srcdir)/shared/getopt.h \
30 30
     $(top_srcdir)/shared/misc.c \
31 31
     $(top_srcdir)/shared/misc.h \
32 32
     $(top_srcdir)/shared/network.c \
33 33
     $(top_srcdir)/shared/network.h \
34
-    $(top_srcdir)/shared/options.c \
35
-    $(top_srcdir)/shared/options.h \
36 34
     clamd.c \
37 35
     tcpserver.c \
38 36
     tcpserver.h \
... ...
@@ -72,25 +72,24 @@ am__installdirs = "$(DESTDIR)$(sbindir)"
72 72
 sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
73 73
 PROGRAMS = $(sbin_PROGRAMS)
74 74
 am__clamd_SOURCES_DIST = $(top_srcdir)/shared/output.c \
75
-	$(top_srcdir)/shared/output.h $(top_srcdir)/shared/cfgparser.c \
76
-	$(top_srcdir)/shared/cfgparser.h $(top_srcdir)/shared/getopt.c \
75
+	$(top_srcdir)/shared/output.h $(top_srcdir)/shared/optparser.c \
76
+	$(top_srcdir)/shared/optparser.h $(top_srcdir)/shared/getopt.c \
77 77
 	$(top_srcdir)/shared/getopt.h $(top_srcdir)/shared/misc.c \
78 78
 	$(top_srcdir)/shared/misc.h $(top_srcdir)/shared/network.c \
79
-	$(top_srcdir)/shared/network.h $(top_srcdir)/shared/options.c \
80
-	$(top_srcdir)/shared/options.h clamd.c tcpserver.c tcpserver.h \
79
+	$(top_srcdir)/shared/network.h clamd.c tcpserver.c tcpserver.h \
81 80
 	localserver.c localserver.h session.c session.h thrmgr.c \
82 81
 	thrmgr.h server-th.c server.h scanner.c scanner.h others.c \
83 82
 	others.h clamuko.c clamuko.h dazukoio_compat12.c \
84 83
 	dazukoio_compat12.h dazukoio.c dazukoio.h dazuko_xp.h \
85 84
 	dazukoio_xp.h shared.h
86 85
 @BUILD_CLAMD_TRUE@am_clamd_OBJECTS = output.$(OBJEXT) \
87
-@BUILD_CLAMD_TRUE@	cfgparser.$(OBJEXT) getopt.$(OBJEXT) \
86
+@BUILD_CLAMD_TRUE@	optparser.$(OBJEXT) getopt.$(OBJEXT) \
88 87
 @BUILD_CLAMD_TRUE@	misc.$(OBJEXT) network.$(OBJEXT) \
89
-@BUILD_CLAMD_TRUE@	options.$(OBJEXT) clamd.$(OBJEXT) \
90
-@BUILD_CLAMD_TRUE@	tcpserver.$(OBJEXT) localserver.$(OBJEXT) \
91
-@BUILD_CLAMD_TRUE@	session.$(OBJEXT) thrmgr.$(OBJEXT) \
92
-@BUILD_CLAMD_TRUE@	server-th.$(OBJEXT) scanner.$(OBJEXT) \
93
-@BUILD_CLAMD_TRUE@	others.$(OBJEXT) clamuko.$(OBJEXT) \
88
+@BUILD_CLAMD_TRUE@	clamd.$(OBJEXT) tcpserver.$(OBJEXT) \
89
+@BUILD_CLAMD_TRUE@	localserver.$(OBJEXT) session.$(OBJEXT) \
90
+@BUILD_CLAMD_TRUE@	thrmgr.$(OBJEXT) server-th.$(OBJEXT) \
91
+@BUILD_CLAMD_TRUE@	scanner.$(OBJEXT) others.$(OBJEXT) \
92
+@BUILD_CLAMD_TRUE@	clamuko.$(OBJEXT) \
94 93
 @BUILD_CLAMD_TRUE@	dazukoio_compat12.$(OBJEXT) \
95 94
 @BUILD_CLAMD_TRUE@	dazukoio.$(OBJEXT)
96 95
 clamd_OBJECTS = $(am_clamd_OBJECTS)
... ...
@@ -271,16 +270,14 @@ top_srcdir = @top_srcdir@
271 271
 @BUILD_CLAMD_TRUE@clamd_SOURCES = \
272 272
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/output.c \
273 273
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/output.h \
274
-@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/cfgparser.c \
275
-@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/cfgparser.h \
274
+@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/optparser.c \
275
+@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/optparser.h \
276 276
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/getopt.c \
277 277
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/getopt.h \
278 278
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/misc.c \
279 279
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/misc.h \
280 280
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/network.c \
281 281
 @BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/network.h \
282
-@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/options.c \
283
-@BUILD_CLAMD_TRUE@    $(top_srcdir)/shared/options.h \
284 282
 @BUILD_CLAMD_TRUE@    clamd.c \
285 283
 @BUILD_CLAMD_TRUE@    tcpserver.c \
286 284
 @BUILD_CLAMD_TRUE@    tcpserver.h \
... ...
@@ -399,7 +396,6 @@ mostlyclean-compile:
399 399
 distclean-compile:
400 400
 	-rm -f *.tab.c
401 401
 
402
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfgparser.Po@am__quote@
403 402
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clamd.Po@am__quote@
404 403
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clamuko.Po@am__quote@
405 404
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dazukoio.Po@am__quote@
... ...
@@ -408,7 +404,7 @@ distclean-compile:
408 408
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/localserver.Po@am__quote@
409 409
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
410 410
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Po@am__quote@
411
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
411
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optparser.Po@am__quote@
412 412
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/others.Po@am__quote@
413 413
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
414 414
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanner.Po@am__quote@
... ...
@@ -452,19 +448,19 @@ output.obj: $(top_srcdir)/shared/output.c
452 452
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
453 453
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output.obj `if test -f '$(top_srcdir)/shared/output.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/output.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/output.c'; fi`
454 454
 
455
-cfgparser.o: $(top_srcdir)/shared/cfgparser.c
456
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cfgparser.o -MD -MP -MF $(DEPDIR)/cfgparser.Tpo -c -o cfgparser.o `test -f '$(top_srcdir)/shared/cfgparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/cfgparser.c
457
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/cfgparser.Tpo $(DEPDIR)/cfgparser.Po
458
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/cfgparser.c' object='cfgparser.o' libtool=no @AMDEPBACKSLASH@
455
+optparser.o: $(top_srcdir)/shared/optparser.c
456
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT optparser.o -MD -MP -MF $(DEPDIR)/optparser.Tpo -c -o optparser.o `test -f '$(top_srcdir)/shared/optparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/optparser.c
457
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/optparser.Tpo $(DEPDIR)/optparser.Po
458
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/optparser.c' object='optparser.o' libtool=no @AMDEPBACKSLASH@
459 459
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
460
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cfgparser.o `test -f '$(top_srcdir)/shared/cfgparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/cfgparser.c
460
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.o `test -f '$(top_srcdir)/shared/optparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/optparser.c
461 461
 
462
-cfgparser.obj: $(top_srcdir)/shared/cfgparser.c
463
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cfgparser.obj -MD -MP -MF $(DEPDIR)/cfgparser.Tpo -c -o cfgparser.obj `if test -f '$(top_srcdir)/shared/cfgparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/cfgparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/cfgparser.c'; fi`
464
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/cfgparser.Tpo $(DEPDIR)/cfgparser.Po
465
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/cfgparser.c' object='cfgparser.obj' libtool=no @AMDEPBACKSLASH@
462
+optparser.obj: $(top_srcdir)/shared/optparser.c
463
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT optparser.obj -MD -MP -MF $(DEPDIR)/optparser.Tpo -c -o optparser.obj `if test -f '$(top_srcdir)/shared/optparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/optparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/optparser.c'; fi`
464
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/optparser.Tpo $(DEPDIR)/optparser.Po
465
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/optparser.c' object='optparser.obj' libtool=no @AMDEPBACKSLASH@
466 466
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
467
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cfgparser.obj `if test -f '$(top_srcdir)/shared/cfgparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/cfgparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/cfgparser.c'; fi`
467
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.obj `if test -f '$(top_srcdir)/shared/optparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/optparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/optparser.c'; fi`
468 468
 
469 469
 getopt.o: $(top_srcdir)/shared/getopt.c
470 470
 @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getopt.o -MD -MP -MF $(DEPDIR)/getopt.Tpo -c -o getopt.o `test -f '$(top_srcdir)/shared/getopt.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/getopt.c
... ...
@@ -508,20 +504,6 @@ network.obj: $(top_srcdir)/shared/network.c
508 508
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
509 509
 @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o network.obj `if test -f '$(top_srcdir)/shared/network.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/network.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/network.c'; fi`
510 510
 
511
-options.o: $(top_srcdir)/shared/options.c
512
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT options.o -MD -MP -MF $(DEPDIR)/options.Tpo -c -o options.o `test -f '$(top_srcdir)/shared/options.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/options.c
513
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/options.Tpo $(DEPDIR)/options.Po
514
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/options.c' object='options.o' libtool=no @AMDEPBACKSLASH@
515
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
516
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o options.o `test -f '$(top_srcdir)/shared/options.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/options.c
517
-
518
-options.obj: $(top_srcdir)/shared/options.c
519
-@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT options.obj -MD -MP -MF $(DEPDIR)/options.Tpo -c -o options.obj `if test -f '$(top_srcdir)/shared/options.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/options.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/options.c'; fi`
520
-@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/options.Tpo $(DEPDIR)/options.Po
521
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/shared/options.c' object='options.obj' libtool=no @AMDEPBACKSLASH@
522
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
523
-@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o options.obj `if test -f '$(top_srcdir)/shared/options.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/options.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/options.c'; fi`
524
-
525 511
 mostlyclean-libtool:
526 512
 	-rm -f *.lo
527 513
 
... ...
@@ -58,8 +58,7 @@
58 58
 #include "libclamav/readdb.h"
59 59
 
60 60
 #include "shared/output.h"
61
-#include "shared/options.h"
62
-#include "shared/cfgparser.h"
61
+#include "shared/optparser.h"
63 62
 #include "shared/misc.h"
64 63
 
65 64
 #include "server.h"
... ...
@@ -85,22 +84,21 @@ static void help(void)
85 85
     printf("    --version                -V             Show version number.\n");
86 86
     printf("    --debug                                 Enable debug mode.\n");
87 87
     printf("    --config-file=FILE       -c FILE        Read configuration from FILE.\n\n");
88
-
89 88
 }
90 89
 
91
-static struct cfgstruct *copt;
90
+static struct optstruct *opts;
92 91
 /* needs to be global, so that valgrind reports it as reachable, and not
93 92
  * as definetely/indirectly lost when daemonizing clamd */
94 93
 static struct cl_engine *engine;
95 94
 int main(int argc, char **argv)
96 95
 {
97
-	const struct cfgstruct *cpt;
96
+	const struct optstruct *opt;
98 97
 #ifndef	C_WINDOWS
99 98
         struct passwd *user = NULL;
100 99
 #endif
101 100
 	time_t currtime;
102 101
 	const char *dbdir, *cfgfile;
103
-	char *pua_cats = NULL;
102
+	char *pua_cats = NULL, *pt;
104 103
 	int ret, tcpsock = 0, localsock = 0, i;
105 104
 	unsigned int sigs = 0;
106 105
 	int lsockets[2], nlsockets = 0;
... ...
@@ -109,16 +107,6 @@ int main(int argc, char **argv)
109 109
 #ifdef C_LINUX
110 110
 	struct stat sb;
111 111
 #endif
112
-	struct optstruct *opt;
113
-	const char *short_options = "hc:V";
114
-
115
-	static struct option long_options[] = {
116
-	    {"help", 0, 0, 'h'},
117
-	    {"config-file", 1, 0, 'c'},
118
-	    {"version", 0, 0, 'V'},
119
-	    {"debug", 0, 0, 0},
120
-	    {0, 0, 0, 0}
121
-    	};
122 112
 
123 113
 #ifdef C_WINDOWS
124 114
     if(!pthread_win32_process_attach_np()) {
... ...
@@ -127,19 +115,18 @@ int main(int argc, char **argv)
127 127
     }
128 128
 #endif
129 129
 
130
-    opt = opt_parse(argc, argv, short_options, long_options, NULL, NULL);
131
-    if(!opt) {
132
-	mprintf("!Can't parse the command line\n");
130
+    if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMD, NULL)) == NULL) {
131
+	mprintf("!Can't parse command line options\n");
133 132
 	return 1;
134 133
     }
135 134
 
136
-    if(opt_check(opt, "help")) {
135
+    if(optget(opts, "help")->enabled) {
137 136
     	help();
138
-	opt_free(opt);
137
+	optfree(opts);
139 138
 	return 0;
140 139
     }
141 140
 
142
-    if(opt_check(opt, "debug")) {
141
+    if(optget(opts, "debug")->enabled) {
143 142
 #if defined(C_LINUX)
144 143
 	    /* njh@bandsman.co.uk: create a dump if needed */
145 144
 	    struct rlimit rlim;
... ...
@@ -152,54 +139,50 @@ int main(int argc, char **argv)
152 152
     }
153 153
 
154 154
     /* parse the config file */
155
-    if(opt_check(opt, "config-file"))
156
-	cfgfile = opt_arg(opt, "config-file");
157
-    else
158
-	cfgfile = CONFDIR"/clamd.conf";
159
-
160
-    if((copt = getcfg(cfgfile, 1, OPT_CLAMD)) == NULL) {
161
-	fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", cfgfile);
162
-	opt_free(opt);
155
+    cfgfile = optget(opts, "config-file")->strarg;
156
+    pt = strdup(cfgfile);
157
+    if((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, opts)) == NULL) {
158
+	fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", pt);
159
+	optfree(opts);
160
+	free(pt);
163 161
 	return 1;
164 162
     }
163
+    free(pt);
165 164
 
166
-    if(opt_check(opt, "version")) {
167
-	print_version(cfgopt(copt, "DatabaseDirectory")->strarg);
168
-	opt_free(opt);
169
-	freecfg(copt);
165
+    if(optget(opts, "version")->enabled) {
166
+	print_version(optget(opts, "DatabaseDirectory")->strarg);
167
+	optfree(opts);
170 168
 	return 0;
171 169
     }
172 170
 
173
-    opt_free(opt);
174
-
175 171
     umask(0);
176 172
 
177 173
     /* drop privileges */
178 174
 #if (!defined(C_OS2)) && (!defined(C_WINDOWS))
179
-    if(geteuid() == 0 && (cpt = cfgopt(copt, "User"))->enabled) {
180
-	if((user = getpwnam(cpt->strarg)) == NULL) {
181
-	    fprintf(stderr, "ERROR: Can't get information about user %s.\n", cpt->strarg);
182
-	    freecfg(copt);
175
+    if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) {
176
+	if((user = getpwnam(opt->strarg)) == NULL) {
177
+	    fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
178
+	    optfree(opts);
183 179
 	    return 1;
184 180
 	}
185 181
 
186
-	if(cfgopt(copt, "AllowSupplementaryGroups")->enabled) {
182
+	if(optget(opts, "AllowSupplementaryGroups")->enabled) {
187 183
 #ifdef HAVE_INITGROUPS
188
-	    if(initgroups(cpt->strarg, user->pw_gid)) {
184
+	    if(initgroups(opt->strarg, user->pw_gid)) {
189 185
 		fprintf(stderr, "ERROR: initgroups() failed.\n");
190
-		freecfg(copt);
186
+		optfree(opts);
191 187
 		return 1;
192 188
 	    }
193 189
 #else
194 190
 	    mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups in %s\n", cfgfile);
195
-	    freecfg(copt);
191
+	    optfree(opts);
196 192
 	    return 1;
197 193
 #endif
198 194
 	} else {
199 195
 #ifdef HAVE_SETGROUPS
200 196
 	    if(setgroups(1, &user->pw_gid)) {
201 197
 		fprintf(stderr, "ERROR: setgroups() failed.\n");
202
-		freecfg(copt);
198
+		optfree(opts);
203 199
 		return 1;
204 200
 	    }
205 201
 #endif
... ...
@@ -207,39 +190,39 @@ int main(int argc, char **argv)
207 207
 
208 208
 	if(setgid(user->pw_gid)) {
209 209
 	    fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
210
-	    freecfg(copt);
210
+	    optfree(opts);
211 211
 	    return 1;
212 212
 	}
213 213
 
214 214
 	if(setuid(user->pw_uid)) {
215 215
 	    fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
216
-	    freecfg(copt);
216
+	    optfree(opts);
217 217
 	    return 1;
218 218
 	}
219 219
     }
220 220
 #endif
221 221
 
222 222
     /* initialize logger */
223
-    logg_lock = !cfgopt(copt, "LogFileUnlock")->enabled;
224
-    logg_time = cfgopt(copt, "LogTime")->enabled;
225
-    logok = cfgopt(copt, "LogClean")->enabled;
226
-    logg_size = cfgopt(copt, "LogFileMaxSize")->numarg;
227
-    logg_verbose = mprintf_verbose = cfgopt(copt, "LogVerbose")->enabled;
223
+    logg_lock = !optget(opts, "LogFileUnlock")->enabled;
224
+    logg_time = optget(opts, "LogTime")->enabled;
225
+    logok = optget(opts, "LogClean")->enabled;
226
+    logg_size = optget(opts, "LogFileMaxSize")->numarg;
227
+    logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled;
228 228
 
229
-    if((cpt = cfgopt(copt, "LogFile"))->enabled) {
229
+    if((opt = optget(opts, "LogFile"))->enabled) {
230 230
 	char timestr[32];
231
-	logg_file = cpt->strarg;
231
+	logg_file = opt->strarg;
232 232
 	if(strlen(logg_file) < 2 || (logg_file[0] != '/' && logg_file[0] != '\\' && logg_file[1] != ':')) {
233 233
 	    fprintf(stderr, "ERROR: LogFile requires full path.\n");
234 234
 	    logg_close();
235
-	    freecfg(copt);
235
+	    optfree(opts);
236 236
 	    return 1;
237 237
 	}
238 238
 	time(&currtime);
239 239
 	if(logg("#+++ Started at %s", cli_ctime(&currtime, timestr, sizeof(timestr)))) {
240 240
 	    fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
241 241
 	    logg_close();
242
-	    freecfg(copt);
242
+	    optfree(opts);
243 243
 	    return 1;
244 244
 	}
245 245
     } else
... ...
@@ -248,22 +231,22 @@ int main(int argc, char **argv)
248 248
     if((ret = cl_init(CL_INIT_DEFAULT))) {
249 249
 	logg("!Can't initialize libclamav: %s\n", cl_strerror(ret));
250 250
 	logg_close();
251
-	freecfg(copt);
251
+	optfree(opts);
252 252
 	return 1;
253 253
     }
254 254
 
255
-    if(cfgopt(copt, "Debug")->enabled) /* enable debug messages in libclamav */
255
+    if(optget(opts, "Debug")->enabled) /* enable debug messages in libclamav */
256 256
 	cl_debug();
257 257
 
258 258
 #if defined(USE_SYSLOG) && !defined(C_AIX)
259
-    if(cfgopt(copt, "LogSyslog")->enabled) {
259
+    if(optget(opts, "LogSyslog")->enabled) {
260 260
 	    int fac = LOG_LOCAL6;
261 261
 
262
-	cpt = cfgopt(copt, "LogFacility");
263
-	if((fac = logg_facility(cpt->strarg)) == -1) {
264
-	    logg("!LogFacility: %s: No such facility.\n", cpt->strarg);
262
+	opt = optget(opts, "LogFacility");
263
+	if((fac = logg_facility(opt->strarg)) == -1) {
264
+	    logg("!LogFacility: %s: No such facility.\n", opt->strarg);
265 265
 	    logg_close();
266
-	    freecfg(copt);
266
+	    optfree(opts);
267 267
 	    return 1;
268 268
 	}
269 269
 
... ...
@@ -280,16 +263,16 @@ int main(int argc, char **argv)
280 280
 
281 281
     /* check socket type */
282 282
 
283
-    if(cfgopt(copt, "TCPSocket")->enabled)
283
+    if(optget(opts, "TCPSocket")->enabled)
284 284
 	tcpsock = 1;
285 285
 
286
-    if(cfgopt(copt, "LocalSocket")->enabled)
286
+    if(optget(opts, "LocalSocket")->enabled)
287 287
 	localsock = 1;
288 288
 
289 289
     if(!tcpsock && !localsock) {
290 290
 	logg("!Please define server type (local and/or TCP).\n");
291 291
 	logg_close();
292
-	freecfg(copt);
292
+	optfree(opts);
293 293
 	return 1;
294 294
     }
295 295
 
... ...
@@ -308,45 +291,45 @@ int main(int argc, char **argv)
308 308
     if(!(engine = cl_engine_new())) {
309 309
 	logg("!Can't initialize antivirus engine\n");
310 310
 	logg_close();
311
-	freecfg(copt);
311
+	optfree(opts);
312 312
 	return 1;
313 313
     }
314 314
 
315 315
     /* load the database(s) */
316
-    dbdir = cfgopt(copt, "DatabaseDirectory")->strarg;
316
+    dbdir = optget(opts, "DatabaseDirectory")->strarg;
317 317
     logg("#Reading databases from %s\n", dbdir);
318 318
 
319
-    if(cfgopt(copt, "DetectPUA")->enabled) {
319
+    if(optget(opts, "DetectPUA")->enabled) {
320 320
 	dboptions |= CL_DB_PUA;
321 321
 
322
-	if((cpt = cfgopt(copt, "ExcludePUA"))->enabled) {
322
+	if((opt = optget(opts, "ExcludePUA"))->enabled) {
323 323
 	    dboptions |= CL_DB_PUA_EXCLUDE;
324 324
 	    i = 0;
325 325
 	    logg("#Excluded PUA categories:");
326
-	    while(cpt) {
327
-		if(!(pua_cats = realloc(pua_cats, i + strlen(cpt->strarg) + 3))) {
326
+	    while(opt) {
327
+		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
328 328
 		    logg("!Can't allocate memory for pua_cats\n");
329 329
 		    logg_close();
330
-		    freecfg(copt);
330
+		    optfree(opts);
331 331
 		    cl_engine_free(engine);
332 332
 		    return 1;
333 333
 		}
334
-		logg("# %s", cpt->strarg);
335
-		sprintf(pua_cats + i, ".%s", cpt->strarg);
336
-		i += strlen(cpt->strarg) + 1;
334
+		logg("# %s", opt->strarg);
335
+		sprintf(pua_cats + i, ".%s", opt->strarg);
336
+		i += strlen(opt->strarg) + 1;
337 337
 		pua_cats[i] = 0;
338
-		cpt = cpt->nextarg;
338
+		opt = opt->nextarg;
339 339
 	    }
340 340
 	    logg("#\n");
341 341
 	    pua_cats[i] = '.';
342 342
 	    pua_cats[i + 1] = 0;
343 343
 	}
344 344
 
345
-	if((cpt = cfgopt(copt, "IncludePUA"))->enabled) {
345
+	if((opt = optget(opts, "IncludePUA"))->enabled) {
346 346
 	    if(pua_cats) {
347 347
 		logg("!ExcludePUA and IncludePUA cannot be used at the same time\n");
348 348
 		logg_close();
349
-		freecfg(copt);
349
+		optfree(opts);
350 350
 		free(pua_cats);
351 351
 		cl_engine_free(engine);
352 352
 		return 1;
... ...
@@ -354,19 +337,19 @@ int main(int argc, char **argv)
354 354
 	    dboptions |= CL_DB_PUA_INCLUDE;
355 355
 	    i = 0;
356 356
 	    logg("#Included PUA categories:");
357
-	    while(cpt) {
358
-		if(!(pua_cats = realloc(pua_cats, i + strlen(cpt->strarg) + 3))) {
357
+	    while(opt) {
358
+		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
359 359
 		    logg("!Can't allocate memory for pua_cats\n");
360 360
 		    logg_close();
361
-		    freecfg(copt);
361
+		    optfree(opts);
362 362
 		    cl_engine_free(engine);
363 363
 		    return 1;
364 364
 		}
365
-		logg("# %s", cpt->strarg);
366
-		sprintf(pua_cats + i, ".%s", cpt->strarg);
367
-		i += strlen(cpt->strarg) + 1;
365
+		logg("# %s", opt->strarg);
366
+		sprintf(pua_cats + i, ".%s", opt->strarg);
367
+		i += strlen(opt->strarg) + 1;
368 368
 		pua_cats[i] = 0;
369
-		cpt = cpt->nextarg;
369
+		opt = opt->nextarg;
370 370
 	    }
371 371
 	    logg("#\n");
372 372
 	    pua_cats[i] = '.';
... ...
@@ -377,7 +360,7 @@ int main(int argc, char **argv)
377 377
 	    if((ret = cl_engine_set(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) {
378 378
 		logg("!cli_engine_set(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret));
379 379
 		logg_close();
380
-		freecfg(copt);
380
+		optfree(opts);
381 381
 		free(pua_cats);
382 382
 		cl_engine_free(engine);
383 383
 		return 1;
... ...
@@ -389,47 +372,47 @@ int main(int argc, char **argv)
389 389
     }
390 390
 
391 391
     /* set the temporary dir */
392
-    if((cpt = cfgopt(copt, "TemporaryDirectory"))->enabled) {
393
-	if((ret = cl_engine_set(engine, CL_ENGINE_TMPDIR, cpt->strarg))) {
392
+    if((opt = optget(opts, "TemporaryDirectory"))->enabled) {
393
+	if((ret = cl_engine_set(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
394 394
 	    logg("!cli_engine_set(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
395 395
 	    logg_close();
396
-	    freecfg(copt);
396
+	    optfree(opts);
397 397
 	    cl_engine_free(engine);
398 398
 	    return 1;
399 399
 	}
400 400
     }
401 401
 
402
-    if(cfgopt(copt, "LeaveTemporaryFiles")->enabled) {
402
+    if(optget(opts, "LeaveTemporaryFiles")->enabled) {
403 403
 	val32 = 1;
404 404
 	cl_engine_set(engine, CL_ENGINE_KEEPTMP, &val32);
405 405
     }
406 406
 
407
-    if(cfgopt(copt, "PhishingSignatures")->enabled)
407
+    if(optget(opts, "PhishingSignatures")->enabled)
408 408
 	dboptions |= CL_DB_PHISHING;
409 409
     else
410 410
 	logg("#Not loading phishing signatures.\n");
411 411
 
412
-    if(cfgopt(copt,"PhishingScanURLs")->enabled)
412
+    if(optget(opts,"PhishingScanURLs")->enabled)
413 413
 	dboptions |= CL_DB_PHISHING_URLS;
414 414
     else
415 415
 	logg("#Disabling URL based phishing detection.\n");
416 416
 
417
-    if(cfgopt(copt,"DevACOnly")->enabled) {
417
+    if(optget(opts,"DevACOnly")->enabled) {
418 418
 	logg("#Only using the A-C matcher.\n");
419 419
         val32 = 1;
420 420
 	cl_engine_set(engine, CL_ENGINE_AC_ONLY, &val32);
421 421
     }
422 422
 
423
-    if((cpt = cfgopt(copt, "DevACDepth"))->enabled) {
424
-	val32 = cpt->numarg;
423
+    if((opt = optget(opts, "DevACDepth"))->enabled) {
424
+	val32 = opt->numarg;
425 425
         cl_engine_set(engine, CL_ENGINE_AC_MAXDEPTH, &val32);
426
-	logg("#Max A-C depth set to %u\n", cpt->numarg);
426
+	logg("#Max A-C depth set to %u\n", opt->numarg);
427 427
     }
428 428
 
429 429
     if((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
430 430
 	logg("!%s\n", cl_strerror(ret));
431 431
 	logg_close();
432
-	freecfg(copt);
432
+	optfree(opts);
433 433
 	cl_engine_free(engine);
434 434
 	return 1;
435 435
     }
... ...
@@ -438,7 +421,7 @@ int main(int argc, char **argv)
438 438
     if((ret = cl_engine_compile(engine)) != 0) {
439 439
 	logg("!Database initialization error: %s\n", cl_strerror(ret));
440 440
 	logg_close();
441
-	freecfg(copt);
441
+	optfree(opts);
442 442
 	cl_engine_free(engine);
443 443
 	return 1;
444 444
     }
... ...
@@ -450,15 +433,15 @@ int main(int argc, char **argv)
450 450
 	if(WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
451 451
 	    logg("!Error at WSAStartup(): %d\n", WSAGetLastError());
452 452
 	    logg_close();
453
-	    freecfg(copt);
453
+	    optfree(opts);
454 454
 	    cl_engine_free(engine);
455 455
 	    return 1;
456 456
 	}
457 457
 #endif
458
-	lsockets[nlsockets] = tcpserver(copt);
458
+	lsockets[nlsockets] = tcpserver(opts);
459 459
 	if(lsockets[nlsockets] == -1) {
460 460
 	    logg_close();
461
-	    freecfg(copt);
461
+	    optfree(opts);
462 462
 	    cl_engine_free(engine);
463 463
 	    return 1;
464 464
 	}
... ...
@@ -466,10 +449,10 @@ int main(int argc, char **argv)
466 466
     }
467 467
 
468 468
     if(localsock) {
469
-	lsockets[nlsockets] = localserver(copt);
469
+	lsockets[nlsockets] = localserver(opts);
470 470
 	if(lsockets[nlsockets] == -1) {
471 471
 	    logg_close();
472
-	    freecfg(copt);
472
+	    optfree(opts);
473 473
 	    if(tcpsock)
474 474
 		closesocket(lsockets[0]);
475 475
 	    cl_engine_free(engine);
... ...
@@ -479,7 +462,7 @@ int main(int argc, char **argv)
479 479
     }
480 480
 
481 481
     /* fork into background */
482
-    if(!cfgopt(copt, "Foreground")->enabled) {
482
+    if(!optget(opts, "Foreground")->enabled) {
483 483
 #ifdef C_BSD	    
484 484
 	/* workaround for OpenBSD bug, see https://wwws.clamav.net/bugzilla/show_bug.cgi?id=885 */
485 485
 	for(ret=0;ret<nlsockets;ret++) {
... ...
@@ -489,7 +472,7 @@ int main(int argc, char **argv)
489 489
 	if(daemonize() == -1) {
490 490
 	    logg("!daemonize() failed\n");
491 491
 	    logg_close();
492
-	    freecfg(copt);
492
+	    optfree(opts);
493 493
 	    cl_engine_free(engine);
494 494
 	    return 1;
495 495
 	}
... ...
@@ -506,7 +489,7 @@ int main(int argc, char **argv)
506 506
         foreground = 1;
507 507
 
508 508
 
509
-    ret = acceptloop_th(lsockets, nlsockets, engine, dboptions, copt);
509
+    ret = acceptloop_th(lsockets, nlsockets, engine, dboptions, opts);
510 510
 
511 511
 #ifdef C_WINDOWS
512 512
     if(tcpsock)
... ...
@@ -515,13 +498,13 @@ int main(int argc, char **argv)
515 515
     if(!pthread_win32_process_detach_np()) {
516 516
 	logg("!Can't stop the win32 pthreads layer\n");
517 517
 	logg_close();
518
-	freecfg(copt);
518
+	optfree(opts);
519 519
 	return 1;
520 520
     }
521 521
 #endif
522 522
 
523 523
     logg_close();
524
-    freecfg(copt);
524
+    optfree(opts);
525 525
 
526 526
     return ret;
527 527
 }
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #include "libclamav/clamav.h"
33 33
 
34
-#include "shared/cfgparser.h"
34
+#include "shared/optparser.h"
35 35
 #include "shared/output.h"
36 36
 
37 37
 #include "server.h"
... ...
@@ -67,7 +67,7 @@ void *clamukoth(void *arg)
67 67
 	const char *virname;
68 68
         struct sigaction act;
69 69
 	unsigned long mask = 0;
70
-	const struct cfgstruct *pt;
70
+	const struct optstruct *pt;
71 71
 	short int scan;
72 72
 	int sizelimit = 0;
73 73
 	struct stat sb;
... ...
@@ -100,15 +100,15 @@ void *clamukoth(void *arg)
100 100
 	logg("Clamuko: Correctly registered with Dazuko.\n");
101 101
 
102 102
     /* access mask */
103
-    if(cfgopt(tharg->copt, "ClamukoScanOnOpen")->enabled) {
103
+    if(optget(tharg->opts, "ClamukoScanOnOpen")->enabled) {
104 104
 	logg("Clamuko: Scan-on-open mode activated.\n");
105 105
 	mask |= DAZUKO_ON_OPEN;
106 106
     }
107
-    if(cfgopt(tharg->copt, "ClamukoScanOnClose")->enabled) {
107
+    if(optget(tharg->opts, "ClamukoScanOnClose")->enabled) {
108 108
 	logg("Clamuko: Scan-on-close mode activated.\n");
109 109
 	mask |= DAZUKO_ON_CLOSE;
110 110
     }
111
-    if(cfgopt(tharg->copt, "ClamukoScanOnExec")->enabled) {
111
+    if(optget(tharg->opts, "ClamukoScanOnExec")->enabled) {
112 112
 	logg("Clamuko: Scan-on-exec mode activated.\n");
113 113
 	mask |= DAZUKO_ON_EXEC;
114 114
     }
... ...
@@ -125,7 +125,7 @@ void *clamukoth(void *arg)
125 125
 	return NULL;
126 126
     }
127 127
 
128
-    if((pt = cfgopt(tharg->copt, "ClamukoIncludePath"))->enabled) {
128
+    if((pt = optget(tharg->opts, "ClamukoIncludePath"))->enabled) {
129 129
 	while(pt) {
130 130
 	    if((dazukoAddIncludePath(pt->strarg))) {
131 131
 		logg("!Clamuko: Dazuko -> Can't include path %s\n", pt->strarg);
... ...
@@ -134,7 +134,7 @@ void *clamukoth(void *arg)
134 134
 	    } else
135 135
 		logg("Clamuko: Included path %s\n", pt->strarg);
136 136
 
137
-	    pt = (struct cfgstruct *) pt->nextarg;
137
+	    pt = (struct optstruct *) pt->nextarg;
138 138
 	}
139 139
     } else {
140 140
 	logg("!Clamuko: please include at least one path.\n");
... ...
@@ -142,7 +142,7 @@ void *clamukoth(void *arg)
142 142
 	return NULL;
143 143
     }
144 144
 
145
-    if((pt = cfgopt(tharg->copt, "ClamukoExcludePath"))->enabled) {
145
+    if((pt = optget(tharg->opts, "ClamukoExcludePath"))->enabled) {
146 146
 	while(pt) {
147 147
 	    if((dazukoAddExcludePath(pt->strarg))) {
148 148
 		logg("!Clamuko: Dazuko -> Can't exclude path %s\n", pt->strarg);
... ...
@@ -151,11 +151,11 @@ void *clamukoth(void *arg)
151 151
 	    } else
152 152
 		logg("Clamuko: Excluded path %s\n", pt->strarg);
153 153
 
154
-	    pt = (struct cfgstruct *) pt->nextarg;
154
+	    pt = (struct optstruct *) pt->nextarg;
155 155
 	}
156 156
     }
157 157
 
158
-    sizelimit = cfgopt(tharg->copt, "ClamukoMaxFileSize")->numarg;
158
+    sizelimit = optget(tharg->opts, "ClamukoMaxFileSize")->numarg;
159 159
     if(sizelimit)
160 160
 	logg("Clamuko: Max file size limited to %d bytes.\n", sizelimit);
161 161
     else
... ...
@@ -177,7 +177,7 @@ void *clamukoth(void *arg)
177 177
 
178 178
 	    if(scan && cl_scanfile(acc->filename, &virname, NULL, tharg->engine, tharg->options) == CL_VIRUS) {
179 179
 		logg("Clamuko: %s: %s FOUND\n", acc->filename, virname);
180
-		virusaction(acc->filename, virname, tharg->copt);
180
+		virusaction(acc->filename, virname, tharg->opts);
181 181
 		acc->deny = 1;
182 182
 	    } else
183 183
 		acc->deny = 0;
... ...
@@ -37,8 +37,7 @@
37 37
 
38 38
 #include "libclamav/clamav.h"
39 39
 
40
-#include "shared/options.h"
41
-#include "shared/cfgparser.h"
40
+#include "shared/optparser.h"
42 41
 
43 42
 #include "others.h"
44 43
 #include "server.h"
... ...
@@ -46,7 +45,7 @@
46 46
 #include "localserver.h"
47 47
 
48 48
 #ifdef C_WINDOWS
49
-int localserver(const struct cfgstruct *copt)
49
+int localserver(const struct optstruct *opts)
50 50
 {
51 51
     logg("!Localserver is not supported on this platform");
52 52
     return -1;
... ...
@@ -54,7 +53,7 @@ int localserver(const struct cfgstruct *copt)
54 54
 
55 55
 #else
56 56
 
57
-int localserver(const struct cfgstruct *copt)
57
+int localserver(const struct optstruct *opts)
58 58
 {
59 59
 	struct sockaddr_un server;
60 60
 	int sockfd, backlog;
... ...
@@ -63,7 +62,7 @@ int localserver(const struct cfgstruct *copt)
63 63
 
64 64
     memset((char *) &server, 0, sizeof(server));
65 65
     server.sun_family = AF_UNIX;
66
-    strncpy(server.sun_path, cfgopt(copt, "LocalSocket")->strarg, sizeof(server.sun_path));
66
+    strncpy(server.sun_path, optget(opts, "LocalSocket")->strarg, sizeof(server.sun_path));
67 67
     server.sun_path[sizeof(server.sun_path)-1]='\0';
68 68
 
69 69
     if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
... ...
@@ -79,7 +78,7 @@ int localserver(const struct cfgstruct *copt)
79 79
 		close(sockfd);
80 80
 		return -1;
81 81
 	    }
82
-	    if(cfgopt(copt, "FixStaleSocket")->enabled) {
82
+	    if(optget(opts, "FixStaleSocket")->enabled) {
83 83
 		logg("#LOCAL: Removing stale socket file %s\n", server.sun_path);
84 84
 		if(unlink(server.sun_path) == -1) {
85 85
 		    estr = strerror(errno);
... ...
@@ -108,7 +107,7 @@ int localserver(const struct cfgstruct *copt)
108 108
 
109 109
     logg("#LOCAL: Unix socket file %s\n", server.sun_path);
110 110
 
111
-    backlog = cfgopt(copt, "MaxConnectionQueueLength")->numarg;
111
+    backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
112 112
     logg("#LOCAL: Setting connection queue length to %d\n", backlog);
113 113
 
114 114
     if(listen(sockfd, backlog) == -1) {
... ...
@@ -19,8 +19,8 @@
19 19
 #ifndef __LOCALSERVER_H
20 20
 #define __LOCALSERVER_H
21 21
 
22
-#include "shared/cfgparser.h"
22
+#include "shared/optparser.h"
23 23
 
24
-int localserver(const struct cfgstruct *copt);
24
+int localserver(const struct optstruct *opts);
25 25
 
26 26
 #endif
... ...
@@ -74,7 +74,7 @@
74 74
 #endif /* HAVE_POLL_H */
75 75
 #endif /* HAVE_POLL */
76 76
 
77
-#include "shared/cfgparser.h"
77
+#include "shared/optparser.h"
78 78
 #include "shared/output.h"
79 79
 
80 80
 #include "session.h"
... ...
@@ -84,24 +84,24 @@
84 84
 #define ENV_VIRUS "CLAM_VIRUSEVENT_VIRUSNAME"
85 85
 
86 86
 #ifdef	C_WINDOWS
87
-void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
87
+void virusaction(const char *filename, const char *virname, const struct optstruct *opts)
88 88
 {
89
-    if(cfgopt(copt, "VirusEvent")->enabled)
89
+    if(optget(opts, "VirusEvent")->enabled)
90 90
 	logg("^VirusEvent is not supported on this platform");	/* Yet */
91 91
 }
92 92
 
93 93
 #else
94 94
 static pthread_mutex_t virusaction_lock = PTHREAD_MUTEX_INITIALIZER;
95 95
 
96
-void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
96
+void virusaction(const char *filename, const char *virname, const struct optstruct *opts)
97 97
 {
98 98
 	pid_t pid;
99
-	const struct cfgstruct *cpt;
99
+	const struct optstruct *opt;
100 100
 	char *buffer, *pt, *cmd, *buffer_file, *buffer_vir;
101 101
 	size_t j;
102 102
 	char *env[4];
103 103
 
104
-	if(!(cpt = cfgopt(copt, "VirusEvent"))->enabled)
104
+	if(!(opt = optget(opts, "VirusEvent"))->enabled)
105 105
 		return;
106 106
 
107 107
 	env[0] = getenv("PATH");
... ...
@@ -120,7 +120,7 @@ void virusaction(const char *filename, const char *virname, const struct cfgstru
120 120
 	}
121 121
 	env[j++] = NULL;
122 122
 
123
-	cmd = strdup(cpt->strarg);
123
+	cmd = strdup(opt->strarg);
124 124
 
125 125
 	if(cmd && (pt = strstr(cmd, "%v"))) {
126 126
 		buffer = (char *) malloc(strlen(cmd) + strlen(virname) + 10);
... ...
@@ -24,12 +24,12 @@
24 24
 #endif
25 25
 
26 26
 #include <stdlib.h>
27
-#include "shared/cfgparser.h"
27
+#include "shared/optparser.h"
28 28
 
29 29
 int poll_fds(int *fds, int nfds, int timeout_sec, int check_signals);
30 30
 int poll_fd(int fd, int timeout_sec, int check_signals);
31 31
 int is_fd_connected(int fd);
32
-void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt);
32
+void virusaction(const char *filename, const char *virname, const struct optstruct *opts);
33 33
 int writen(int fd, void *buff, unsigned int count);
34 34
 
35 35
 int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeout_sec, int force_delim, int read_command);
... ...
@@ -56,7 +56,7 @@
56 56
 #include "libclamav/clamav.h"
57 57
 #include "libclamav/others.h"
58 58
 
59
-#include "shared/cfgparser.h"
59
+#include "shared/optparser.h"
60 60
 #include "shared/output.h"
61 61
 #include "shared/misc.h"
62 62
 
... ...
@@ -79,7 +79,7 @@ extern int progexit;
79 79
 struct multi_tag {
80 80
     int sd;
81 81
     unsigned int options;
82
-    const struct cfgstruct *copt;
82
+    const struct optstruct *opts;
83 83
     char *fname;
84 84
     const struct cl_engine *engine;
85 85
 };
... ...
@@ -100,7 +100,7 @@ static int checksymlink(const char *path)
100 100
     return 0;
101 101
 }
102 102
 
103
-static int dirscan(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int odesc, unsigned int *reclev, unsigned int type, threadpool_t *multi_pool)
103
+static int dirscan(const char *dirname, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc, unsigned int *reclev, unsigned int type, threadpool_t *multi_pool)
104 104
 {
105 105
 	DIR *dd;
106 106
 	struct dirent *dent;
... ...
@@ -115,20 +115,20 @@ static int dirscan(const char *dirname, const char **virname, unsigned long int
115 115
 	int ret = 0, scanret = 0;
116 116
 	unsigned int maxdirrec = 0;
117 117
 	struct multi_tag *scandata;
118
-	const struct cfgstruct *cpt;
118
+	const struct optstruct *opt;
119 119
 
120 120
 
121
-    if((cpt = cfgopt(copt, "ExcludePath"))->enabled) {
122
-	while(cpt) {
123
-	    if(match_regex(dirname, cpt->strarg) == 1) {
121
+    if((opt = optget(opts, "ExcludePath"))->enabled) {
122
+	while(opt) {
123
+	    if(match_regex(dirname, opt->strarg) == 1) {
124 124
 		mdprintf(odesc, "%s: Excluded\n", dirname);
125 125
 		return 0;
126 126
 	    }
127
-	    cpt = (struct cfgstruct *) cpt->nextarg;
127
+	    opt = (struct optstruct *) opt->nextarg;
128 128
 	}
129 129
     }
130 130
 
131
-    maxdirrec = cfgopt(copt, "MaxDirectoryRecursion")->numarg;
131
+    maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
132 132
     if(maxdirrec) {
133 133
 	if(*reclev > maxdirrec) {
134 134
 	    logg("*Directory recursion limit exceeded at %s\n", dirname);
... ...
@@ -172,15 +172,15 @@ static int dirscan(const char *dirname, const char **virname, unsigned long int
172 172
 
173 173
 		    /* stat the file */
174 174
 		    if(lstat(fname, &statbuf) != -1) {
175
-			if((S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 1) && cfgopt(copt, "FollowDirectorySymlinks")->enabled)) {
176
-			    if(dirscan(fname, virname, scanned, engine, options, copt, odesc, reclev, type, multi_pool) == 1) {
175
+			if((S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 1) && optget(opts, "FollowDirectorySymlinks")->enabled)) {
176
+			    if(dirscan(fname, virname, scanned, engine, options, opts, odesc, reclev, type, multi_pool) == 1) {
177 177
 				free(fname);
178 178
 				closedir(dd);
179 179
 				return 1;
180 180
 			    }
181 181
 			    free(fname);
182 182
 			} else {
183
-			    if(S_ISREG(statbuf.st_mode) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 2) && cfgopt(copt, "FollowFileSymlinks")->enabled)) {
183
+			    if(S_ISREG(statbuf.st_mode) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 2) && optget(opts, "FollowFileSymlinks")->enabled)) {
184 184
 
185 185
 #ifdef C_LINUX
186 186
 				if(procdev && (statbuf.st_dev == procdev))
... ...
@@ -199,7 +199,7 @@ static int dirscan(const char *dirname, const char **virname, unsigned long int
199 199
 					}
200 200
 					scandata->sd = odesc;
201 201
 					scandata->options = options;
202
-					scandata->copt = copt;
202
+					scandata->opts = opts;
203 203
 					scandata->fname = fname;
204 204
 					scandata->engine = engine;
205 205
 					if(!thrmgr_dispatch(multi_pool, scandata)) {
... ...
@@ -226,7 +226,7 @@ static int dirscan(const char *dirname, const char **virname, unsigned long int
226 226
 
227 227
 					    mdprintf(odesc, "%s: %s FOUND\n", fname, *virname);
228 228
 					    logg("~%s: %s FOUND\n", fname, *virname);
229
-					    virusaction(fname, *virname, copt);
229
+					    virusaction(fname, *virname, opts);
230 230
 					    if(type == TYPE_SCAN) {
231 231
 						closedir(dd);
232 232
 						free(fname);
... ...
@@ -292,7 +292,7 @@ static void multiscanfile(void *arg)
292 292
     if(ret == CL_VIRUS) {
293 293
 	mdprintf(tag->sd, "%s: %s FOUND\n", tag->fname, virname);
294 294
 	logg("~%s: %s FOUND\n", tag->fname, virname);
295
-	virusaction(tag->fname, virname, tag->copt);
295
+	virusaction(tag->fname, virname, tag->opts);
296 296
     } else if(ret != CL_CLEAN) {
297 297
 	mdprintf(tag->sd, "%s: %s ERROR\n", tag->fname, cl_strerror(ret));
298 298
 	logg("~%s: %s ERROR\n", tag->fname, cl_strerror(ret));
... ...
@@ -305,13 +305,13 @@ static void multiscanfile(void *arg)
305 305
     return;
306 306
 }
307 307
 
308
-int scan(const char *filename, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int odesc, unsigned int type)
308
+int scan(const char *filename, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc, unsigned int type)
309 309
 {
310 310
 	struct stat sb;
311 311
 	int ret = 0;
312 312
 	unsigned int reclev = 0;
313 313
 	const char *virname;
314
-	const struct cfgstruct *cpt;
314
+	const struct optstruct *opt;
315 315
 	threadpool_t *multi_pool = NULL;
316 316
 
317 317
 
... ...
@@ -327,8 +327,8 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
327 327
 	return -1;
328 328
     }
329 329
 
330
-    if((cpt = cfgopt(copt, "ExcludePath"))->enabled) {
331
-	if(match_regex(filename, cpt->strarg) == 1) {
330
+    if((opt = optget(opts, "ExcludePath"))->enabled) {
331
+	if(match_regex(filename, opt->strarg) == 1) {
332 332
 	    mdprintf(odesc, "%s: Excluded\n", filename);
333 333
 	    return 0;
334 334
 	}
... ...
@@ -337,7 +337,7 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
337 337
     switch(sb.st_mode & S_IFMT) {
338 338
 #ifdef	S_IFLNK
339 339
 	case S_IFLNK:
340
-	    if(!cfgopt(copt, "FollowFileSymlinks")->enabled)
340
+	    if(!optget(opts, "FollowFileSymlinks")->enabled)
341 341
 		break;
342 342
 	    /* else go to the next case */
343 343
 #endif
... ...
@@ -360,7 +360,7 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
360 360
 	    if(ret == CL_VIRUS) {
361 361
 		mdprintf(odesc, "%s: %s FOUND\n", filename, virname);
362 362
 		logg("~%s: %s FOUND\n", filename, virname);
363
-		virusaction(filename, virname, copt);
363
+		virusaction(filename, virname, opts);
364 364
 	    } else if(ret != CL_CLEAN) {
365 365
 		mdprintf(odesc, "%s: %s ERROR\n", filename, cl_strerror(ret));
366 366
 		logg("~%s: %s ERROR\n", filename, cl_strerror(ret));
... ...
@@ -372,8 +372,8 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
372 372
 	    break;
373 373
 	case S_IFDIR:
374 374
 	    if(type == TYPE_MULTISCAN) {
375
-		    int idletimeout = cfgopt(copt, "IdleTimeout")->numarg;
376
-		    int max_threads = cfgopt(copt, "MaxThreads")->numarg;
375
+		    int idletimeout = optget(opts, "IdleTimeout")->numarg;
376
+		    int max_threads = optget(opts, "MaxThreads")->numarg;
377 377
 
378 378
 		if((multi_pool = thrmgr_new(max_threads, idletimeout, multiscanfile)) == NULL) {
379 379
 		    logg("!thrmgr_new failed for multi_pool\n");
... ...
@@ -382,7 +382,7 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
382 382
 		}
383 383
 	    }
384 384
 
385
-	    ret = dirscan(filename, &virname, scanned, engine, options, copt, odesc, &reclev, type, multi_pool);
385
+	    ret = dirscan(filename, &virname, scanned, engine, options, opts, odesc, &reclev, type, multi_pool);
386 386
 
387 387
 	    if(multi_pool)
388 388
 		thrmgr_destroy(multi_pool);
... ...
@@ -406,7 +406,7 @@ int scan(const char *filename, unsigned long int *scanned, const struct cl_engin
406 406
  */
407 407
 int scanfd(const int fd, unsigned long int *scanned,
408 408
     const struct cl_engine *engine,
409
-    unsigned int options, const struct cfgstruct *copt, int odesc)  
409
+    unsigned int options, const struct optstruct *opts, int odesc)  
410 410
 {
411 411
 	int ret;
412 412
 	const char *virname;
... ...
@@ -429,7 +429,7 @@ int scanfd(const int fd, unsigned long int *scanned,
429 429
 	if(ret == CL_VIRUS) {
430 430
 	mdprintf(odesc, "%s: %s FOUND\n", fdstr, virname);
431 431
 		logg("%s: %s FOUND\n", fdstr, virname);
432
-		virusaction(fdstr, virname, copt);
432
+		virusaction(fdstr, virname, opts);
433 433
 	} else if(ret != CL_CLEAN) {
434 434
 		mdprintf(odesc, "%s: %s ERROR\n", fdstr, cl_strerror(ret));
435 435
 		logg("%s: %s ERROR\n", fdstr, cl_strerror(ret));
... ...
@@ -441,7 +441,7 @@ int scanfd(const int fd, unsigned long int *scanned,
441 441
 	return ret;
442 442
 }
443 443
 
444
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt)
444
+int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts)
445 445
 {
446 446
 	int ret, sockfd, acceptd;
447 447
 	int tmpd, bread, retval, timeout, btread;
... ...
@@ -455,17 +455,17 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
455 455
 	struct sockaddr_in peer;
456 456
 	socklen_t addrlen;
457 457
 	struct hostent he;
458
-	const struct cfgstruct *cpt;
458
+	const struct optstruct *opt;
459 459
 	char *tmpname;
460 460
 
461 461
 
462 462
     /* get min port */
463
-    min_port = cfgopt(copt, "StreamMinPort")->numarg;
463
+    min_port = optget(opts, "StreamMinPort")->numarg;
464 464
     if(min_port < 1024 || min_port > 65535)
465 465
 	min_port = 1024;
466 466
 
467 467
     /* get max port */
468
-    max_port = cfgopt(copt, "StreamMaxPort")->numarg;
468
+    max_port = optget(opts, "StreamMaxPort")->numarg;
469 469
     if(max_port < min_port || max_port > 65535)
470 470
 	max_port = 65535;
471 471
 
... ...
@@ -485,10 +485,10 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
485 485
 	server.sin_family = AF_INET;
486 486
 	server.sin_port = htons(port);
487 487
 
488
-	if((cpt = cfgopt(copt, "TCPAddr"))->enabled) {
489
-	    if(r_gethostbyname(cpt->strarg, &he, buff, sizeof(buff)) == -1) {
490
-		logg("!r_gethostbyname(%s) error: %s\n", cpt->strarg, strerror(errno));
491
-		mdprintf(odesc, "r_gethostbyname(%s) ERROR\n", cpt->strarg);
488
+	if((opt = optget(opts, "TCPAddr"))->enabled) {
489
+	    if(r_gethostbyname(opt->strarg, &he, buff, sizeof(buff)) == -1) {
490
+		logg("!r_gethostbyname(%s) error: %s\n", opt->strarg, strerror(errno));
491
+		mdprintf(odesc, "r_gethostbyname(%s) ERROR\n", opt->strarg);
492 492
 		return -1;
493 493
 	    }
494 494
 	    server.sin_addr = *(struct in_addr *) he.h_addr_list[0];
... ...
@@ -504,7 +504,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
504 504
 	    bound = 1;
505 505
     }
506 506
 
507
-    timeout = cfgopt(copt, "ReadTimeout")->numarg;
507
+    timeout = optget(opts, "ReadTimeout")->numarg;
508 508
     if(timeout == 0)
509 509
     	timeout = -1;
510 510
 
... ...
@@ -546,7 +546,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
546 546
     snprintf(peer_addr, sizeof(peer_addr), "%s", inet_ntoa(peer.sin_addr));
547 547
     logg("*Accepted connection from %s on port %u, fd %d\n", peer_addr, port, acceptd);
548 548
 
549
-    if(cli_gentempfd(cfgopt(copt, "TemporaryDirectory")->strarg, &tmpname, &tmpd)) {
549
+    if(cli_gentempfd(optget(opts, "TemporaryDirectory")->strarg, &tmpname, &tmpd)) {
550 550
 	shutdown(sockfd, 2);
551 551
 	closesocket(sockfd);
552 552
 	closesocket(acceptd);
... ...
@@ -555,7 +555,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
555 555
 	return -1;
556 556
     }
557 557
 
558
-    maxsize = cfgopt(copt, "StreamMaxLength")->numarg;
558
+    maxsize = optget(opts, "StreamMaxLength")->numarg;
559 559
 
560 560
     btread = sizeof(buff);
561 561
 
... ...
@@ -572,7 +572,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
572 572
 	    mdprintf(odesc, "Temporary file -> write ERROR\n");
573 573
 	    logg("!ScanStream(%s@%u): Can't write to temporary file.\n", peer_addr, port);
574 574
 	    close(tmpd);
575
-	    if(!cfgopt(copt, "LeaveTemporaryFiles")->enabled)
575
+	    if(!optget(opts, "LeaveTemporaryFiles")->enabled)
576 576
 		unlink(tmpname);
577 577
 	    free(tmpname);
578 578
 	    return -1;
... ...
@@ -608,7 +608,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
608 608
     	ret = -1;
609 609
     }
610 610
     close(tmpd);
611
-    if(!cfgopt(copt, "LeaveTemporaryFiles")->enabled)
611
+    if(!optget(opts, "LeaveTemporaryFiles")->enabled)
612 612
 	unlink(tmpname);
613 613
     free(tmpname);
614 614
 
... ...
@@ -618,7 +618,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
618 618
     if(ret == CL_VIRUS) {
619 619
 	mdprintf(odesc, "stream: %s FOUND\n", virname);
620 620
 	logg("stream(%s@%u): %s FOUND\n", peer_addr, port, virname);
621
-	virusaction("stream", virname, copt);
621
+	virusaction("stream", virname, opts);
622 622
     } else if(ret != CL_CLEAN) {
623 623
     	if(retval == 1) {
624 624
 	    mdprintf(odesc, "stream: %s ERROR\n", cl_strerror(ret));
... ...
@@ -24,12 +24,12 @@
24 24
 #define TYPE_MULTISCAN	2
25 25
 
26 26
 #include "libclamav/clamav.h"
27
-#include "shared/cfgparser.h"
27
+#include "shared/optparser.h"
28 28
 
29
-int scan(const char *filename, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int odesc, unsigned int type);
29
+int scan(const char *filename, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc, unsigned int type);
30 30
 
31
-int scanfd(const int fd, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int odesc);
31
+int scanfd(const int fd, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc);
32 32
 
33
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt);
33
+int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts);
34 34
 
35 35
 #endif
... ...
@@ -45,6 +45,7 @@
45 45
 #include "libclamav/clamav.h"
46 46
 
47 47
 #include "shared/output.h"
48
+#include "shared/optparser.h"
48 49
 
49 50
 #include "server.h"
50 51
 #include "thrmgr.h"
... ...
@@ -79,7 +80,7 @@ static struct cl_stat *dbstat = NULL;
79 79
 typedef struct client_conn_tag {
80 80
     int sd;
81 81
     unsigned int options;
82
-    const struct cfgstruct *copt;
82
+    const struct optstruct *opts;
83 83
     struct cl_engine *engine;
84 84
     time_t engine_timestamp;
85 85
     int *socketds;
... ...
@@ -109,12 +110,12 @@ static void scanner_thread(void *arg)
109 109
     pthread_sigmask(SIG_SETMASK, &sigset, NULL);
110 110
 #endif
111 111
 
112
-    timeout = cfgopt(conn->copt, "ReadTimeout")->numarg;
112
+    timeout = optget(conn->opts, "ReadTimeout")->numarg;
113 113
     if(!timeout)
114 114
     	timeout = -1;
115 115
 
116 116
     do {
117
-    	ret = command(conn->sd, conn->engine, conn->options, conn->copt, timeout);
117
+    	ret = command(conn->sd, conn->engine, conn->options, conn->opts, timeout);
118 118
 	if (ret < 0) {
119 119
 		break;
120 120
 	}
... ...
@@ -191,7 +192,7 @@ void sighandler_th(int sig)
191 191
     }
192 192
 }
193 193
 
194
-static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dboptions, const struct cfgstruct *copt, int do_check, int *ret)
194
+static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts, int do_check, int *ret)
195 195
 {
196 196
 	const char *dbdir;
197 197
 	int retval;
... ...
@@ -225,7 +226,7 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti
225 225
 	cl_engine_free(engine);
226 226
     }
227 227
 
228
-    dbdir = cfgopt(copt, "DatabaseDirectory")->strarg;
228
+    dbdir = optget(opts, "DatabaseDirectory")->strarg;
229 229
     logg("Reading databases from %s\n", dbdir);
230 230
 
231 231
     if(dbstat == NULL) {
... ...
@@ -280,7 +281,7 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti
280 280
     return engine;
281 281
 }
282 282
 
283
-int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigned int dboptions, const struct cfgstruct *copt)
283
+int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts)
284 284
 {
285 285
 	int max_threads, i, ret = 0;
286 286
 	unsigned int options = 0;
... ...
@@ -293,7 +294,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
293 293
 #endif
294 294
 	mode_t old_umask;
295 295
 	client_conn_t *client_conn;
296
-	const struct cfgstruct *cpt;
296
+	const struct optstruct *opt;
297 297
 #ifdef HAVE_STRERROR_R
298 298
 	char buff[BUFFSIZE + 1];
299 299
 #endif
... ...
@@ -315,8 +316,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
315 315
 #endif
316 316
 
317 317
     /* set up limits */
318
-    if((cpt = cfgopt(copt, "MaxScanSize"))->enabled) {
319
-	val64 = cpt->numarg;
318
+    if((opt = optget(opts, "MaxScanSize"))->enabled) {
319
+	val64 = opt->numarg;
320 320
 	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_SCANSIZE, &val64))) {
321 321
 	    logg("!cli_engine_set(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret));
322 322
 	    cl_engine_free(engine);
... ...
@@ -329,8 +330,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
329 329
     else
330 330
     	logg("^Limits: Global size limit protection disabled.\n");
331 331
 
332
-    if((cpt = cfgopt(copt, "MaxFileSize"))->enabled) {
333
-	val64 = cpt->numarg;
332
+    if((opt = optget(opts, "MaxFileSize"))->enabled) {
333
+	val64 = opt->numarg;
334 334
 	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_FILESIZE, &val64))) {
335 335
 	    logg("!cli_engine_set(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret));
336 336
 	    cl_engine_free(engine);
... ...
@@ -356,8 +357,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
356 356
     }
357 357
 #endif
358 358
 
359
-    if((cpt = cfgopt(copt, "MaxRecursion"))->enabled) {
360
-	val32 = cpt->numarg;
359
+    if((opt = optget(opts, "MaxRecursion"))->enabled) {
360
+	val32 = opt->numarg;
361 361
 	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_RECURSION, &val32))) {
362 362
 	    logg("!cli_engine_set(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret));
363 363
 	    cl_engine_free(engine);
... ...
@@ -370,8 +371,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
370 370
     else
371 371
     	logg("^Limits: Recursion level limit protection disabled.\n");
372 372
 
373
-    if((cpt = cfgopt(copt, "MaxFiles"))->enabled) {
374
-	val32 = cpt->numarg;
373
+    if((opt = optget(opts, "MaxFiles"))->enabled) {
374
+	val32 = opt->numarg;
375 375
 	if((ret = cl_engine_set(engine, CL_ENGINE_MAX_FILES, &val32))) {
376 376
 	    logg("!cli_engine_set(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret));
377 377
 	    cl_engine_free(engine);
... ...
@@ -385,11 +386,11 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
385 385
     	logg("^Limits: Files limit protection disabled.\n");
386 386
 
387 387
 
388
-    if(cfgopt(copt, "ScanArchive")->enabled) {
388
+    if(optget(opts, "ScanArchive")->enabled) {
389 389
 	logg("Archive support enabled.\n");
390 390
 	options |= CL_SCAN_ARCHIVE;
391 391
 
392
-	if(cfgopt(copt, "ArchiveBlockEncrypted")->enabled) {
392
+	if(optget(opts, "ArchiveBlockEncrypted")->enabled) {
393 393
 	    logg("Archive: Blocking encrypted archives.\n");
394 394
 	    options |= CL_SCAN_BLOCKENCRYPTED;
395 395
 	}
... ...
@@ -398,44 +399,44 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
398 398
 	logg("Archive support disabled.\n");
399 399
     }
400 400
 
401
-    if(cfgopt(copt, "AlgorithmicDetection")->enabled) {
401
+    if(optget(opts, "AlgorithmicDetection")->enabled) {
402 402
 	logg("Algorithmic detection enabled.\n");
403 403
 	options |= CL_SCAN_ALGORITHMIC;
404 404
     } else {
405 405
 	logg("Algorithmic detection disabled.\n");
406 406
     }
407 407
 
408
-    if(cfgopt(copt, "ScanPE")->enabled) {
408
+    if(optget(opts, "ScanPE")->enabled) {
409 409
 	logg("Portable Executable support enabled.\n");
410 410
 	options |= CL_SCAN_PE;
411 411
     } else {
412 412
 	logg("Portable Executable support disabled.\n");
413 413
     }
414 414
 
415
-    if(cfgopt(copt, "ScanELF")->enabled) {
415
+    if(optget(opts, "ScanELF")->enabled) {
416 416
 	logg("ELF support enabled.\n");
417 417
 	options |= CL_SCAN_ELF;
418 418
     } else {
419 419
 	logg("ELF support disabled.\n");
420 420
     }
421 421
 
422
-    if(cfgopt(copt, "ScanPE")->enabled || cfgopt(copt, "ScanELF")->enabled) {
423
-	if(cfgopt(copt, "DetectBrokenExecutables")->enabled) {
422
+    if(optget(opts, "ScanPE")->enabled || optget(opts, "ScanELF")->enabled) {
423
+	if(optget(opts, "DetectBrokenExecutables")->enabled) {
424 424
 	    logg("Detection of broken executables enabled.\n");
425 425
 	    options |= CL_SCAN_BLOCKBROKEN;
426 426
 	}
427 427
     }
428 428
 
429
-    if(cfgopt(copt, "ScanMail")->enabled) {
429
+    if(optget(opts, "ScanMail")->enabled) {
430 430
 	logg("Mail files support enabled.\n");
431 431
 	options |= CL_SCAN_MAIL;
432 432
 
433
-	if(cfgopt(copt, "MailFollowURLs")->enabled) {
433
+	if(optget(opts, "MailFollowURLs")->enabled) {
434 434
 	    logg("Mail: URL scanning enabled.\n");
435 435
 	    options |= CL_SCAN_MAILURL;
436 436
 	}
437 437
 
438
-	if(cfgopt(copt, "ScanPartialMessages")->enabled) {
438
+	if(optget(opts, "ScanPartialMessages")->enabled) {
439 439
 	    logg("Mail: RFC1341 handling enabled.\n");
440 440
 	    options |= CL_SCAN_PARTIAL_MESSAGE;
441 441
 	}
... ...
@@ -444,50 +445,50 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
444 444
 	logg("Mail files support disabled.\n");
445 445
     }
446 446
 
447
-    if(cfgopt(copt, "ScanOLE2")->enabled) {
447
+    if(optget(opts, "ScanOLE2")->enabled) {
448 448
 	logg("OLE2 support enabled.\n");
449 449
 	options |= CL_SCAN_OLE2;
450 450
     } else {
451 451
 	logg("OLE2 support disabled.\n");
452 452
     }
453 453
 
454
-    if(cfgopt(copt, "ScanPDF")->enabled) {
454
+    if(optget(opts, "ScanPDF")->enabled) {
455 455
 	logg("PDF support enabled.\n");
456 456
 	options |= CL_SCAN_PDF;
457 457
     } else {
458 458
 	logg("PDF support disabled.\n");
459 459
     }
460 460
 
461
-    if(cfgopt(copt, "ScanHTML")->enabled) {
461
+    if(optget(opts, "ScanHTML")->enabled) {
462 462
 	logg("HTML support enabled.\n");
463 463
 	options |= CL_SCAN_HTML;
464 464
     } else {
465 465
 	logg("HTML support disabled.\n");
466 466
     }
467 467
 
468
-    if(cfgopt(copt,"PhishingScanURLs")->enabled) {
468
+    if(optget(opts,"PhishingScanURLs")->enabled) {
469 469
 
470
-	if(cfgopt(copt,"PhishingAlwaysBlockCloak")->enabled) {
470
+	if(optget(opts,"PhishingAlwaysBlockCloak")->enabled) {
471 471
 	    options |= CL_SCAN_PHISHING_BLOCKCLOAK; 
472 472
 	    logg("Phishing: Always checking for cloaked urls\n");
473 473
 	}
474 474
 
475
-	if(cfgopt(copt,"PhishingAlwaysBlockSSLMismatch")->enabled) {
475
+	if(optget(opts,"PhishingAlwaysBlockSSLMismatch")->enabled) {
476 476
 	    options |= CL_SCAN_PHISHING_BLOCKSSL;
477 477
 	    logg("Phishing: Always checking for ssl mismatches\n");
478 478
 	}
479 479
     }
480 480
 
481
-    if(cfgopt(copt,"HeuristicScanPrecedence")->enabled) {
481
+    if(optget(opts,"HeuristicScanPrecedence")->enabled) {
482 482
 	    options |= CL_SCAN_HEURISTIC_PRECEDENCE;
483 483
 	    logg("Heuristic: precedence enabled\n");
484 484
     }
485 485
 
486
-    if(cfgopt(copt, "StructuredDataDetection")->enabled) {
486
+    if(optget(opts, "StructuredDataDetection")->enabled) {
487 487
         options |= CL_SCAN_STRUCTURED;
488 488
 
489
-	if((cpt = cfgopt(copt, "StructuredMinCreditCardCount"))->enabled) {
490
-	    val32 = cpt->numarg;
489
+	if((opt = optget(opts, "StructuredMinCreditCardCount"))->enabled) {
490
+	    val32 = opt->numarg;
491 491
 	    if((ret = cl_engine_set(engine, CL_ENGINE_MIN_CC_COUNT, &val32))) {
492 492
 		logg("!cli_engine_set(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret));
493 493
 		cl_engine_free(engine);
... ...
@@ -497,8 +498,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
497 497
 	cl_engine_get(engine, CL_ENGINE_MIN_CC_COUNT, &val32);
498 498
 	logg("Structured: Minimum Credit Card Number Count set to %u\n", (unsigned int) val32);
499 499
 
500
-	if((cpt = cfgopt(copt, "StructuredMinSSNCount"))->enabled) {
501
-	    val32 = cpt->numarg;
500
+	if((opt = optget(opts, "StructuredMinSSNCount"))->enabled) {
501
+	    val32 = opt->numarg;
502 502
 	    if((ret = cl_engine_set(engine, CL_ENGINE_MIN_SSN_COUNT, &val32))) {
503 503
 		logg("!cli_engine_set(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret));
504 504
 		cl_engine_free(engine);
... ...
@@ -508,14 +509,14 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
508 508
 	cl_engine_get(engine, CL_ENGINE_MIN_SSN_COUNT, &val32);
509 509
         logg("Structured: Minimum Social Security Number Count set to %u\n", (unsigned int) val32);
510 510
 
511
-        if(cfgopt(copt, "StructuredSSNFormatNormal")->enabled)
511
+        if(optget(opts, "StructuredSSNFormatNormal")->enabled)
512 512
             options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
513 513
 
514
-        if(cfgopt(copt, "StructuredSSNFormatStripped")->enabled)
514
+        if(optget(opts, "StructuredSSNFormatStripped")->enabled)
515 515
 	    options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
516 516
     }
517 517
 
518
-    selfchk = cfgopt(copt, "SelfCheck")->numarg;
518
+    selfchk = optget(opts, "SelfCheck")->numarg;
519 519
     if(!selfchk) {
520 520
 	logg("Self checking disabled.\n");
521 521
     } else {
... ...
@@ -524,14 +525,14 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
524 524
 
525 525
     /* save the PID */
526 526
     mainpid = getpid();
527
-    if((cpt = cfgopt(copt, "PidFile"))->enabled) {
527
+    if((opt = optget(opts, "PidFile"))->enabled) {
528 528
 	    FILE *fd;
529 529
 	old_umask = umask(0006);
530
-	if((fd = fopen(cpt->strarg, "w")) == NULL) {
531
-	    logg("!Can't save PID in file %s\n", cpt->strarg);
530
+	if((fd = fopen(opt->strarg, "w")) == NULL) {
531
+	    logg("!Can't save PID in file %s\n", opt->strarg);
532 532
 	} else {
533 533
 	    if (fprintf(fd, "%u", (unsigned int) mainpid)<0) {
534
-	    	logg("!Can't save PID in file %s\n", cpt->strarg);
534
+	    	logg("!Can't save PID in file %s\n", opt->strarg);
535 535
 	    }
536 536
 	    fclose(fd);
537 537
 	}
... ...
@@ -539,16 +540,16 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
539 539
     }
540 540
 
541 541
     logg("*Listening daemon: PID: %u\n", (unsigned int) mainpid);
542
-    max_threads = cfgopt(copt, "MaxThreads")->numarg;
542
+    max_threads = optget(opts, "MaxThreads")->numarg;
543 543
 
544
-    if(cfgopt(copt, "ClamukoScanOnAccess")->enabled)
544
+    if(optget(opts, "ClamukoScanOnAccess")->enabled)
545 545
 #ifdef CLAMUKO
546 546
     {
547 547
         do {
548 548
 	    if(pthread_attr_init(&clamuko_attr)) break;
549 549
 	    pthread_attr_setdetachstate(&clamuko_attr, PTHREAD_CREATE_JOINABLE);
550 550
 	    if(!(tharg = (struct thrarg *) malloc(sizeof(struct thrarg)))) break;
551
-	    tharg->copt = copt;
551
+	    tharg->opts = opts;
552 552
 	    tharg->engine = engine;
553 553
 	    tharg->options = options;
554 554
 	    if(!pthread_create(&clamuko_pid, &clamuko_attr, clamukoth, tharg)) break;
... ...
@@ -595,7 +596,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
595 595
     sigaction(SIGUSR2, &sigact, NULL);
596 596
 #endif
597 597
 
598
-    idletimeout = cfgopt(copt, "IdleTimeout")->numarg;
598
+    idletimeout = optget(opts, "IdleTimeout")->numarg;
599 599
 
600 600
     if((thr_pool=thrmgr_new(max_threads, idletimeout, scanner_thread)) == NULL) {
601 601
 	logg("!thrmgr_new failed\n");
... ...
@@ -653,8 +654,8 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
653 653
 		logg("SIGHUP caught: re-opening log file.\n");
654 654
 		logg_close();
655 655
 		sighup = 0;
656
-		if(!logg_file && (cpt = cfgopt(copt, "LogFile"))->enabled)
657
-		    logg_file = cpt->strarg;
656
+		if(!logg_file && (opt = optget(opts, "LogFile"))->enabled)
657
+		    logg_file = opt->strarg;
658 658
 	}
659 659
 
660 660
 	if (!progexit && new_sd >= 0) {
... ...
@@ -662,7 +663,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
662 662
 		if(client_conn) {
663 663
 		    client_conn->sd = new_sd;
664 664
 		    client_conn->options = options;
665
-		    client_conn->copt = copt;
665
+		    client_conn->opts = opts;
666 666
 		    if(cl_engine_addref(engine)) {
667 667
 			closesocket(client_conn->sd);
668 668
 			free(client_conn);
... ...
@@ -684,7 +685,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
684 684
 		} else {
685 685
 		    logg("!Can't allocate memory for client_conn\n");
686 686
 		    closesocket(new_sd);
687
-		    if(cfgopt(copt, "ExitOnOOM")->enabled) {
687
+		    if(optget(opts, "ExitOnOOM")->enabled) {
688 688
 			pthread_mutex_lock(&exit_mutex);
689 689
 			progexit = 1;
690 690
 			pthread_mutex_unlock(&exit_mutex);
... ...
@@ -708,7 +709,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
708 708
 	if(selfchk) {
709 709
 	    time(&current_time);
710 710
 	    if((current_time - start_time) > (time_t)selfchk) {
711
-		if(reload_db(engine, dboptions, copt, TRUE, &ret)) {
711
+		if(reload_db(engine, dboptions, opts, TRUE, &ret)) {
712 712
 		    pthread_mutex_lock(&reload_mutex);
713 713
 		    reload = 1;
714 714
 		    pthread_mutex_unlock(&reload_mutex);
... ...
@@ -720,7 +721,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
720 720
 	pthread_mutex_lock(&reload_mutex);
721 721
 	if(reload) {
722 722
 	    pthread_mutex_unlock(&reload_mutex);
723
-	    engine = reload_db(engine, dboptions, copt, FALSE, &ret);
723
+	    engine = reload_db(engine, dboptions, opts, FALSE, &ret);
724 724
 	    if(ret) {
725 725
 		logg("Terminating because of a fatal error.\n");
726 726
 #ifdef C_WINDOWS
... ...
@@ -737,7 +738,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
737 737
 	    time(&reloaded_time);
738 738
 	    pthread_mutex_unlock(&reload_mutex);
739 739
 #ifdef CLAMUKO
740
-	    if(cfgopt(copt, "ClamukoScanOnAccess")->enabled && tharg) {
740
+	    if(optget(opts, "ClamukoScanOnAccess")->enabled && tharg) {
741 741
 		logg("Stopping and restarting Clamuko.\n");
742 742
 		pthread_kill(clamuko_pid, SIGUSR1);
743 743
 		pthread_join(clamuko_pid, NULL);
... ...
@@ -755,7 +756,7 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
755 755
      */
756 756
     thrmgr_destroy(thr_pool);
757 757
 #ifdef CLAMUKO
758
-    if(cfgopt(copt, "ClamukoScanOnAccess")->enabled) {
758
+    if(optget(opts, "ClamukoScanOnAccess")->enabled) {
759 759
 	logg("Stopping Clamuko.\n");
760 760
 	pthread_kill(clamuko_pid, SIGUSR1);
761 761
 	pthread_join(clamuko_pid, NULL);
... ...
@@ -775,17 +776,17 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
775 775
     for (i = 0; i < nsockets; i++)
776 776
 	closesocket(socketds[i]);
777 777
 #ifndef C_OS2
778
-    if((cpt = cfgopt(copt, "LocalSocket"))->enabled) {
779
-	if(unlink(cpt->strarg) == -1)
780
-	    logg("!Can't unlink the socket file %s\n", cpt->strarg);
778
+    if((opt = optget(opts, "LocalSocket"))->enabled) {
779
+	if(unlink(opt->strarg) == -1)
780
+	    logg("!Can't unlink the socket file %s\n", opt->strarg);
781 781
 	else
782 782
 	     logg("Socket file removed.\n");
783 783
     }
784 784
 #endif
785 785
 
786
-    if((cpt = cfgopt(copt, "PidFile"))->enabled) {
787
-	if(unlink(cpt->strarg) == -1)
788
-	    logg("!Can't unlink the pid file %s\n", cpt->strarg);
786
+    if((opt = optget(opts, "PidFile"))->enabled) {
787
+	if(unlink(opt->strarg) == -1)
788
+	    logg("!Can't unlink the pid file %s\n", opt->strarg);
789 789
 	else
790 790
 	    logg("Pid file removed.\n");
791 791
     }
... ...
@@ -24,12 +24,12 @@
24 24
 #include <pthread.h>
25 25
 
26 26
 #include "libclamav/clamav.h"
27
-#include "shared/cfgparser.h"
27
+#include "shared/optparser.h"
28 28
 
29 29
 struct thrarg {
30 30
     int sid;
31 31
     int options;
32
-    const struct cfgstruct *copt;
32
+    const struct optstruct *opts;
33 33
     const struct cl_engine *engine;
34 34
     const struct cl_limits *limits;
35 35
 };
... ...
@@ -38,12 +38,12 @@ struct thrarg {
38 38
 struct thrwarg {
39 39
     int socketd;
40 40
     struct cl_engine **engine;
41
-    const struct cfgstruct *copt;
41
+    const struct optstruct *opts;
42 42
     const struct cl_limits *limits;
43 43
     unsigned int options;
44 44
 };
45 45
 
46
-int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigned int dboptions, const struct cfgstruct *copt);
46
+int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts);
47 47
 void sighandler(int sig);
48 48
 void sighandler_th(int sig);
49 49
 void sigsegv(int sig);
... ...
@@ -57,7 +57,7 @@
57 57
 #include "libclamav/str.h"
58 58
 #include "libclamav/others.h"
59 59
 
60
-#include "shared/cfgparser.h"
60
+#include "shared/optparser.h"
61 61
 #include "shared/output.h"
62 62
 #include "shared/misc.h"
63 63
 
... ...
@@ -68,7 +68,7 @@
68 68
 #include "thrmgr.h"
69 69
 
70 70
 #ifdef HAVE_FD_PASSING
71
-static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt)
71
+static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts)
72 72
 {
73 73
 	struct msghdr msg;
74 74
 	struct cmsghdr *cmsg;
... ...
@@ -99,7 +99,7 @@ static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned in
99 99
 		    cmsg->cmsg_level == SOL_SOCKET &&
100 100
 		    cmsg->cmsg_type == SCM_RIGHTS) {
101 101
 			int fd = *(int *)CMSG_DATA(cmsg);
102
-			ret = scanfd(fd, NULL, engine, options, copt, desc);
102
+			ret = scanfd(fd, NULL, engine, options, opts, desc);
103 103
 			close(fd);
104 104
 		}
105 105
 	}
... ...
@@ -107,14 +107,14 @@ static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned in
107 107
 }
108 108
 
109 109
 #else
110
-static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt)
110
+static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts)
111 111
 {
112 112
 	mdprintf(desc, "ERROR: FILDES support not compiled in\n");
113 113
 	return -1;
114 114
 }
115 115
 #endif
116 116
 
117
-int command(int desc, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int timeout)
117
+int command(int desc, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int timeout)
118 118
 {
119 119
 	char buff[1025];
120 120
 	int bread;
... ...
@@ -136,8 +136,8 @@ int command(int desc, const struct cl_engine *engine, unsigned int options, cons
136 136
 
137 137
     if(!strncmp(buff, CMD1, strlen(CMD1))) { /* SCAN */
138 138
 	thrmgr_setactivetask(NULL, CMD1);
139
-	if(scan(buff + strlen(CMD1) + 1, NULL, engine, options, copt, desc, TYPE_SCAN) == -2)
140
-	    if(cfgopt(copt, "ExitOnOOM")->enabled)
139
+	if(scan(buff + strlen(CMD1) + 1, NULL, engine, options, opts, desc, TYPE_SCAN) == -2)
140
+	    if(optget(opts, "ExitOnOOM")->enabled)
141 141
 		return COMMAND_SHUTDOWN;
142 142
 
143 143
     } else if(!strncmp(buff, CMD3, strlen(CMD3))) { /* QUIT */
... ...
@@ -159,8 +159,8 @@ int command(int desc, const struct cl_engine *engine, unsigned int options, cons
159 159
 
160 160
     } else if(!strncmp(buff, CMD6, strlen(CMD6))) { /* CONTSCAN */
161 161
 	thrmgr_setactivetask(NULL, CMD6);
162
-	if(scan(buff + strlen(CMD6) + 1, NULL, engine, options, copt, desc, TYPE_CONTSCAN) == -2)
163
-	    if(cfgopt(copt, "ExitOnOOM")->enabled)
162
+	if(scan(buff + strlen(CMD6) + 1, NULL, engine, options, opts, desc, TYPE_CONTSCAN) == -2)
163
+	    if(optget(opts, "ExitOnOOM")->enabled)
164 164
 		return COMMAND_SHUTDOWN;
165 165
 
166 166
     } else if(!strncmp(buff, CMD7, strlen(CMD7))) { /* VERSION */
... ...
@@ -180,8 +180,8 @@ int command(int desc, const struct cl_engine *engine, unsigned int options, cons
180 180
 
181 181
     } else if(!strncmp(buff, CMD8, strlen(CMD8))) { /* STREAM */
182 182
 	thrmgr_setactivetask(NULL, CMD8);
183
-	if(scanstream(desc, NULL, engine, options, copt) == CL_EMEM)
184
-	    if(cfgopt(copt, "ExitOnOOM")->enabled)
183
+	if(scanstream(desc, NULL, engine, options, opts) == CL_EMEM)
184
+	    if(optget(opts, "ExitOnOOM")->enabled)
185 185
 		return COMMAND_SHUTDOWN;
186 186
 
187 187
     } else if(!strncmp(buff, CMD9, strlen(CMD9))) { /* SESSION */
... ...
@@ -198,14 +198,14 @@ int command(int desc, const struct cl_engine *engine, unsigned int options, cons
198 198
 
199 199
     } else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MULTISCAN */
200 200
 	thrmgr_setactivetask(buff+strlen(CMD13)+1, CMD13);
201
-	if(scan(buff + strlen(CMD13) + 1, NULL, engine, options, copt, desc, TYPE_MULTISCAN) == -2)
202
-	    if(cfgopt(copt, "ExitOnOOM")->enabled)
201
+	if(scan(buff + strlen(CMD13) + 1, NULL, engine, options, opts, desc, TYPE_MULTISCAN) == -2)
202
+	    if(optget(opts, "ExitOnOOM")->enabled)
203 203
 		return COMMAND_SHUTDOWN;
204 204
 
205 205
     } else if(!strncmp(buff, CMD14, strlen(CMD14))) { /* FILDES */
206 206
 	thrmgr_setactivetask(NULL, CMD14);
207
-	if(recvfd_and_scan(desc, engine, options, copt) == -2)
208
-	    if(cfgopt(copt, "ExitOnOOM")->enabled)
207
+	if(recvfd_and_scan(desc, engine, options, opts) == -2)
208
+	    if(optget(opts, "ExitOnOOM")->enabled)
209 209
 		return COMMAND_SHUTDOWN;
210 210
     } else if(!strncmp(buff, CMD15, strlen(CMD15))) { /* STATS */
211 211
 	    thrmgr_setactivetask(NULL, CMD15);
... ...
@@ -41,8 +41,8 @@
41 41
 #define CMD15 "STATS"
42 42
 
43 43
 #include "libclamav/clamav.h"
44
-#include "shared/cfgparser.h"
44
+#include "shared/optparser.h"
45 45
 
46
-int command(int desc, const struct cl_engine *engine, unsigned int options, const struct cfgstruct *copt, int timeout);
46
+int command(int desc, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int timeout);
47 47
 
48 48
 #endif
... ...
@@ -42,8 +42,7 @@
42 42
 
43 43
 #include "libclamav/clamav.h"
44 44
 
45
-#include "shared/options.h"
46
-#include "shared/cfgparser.h"
45
+#include "shared/optparser.h"
47 46
 #include "shared/output.h"
48 47
 #include "shared/network.h"
49 48
 
... ...
@@ -55,20 +54,20 @@
55 55
 #define	closesocket(s)	close(s)
56 56
 #endif
57 57
 
58
-int tcpserver(const struct cfgstruct *copt)
58
+int tcpserver(const struct optstruct *opts)
59 59
 {
60 60
 	struct sockaddr_in server;
61 61
 	int sockfd, backlog;
62
-	const struct cfgstruct *taddr;
62
+	const struct optstruct *taddr;
63 63
 	struct hostent he;
64 64
 	char *estr, buf[1024];
65 65
 	int true = 1;
66 66
 
67 67
     memset((char *) &server, 0, sizeof(server));
68 68
     server.sin_family = AF_INET;
69
-    server.sin_port = htons(cfgopt(copt, "TCPSocket")->numarg);
69
+    server.sin_port = htons(optget(opts, "TCPSocket")->numarg);
70 70
 
71
-    if((taddr = cfgopt(copt, "TCPAddr"))->enabled) {
71
+    if((taddr = optget(opts, "TCPAddr"))->enabled) {
72 72
 	if(r_gethostbyname(taddr->strarg, &he, buf, sizeof(buf)) == -1) {
73 73
 	    logg("!TCP: r_gethostbyname(%s) error: %s\n", taddr->strarg, strerror(errno));
74 74
 	    return -1;
... ...
@@ -95,12 +94,12 @@ int tcpserver(const struct cfgstruct *copt)
95 95
 	return -1;
96 96
     } else {
97 97
 	if(taddr->enabled)
98
-	    logg("#TCP: Bound to address %s on port %u\n", taddr->strarg, cfgopt(copt, "TCPSocket")->numarg);
98
+	    logg("#TCP: Bound to address %s on port %u\n", taddr->strarg, optget(opts, "TCPSocket")->numarg);
99 99
 	else
100
-	    logg("#TCP: Bound to port %u\n", cfgopt(copt, "TCPSocket")->numarg);
100
+	    logg("#TCP: Bound to port %u\n", optget(opts, "TCPSocket")->numarg);
101 101
     }
102 102
 
103
-    backlog = cfgopt(copt, "MaxConnectionQueueLength")->numarg;
103
+    backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
104 104
     logg("#TCP: Setting connection queue length to %d\n", backlog);
105 105
 
106 106
     if(listen(sockfd, backlog) == -1) {
... ...
@@ -19,8 +19,8 @@
19 19
 #ifndef __TCPSERVER_H
20 20
 #define __TCPSERVER_H
21 21
 
22
-#include "shared/cfgparser.h"
22
+#include "shared/optparser.h"
23 23
 
24
-int tcpserver(const struct cfgstruct *copt);
24
+int tcpserver(const struct optstruct *opts);
25 25
 
26 26
 #endif
... ...
@@ -36,7 +36,7 @@
36 36
 #include <ctype.h>
37 37
 #include <errno.h>
38 38
 
39
-#include "shared/cfgparser.h"
39
+/* #include "shared/cfgparser.h" */
40 40
 #include "shared/output.h"
41 41
 
42 42
 #include "libclamav/clamav.h"
... ...
@@ -66,15 +66,18 @@ const char *get_version(void)
66 66
 #ifndef CL_NOLIBCLAMAV
67 67
 char *freshdbdir(void)
68 68
 {
69
+/* FIXME
69 70
 	struct cl_cvd *d1, *d2;
70 71
 	struct cfgstruct *copt;
71 72
 	const struct cfgstruct *cpt;
73
+*/
72 74
 	const char *dbdir;
73 75
 	char *retdir;
74 76
 
75 77
 
76 78
     /* try to find fresh directory */
77 79
     dbdir = cl_retdbdir();
80
+    /*
78 81
     if((copt = getcfg(CONFDIR"/freshclam.conf", 0, OPT_FRESHCLAM))) {
79 82
 	if((cpt = cfgopt(copt, "DatabaseDirectory"))->enabled || (cpt = cfgopt(copt, "DataDirectory"))->enabled) {
80 83
 	    if(strcmp(dbdir, cpt->strarg)) {
... ...
@@ -104,11 +107,14 @@ char *freshdbdir(void)
104 104
 	    }
105 105
 	}
106 106
     }
107
+    */
107 108
 
108 109
     retdir = strdup(dbdir);
109 110
 
111
+/*
110 112
     if(copt)
111 113
 	freecfg(copt);
114
+*/
112 115
 
113 116
     return retdir;
114 117
 }
... ...
@@ -30,8 +30,6 @@
30 30
 # endif
31 31
 #endif
32 32
 
33
-#include "cfgparser.h"
34
-
35 33
 char *freshdbdir(void);
36 34
 void print_version(const char *dbdir);
37 35
 int filecopy(const char *src, const char *dest);
38 36
new file mode 100644
... ...
@@ -0,0 +1,814 @@
0
+/*
1
+ *  Copyright (C) 2008 Sourcefire, Inc.
2
+ *
3
+ *  Author: Tomasz Kojm <tkojm@clamav.net>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+/*
21
+ * TODO:
22
+ * - freshclam, clamscan, clamdscan, clamconf, milter
23
+ * - clamconf: generation/verification/updating of config files and man page entries
24
+ * - automatically generate --help pages (use the first line from the description)
25
+ */
26
+
27
+#if HAVE_CONFIG_H
28
+#include "clamav-config.h"
29
+#endif
30
+
31
+#include <stdio.h>
32
+#include <stdlib.h>
33
+#include <string.h>
34
+#ifdef HAVE_STRINGS_H
35
+#include <strings.h>
36
+#endif
37
+#include <ctype.h>
38
+
39
+#include "shared/optparser.h"
40
+#include "shared/misc.h"
41
+
42
+#include "libclamav/regex/regex.h"
43
+
44
+#include "getopt.h"
45
+
46
+#define MAXCMDOPTS  64
47
+#define MAX(a,b) (a > b ? a : b)
48
+
49
+#define MATCH_NUMBER "^[0-9]+$"
50
+#define MATCH_SIZE "^[0-9]+[kKmM]?$"
51
+#define MATCH_BOOL "^(yes|true|1|no|false|0)$"
52
+
53
+static const struct clam_option {
54
+    const char *name;
55
+    const char *longopt;
56
+    char shortopt;
57
+    unsigned short argtype;
58
+    const char *regex;
59
+    int numarg;
60
+    const char *strarg;
61
+    short multiple;
62
+    unsigned short owner;
63
+    const char *description;
64
+    const char *suggested;
65
+} clam_options[] = {
66
+    /* name,   longopt, sopt, argtype, regex, num, str, mul, owner, description, suggested */
67
+
68
+    { NULL, "help", 'h', OPT_BOOL, NULL, 0, NULL, 0, OPT_CLAMD, "", "" },
69
+    { NULL, "config-file", 'c', OPT_STRING, NULL, 0, CONFDIR"/clamd.conf", 0, OPT_CLAMD, "", "" },
70
+    { NULL, "version", 'V', OPT_BOOL, NULL, 0, NULL, 0, OPT_CLAMD, "", "" },
71
+    { NULL, "debug", 0, OPT_BOOL, NULL, 0, NULL, 0, OPT_CLAMD, "", "" },
72
+
73
+    { "LogFile", "log", 'l', OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Save all reports to a log file.", "/tmp/clamav.log" },
74
+
75
+    { "LogFileUnlock", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_MILTER, "By default the log file is locked for writing and only a single\ndaemon process can write to it. This option disables the lock.", "no" },
76
+
77
+    { "LogFileMaxSize", NULL, 0, OPT_SIZE, MATCH_SIZE, 1048576, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Maximum size of the log file.\nValue of 0 disables the limit.", "5M" },
78
+
79
+    { "LogTime", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Log time with each message.", "yes" },
80
+
81
+    { "LogClean", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Log all clean files.\nUseful in debugging but drastically increases the log size.", "no" },
82
+
83
+    { "LogVerbose", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Enable verbose logging.", "no" },
84
+
85
+    { "LogSyslog", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Use the system logger (can work together with LogFile).", "yes" },
86
+
87
+    { "LogFacility", NULL, 0, OPT_STRING, NULL, -1, "LOG_LOCAL6", 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Type of syslog messages.\nPlease refer to 'man syslog' for the facility names.", "LOG_MAIL" },
88
+
89
+    { "PidFile", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Save the process ID to a file.", "/var/run/clamd.pid" },
90
+
91
+    { "TemporaryDirectory", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "This option allows you to change the default temporary directory.", "/tmp" },
92
+
93
+    { "DatabaseDirectory", NULL, 0, OPT_STRING, NULL, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM, "This option allows you to change the default database directory.\nIf you enable it, please make sure it points to the same directory in\nboth clamd and freshclam.", "/var/lib/clamav" },
94
+
95
+    { "LocalSocket", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Path to a local socket file the daemon will listen on.", "/tmp/clamd.socket" },
96
+
97
+    { "FixStaleSocket", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Remove a stale socket after unclean shutdown", "yes" },
98
+
99
+    { "TCPSocket", NULL, 0, OPT_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_CLAMD, "A TCP port number the daemon will listen on.", "3310" },
100
+
101
+    /* FIXME: add a regex for IP addr */
102
+    { "TCPAddr", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "By default clamd binds to INADDR_ANY.\nThis option allows you to restrict the TCP address and provide\nsome degree of protection from the outside world.", "3310" },
103
+
104
+    { "MaxConnectionQueueLength", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 15, NULL, 0, OPT_CLAMD, "Maximum length the queue of pending connections may grow to.", "30" },
105
+
106
+    { "StreamMaxLength", NULL, 0, OPT_SIZE, MATCH_SIZE, 10485760, NULL, 0, OPT_CLAMD, "Close the STREAM session when the data size limit is exceeded.\nThe value should match your MTA's limit for the maximum attachment size.", "25M" },
107
+
108
+    { "StreamMinPort", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 1024, NULL, 0, OPT_CLAMD, "The STREAM command uses an FTP-like protocol.\nThis option sets the lower boundary for the port range.", "1024" },
109
+
110
+    { "StreamMaxPort", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 2048, NULL, 0, OPT_CLAMD, "This option sets the upper boundary for the port range.", "2048" },
111
+
112
+    { "MaxThreads", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 10, NULL, 0, OPT_CLAMD | OPT_MILTER, "Maximum number of threads running at the same time.", "20" },
113
+
114
+    { "ReadTimeout", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 120, NULL, 0, OPT_CLAMD | OPT_MILTER, "This option specifies the time (in seconds) after which clamd should\ntimeout if a client doesn't provide any data.", "120" },
115
+
116
+    { "IdleTimeout", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 30, NULL, 0, OPT_CLAMD, "This option specifies how long (in seconds) the process should wait for a new job.", "60" },
117
+
118
+    { "ExcludePath", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_CLAMD, "Don't scan files/directories whose names match the provided\nregular expression. This option can be specified multiple times.", "^/proc/" },
119
+
120
+    { "MaxDirectoryRecursion", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 15, NULL, 0, OPT_CLAMD, "Maximum depth the directories are scanned at.", "15" },
121
+
122
+    { "FollowDirectorySymlinks", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Follow directory symlinks.", "no" },
123
+
124
+    { "FollowFileSymlinks", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Follow symlinks to regular files.", "no" },
125
+
126
+    { "SelfCheck", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 600, NULL, 0, OPT_CLAMD, "This option specifies the time intervals (in seconds) in which clamd\nshould perform a database check.", "600" },
127
+
128
+    { "VirusEvent", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Execute a command when a virus is found. In the command string %v will be\nreplaced with the virus name. Additionally, two environment variables will\nbe defined: $CLAM_VIRUSEVENT_FILENAME and $CLAM_VIRUSEVENT_VIRUSNAME.", "/usr/bin/mailx -s \"ClamAV VIRUS ALERT: %v\" alert < /dev/null" },
129
+
130
+    { "ExitOnOOM", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Stop the daemon when libclamav reports an out of memory condition.", "yes" },
131
+
132
+    { "Foreground", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Don't fork into background.", "no" },
133
+
134
+    { "Debug", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM, "Enable debug messages in libclamav.", "no" },
135
+
136
+    { "LeaveTemporaryFiles", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Don't remove temporary files (for debugging purposes).", "no" },
137
+
138
+    { "User", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Run the daemon as a specified user (the process must be started by root).", "clamav" },
139
+
140
+    { "AllowSupplementaryGroups", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Initialize a supplementary group access (the process must be started by root).", "no" },
141
+
142
+    /* Scan options */
143
+
144
+    { "DetectPUA", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Detect Potentially Unwanted Applications.", "yes" },
145
+
146
+    { "ExcludePUA", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_CLAMD, "Exclude a specific PUA category. This directive can be used multiple times.\nSee http://www.clamav.net/support/pua for the complete list of PUA\ncategories.", "NetTool" },
147
+
148
+    { "IncludePUA", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_CLAMD, "Only include a specific PUA category. This directive can be used multiple\ntimes.", "Spy" },
149
+
150
+    { "AlgorithmicDetection", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "In some cases (eg. complex malware, exploits in graphic files, and others),\nClamAV uses special algorithms to provide accurate detection. This option\ncontrols the algorithmic detection.", "yes" },
151
+
152
+    { "ScanPE", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "PE stands for Portable Executable - it's an executable file format used\nin all 32- and 64-bit versions of Windows operating systems. This option\nallows ClamAV to perform a deeper analysis of executable files and it's also\nrequired for decompression of popular executable packers such as UPX or FSG.", "yes" },
153
+
154
+    { "ScanELF", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "Executable and Linking Format is a standard format for UN*X executables.\nThis option allows you to control the scanning of ELF files.", "yes" },
155
+
156
+    { "DetectBrokenExecutables", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "With this option enabled clamav will try to detect broken executables\n(both PE and ELF) and mark them as Broken.Executable.", "yes" },
157
+
158
+    { "ScanMail", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "Enable the built in email scanner.", "yes" },
159
+
160
+    { "MailFollowURLs", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "If an email contains URLs ClamAV can download and scan them.\nWARNING: This option may open your system to a DoS attack. Please don't use\nthis feature on highly loaded servers.", "no" },
161
+
162
+    { "ScanPartialMessages", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Scan RFC1341 messages split over many emails. You will need to\nperiodically clean up $TemporaryDirectory/clamav-partial directory.\nWARNING: This option may open your system to a DoS attack. Please don't use\nthis feature on highly loaded servers.", "no" },
163
+
164
+    { "PhishingSignatures", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "With this option enabled ClamAV will try to detect phishing attempts by using\nsignatures.", "yes" },
165
+
166
+    { "PhishingScanURLs", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "Scan URLs found in mails for phishing attempts using heuristics.", "yes" },
167
+
168
+    { "PhishingAlwaysBlockCloak", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Always block cloaked URLs, even if they're not in the database.\nThis feature can lead to false positives.", "no" },
169
+
170
+    { "PhishingAlwaysBlockSSLMismatch", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Always block SSL mismatches in URLs, even if they're not in the database.\nThis feature can lead to false positives.", "" },
171
+
172
+    { "HeuristicScanPrecedence", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Allow heuristic match to take precedence.\nWhen enabled, if a heuristic scan (such as phishingScan) detects\na possible virus/phish it will stop scan immediately. Recommended, saves CPU\nscan-time.\nWhen disabled, virus/phish detected by heuristic scans will be reported only\nat the end of a scan. If an archive contains both a heuristically detected\nvirus/phish, and a real malware, the real malware will be reported.\nKeep this disabled if you intend to handle \"*.Heuristics.*\" viruses\ndifferently from \"real\" malware.\nIf a non-heuristically-detected virus (signature-based) is found first,\nthe scan is interrupted immediately, regardless of this config option.", "yes" },
173
+
174
+    { "StructuredDataDetection", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Enable the Data Loss Prevention module.", "no" },
175
+
176
+    { "StructuredMinCreditCardCount", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 3, NULL, 0, OPT_CLAMD, "This option sets the lowest number of Credit Card numbers found in a file\nto generate a detect.", "5" },
177
+
178
+    { "StructuredMinSSNCount", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 3, NULL, 0, OPT_CLAMD, "This option sets the lowest number of Social Security Numbers found\nin a file to generate a detect.", "5" },
179
+
180
+    { "StructuredSSNFormatNormal", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "With this option enabled the DLP module will search for valid\nSSNs formatted as xxx-yy-zzzz.", "yes" },
181
+
182
+    { "StructuredSSNFormatStripped", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "With this option enabled the DLP module will search for valid\nSSNs formatted as xxxyyzzzz", "no" },
183
+
184
+    { "ScanHTML", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "Perform HTML/JavaScript/ScriptEncoder normalisation and decryption.", "yes" },
185
+
186
+    { "ScanOLE2", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "This option enables scanning of OLE2 files, such as Microsoft Office\ndocuments and .msi files.", "yes" },
187
+
188
+    { "ScanPDF", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "This option enables scanning within PDF files.", "yes" },
189
+
190
+    { "ScanArchive", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD, "Scan within archives and compressed files.", "yes" },
191
+
192
+    { "ArchiveBlockEncrypted", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR).", "no" },
193
+
194
+    { "MaxScanSize", NULL, 0, OPT_SIZE, MATCH_SIZE, -1, NULL, 0, OPT_CLAMD, "This option sets the maximum amount of data to be scanned for each input file.\nArchives and other containers are recursively extracted and scanned up to this\nvalue.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe damage.", "100M" },
195
+
196
+    { "MaxFileSize", NULL, 0, OPT_SIZE, MATCH_SIZE, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Files larger than this limit won't be scanned. Affects the input file itself\nas well as files contained inside it (when the input file is an archive, a\ndocument or some other kind of container).\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe damage to the system.", "25M" },
197
+
198
+    { "MaxRecursion", NULL, 0, OPT_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_CLAMD, "Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR\nfile, all files within it will also be scanned. This option specifies how\ndeeply the process should be continued.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe damage to the system.", "16" },
199
+
200
+    { "MaxFiles", NULL, 0, OPT_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_CLAMD, "Number of files to be scanned within an archive, a document, or any other\ncontainer file.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe damage to the system.", "10000" },
201
+
202
+    { "ClamukoScanOnAccess", NULL, 0, OPT_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "This option enables Clamuko. Dazuko needs to be already configured and\nrunning.", "no" },
203
+
204
+    { "ClamukoScanOnOpen", NULL, 0, OPT_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "Scan files when they get opened by the system.", "yes" },
205
+
206
+    { "ClamukoScanOnClose", NULL, 0, OPT_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "Scan files when they get closed by the system.", "yes" },
207
+
208
+    { "ClamukoScanOnExec", NULL, 0, OPT_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "Scan files when they get executed by the system.", "yes" },
209
+
210
+    { "ClamukoIncludePath", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_CLAMD, "This option specifies a directory (together will all files and directories\ninside this directory) which should be scanned on-access. This option can\nbe used multiple times.", "/home" },
211
+
212
+    { "ClamukoExcludePath", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_CLAMD, "This option allows excluding directories from on-access scanning. It can be used multiple times.", "/home/bofh" },
213
+
214
+    { "ClamukoMaxFileSize", NULL, 0, OPT_SIZE, MATCH_SIZE, 5242880, NULL, 0, OPT_CLAMD, "Files larger than this value will not be scanned.", "5M" },
215
+
216
+    /* FIXME: mark these as private and don't output into clamd.conf/man */
217
+    { "DevACOnly", NULL, 0, OPT_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "", "" },
218
+
219
+    { "DevACDepth", NULL, 0, OPT_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_CLAMD, "", "" },
220
+
221
+    /* Freshclam-only entries */
222
+
223
+    /* FIXME: drop this entry and use LogFile */
224
+    { "UpdateLogFile", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "Save all reports to a log file.", "/var/log/freshclam.log" },
225
+
226
+    { "DatabaseOwner", NULL, 0, OPT_STRING, NULL, -1, CLAMAVUSER, 0, OPT_FRESHCLAM, "When started by root freshclam will drop privileges and switch to the user\ndefined in this option.", CLAMAVUSER },
227
+
228
+    { "Checks", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 12, NULL, 0, OPT_FRESHCLAM, "This option defined how many times daily freshclam should check for\na database update.", "24" },
229
+
230
+    { "DNSDatabaseInfo", NULL, 0, OPT_STRING, NULL, -1, "current.cvd.clamav.net", 0, OPT_FRESHCLAM, "Use DNS to verify the virus database version. Freshclam uses DNS TXT records\nto verify the versions of the database and software itself. With this\ndirective you can change the database verification domain.\nWARNING: Please don't change it unless you're configuring freshclam to use\nyour own database verification domain.", "current.cvd.clamav.net" },
231
+
232
+    /* FIXME: - add an inactive entry for db.XY.clamav.net for freshclam.conf
233
+     * purposes
234
+     * - 
235
+     */
236
+    { "DatabaseMirror", NULL, 0, OPT_STRING, NULL, -1, NULL, 1, OPT_FRESHCLAM, "FIXME", "" },
237
+
238
+    { "MaxAttempts", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 3, NULL, 0, OPT_FRESHCLAM, "This option defines how many attempts freshclam should make before giving up.", "5" },
239
+
240
+    { "ScriptedUpdates", NULL, 0, OPT_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_FRESHCLAM, "With this option you can control scripted updates. It's highly recommended to keep them enabled.", "yes" },
241
+
242
+    { "CompressLocalDatabase", NULL, 0, OPT_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM, "By default freshclam will keep the local databases (.cld) uncompressed to\nmake their handling faster. With this option you can enable the compression.\nThe change will take effect with the next database update.", "" },
243
+
244
+    { "HTTPProxyServer", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "If you're behind a proxy, please enter its address here.", "your-proxy" },
245
+
246
+    { "HTTPProxyPort", NULL, 0, OPT_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_FRESHCLAM, "HTTP proxy's port", "8080" },
247
+
248
+    { "HTTPProxyUsername", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "A user name for the HTTP proxy authentication.", "username" },
249
+
250
+    { "HTTPProxyPassword", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "A password for the HTTP proxy authentication.", "pass" },
251
+
252
+    { "HTTPUserAgent", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "If your servers are behind a firewall/proxy which does a User-Agent\nfiltering you can use this option to force the use of a different\nUser-Agent header.", "default" },
253
+
254
+    { "NotifyClamd", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "Send the RELOAD command to clamd after a successful update.", "yes" },
255
+
256
+    { "OnUpdateExecute", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "Run a command after a successful database update.", "command" },
257
+
258
+    { "OnErrorExecute", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "Run a command when a database update error occurs.", "command" },
259
+
260
+    { "OnOutdatedExecute", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "Run a command when freshclam reports an outdated version.\nIn the command string %v will be replaced with the new version number.", "command" },
261
+
262
+    /* FIXME: MATCH_IPADDR */
263
+    { "LocalIPAddress", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "With this option you can provide a client address for the database downlading.\nUseful for multi-homed systems.", "aaa.bbb.ccc.ddd" },
264
+
265
+    { "ConnectTimeout", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 30, NULL, 0, OPT_FRESHCLAM, "Timeout in seconds when connecting to database server.", "30" },
266
+
267
+    { "ReceiveTimeout", NULL, 0, OPT_NUMBER, MATCH_NUMBER, 30, NULL, 0, OPT_FRESHCLAM, "Timeout in seconds when reading from database server.", "30" },
268
+
269
+    { "SubmitDetectionStats", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "", "" },
270
+
271
+    { "DetectionStatsCountry", NULL, 0, OPT_STRING, NULL, -1, NULL, 0, OPT_FRESHCLAM, "When enabled freshclam will submit statistics to the ClamAV Project about\nthe latest virus detections in your environment. The ClamAV maintainers\nwill then use this data to determine what types of malware are the most\ndetected in the field and in what geographic area they are.\nThis feature requires LogTime and LogFile to be enabled in clamd.conf.", "/path/to/clamd.conf" },
272
+
273
+    /* Deprecated options */
274
+
275
+    { "MailMaxRecursion", NULL, 0, OPT_NUMBER, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
276
+    { "ArchiveMaxScanSize", NULL, 0, OPT_SIZE, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
277
+    { "ArchiveMaxRecursion", NULL, 0, OPT_NUMBER, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
278
+    { "ArchiveMaxFiles", NULL, 0, OPT_NUMBER, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
279
+    { "ArchiveMaxCompressionRatio", NULL, 0, OPT_NUMBER, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
280
+    { "ArchiveBlockMax", NULL, 0, OPT_BOOL, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
281
+    { "ArchiveLimitMemoryUsage", NULL, 0, OPT_BOOL, NULL, -1, NULL, 0, OPT_CLAMD | OPT_DEPRECATED, "", "" },
282
+
283
+    /* Milter specific options */
284
+/*
285
+    {"ClamdSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
286
+    {"MilterSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
287
+    {"LocalNet", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
288
+    {"OnClean", OPT_QUOTESTR, -1, "Accept", 0, OPT_MILTER},
289
+    {"OnInfected", OPT_QUOTESTR, -1, "Quarantine", 0, OPT_MILTER},
290
+    {"OnFail", OPT_QUOTESTR, -1, "Defer", 0, OPT_MILTER},
291
+    {"AddHeader", OPT_BOOL, 0, NULL, 0, OPT_MILTER},
292
+    {"Chroot", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER},
293
+    {"Whitelist", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER},
294
+*/
295
+    /* Deprecated milter options */
296
+/*
297
+    {"ArchiveBlockEncrypted", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
298
+    {"DatabaseDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
299
+    {"Debug", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
300
+    {"DetectBrokenExecutables", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
301
+    {"LeaveTemporaryFiles", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
302
+    {"LocalSocket", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
303
+    {"MailFollowURLs", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
304
+    {"MaxScanSize", OPT_COMPSIZE, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
305
+    {"MaxFiles", OPT_NUM, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
306
+    {"MaxRecursion", OPT_NUM, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
307
+    {"PhishingSignatures", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
308
+    {"ScanArchive", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
309
+    {"ScanHTML", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
310
+    {"ScanMail", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
311
+    {"ScanOLE2", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
312
+    {"ScanPE", OPT_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
313
+    {"StreamMaxLength", OPT_COMPSIZE, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
314
+    {"TCPAddr", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
315
+    {"TCPSocket", OPT_NUM, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
316
+    {"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
317
+*/
318
+    { NULL, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL, NULL }
319
+};
320
+
321
+const struct optstruct *optget(const struct optstruct *opts, const char *name)
322
+{
323
+    while(opts) {
324
+	if((opts->name && (!strcmp(opts->name, name)) || (opts->cmd && !strcmp(opts->cmd, name))))
325
+	    return opts;
326
+	opts = opts->next;
327
+    }
328
+    return NULL;
329
+}
330
+
331
+static struct optstruct *optget_i(struct optstruct *opts, const char *name)
332
+{
333
+    while(opts) {
334
+	if((opts->name && (!strcmp(opts->name, name)) || (opts->cmd && !strcmp(opts->cmd, name))))
335
+	    return opts;
336
+	opts = opts->next;
337
+    }
338
+    return NULL;
339
+}
340
+
341
+/*
342
+static void optprint(const struct optstruct *opts)
343
+{
344
+	const struct optstruct *h;
345
+
346
+    printf("\nOPTIONS:\n\n");
347
+
348
+    while(opts) {
349
+	printf("OPT_NAME: %s\n", opts->name);
350
+	printf("OPT_CMD: %s\n", opts->cmd);
351
+	printf("OPT_STRARG: %s\n", opts->strarg ? opts->strarg : "NONE");
352
+	printf("OPT_NUMARG: %d\n", opts->numarg);
353
+	h = opts;
354
+	while((h = h->nextarg)) {
355
+	    printf("SUBARG_OPT_STRARG: %s\n", h->strarg ? h->strarg : "NONE");
356
+	    printf("SUBARG_OPT_NUMARG: %d\n", h->numarg);
357
+	}
358
+	printf("----------------\n");
359
+	opts = opts->next;
360
+    }
361
+}
362
+*/
363
+
364
+static int optadd(struct optstruct **opts, const char *name, const char *cmd, const char *strarg, int numarg, int multiple, int idx)
365
+{
366
+	struct optstruct *newnode;
367
+
368
+
369
+    newnode = (struct optstruct *) malloc(sizeof(struct optstruct));
370
+
371
+    if(!newnode)
372
+	return -1;
373
+
374
+    if(name) {
375
+	newnode->name = strdup(name);
376
+	if(!newnode->name) {
377
+	    free(newnode);
378
+	    return -1;
379
+	}
380
+    } else {
381
+	newnode->name = NULL;
382
+    }
383
+
384
+    if(cmd) {
385
+	newnode->cmd = strdup(cmd);
386
+	if(!newnode->cmd) {
387
+	    free(newnode->name);
388
+	    free(newnode);
389
+	    return -1;
390
+	}
391
+    } else {
392
+	newnode->cmd = NULL;
393
+    }
394
+
395
+    if(strarg) {
396
+	newnode->strarg = strdup(strarg);
397
+	if(!newnode->strarg) {
398
+	    free(newnode->cmd);
399
+	    free(newnode->name);
400
+	    free(newnode);
401
+	    return -1;
402
+	}
403
+	newnode->enabled = 1;
404
+    } else {
405
+	newnode->strarg = NULL;
406
+	newnode->enabled = 0;
407
+    }
408
+    newnode->numarg = numarg;
409
+    if(numarg && numarg != -1)
410
+	newnode->enabled = 1;
411
+    newnode->nextarg = NULL;
412
+    newnode->next = NULL;
413
+    newnode->active = 0;
414
+    newnode->multiple = multiple;
415
+    newnode->idx = idx;
416
+
417
+    newnode->next = *opts;
418
+    *opts = newnode;
419
+    return 0;
420
+}
421
+
422
+static int optaddarg(struct optstruct *opts, const char *name, const char *strarg, int numarg)
423
+{
424
+	struct optstruct *pt, *h, *new;
425
+
426
+
427
+    if(!(pt = optget_i(opts, name))) {
428
+	fprintf(stderr, "ERROR: optaddarg: Unregistered option %s\n", name);
429
+	return -1;
430
+    }
431
+
432
+    if(pt->multiple) {
433
+	if(!pt->active) {
434
+	    if(strarg) {
435
+		pt->strarg = strdup(strarg);
436
+	 	if(!pt->strarg) {
437
+		    fprintf(stderr, "ERROR: optaddarg: strdup() failed\n");
438
+		    return -1;
439
+		}
440
+	    }
441
+	    pt->numarg = numarg;
442
+	} else {
443
+	    new = (struct optstruct *) calloc(1, sizeof(struct optstruct));
444
+	    if(!new) {
445
+		fprintf(stderr, "ERROR: optaddarg: malloc() failed\n");
446
+		return -1;
447
+	    }
448
+	    if(strarg) {
449
+		new->strarg = strdup(strarg);
450
+	 	if(!new->strarg) {
451
+		    fprintf(stderr, "ERROR: optaddarg: strdup() failed\n");
452
+		    free(new);
453
+		    return -1;
454
+		}
455
+	    }
456
+	    new->numarg = numarg;
457
+	    h = pt;
458
+	    while(h->nextarg)
459
+		h = h->nextarg;
460
+	    h->nextarg = new;
461
+	}
462
+    } else {
463
+	if(strarg) {
464
+	    pt->strarg = strdup(strarg);
465
+	    if(!pt->strarg) {
466
+		fprintf(stderr, "ERROR: optaddarg: strdup() failed\n");
467
+		return -1;
468
+	    }
469
+	}
470
+	pt->numarg = numarg;
471
+    }
472
+
473
+    pt->active = 1;
474
+    if(pt->strarg || (pt->numarg && pt->numarg != -1))
475
+	pt->enabled = 1;
476
+
477
+    return 0;
478
+}
479
+
480
+void optfree(struct optstruct *opts)
481
+{
482
+    	struct optstruct *h, *a;
483
+
484
+    while(opts) {
485
+	a = opts->nextarg;
486
+	while(a) {
487
+	    if(a->strarg) {
488
+		free(a->name);
489
+		free(a->cmd);
490
+		free(a->strarg);
491
+		h = a;
492
+		a = a->nextarg;
493
+		free(h);
494
+	    } else {
495
+		a = a->nextarg;
496
+	    }
497
+	}
498
+	free(opts->name);
499
+	free(opts->cmd);
500
+	free(opts->strarg);
501
+	h = opts;
502
+	opts = opts->next;
503
+	free(h);
504
+    }
505
+    return;
506
+}
507
+
508
+struct optstruct *optparse(const char *cfgfile, int argc, char * const *argv, int verbose, int toolmask, struct optstruct *oldopts)
509
+{
510
+	FILE *fs = NULL;
511
+	const struct clam_option *optentry;
512
+	char *pt;
513
+	const char *name = NULL, *arg;
514
+	int i, err = 0, lc = 0, sc = 0, opt_index, line = 0, ret, numarg;
515
+	struct optstruct *opts = NULL, *opt;
516
+	char buff[512];
517
+	struct option longopts[MAXCMDOPTS];
518
+	char shortopts[MAXCMDOPTS];
519
+	regex_t regex;
520
+
521
+
522
+    if(oldopts)
523
+	opts = oldopts;
524
+
525
+    shortopts[sc++] = ':';
526
+    for(i = 0; ; i++) {
527
+	optentry = &clam_options[i];
528
+	if(!optentry->name && !optentry->longopt)
529
+	    break;
530
+
531
+	if(optentry->owner & toolmask) {
532
+	    if(!oldopts && optadd(&opts, optentry->name, optentry->longopt, optentry->strarg, optentry->numarg, optentry->multiple, i) < 0) {
533
+		fprintf(stderr, "ERROR: optparse: Can't register new option (not enough memory)\n");
534
+		optfree(opts);
535
+		return NULL;
536
+	    }
537
+
538
+	    if(!cfgfile) {
539
+		if(optentry->longopt) {
540
+		    if(lc >= MAXCMDOPTS) {
541
+			fprintf(stderr, "ERROR: optparse: longopts[] is too small\n");
542
+			optfree(opts);
543
+			return NULL;
544
+		    }
545
+		    longopts[lc].name = optentry->longopt;
546
+		    if(optentry->argtype == OPT_BOOL)
547
+			longopts[lc].has_arg = 2;
548
+		    else
549
+			longopts[lc].has_arg = 1;
550
+		    longopts[lc].flag = NULL;
551
+		    longopts[lc++].val = optentry->shortopt;
552
+		}
553
+		if(optentry->shortopt) {
554
+		    if(sc + 1 >= MAXCMDOPTS) {
555
+			fprintf(stderr, "ERROR: optparse: shortopts[] is too small\n");
556
+			optfree(opts);
557
+			return NULL;
558
+		    }
559
+		    shortopts[sc++] = optentry->shortopt;
560
+		    /* FIXME: we may need to handle optional args for short
561
+		     * BOOL opts
562
+		     */
563
+		    if(optentry->argtype != OPT_BOOL)
564
+			shortopts[sc++] = ':';
565
+		}
566
+	    }
567
+	}
568
+    }
569
+
570
+    if(cfgfile) {
571
+	if((fs = fopen(cfgfile, "rb")) == NULL) {
572
+	    /* don't print error messages here! */
573
+	    optfree(opts);
574
+	    return NULL;
575
+	}
576
+    } else {
577
+	if(MAX(sc, lc) > MAXCMDOPTS) {
578
+	    fprintf(stderr, "ERROR: optparse: (short|long)opts[] is too small\n");
579
+	    optfree(opts);
580
+	    return NULL;
581
+	}
582
+	shortopts[sc] = 0;
583
+	longopts[lc].name = NULL;
584
+	longopts[lc].flag = NULL;
585
+	longopts[lc].has_arg = longopts[lc].val = 0;
586
+    }
587
+
588
+    while(1) {
589
+
590
+	if(cfgfile) {
591
+	    if(!fgets(buff, sizeof(buff), fs))
592
+		break;
593
+
594
+	    line++;
595
+	    if(strlen(buff) <= 2 || buff[0] == '#')
596
+		continue;
597
+
598
+	    if(!strncmp("Example", buff, 7)) {
599
+		if(verbose)
600
+		    fprintf(stderr, "ERROR: Please edit the example config file %s\n", cfgfile);
601
+		err = 1;
602
+		break;
603
+	    }
604
+
605
+	    if(!(pt = strchr(buff, ' '))) {
606
+		if(verbose)
607
+		    fprintf(stderr, "ERROR: Missing argument for option at line %d\n", line);
608
+		err = 1;
609
+		break;
610
+	    }
611
+	    name = buff;
612
+	    *pt++ = 0;
613
+	    for(i = 0; i < (int) strlen(pt) - 1 && pt[i] == ' '; i++);
614
+	    pt += i;
615
+	    if((i = strlen(pt)) && pt[i - 1] == '\n')
616
+		pt[i-- - 1] = 0;
617
+	    if(!i) {
618
+		if(verbose)
619
+		    fprintf(stderr, "ERROR: Missing argument for option at line %d\n", line);
620
+		err = 1;
621
+		break;
622
+	    }
623
+	    arg = pt;
624
+	    if(*arg == '"') {
625
+		arg++; pt++;
626
+		pt = strrchr(pt, '"');
627
+		if(!pt) {
628
+		    if(verbose)
629
+			fprintf(stderr, "ERROR: Missing closing parenthesis in option %s at line %d\n", name, line);
630
+		    err = 1;
631
+		    break;
632
+		}
633
+		*pt = 0;
634
+		if(!strlen(arg)) {
635
+		    if(verbose)
636
+			fprintf(stderr, "ERROR: Empty argument for option %s at line %d\n", name, line);
637
+		    err = 1;
638
+		    break;
639
+		}
640
+	    }
641
+
642
+	} else {
643
+	    opt_index = 0;
644
+	    ret = getopt_long(argc, argv, shortopts, longopts, &opt_index);
645
+	    if(ret == -1)
646
+		break;
647
+
648
+	    if(ret == ':') {
649
+		fprintf(stderr, "ERROR: Incomplete option passed (missing argument)\n");
650
+		err = 1;
651
+		break;
652
+	    } else if(!ret || strchr(shortopts, ret)) {
653
+		name = NULL;
654
+		if(ret) {
655
+		    for(i = 0; i < lc; i++) {
656
+			if(ret == longopts[i].val) {
657
+			    name = longopts[i].name;
658
+			    break;
659
+			}
660
+		    }
661
+		} else {
662
+		    name = longopts[opt_index].name;
663
+		}
664
+		if(!name) {
665
+		    fprintf(stderr, "ERROR: optparse: No corresponding long name for option '-%c'\n", (char) ret);
666
+		    err = 1;
667
+		    break;
668
+		}
669
+		optarg ? (arg = optarg) : (arg = NULL);
670
+	    } else {
671
+		fprintf(stderr, "ERROR: Unknown option passed\n");
672
+		err = 1;
673
+		break;
674
+	    }
675
+	}
676
+
677
+	if(!name) {
678
+	    fprintf(stderr, "ERROR: Problem parsing options (name == NULL)\n");
679
+	    err = 1;
680
+	    break;
681
+	}
682
+
683
+	opt = optget_i(opts, name);
684
+	if(!opt) {
685
+	    if(cfgfile) {
686
+		if(verbose)
687
+		    fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s\n", line, name);
688
+	    }
689
+	    err = 1;
690
+	    break;
691
+	}
692
+	optentry = &clam_options[opt->idx];
693
+
694
+	if(optentry->owner & OPT_DEPRECATED) {
695
+	    if(toolmask & OPT_DEPRECATED) {
696
+		/* FIXME: optadd() -- needed for clamconf */
697
+	    } else {
698
+		if(cfgfile) {
699
+		    if(verbose)
700
+			fprintf(stderr, "WARNING: Ignoring deprecated option %s at line %u\n", opt->name, line);
701
+		} else {
702
+		    if(verbose) {
703
+			if(optentry->shortopt)
704
+			    fprintf(stderr, "WARNING: Ignoring deprecated option --%s (-%c)\n", optentry->longopt, optentry->shortopt);
705
+			else
706
+			    fprintf(stderr, "WARNING: Ignoring deprecated option --%s\n", optentry->longopt);
707
+		    }
708
+		}
709
+		continue;
710
+	    }
711
+	}
712
+
713
+	if(!cfgfile && !arg && optentry->argtype == OPT_BOOL) {
714
+	    arg = "yes"; /* default to yes */
715
+	} else if(optentry->regex) {
716
+	    if(cli_regcomp(&regex, optentry->regex, REG_EXTENDED | REG_NOSUB)) {
717
+		fprintf(stderr, "ERROR: optparse: Can't compile regular expression %s for option %s\n", optentry->regex, name);
718
+		err = 1;
719
+		break;
720
+	    }
721
+	    ret = cli_regexec(&regex, arg, 0, NULL, 0);
722
+	    cli_regfree(&regex);
723
+	    if(ret == REG_NOMATCH) {
724
+		if(cfgfile) {
725
+		    fprintf(stderr, "ERROR: Incorrect argument format for option %s\n", name);
726
+		} else {
727
+		    if(optentry->shortopt)
728
+			fprintf(stderr, "ERROR: Incorrect argument format for option --%s (-%c)\n", optentry->longopt, optentry->shortopt);
729
+		    else
730
+			fprintf(stderr, "ERROR: Incorrect argument format for option --%s\n", optentry->longopt);
731
+		}
732
+		err = 1;
733
+		break;
734
+	    }
735
+	}
736
+
737
+	numarg = -1;
738
+	switch(optentry->argtype) {
739
+	    case OPT_STRING:
740
+		if(!cfgfile && !strlen(arg)) {
741
+		    if(optentry->shortopt)
742
+			fprintf(stderr, "ERROR: Option --%s (-%c) requires a non-empty string argument\n", optentry->longopt, optentry->shortopt);
743
+		    else
744
+			fprintf(stderr, "ERROR: Option --%s requires a non-empty string argument\n", optentry->longopt);
745
+		    err = 1;
746
+		    break;
747
+		}
748
+		break;
749
+
750
+	    case OPT_NUMBER:
751
+		numarg = atoi(arg);
752
+		arg = NULL;
753
+		break;
754
+
755
+	    case OPT_SIZE:
756
+		if(sscanf(arg, "%d", &numarg) != 1) {
757
+		    if(cfgfile) {
758
+			fprintf(stderr, "ERROR: Can't parse numerical argument for option %s\n", name);
759
+		    } else {
760
+			if(optentry->shortopt)
761
+			    fprintf(stderr, "ERROR: Can't parse numerical argument for option --%s (-%c)\n", optentry->longopt, optentry->shortopt);
762
+			else
763
+			    fprintf(stderr, "ERROR: Can't parse numerical argument for option --%s\n", optentry->longopt);
764
+		    }
765
+		    err = 1;
766
+		    break;
767
+		}
768
+		i = strlen(arg) - 1;
769
+		if(arg[i] == 'M' || arg[i] == 'm')
770
+		    numarg *= 1048576;
771
+		else if(arg[i] == 'K' || arg[i] == 'k')
772
+		    numarg *= 1024;
773
+		else
774
+		    numarg = atoi(arg);
775
+
776
+		arg = NULL;
777
+		break;
778
+
779
+	    case OPT_BOOL:
780
+                if(!strcasecmp(arg, "yes") || !strcmp(arg, "1") || !strcasecmp(arg, "true"))
781
+		    numarg = 1;
782
+		else
783
+		    numarg = 0;
784
+
785
+		arg = NULL;
786
+		break;
787
+	}
788
+
789
+	if(err)
790
+	    break;
791
+
792
+	if(optaddarg(opts, name, arg, numarg) < 0) {
793
+	    if(cfgfile)
794
+		fprintf(stderr, "ERROR: Can't register argument for option %s\n", name);
795
+	    else
796
+		fprintf(stderr, "ERROR: Can't register argument for option --%s\n", optentry->longopt);
797
+	    err = 1;
798
+	    break;
799
+	}
800
+    }
801
+
802
+    if(fs)
803
+	fclose(fs);
804
+
805
+    if(err) {
806
+	optfree(opts);
807
+	return NULL;
808
+    }
809
+
810
+    /* optprint(opts); */
811
+
812
+    return opts;
813
+}
0 814
new file mode 100644
... ...
@@ -0,0 +1,54 @@
0
+/*
1
+ *  Copyright (C) 2008 Sourcefire, Inc.
2
+ *
3
+ *  Author: Tomasz Kojm <tkojm@clamav.net>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#ifndef __OPTPARSER_H
21
+#define __OPTPARSER_H
22
+
23
+#define OPT_STRING  1	/* quoted/regular string */
24
+#define OPT_NUMBER  2	/* raw number */
25
+#define OPT_SIZE    3	/* number possibly followed by modifers (M/m or K/k) */
26
+#define OPT_BOOL    4	/* boolean */
27
+
28
+/* don't share bits! */
29
+#define OPT_CLAMD	1
30
+#define OPT_FRESHCLAM	2
31
+#define OPT_MILTER	4
32
+#define OPT_DEPRECATED	8
33
+
34
+struct optstruct {
35
+    char *name;
36
+    char *cmd;
37
+    char *strarg;
38
+    int numarg;
39
+    int enabled;
40
+    int active;
41
+    int multiple;
42
+    int idx;
43
+    struct optstruct *nextarg;
44
+    struct optstruct *next;
45
+};
46
+
47
+const struct optstruct *optget(const struct optstruct *opts, const char *name);
48
+
49
+void optfree(struct optstruct *opts);
50
+
51
+struct optstruct *optparse(const char *cfgfile, int argc, char * const *argv, int verbose, int toolmask, struct optstruct *oldopts);
52
+
53
+#endif
... ...
@@ -24,7 +24,6 @@
24 24
 #endif
25 25
 
26 26
 #include <stdlib.h>
27
-#include "cfgparser.h"
28 27
 
29 28
 #ifdef __GNUC__
30 29
 int mdprintf(int desc, const char *str, ...) __attribute__((format(printf, 2,3)));