Browse code

initial support for hardware acceleration

git-svn: trunk@1895

Tomasz Kojm authored on 2006/04/08 04:22:21
Showing 11 changed files
... ...
@@ -1,3 +1,9 @@
1
+Fri Apr  7 21:09:25 CEST 2006 (tk)
2
+----------------------------------
3
+  * libclamav: initial support for Sensory Network's NodalCore Accelerator
4
+  * clamscan: new option --hwaccel (only available on systems with hardware
5
+	      accelerators)
6
+
1 7
 Fri Apr  7 12:25:20 BST 2006 (njh)
2 8
 ----------------------------------
3 9
   * libclamav/mbox.c:		Better handling of messages with lots of
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  This program is free software; you can redistribute it and/or modify
5 5
  *  it under the terms of the GNU General Public License as published by
... ...
@@ -161,7 +161,10 @@ int clamscan(struct optstruct *opt)
161 161
 	dms += (dms < 0) ? (1000000):(0);
162 162
 	logg("\n----------- SCAN SUMMARY -----------\n");
163 163
 	logg("Known viruses: %d\n", claminfo.signs);
164
-	logg("Engine version: %s\n", cl_retver());
164
+	if(optl(opt, "hwaccel"))
165
+	    logg("Engine version: %s [hwaccel]\n", cl_retver());
166
+	else
167
+	    logg("Engine version: %s\n", cl_retver());
165 168
 	logg("Scanned directories: %d\n", claminfo.dirs);
166 169
 	logg("Scanned files: %d\n", claminfo.files);
167 170
 	logg("Infected files: %d\n", claminfo.ifiles);
... ...
@@ -223,7 +226,9 @@ void help(void)
223 223
     mprintf("    --include=PATT                       Only scan file names containing PATT\n");
224 224
     mprintf("    --include-dir=PATT                   Only scan directories containing PATT\n");
225 225
 #endif
226
-
226
+#ifdef HAVE_HWACCEL
227
+    mprintf("\n    --hwaccel                            Use hardware acceleration\n");
228
+#endif
227 229
     mprintf("\n");
228 230
     mprintf("    --no-mail                            Disable mail file support\n");
229 231
     mprintf("    --no-phishing                        Disable phishing detection\n");
... ...
@@ -85,7 +85,10 @@ int scanmanager(const struct optstruct *opt)
85 85
        optl(opt, "tar") || optl(opt, "tgz") || optl(opt, "deb"))
86 86
 	    compression = 1;
87 87
 
88
-    /* now initialize the database */
88
+
89
+    if(optl(opt, "hwaccel"))
90
+	dboptions |= CL_DB_HWACCEL;
91
+
89 92
     if(optl(opt, "no-phishing"))
90 93
 	dboptions |= CL_DB_NOPHISHING;
91 94
 
... ...
@@ -93,6 +93,9 @@ int main(int argc, char **argv)
93 93
             {"max-ratio", 1, 0, 0},
94 94
 	    {"max-recursion", 1, 0, 0},
95 95
 	    {"max-dir-recursion", 1, 0, 0},
96
+#ifdef HWACCEL
97
+	    {"hwaccel", 0, 0, 0},
98
+#endif
96 99
 	    {"disable-archive", 0, 0, 0},
97 100
 	    {"no-archive", 0, 0, 0},
98 101
 	    {"detect-broken", 0, 0, 0},
... ...
@@ -10825,13 +10825,160 @@ fi
10825 10825
 echo "$as_me:$LINENO: result: $ac_cv_lib_sn_sigscan_sn_sigscan_initdb" >&5
10826 10826
 echo "${ECHO_T}$ac_cv_lib_sn_sigscan_sn_sigscan_initdb" >&6
10827 10827
 if test $ac_cv_lib_sn_sigscan_sn_sigscan_initdb = yes; then
10828
+  have_sigscan=yes
10829
+fi
10830
+
10831
+    if test "$have_sigscan" = "yes"
10832
+    then
10833
+	if test "${ac_cv_header_sn_sigscan_sn_sigscan_h+set}" = set; then
10834
+  echo "$as_me:$LINENO: checking for sn_sigscan/sn_sigscan.h" >&5
10835
+echo $ECHO_N "checking for sn_sigscan/sn_sigscan.h... $ECHO_C" >&6
10836
+if test "${ac_cv_header_sn_sigscan_sn_sigscan_h+set}" = set; then
10837
+  echo $ECHO_N "(cached) $ECHO_C" >&6
10838
+fi
10839
+echo "$as_me:$LINENO: result: $ac_cv_header_sn_sigscan_sn_sigscan_h" >&5
10840
+echo "${ECHO_T}$ac_cv_header_sn_sigscan_sn_sigscan_h" >&6
10841
+else
10842
+  # Is the header compilable?
10843
+echo "$as_me:$LINENO: checking sn_sigscan/sn_sigscan.h usability" >&5
10844
+echo $ECHO_N "checking sn_sigscan/sn_sigscan.h usability... $ECHO_C" >&6
10845
+cat >conftest.$ac_ext <<_ACEOF
10846
+/* confdefs.h.  */
10847
+_ACEOF
10848
+cat confdefs.h >>conftest.$ac_ext
10849
+cat >>conftest.$ac_ext <<_ACEOF
10850
+/* end confdefs.h.  */
10851
+$ac_includes_default
10852
+#include <sn_sigscan/sn_sigscan.h>
10853
+_ACEOF
10854
+rm -f conftest.$ac_objext
10855
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
10856
+  (eval $ac_compile) 2>conftest.er1
10857
+  ac_status=$?
10858
+  grep -v '^ *+' conftest.er1 >conftest.err
10859
+  rm -f conftest.er1
10860
+  cat conftest.err >&5
10861
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
10862
+  (exit $ac_status); } &&
10863
+	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
10864
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
10865
+  (eval $ac_try) 2>&5
10866
+  ac_status=$?
10867
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
10868
+  (exit $ac_status); }; } &&
10869
+	 { ac_try='test -s conftest.$ac_objext'
10870
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
10871
+  (eval $ac_try) 2>&5
10872
+  ac_status=$?
10873
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
10874
+  (exit $ac_status); }; }; then
10875
+  ac_header_compiler=yes
10876
+else
10877
+  echo "$as_me: failed program was:" >&5
10878
+sed 's/^/| /' conftest.$ac_ext >&5
10828 10879
 
10880
+ac_header_compiler=no
10881
+fi
10882
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
10883
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
10884
+echo "${ECHO_T}$ac_header_compiler" >&6
10885
+
10886
+# Is the header present?
10887
+echo "$as_me:$LINENO: checking sn_sigscan/sn_sigscan.h presence" >&5
10888
+echo $ECHO_N "checking sn_sigscan/sn_sigscan.h presence... $ECHO_C" >&6
10889
+cat >conftest.$ac_ext <<_ACEOF
10890
+/* confdefs.h.  */
10891
+_ACEOF
10892
+cat confdefs.h >>conftest.$ac_ext
10893
+cat >>conftest.$ac_ext <<_ACEOF
10894
+/* end confdefs.h.  */
10895
+#include <sn_sigscan/sn_sigscan.h>
10896
+_ACEOF
10897
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
10898
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
10899
+  ac_status=$?
10900
+  grep -v '^ *+' conftest.er1 >conftest.err
10901
+  rm -f conftest.er1
10902
+  cat conftest.err >&5
10903
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
10904
+  (exit $ac_status); } >/dev/null; then
10905
+  if test -s conftest.err; then
10906
+    ac_cpp_err=$ac_c_preproc_warn_flag
10907
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
10908
+  else
10909
+    ac_cpp_err=
10910
+  fi
10911
+else
10912
+  ac_cpp_err=yes
10913
+fi
10914
+if test -z "$ac_cpp_err"; then
10915
+  ac_header_preproc=yes
10916
+else
10917
+  echo "$as_me: failed program was:" >&5
10918
+sed 's/^/| /' conftest.$ac_ext >&5
10919
+
10920
+  ac_header_preproc=no
10921
+fi
10922
+rm -f conftest.err conftest.$ac_ext
10923
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
10924
+echo "${ECHO_T}$ac_header_preproc" >&6
10925
+
10926
+# So?  What about this header?
10927
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
10928
+  yes:no: )
10929
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: accepted by the compiler, rejected by the preprocessor!" >&5
10930
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
10931
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: proceeding with the compiler's result" >&5
10932
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: proceeding with the compiler's result" >&2;}
10933
+    ac_header_preproc=yes
10934
+    ;;
10935
+  no:yes:* )
10936
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: present but cannot be compiled" >&5
10937
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: present but cannot be compiled" >&2;}
10938
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h:     check for missing prerequisite headers?" >&5
10939
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h:     check for missing prerequisite headers?" >&2;}
10940
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: see the Autoconf documentation" >&5
10941
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: see the Autoconf documentation" >&2;}
10942
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h:     section \"Present But Cannot Be Compiled\"" >&5
10943
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h:     section \"Present But Cannot Be Compiled\"" >&2;}
10944
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: proceeding with the preprocessor's result" >&5
10945
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: proceeding with the preprocessor's result" >&2;}
10946
+    { echo "$as_me:$LINENO: WARNING: sn_sigscan/sn_sigscan.h: in the future, the compiler will take precedence" >&5
10947
+echo "$as_me: WARNING: sn_sigscan/sn_sigscan.h: in the future, the compiler will take precedence" >&2;}
10948
+    (
10949
+      cat <<\_ASBOX
10950
+## ------------------------------------------ ##
10951
+## Report this to the AC_PACKAGE_NAME lists.  ##
10952
+## ------------------------------------------ ##
10953
+_ASBOX
10954
+    ) |
10955
+      sed "s/^/$as_me: WARNING:     /" >&2
10956
+    ;;
10957
+esac
10958
+echo "$as_me:$LINENO: checking for sn_sigscan/sn_sigscan.h" >&5
10959
+echo $ECHO_N "checking for sn_sigscan/sn_sigscan.h... $ECHO_C" >&6
10960
+if test "${ac_cv_header_sn_sigscan_sn_sigscan_h+set}" = set; then
10961
+  echo $ECHO_N "(cached) $ECHO_C" >&6
10962
+else
10963
+  ac_cv_header_sn_sigscan_sn_sigscan_h=$ac_header_preproc
10964
+fi
10965
+echo "$as_me:$LINENO: result: $ac_cv_header_sn_sigscan_sn_sigscan_h" >&5
10966
+echo "${ECHO_T}$ac_cv_header_sn_sigscan_sn_sigscan_h" >&6
10967
+
10968
+fi
10969
+if test $ac_cv_header_sn_sigscan_sn_sigscan_h = yes; then
10970
+  LIBCLAMAV_LIBS="$LIBCLAMAV_LIBS -lsn_sigscan";
10829 10971
 cat >>confdefs.h <<\_ACEOF
10830 10972
 #define HAVE_HWACCEL 1
10831 10973
 _ACEOF
10832 10974
 
10975
+else
10976
+  { echo "$as_me:$LINENO: WARNING: ****** hardware acceleration support disabled -- please install libsigscan-devel " >&5
10977
+echo "$as_me: WARNING: ****** hardware acceleration support disabled -- please install libsigscan-devel " >&2;}
10833 10978
 fi
10834 10979
 
10980
+
10981
+    fi
10835 10982
 fi
10836 10983
 
10837 10984
 # Check whether --enable-dns or --disable-dns was given.
... ...
@@ -1,5 +1,5 @@
1 1
 dnl
2
-dnl   Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+dnl   Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
 dnl   gethostbyname_r and readdir_r checks (c) COPYRIGHT MIT 1995
4 4
 dnl
5 5
 dnl   This program is free software; you can redistribute it and/or modify
... ...
@@ -143,7 +143,11 @@ want_hwaccel=$enableval, want_hwaccel="yes")
143 143
 
144 144
 if test "$want_hwaccel" = "yes"
145 145
 then
146
-    AC_CHECK_LIB(sn_sigscan, sn_sigscan_initdb, AC_DEFINE(HAVE_HWACCEL,1,hardware acceleration),)
146
+    AC_CHECK_LIB(sn_sigscan, sn_sigscan_initdb, have_sigscan=yes,)
147
+    if test "$have_sigscan" = "yes"
148
+    then
149
+	AC_CHECK_HEADER(sn_sigscan/sn_sigscan.h,[LIBCLAMAV_LIBS="$LIBCLAMAV_LIBS -lsn_sigscan"; AC_DEFINE(HAVE_HWACCEL,1,hardware acceleration)], AC_MSG_WARN([****** hardware acceleration support disabled -- please install libsigscan-devel ]))
150
+    fi
147 151
 fi
148 152
 
149 153
 AC_ARG_ENABLE(dns,
... ...
@@ -34,6 +34,7 @@ extern "C"
34 34
 /* return codes */
35 35
 #define CL_CLEAN	0   /* virus not found */
36 36
 #define CL_VIRUS	1   /* virus found */
37
+#define CL_SUCCESS	CL_CLEAN
37 38
 
38 39
 #define CL_EMAXREC	10  /* recursion level limit exceeded */
39 40
 #define CL_EMAXSIZE	11  /* size limit exceeded */
... ...
@@ -63,6 +64,11 @@ extern "C"
63 63
 #define CL_EIO		-12 /* general I/O error */
64 64
 #define CL_EFORMAT	-13 /* bad format or broken file */
65 65
 
66
+#define CL_EHWINIT	-14 /* hardware initialization failed */
67
+#define	CL_EHWLOAD	-15 /* error loading hardware database */
68
+#define CL_EHWIO	-16 /* general hardware I/O error */
69
+
70
+
66 71
 /* db options */
67 72
 #define CL_DB_HWACCEL		1
68 73
 #define CL_DB_NOPHISHING	2
... ...
@@ -164,6 +170,8 @@ struct cl_engine {
164 164
     /* RAR metadata */
165 165
     struct cli_meta_node *rar_mlist;
166 166
 
167
+    /* Hardware database handle */
168
+    void *hwdb;
167 169
 };
168 170
 
169 171
 struct cl_limits {
... ...
@@ -293,8 +293,10 @@ int cli_addtypesigs(struct cl_engine *engine)
293 293
 	}
294 294
 
295 295
 	if(engine->hwaccel) {
296
+	    /*
296 297
 	    cli_dbgmsg("cli_addtypesigs: AC depth 10 (hwaccel mode)\n");
297 298
 	    cli_ac_setdepth(10);
299
+	    */
298 300
 	}
299 301
 
300 302
 	root->ac_root =  (struct cli_ac_node *) cli_calloc(1, sizeof(struct cli_ac_node));
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  This program is free software; you can redistribute it and/or modify
5 5
  *  it under the terms of the GNU General Public License as published by
... ...
@@ -45,16 +45,23 @@ static int targettab[CL_TARGET_TABLE_SIZE] = { 0, CL_TYPE_MSEXE, CL_TYPE_MSOLE2,
45 45
 
46 46
 extern short cli_debug_flag;
47 47
 
48
-#ifdef CL_THREAD_SAFE
49
-#  include <pthread.h>
50
-static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
48
+#ifdef HAVE_HWACCEL
49
+#include <sn_sigscan/sn_sigscan.h>
50
+#define HWBUFFSIZE 32768
51 51
 #endif
52 52
 
53 53
 int cli_scanbuff(const char *buffer, unsigned int length, const char **virname, const struct cl_engine *engine, unsigned short ftype)
54 54
 {
55
-	int ret, i, tid = 0, *partcnt;
55
+	int ret = CL_CLEAN, i, tid = 0, *partcnt;
56 56
 	unsigned long int *partoff;
57 57
 	struct cli_matcher *groot, *troot = NULL;
58
+#ifdef HAVE_HWACCEL
59
+	void *streamhandle;
60
+	void *resulthandle;
61
+	uint32_t datamask[2] = { 1, 1 };
62
+	int count, hret;
63
+	unsigned long long offset;
64
+#endif
58 65
 
59 66
 
60 67
     if(!engine) {
... ...
@@ -62,6 +69,49 @@ int cli_scanbuff(const char *buffer, unsigned int length, const char **virname,
62 62
 	return CL_ENULLARG;
63 63
     }
64 64
 
65
+#ifdef HAVE_HWACCEL
66
+    if(engine->hwaccel) {
67
+	/* TODO: Setup proper data bitmask (need specs) */
68
+	if((hret = sn_sigscan_createstream(engine->hwdb, datamask, 2, &streamhandle)) < 0) {
69
+	    cli_errmsg("cli_scanbuff: can't create new hardware stream: %d\n", hret);
70
+	    return CL_EHWIO;
71
+	}
72
+
73
+	if((hret = sn_sigscan_writestream(streamhandle, buffer, length)) < 0) {
74
+	    cli_errmsg("cli_scanbuff: can't write %u bytes to hardware stream: %d\n", length, hret);
75
+	    sn_sigscan_closestream(streamhandle, &resulthandle);
76
+	    return CL_EHWIO;
77
+	}
78
+
79
+	if((hret = sn_sigscan_closestream(streamhandle, &resulthandle)) < 0) {
80
+	    cli_errmsg("cli_scanbuff: can't close hardware stream: %d\n", hret);
81
+	    return CL_EHWIO;
82
+	}
83
+
84
+	count = sn_sigscan_resultcount(resulthandle);
85
+	cli_dbgmsg("cli_scanbuff: number of results: %d\n", count);
86
+
87
+	if(count > 0) {
88
+	    if((hret = sn_sigscan_resultget(resulthandle, 0, virname, &offset)) < 0) {
89
+		cli_errmsg("cli_scanbuff: can't get hardware match result: %d\n", hret);
90
+		sn_sigscan_resultfree(resulthandle);
91
+		return CL_EHWIO;
92
+	    } else {
93
+		cli_dbgmsg("cli_scanbuff: hardware match %s at %u\n", *virname, offset);
94
+		ret = CL_VIRUS;
95
+	    }
96
+	}
97
+
98
+	if((hret = sn_sigscan_resultfree(resulthandle)) < 0) {
99
+	    cli_errmsg("cli_scanbuff: can't free results: %d\n", ret);
100
+	    return CL_EHWIO;
101
+	}
102
+
103
+	return ret;
104
+    }
105
+#endif /* HAVE_HWACCEL */
106
+
107
+
65 108
     groot = engine->root[0]; /* generic signatures */
66 109
 
67 110
     if(ftype) {
... ...
@@ -277,13 +327,20 @@ int cli_validatesig(unsigned short target, unsigned short ftype, const char *off
277 277
 int cli_scandesc(int desc, cli_ctx *ctx, unsigned short otfrec, unsigned short ftype, struct cli_matched_type **ftoffset)
278 278
 {
279 279
  	char *buffer, *buff, *endbl, *pt;
280
-	int ret, *gpartcnt, *tpartcnt, type = CL_CLEAN, i, tid = 0, bytes;
280
+	int ret = CL_CLEAN, *gpartcnt, *tpartcnt, type = CL_CLEAN, i, tid = 0, bytes;
281 281
 	unsigned int buffersize, length, maxpatlen, shift = 0;
282 282
 	unsigned long int *gpartoff, *tpartoff, offset = 0;
283 283
 	MD5_CTX md5ctx;
284 284
 	unsigned char digest[16];
285 285
 	struct cli_md5_node *md5_node;
286 286
 	struct cli_matcher *groot, *troot = NULL;
287
+#ifdef HAVE_HWACCEL
288
+	void *streamhandle;
289
+	void *resulthandle;
290
+	unsigned long long hoffset;
291
+	uint32_t datamask[2] = { 1, 1 };
292
+	int count, hret;
293
+#endif
287 294
 
288 295
 
289 296
     if(!ctx->engine) {
... ...
@@ -291,6 +348,61 @@ int cli_scandesc(int desc, cli_ctx *ctx, unsigned short otfrec, unsigned short f
291 291
 	return CL_ENULLARG;
292 292
     }
293 293
 
294
+#ifdef HAVE_HWACCEL
295
+    if(ctx->engine->hwaccel) {
296
+	/* TODO: Setup proper data bitmask (need specs) */
297
+	if((hret = sn_sigscan_createstream(ctx->engine->hwdb, datamask, 2, &streamhandle)) < 0) {
298
+	    cli_errmsg("cli_scandesc: can't create new hardware stream: %d\n", hret);
299
+	    return CL_EHWIO;
300
+	}
301
+
302
+	if(!(buffer = (char *) cli_calloc(HWBUFFSIZE, sizeof(char)))) {
303
+	    cli_dbgmsg("cli_scandesc: unable to cli_calloc(%u)\n", HWBUFFSIZE);
304
+	    return CL_EMEM;
305
+	}
306
+
307
+	while((bytes = cli_readn(desc, buffer, HWBUFFSIZE)) > 0) {
308
+	    if((hret = sn_sigscan_writestream(streamhandle, buffer, bytes)) < 0) {
309
+		cli_errmsg("cli_scandesc: can't write to hardware stream: %d\n", hret);
310
+		ret = CL_EHWIO;
311
+		break;
312
+	    } else {
313
+		if(ctx->scanned)
314
+		    *ctx->scanned += bytes / CL_COUNT_PRECISION;
315
+	    }
316
+	}
317
+
318
+	free(buffer);
319
+
320
+	if((hret = sn_sigscan_closestream(streamhandle, &resulthandle)) < 0) {
321
+	    cli_errmsg("cli_scandesc: can't close hardware stream: %d\n", hret);
322
+	    return CL_EHWIO;
323
+	}
324
+
325
+	count = sn_sigscan_resultcount(resulthandle);
326
+	cli_dbgmsg("cli_scandesc: number of results: %d\n", count);
327
+
328
+	if(count > 0) {
329
+	    if((hret = sn_sigscan_resultget(resulthandle, 0, ctx->virname, &hoffset)) < 0) {
330
+		cli_errmsg("cli_scandesc: can't get hardware match result: %d\n", hret);
331
+		sn_sigscan_resultfree(resulthandle);
332
+		return CL_EHWIO;
333
+	    } else {
334
+		cli_dbgmsg("cli_scandesc: hardware match %s at %u\n", *ctx->virname, hoffset);
335
+		ret = CL_VIRUS;
336
+	    }
337
+	}
338
+
339
+	if((hret = sn_sigscan_resultfree(resulthandle)) < 0) {
340
+	    cli_errmsg("cli_scandesc: can't free results: %d\n", ret);
341
+	    return CL_EHWIO;
342
+	}
343
+
344
+	return ret;
345
+    }
346
+#endif /* HAVE_HWACCEL */
347
+
348
+
294 349
     groot = ctx->engine->root[0]; /* generic signatures */
295 350
 
296 351
     if(ftype) {
... ...
@@ -472,115 +584,3 @@ int cli_scandesc(int desc, cli_ctx *ctx, unsigned short otfrec, unsigned short f
472 472
 
473 473
     return otfrec ? type : CL_CLEAN;
474 474
 }
475
-
476
-int cl_build(struct cl_engine *engine)
477
-{
478
-	int i, ret;
479
-	struct cli_matcher *root;
480
-
481
-
482
-    if((ret = cli_addtypesigs(engine)))
483
-	return ret;
484
-
485
-    for(i = 0; i < CL_TARGET_TABLE_SIZE; i++)
486
-	if((root = engine->root[i]))
487
-	    cli_ac_buildtrie(root);
488
-    /* FIXME: check return values of cli_ac_buildtree */
489
-
490
-    return 0;
491
-}
492
-
493
-struct cl_engine *cl_dup(struct cl_engine *engine)
494
-{
495
-    if(!engine) {
496
-	cli_errmsg("cl_dup: engine == NULL\n");
497
-	return NULL;
498
-    }
499
-
500
-#ifdef CL_THREAD_SAFE
501
-    pthread_mutex_lock(&cli_ref_mutex);
502
-#endif
503
-
504
-    engine->refcount++;
505
-
506
-#ifdef CL_THREAD_SAFE
507
-    pthread_mutex_unlock(&cli_ref_mutex);
508
-#endif
509
-
510
-    return engine;
511
-}
512
-
513
-void cl_free(struct cl_engine *engine)
514
-{
515
-	int i;
516
-	struct cli_md5_node *md5pt, *md5h;
517
-	struct cli_meta_node *metapt, *metah;
518
-	struct cli_matcher *root;
519
-
520
-    if(!engine) {
521
-	cli_errmsg("cl_free: engine == NULL\n");
522
-	return;
523
-    }
524
-
525
-#ifdef CL_THREAD_SAFE
526
-    pthread_mutex_lock(&cli_ref_mutex);
527
-#endif
528
-
529
-    engine->refcount--;
530
-    if(engine->refcount) {
531
-#ifdef CL_THREAD_SAFE
532
-	pthread_mutex_unlock(&cli_ref_mutex);
533
-#endif
534
-	return;
535
-    }
536
-    
537
-#ifdef CL_THREAD_SAFE
538
-    pthread_mutex_unlock(&cli_ref_mutex);
539
-#endif
540
-
541
-    for(i = 0; i < CL_TARGET_TABLE_SIZE; i++) {
542
-	if((root = engine->root[i])) {
543
-	    cli_ac_free(root);
544
-	    if(!engine->root[i]->ac_only)
545
-		cli_bm_free(root);
546
-	}
547
-    }
548
-
549
-    if(engine->md5_hlist) {
550
-	for(i = 0; i < 256; i++) {
551
-	    md5pt = engine->md5_hlist[i];
552
-	    while(md5pt) {
553
-		md5h = md5pt;
554
-		md5pt = md5pt->next;
555
-		free(md5h->md5);
556
-		free(md5h->virname);
557
-		if(md5h->viralias)
558
-		    free(md5h->viralias);
559
-		free(md5h);
560
-	    }
561
-	}
562
-	free(engine->md5_hlist);
563
-    }
564
-
565
-    metapt = engine->zip_mlist;
566
-    while(metapt) {
567
-	metah = metapt;
568
-	metapt = metapt->next;
569
-	free(metah->virname);
570
-	if(metah->filename)
571
-	    free(metah->filename);
572
-	free(metah);
573
-    }
574
-
575
-    metapt = engine->rar_mlist;
576
-    while(metapt) {
577
-	metah = metapt;
578
-	metapt = metapt->next;
579
-	free(metah->virname);
580
-	if(metah->filename)
581
-	    free(metah->filename);
582
-	free(metah);
583
-    }
584
-
585
-    free(engine);
586
-}
... ...
@@ -195,6 +195,12 @@ const char *cl_strerror(int clerror)
195 195
 	    return "Input/Output error";
196 196
 	case CL_EFORMAT:
197 197
 	    return "Bad format or broken data";
198
+	case CL_EHWINIT:
199
+	    return "Hardware initialization failure";
200
+	case CL_EHWLOAD:
201
+	    return "Error loading hardware database";
202
+	case CL_EHWIO:
203
+	    return "Hardware accelerator Input/Output error";
198 204
 	default:
199 205
 	    return "Unknown error code";
200 206
     }
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
2
+ *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3 3
  *
4 4
  *  This program is free software; you can redistribute it and/or modify
5 5
  *  it under the terms of the GNU General Public License as published by
... ...
@@ -58,6 +58,16 @@
58 58
 # endif
59 59
 #endif
60 60
 
61
+#ifdef CL_THREAD_SAFE
62
+#  include <pthread.h>
63
+static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
64
+#endif
65
+
66
+#ifdef HAVE_HWACCEL
67
+#include <sn_sigscan/sn_sigscan.h>
68
+#endif
69
+
70
+
61 71
 /* TODO: clean up the code */
62 72
 
63 73
 static int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, int sigid, int parts, int partno, unsigned short type, unsigned int mindist, unsigned int maxdist, char *offset, unsigned short target)
... ...
@@ -962,14 +972,56 @@ static int cli_loadmd(FILE *fd, struct cl_engine **engine, unsigned int *signo,
962 962
     return 0;
963 963
 }
964 964
 
965
+#ifdef HAVE_HWACCEL
966
+static int cli_loadhw(const char *filename, struct cl_engine **engine, unsigned int *signo, unsigned int options)
967
+{
968
+	int ret = 0;
969
+
970
+
971
+    if((ret = cli_initengine(engine, options))) {
972
+	cl_free(*engine);
973
+	return ret;
974
+    }
975
+
976
+    if((ret = sn_sigscan_initdb(&(*engine)->hwdb)) < 0) {
977
+	cli_errmsg("hwaccel: error initializing the matcher: %d\n", ret);
978
+	cl_free(*engine);
979
+	return CL_EHWINIT;
980
+    }
981
+
982
+    (*engine)->hwaccel = 1;
983
+
984
+    if((ret = sn_sigscan_loaddb((*engine)->hwdb, filename, 0, signo)) < 0) {
985
+	cli_errmsg("hwaccel: can't load hardware database: %d\n", ret);
986
+	cl_free(*engine);
987
+	return CL_EHWLOAD;
988
+    }
989
+
990
+    return CL_SUCCESS;
991
+}
992
+#endif /* HAVE_HWACCEL */
993
+
965 994
 static int cli_load(const char *filename, struct cl_engine **engine, unsigned int *signo, unsigned int options)
966 995
 {
967 996
 	FILE *fd;
968
-	int ret;
997
+	int ret = CL_SUCCESS;
998
+
969 999
 
1000
+#ifdef HAVE_HWACCEL
1001
+    if(options & CL_DB_HWACCEL) {
1002
+	if(cli_strbcasestr(filename, ".hw")) {
1003
+	    cli_dbgmsg("Loading %s\n", filename);
1004
+	    ret = cli_loadhw(filename, engine, signo, options);
1005
+	} else {
1006
+	    cli_dbgmsg("Ignoring %s\n", filename);
1007
+	}
1008
+
1009
+	return ret;
1010
+    }
1011
+#endif /* HAVE_HWACCEL */
970 1012
 
971 1013
     if((fd = fopen(filename, "rb")) == NULL) {
972
-	cli_errmsg("cli_loaddb(): Can't open file %s\n", filename);
1014
+	cli_errmsg("cli_load(): Can't open file %s\n", filename);
973 1015
 	return CL_EOPEN;
974 1016
     }
975 1017
 
... ...
@@ -1005,7 +1057,7 @@ static int cli_load(const char *filename, struct cl_engine **engine, unsigned in
1005 1005
 	ret = cli_loadmd(fd, engine, signo, 2, options);
1006 1006
 
1007 1007
     } else {
1008
-	cli_dbgmsg("cli_loaddb: unknown extension - assuming old database format\n");
1008
+	cli_dbgmsg("cli_load: unknown extension - assuming old database format\n");
1009 1009
 	ret = cli_loaddb(fd, engine, signo, options);
1010 1010
     }
1011 1011
 
... ...
@@ -1062,6 +1114,7 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine **engine, unsigne
1062 1062
 	     cli_strbcasestr(dent->d_name, ".sdb")  ||
1063 1063
 	     cli_strbcasestr(dent->d_name, ".zmd")  ||
1064 1064
 	     cli_strbcasestr(dent->d_name, ".rmd")  ||
1065
+	     cli_strbcasestr(dent->d_name, ".hw")  ||
1065 1066
 	     cli_strbcasestr(dent->d_name, ".cvd"))) {
1066 1067
 
1067 1068
 		dbfile = (char *) cli_calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));
... ...
@@ -1107,14 +1160,7 @@ int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, un
1107 1107
 	return ret;
1108 1108
     }
1109 1109
 
1110
-    if(options & CL_DB_HWACCEL) {
1111
-	(*engine)->hwaccel = 1;
1112
-
1113
-	/* load hw db  */
1114
-
1115
-	return 0;
1116
-
1117
-    } else switch(sb.st_mode & S_IFMT) {
1110
+    switch(sb.st_mode & S_IFMT) {
1118 1111
 	case S_IFREG: 
1119 1112
 	    return cli_load(path, engine, signo, options);
1120 1113
 
... ...
@@ -1178,11 +1224,12 @@ int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
1178 1178
 	    cli_strbcasestr(dent->d_name, ".db2")  || 
1179 1179
 	    cli_strbcasestr(dent->d_name, ".db3")  || 
1180 1180
 	    cli_strbcasestr(dent->d_name, ".hdb")  || 
1181
-	    cli_strbcasestr(dent->d_name, ".fp")  || 
1181
+	    cli_strbcasestr(dent->d_name, ".fp")   || 
1182 1182
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1183 1183
 	    cli_strbcasestr(dent->d_name, ".sdb")  || 
1184 1184
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1185 1185
 	    cli_strbcasestr(dent->d_name, ".rmd")  || 
1186
+	    cli_strbcasestr(dent->d_name, ".hw")   ||
1186 1187
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
1187 1188
 
1188 1189
 		dbstat->no++;
... ...
@@ -1250,11 +1297,12 @@ int cl_statchkdir(const struct cl_stat *dbstat)
1250 1250
 	    cli_strbcasestr(dent->d_name, ".db2")  || 
1251 1251
 	    cli_strbcasestr(dent->d_name, ".db3")  || 
1252 1252
 	    cli_strbcasestr(dent->d_name, ".hdb")  || 
1253
-	    cli_strbcasestr(dent->d_name, ".fp")  || 
1253
+	    cli_strbcasestr(dent->d_name, ".fp")   || 
1254 1254
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1255 1255
 	    cli_strbcasestr(dent->d_name, ".sdb")  || 
1256 1256
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1257 1257
 	    cli_strbcasestr(dent->d_name, ".rmd")  || 
1258
+	    cli_strbcasestr(dent->d_name, ".hw")   ||
1258 1259
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
1259 1260
 
1260 1261
                 fname = cli_calloc(strlen(dbstat->dir) + strlen(dent->d_name) + 2, sizeof(char));
... ...
@@ -1318,3 +1366,123 @@ int cl_statfree(struct cl_stat *dbstat)
1318 1318
 
1319 1319
     return 0;
1320 1320
 }
1321
+
1322
+void cl_free(struct cl_engine *engine)
1323
+{
1324
+	int i, ret;
1325
+	struct cli_md5_node *md5pt, *md5h;
1326
+	struct cli_meta_node *metapt, *metah;
1327
+	struct cli_matcher *root;
1328
+
1329
+    if(!engine) {
1330
+	cli_errmsg("cl_free: engine == NULL\n");
1331
+	return;
1332
+    }
1333
+
1334
+#ifdef CL_THREAD_SAFE
1335
+    pthread_mutex_lock(&cli_ref_mutex);
1336
+#endif
1337
+
1338
+    engine->refcount--;
1339
+    if(engine->refcount) {
1340
+#ifdef CL_THREAD_SAFE
1341
+	pthread_mutex_unlock(&cli_ref_mutex);
1342
+#endif
1343
+	return;
1344
+    }
1345
+
1346
+#ifdef CL_THREAD_SAFE
1347
+    pthread_mutex_unlock(&cli_ref_mutex);
1348
+#endif
1349
+
1350
+#ifdef HAVE_HWACCEL
1351
+    if(engine->hwaccel) {
1352
+	if((ret = sn_sigscan_closedb(engine->hwdb)) < 0) {
1353
+	    cli_errmsg("cl_free: can't close hardware database: %d\n", ret);
1354
+	}
1355
+    }
1356
+#endif
1357
+
1358
+    for(i = 0; i < CL_TARGET_TABLE_SIZE; i++) {
1359
+	if((root = engine->root[i])) {
1360
+	    cli_ac_free(root);
1361
+	    if(!engine->root[i]->ac_only)
1362
+		cli_bm_free(root);
1363
+	}
1364
+    }
1365
+
1366
+    if(engine->md5_hlist) {
1367
+	for(i = 0; i < 256; i++) {
1368
+	    md5pt = engine->md5_hlist[i];
1369
+	    while(md5pt) {
1370
+		md5h = md5pt;
1371
+		md5pt = md5pt->next;
1372
+		free(md5h->md5);
1373
+		free(md5h->virname);
1374
+		if(md5h->viralias)
1375
+		    free(md5h->viralias);
1376
+		free(md5h);
1377
+	    }
1378
+	}
1379
+	free(engine->md5_hlist);
1380
+    }
1381
+
1382
+    metapt = engine->zip_mlist;
1383
+    while(metapt) {
1384
+	metah = metapt;
1385
+	metapt = metapt->next;
1386
+	free(metah->virname);
1387
+	if(metah->filename)
1388
+	    free(metah->filename);
1389
+	free(metah);
1390
+    }
1391
+
1392
+    metapt = engine->rar_mlist;
1393
+    while(metapt) {
1394
+	metah = metapt;
1395
+	metapt = metapt->next;
1396
+	free(metah->virname);
1397
+	if(metah->filename)
1398
+	    free(metah->filename);
1399
+	free(metah);
1400
+    }
1401
+
1402
+    free(engine);
1403
+}
1404
+
1405
+int cl_build(struct cl_engine *engine)
1406
+{
1407
+	int i, ret;
1408
+	struct cli_matcher *root;
1409
+
1410
+
1411
+    if((ret = cli_addtypesigs(engine)))
1412
+	return ret;
1413
+
1414
+    for(i = 0; i < CL_TARGET_TABLE_SIZE; i++)
1415
+	if((root = engine->root[i]))
1416
+	    cli_ac_buildtrie(root);
1417
+    /* FIXME: check return values of cli_ac_buildtree */
1418
+
1419
+    return 0;
1420
+}
1421
+
1422
+struct cl_engine *cl_dup(struct cl_engine *engine)
1423
+{
1424
+    if(!engine) {
1425
+	cli_errmsg("cl_dup: engine == NULL\n");
1426
+	return NULL;
1427
+    }
1428
+
1429
+#ifdef CL_THREAD_SAFE
1430
+    pthread_mutex_lock(&cli_ref_mutex);
1431
+#endif
1432
+
1433
+    engine->refcount++;
1434
+
1435
+#ifdef CL_THREAD_SAFE
1436
+    pthread_mutex_unlock(&cli_ref_mutex);
1437
+#endif
1438
+
1439
+    return engine;
1440
+}