Browse code

Multiple roots for updating

git-svn: trunk@1590

Nigel Horne authored on 2005/05/27 23:56:19
Showing 3 changed files
... ...
@@ -1,3 +1,12 @@
1
+Fri May 27 15:55:00 BST 2005 (njh)
2
+----------------------------------
3
+  * clamav-milter:	EXPERIMENTAL
4
+			When loading a new database when not in external mode,
5
+				keep scanning with the old one rather than
6
+				hold up incoming mails while waiting for
7
+				clamav-milter to become idle then reloading the
8
+				database
9
+
1 10
 Thu May 26 04:03:31 CEST 2005 (tk)
2 11
 ----------------------------------
3 12
   * clamd/scanner.c: quick recovery of thread resources when clamd clients
... ...
@@ -812,6 +812,11 @@ Changes
812 812
 			When dying use LOG_CRIT rather than LOG_ERR
813 813
 0.85d	25/5/05:	When not in external mode, TEMPFAIL when loading a new
814 814
 				database, even when --dont-wait isn't given
815
+0.85e	27/5/05:	When loading a new database when not in external mode,
816
+				keep scanning with the old one rather than
817
+				hold up incoming mails while waiting for
818
+				clamav-milter to become idle then reloading the
819
+				database
815 820
 
816 821
 4. INTERNATIONALISATION
817 822
 
... ...
@@ -22,9 +22,9 @@
22 22
  *
23 23
  * For installation instructions see the file INSTALL that came with this file
24 24
  */
25
-static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.205 2005/05/25 19:39:03 nigelhorne Exp $";
25
+static	char	const	rcsid[] = "$Id: clamav-milter.c,v 1.206 2005/05/27 14:52:58 nigelhorne Exp $";
26 26
 
27
-#define	CM_VERSION	"0.85d"
27
+#define	CM_VERSION	"0.85e"
28 28
 
29 29
 #if HAVE_CONFIG_H
30 30
 #include "clamav-config.h"
... ...
@@ -285,6 +285,7 @@ static	const	char	*progname;	/* our name - usually clamav-milter */
285 285
 
286 286
 /* Variables for --external */
287 287
 static	int	external = 0;	/* scan messages ourself or use clamd? */
288
+static	pthread_mutex_t	root_mutex = PTHREAD_MUTEX_INITIALIZER;
288 289
 static	struct	cl_node	*root = NULL;
289 290
 static	struct	cl_limits	limits;
290 291
 static	struct	cl_stat	dbstat;
... ...
@@ -371,9 +372,6 @@ static	pthread_mutex_t	n_children_mutex = PTHREAD_MUTEX_INITIALIZER;
371 371
 static	pthread_cond_t	n_children_cond = PTHREAD_COND_INITIALIZER;
372 372
 static	volatile	unsigned	int	n_children = 0;
373 373
 static	unsigned	int	max_children = 0;
374
-static	pthread_mutex_t	accept_mutex = PTHREAD_MUTEX_INITIALIZER;
375
-static	pthread_cond_t	accept_cond = PTHREAD_COND_INITIALIZER;
376
-static	volatile	int	accept_inputs;
377 374
 static	int	child_timeout = 0;	/* number of seconds to wait for
378 375
 					 * a child to die. Set to 0 to
379 376
 					 * wait forever
... ...
@@ -1051,11 +1049,9 @@ main(int argc, char **argv)
1051 1051
 
1052 1052
 		if(cfgopt(copt, "LogVerbose")) {
1053 1053
 			logVerbose = 1;
1054
-#if	0
1055
-#if	SENDMAIL_VERSION > 8.13
1054
+#if	((SENDMAIL_VERSION_A > 8) || ((SENDMAIL_VERSION_A == 8) && (SENDMAIL_VERSION_B >= 13)))
1056 1055
 			smfi_setdbg(6);
1057 1056
 #endif
1058
-#endif
1059 1057
 		}
1060 1058
 		use_syslog = 1;
1061 1059
 
... ...
@@ -1485,7 +1481,6 @@ main(int argc, char **argv)
1485 1485
 				limits.archivememlim = 0;
1486 1486
 		}
1487 1487
 	}
1488
-	accept_inputs = 1;
1489 1488
 
1490 1489
 #ifdef	SESSION
1491 1490
 	/* FIXME: add localSocket support to watchdog */
... ...
@@ -1573,14 +1568,12 @@ main(int argc, char **argv)
1573 1573
 		return EX_UNAVAILABLE;
1574 1574
 	}
1575 1575
 
1576
-#if	0
1577
-#if	SENDMAIL_VERSION > 8.13
1576
+#if	((SENDMAIL_VERSION_A > 8) || ((SENDMAIL_VERSION_A == 8) && (SENDMAIL_VERSION_B >= 13)))
1578 1577
 	if(smfi_opensocket(1) == MI_FAILURE) {
1579 1578
 		cli_errmsg("Can't open/create %s\n", port);
1580 1579
 		return EX_CONFIG;
1581 1580
 	}
1582 1581
 #endif
1583
-#endif
1584 1582
 
1585 1583
 	signal(SIGPIPE, SIG_IGN);	/* libmilter probably does this as well */
1586 1584
 
... ...
@@ -1991,34 +1984,10 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
1991 1991
 	char ip[INET_ADDRSTRLEN];	/* IPv4 only */
1992 1992
 #endif
1993 1993
 	const char *remoteIP;
1994
-	int accepting;
1995 1994
 
1996 1995
 	if(quitting)
1997 1996
 		return cl_error;
1998 1997
 
1999
-	pthread_mutex_lock(&accept_mutex);
2000
-	accepting = accept_inputs;
2001
-	pthread_mutex_unlock(&accept_mutex);
2002
-	if(!accepting) {
2003
-		cli_warnmsg("Not accepting inputs at the moment\n");
2004
-#if	0
2005
-		/*
2006
-		 * We must refuse here even if dont_wait isn't set, since
2007
-		 * it could take some time, and sendmail could time us out
2008
-		 * and refuse to have anything more to do with us until
2009
-		 * the program is restarted
2010
-		 */
2011
-		if(dont_wait)
2012
-			return SMFIS_TEMPFAIL;
2013
-		pthread_mutex_lock(&accept_mutex);
2014
-		while(!accept_inputs)
2015
-			pthread_cond_wait(&accept_cond, &accept_mutex);
2016
-		pthread_mutex_unlock(&accept_mutex);
2017
-		cli_warnmsg("Accepting inputs again\n");
2018
-#endif
2019
-		return SMFIS_TEMPFAIL;
2020
-	}
2021
-
2022 1998
 	if(ctx == NULL) {
2023 1999
 		if(use_syslog)
2024 2000
 			syslog(LOG_ERR, _("clamfi_connect: ctx is null"));
... ...
@@ -2604,12 +2573,21 @@ clamfi_eom(SMFICTX *ctx)
2604 2604
 	if(!external) {
2605 2605
 		const char *virname;
2606 2606
 		unsigned long int scanned = 0L;
2607
+		struct cl_node *scanning_root;
2607 2608
 
2608 2609
 		/*
2609 2610
 		 * TODO: consider using cl_scandesc and not using a temporary
2610 2611
 		 *	file from the mail being read in
2611 2612
 		 */
2612
-		switch(cl_scanfile(privdata->filename, &virname, &scanned, root, &limits, options)) {
2613
+		pthread_mutex_lock(&root_mutex);
2614
+		scanning_root = cl_dup(root);
2615
+		pthread_mutex_unlock(&root_mutex);
2616
+		if(scanning_root == NULL) {
2617
+			cli_errmsg("scanning_root == NULL\n");
2618
+			clamfi_cleanup(ctx);
2619
+			return cl_error;
2620
+		}
2621
+		switch(cl_scanfile(privdata->filename, &virname, &scanned, scanning_root, &limits, options)) {
2613 2622
 			case CL_CLEAN:
2614 2623
 				strcpy(mess, "OK");
2615 2624
 				break;
... ...
@@ -2622,6 +2600,7 @@ clamfi_eom(SMFICTX *ctx)
2622 2622
 				logger(mess);
2623 2623
 				break;
2624 2624
 		}
2625
+		cl_free(scanning_root);
2625 2626
 
2626 2627
 #ifdef	SESSION
2627 2628
 		session = NULL;
... ...
@@ -4426,71 +4405,29 @@ watchdog(void *a)
4426 4426
 		pthread_mutex_unlock(&watchdog_mutex);
4427 4427
 
4428 4428
 		if(!external) {
4429
-			int dbstatus = cl_statchkdir(&dbstat);
4430
-
4431 4429
 			/*
4432
-			 * Re-load the database if the server's not busy.
4433
-			 * TODO: If a reload is needed go into a mode when
4434
-			 *	new scans aren't accepted, to force the number
4435
-			 *	of children to 0 so that we can reload,
4436
-			 *	otherwise a reload may not occur on overloaded
4437
-			 *	servers
4430
+			 * Re-load the database if needed
4438 4431
 			 */
4439
-			pthread_mutex_lock(&n_children_mutex);
4440
-			if((n_children == 0) && (dbstatus == 1)) {
4441
-				pthread_mutex_lock(&accept_mutex);
4442
-				accept_inputs = 0;
4443
-				pthread_mutex_unlock(&accept_mutex);
4444
-				cli_dbgmsg("Database has changed\n");
4445
-				cl_statfree(&dbstat);
4446
-				/* check for race condition */
4447
-				while(n_children > 0)
4448
-					pthread_cond_wait(&n_children_cond, &n_children_mutex);
4449
-				if(use_syslog)
4450
-					syslog(LOG_WARNING, _("Loading new database"));
4451
-				if(loadDatabase() != 0) {
4452
-					pthread_mutex_unlock(&n_children_mutex);
4453
-					smfi_stop();
4454
-					cli_errmsg("Failed to load updated database\n");
4455
-					return NULL;
4456
-				}
4457
-				pthread_mutex_lock(&accept_mutex);
4458
-				accept_inputs = 1;
4459
-				pthread_cond_broadcast(&accept_cond);
4460
-				pthread_mutex_unlock(&accept_mutex);
4461
-			} else if(dbstatus == 0)
4462
-				cli_dbgmsg("Database has not changed\n");
4463
-			else if(dbstatus == 1) {
4464
-				cli_warnmsg("Not reloading database until idle - waiting for %d children\n", n_children);
4465
-				pthread_mutex_lock(&accept_mutex);
4466
-				accept_inputs = 0;
4467
-				pthread_mutex_unlock(&accept_mutex);
4468
-
4469
-				while(n_children > 0) {
4470
-					pthread_cond_wait(&n_children_cond, &n_children_mutex);
4471
-					cli_warnmsg("Waiting for %d children until database reload\n", n_children);
4472
-				}
4473
-
4474
-				cl_statfree(&dbstat);
4475
-				if(use_syslog)
4476
-					syslog(LOG_WARNING, _("Loading new database"));
4477
-				if(loadDatabase() != 0) {
4478
-					pthread_mutex_unlock(&n_children_mutex);
4432
+			switch(cl_statchkdir(&dbstat)) {
4433
+				case 1:
4434
+					cli_dbgmsg("Database has changed\n");
4435
+					cl_statfree(&dbstat);
4436
+					if(use_syslog)
4437
+						syslog(LOG_WARNING, _("Loading new database"));
4438
+					if(loadDatabase() != 0) {
4439
+						smfi_stop();
4440
+						cli_errmsg("Failed to load updated database\n");
4441
+						return NULL;
4442
+					}
4443
+					break;
4444
+				case 0:
4445
+					cli_dbgmsg("Database has not changed\n");
4446
+					break;
4447
+				default:
4479 4448
 					smfi_stop();
4480
-					cli_errmsg("Failed to load updated database\n");
4449
+					cli_errmsg("Database error - %s is stopping\n", progname);
4481 4450
 					return NULL;
4482
-				}
4483
-				pthread_mutex_lock(&accept_mutex);
4484
-				accept_inputs = 1;
4485
-				pthread_cond_broadcast(&accept_cond);
4486
-				pthread_mutex_unlock(&accept_mutex);
4487
-			} else {
4488
-				smfi_stop();
4489
-				cli_errmsg("Database error - %s is stopping\n", progname);
4490
-				pthread_mutex_unlock(&n_children_mutex);
4491
-				return NULL;
4492 4451
 			}
4493
-			pthread_mutex_unlock(&n_children_mutex);
4494 4452
 			continue;
4495 4453
 		}
4496 4454
 		i = 0;
... ...
@@ -4597,7 +4534,6 @@ watchdog(void *a)
4597 4597
 	while(!quitting) {
4598 4598
 		struct timespec ts;
4599 4599
 		struct timeval tp;
4600
-		int dbstatus;
4601 4600
 
4602 4601
 		gettimeofday(&tp, NULL);
4603 4602
 
... ...
@@ -4621,69 +4557,29 @@ watchdog(void *a)
4621 4621
 		pthread_mutex_unlock(&watchdog_mutex);
4622 4622
 
4623 4623
 		/*
4624
-		 * Re-load the database if the server's not busy.
4625
-		 * TODO: If a reload is needed go into a mode when
4626
-		 *	new scans aren't accepted, to force the number
4627
-		 *	of children to 0 so that we can reload,
4628
-		 *	otherwise a reload may not occur on overloaded
4629
-		 *	servers
4624
+		 * Re-load the database.
4630 4625
 		 */
4631
-		dbstatus = cl_statchkdir(&dbstat);
4632
-		pthread_mutex_lock(&n_children_mutex);
4633
-		if((n_children == 0) && (dbstatus == 1)) {
4634
-			pthread_mutex_lock(&accept_mutex);
4635
-			accept_inputs = 0;
4636
-			pthread_mutex_unlock(&accept_mutex);
4637
-			cli_dbgmsg("Database has changed\n");
4638
-			cl_statfree(&dbstat);
4639
-			/* check for race condition */
4640
-			while(n_children > 0)
4641
-				pthread_cond_wait(&n_children_cond, &n_children_mutex);
4642
-			if(use_syslog)
4643
-				syslog(LOG_WARNING, _("Loading new database"));
4644
-			if(loadDatabase() != 0) {
4645
-				pthread_mutex_unlock(&n_children_mutex);
4646
-				smfi_stop();
4647
-				cli_errmsg("Failed to load updated database\n");
4648
-				return NULL;
4649
-			}
4650
-			pthread_mutex_lock(&accept_mutex);
4651
-			accept_inputs = 1;
4652
-			pthread_cond_broadcast(&accept_cond);
4653
-			pthread_mutex_unlock(&accept_mutex);
4654
-		} else if(dbstatus == 0)
4655
-			cli_dbgmsg("Database has not changed\n");
4656
-		else if(dbstatus == 1) {
4657
-			cli_warnmsg("Not reloading database until idle - waiting for %d children\n", n_children);
4658
-			pthread_mutex_lock(&accept_mutex);
4659
-			accept_inputs = 0;
4660
-			pthread_mutex_unlock(&accept_mutex);
4661
-
4662
-			while(n_children > 0) {
4663
-				pthread_cond_wait(&n_children_cond, &n_children_mutex);
4664
-				cli_warnmsg("Waiting for %d children until database reload\n", n_children);
4665
-			}
4666
-			cl_statfree(&dbstat);
4667
-			if(use_syslog)
4668
-				syslog(LOG_WARNING, _("Loading new database"));
4669
-			if(loadDatabase() != 0) {
4670
-				pthread_mutex_unlock(&n_children_mutex);
4626
+		switch(cl_statchkdir(&dbstat)) {
4627
+			case 1:
4628
+				cli_dbgmsg("Database has changed\n");
4629
+				cl_statfree(&dbstat);
4630
+				if(use_syslog)
4631
+					syslog(LOG_WARNING, _("Loading new database"));
4632
+				if(loadDatabase() != 0) {
4633
+					smfi_stop();
4634
+					cli_errmsg("Failed to load updated database\n");
4635
+					return NULL;
4636
+				}
4637
+				break;
4638
+			case 0:
4639
+				cli_dbgmsg("Database has not changed\n");
4640
+				break;
4641
+			default:
4671 4642
 				smfi_stop();
4672
-				cli_errmsg("Failed to load updated database\n");
4643
+				cli_errmsg("Database error - %s is stopping\n", progname);
4673 4644
 				return NULL;
4674
-			}
4675
-			pthread_mutex_lock(&accept_mutex);
4676
-			accept_inputs = 1;
4677
-			if(pthread_cond_broadcast(&accept_cond) < 0)
4678
-				perror("pthread_cond_broadcast");
4679
-			pthread_mutex_unlock(&accept_mutex);
4680
-		} else {
4681
-			smfi_stop();
4682
-			cli_errmsg("Database error - %s is stopping\n", progname);
4683
-			pthread_mutex_unlock(&n_children_mutex);
4684
-			return NULL;
4685 4645
 		}
4686
-		pthread_mutex_unlock(&n_children_mutex);
4646
+		continue;
4687 4647
 	}
4688 4648
 	cli_dbgmsg("watchdog quits\n");
4689 4649
 	return NULL;
... ...
@@ -4779,10 +4675,6 @@ quit(void)
4779 4779
 
4780 4780
 	quitting++;
4781 4781
 
4782
-	pthread_mutex_lock(&accept_mutex);
4783
-	accept_inputs = 0;
4784
-	pthread_mutex_unlock(&accept_mutex);
4785
-
4786 4782
 #ifdef	SESSION
4787 4783
 	pthread_mutex_lock(&version_mutex);
4788 4784
 #endif
... ...
@@ -4793,10 +4685,12 @@ quit(void)
4793 4793
 #endif
4794 4794
 
4795 4795
 	if(!external) {
4796
+		pthread_mutex_lock(&root_mutex);
4796 4797
 		if(root) {
4797 4798
 			cl_free(root);
4798 4799
 			root = NULL;
4799 4800
 		}
4801
+		pthread_mutex_unlock(&root_mutex);
4800 4802
 	} else {
4801 4803
 #ifdef	SESSION
4802 4804
 		int i = 0;
... ...
@@ -4862,8 +4756,7 @@ broadcast(const char *mess)
4862 4862
 }
4863 4863
 
4864 4864
 /*
4865
- * Load a new database into the internal scanner - it is up to the caller to
4866
- * ensure that no threads are currently scanning
4865
+ * Load a new database into the internal scanner
4867 4866
  */
4868 4867
 static int
4869 4868
 loadDatabase(void)
... ...
@@ -4875,6 +4768,7 @@ loadDatabase(void)
4875 4875
 	char *daily, *ptr;
4876 4876
 	struct cl_cvd *d;
4877 4877
 	const struct cfgstruct *cpt;
4878
+	struct cl_node *newroot, *oldroot;
4878 4879
 	static const char *dbdir;
4879 4880
 
4880 4881
 	assert(!external);
... ...
@@ -4933,30 +4827,30 @@ loadDatabase(void)
4933 4933
 	if((ptr = strchr(clamav_version, '\n')) != NULL)
4934 4934
 		*ptr = '\0';
4935 4935
 
4936
-	if(root) {
4937
-		cl_free(root);
4938
-		root = NULL;
4939
-	}
4940 4936
 	signatures = 0;
4941
-	ret = cl_loaddbdir(dbdir, &root, &signatures);
4937
+	newroot = NULL;
4938
+	ret = cl_loaddbdir(dbdir, &newroot, &signatures);
4942 4939
 	if(ret != 0) {
4943 4940
 		cli_errmsg("%s\n", cl_strerror(ret));
4944 4941
 		return -1;
4945 4942
 	}
4946
-	if(root == NULL) {
4943
+	if(newroot == NULL) {
4947 4944
 		cli_errmsg("Can't initialize the virus database.\n");
4948 4945
 		return -1;
4949 4946
 	}
4950 4947
 
4951
-	ret = cl_build(root);
4948
+	ret = cl_build(newroot);
4952 4949
 	if(ret != 0) {
4953 4950
 		cli_errmsg("Database initialization error: %s\n", cl_strerror(ret));
4951
+		cl_free(newroot);
4954 4952
 		return -1;
4955 4953
 	}
4956
-	cli_dbgmsg("Database updated\n");
4957
-	if(use_syslog) {
4958
-		syslog(LOG_INFO, _("ClamAV: Protecting against %u viruses"), signatures);
4954
+	pthread_mutex_lock(&root_mutex);
4955
+	oldroot = root;
4956
+	root = newroot;
4957
+	pthread_mutex_unlock(&root_mutex);
4959 4958
 
4959
+	if(use_syslog) {
4960 4960
 #ifdef	SESSION
4961 4961
 		pthread_mutex_lock(&version_mutex);
4962 4962
 #endif
... ...
@@ -4964,7 +4858,13 @@ loadDatabase(void)
4964 4964
 #ifdef	SESSION
4965 4965
 		pthread_mutex_unlock(&version_mutex);
4966 4966
 #endif
4967
+		syslog(LOG_INFO, _("ClamAV: Protecting against %u viruses"), signatures);
4967 4968
 	}
4969
+	if(oldroot) {
4970
+		cli_dbgmsg("Database updated\n");
4971
+		cl_free(oldroot);
4972
+	} else
4973
+		cli_dbgmsg("Database loaded\n");
4968 4974
 
4969 4975
 	return cl_statinidir(dbdir, &dbstat);
4970 4976
 }