diff -up cronie-1.1/src/cron.c.inotify-fixes cronie-1.1/src/cron.c
--- cronie-1.1/src/cron.c.inotify-fixes	2008-06-18 22:49:02.000000000 +0200
+++ cronie-1.1/src/cron.c	2008-06-18 23:15:15.000000000 +0200
@@ -47,48 +47,56 @@ static	int			timeRunning, virtualTime, c
 static	long			GMToff;
 
 #if defined WITH_INOTIFY
-int wd1, wd2, wd3, wd4;
 
-void
-set_cron_watched(int fd) {
-    pid_t pid = getpid();
-
-    wd1 = inotify_add_watch(fd, CRONDIR, IN_MODIFY | IN_DELETE | IN_CREATE | IN_ATTRIB);
-    if (wd1 < 0) 
-        log_it("CRON", pid, "This directory can't be watched", CRONDIR, errno);
+#define NUM_WATCHES 3
 
-    wd2 = inotify_add_watch(fd, RH_CROND_DIR, IN_MODIFY | IN_DELETE | IN_CREATE | IN_ATTRIB);
-    if (wd2 < 0) 
-        log_it("CRON", pid, "This directory can't be watched", RH_CROND_DIR, errno);
+int wd[NUM_WATCHES];
+const char *watchpaths[NUM_WATCHES] = { SPOOL_DIR, RH_CROND_DIR, SYSCRONTAB };
 
-    wd3 = inotify_add_watch(fd, SYSCRONTAB, IN_MODIFY | IN_DELETE | IN_CREATE | IN_ATTRIB);
-    if (wd3 < 0) 
-        log_it("CRON", pid, "This file can't be watched", SYSCRONTAB, errno);
+void
+set_cron_unwatched(int fd) {
+	int i;
+	
+	for (i = 0; i < sizeof(wd)/sizeof(wd[0]); ++i) {
+		if (wd[i] < 0) {
+			inotify_rm_watch(fd, wd[i]);
+			wd[i] = -1;
+		}
+	}
+}
 
-    wd4 = inotify_add_watch(fd, "/var/spool/cron/", IN_MODIFY | IN_DELETE | IN_CREATE | IN_ATTRIB);
-    if (wd4 < 0)
-        log_it("CRON", pid, "This directory can't be watched", "/var/spool/cron", errno);
+void
+set_cron_watched(int fd) {
+	pid_t pid = getpid();
+	int i;
 
-	if (wd1 <0 || wd2<0 || wd3<0 || wd4<0) {
+	if (fd < 0) {
 		inotify_enabled = 0;
-		log_it("CRON", pid, "INFO", "running without inotify support", 0);
+		return;
 	}
-	else
-		inotify_enabled = 1;
-}
 
-void
-set_cron_unwatched(int fd) {
-    int ret1, ret2, ret3, ret4;
+	for (i = 0; i < sizeof(wd)/sizeof(wd[0]); ++i) {
+		int w;
+
+		w = inotify_add_watch(fd, watchpaths[i],
+			IN_CLOSE_WRITE | IN_ATTRIB | IN_MOVED_TO | IN_MOVED_FROM | IN_MOVE_SELF | IN_DELETE);
+		if (w < 0) {
+			if (wd[i] != -1) {
+        			log_it("CRON", pid, "This directory or file can't be watched", watchpaths[i], errno);
+				log_it("CRON", pid, "INFO", "running without inotify support", 0);
+			}
+			inotify_enabled = 0;
+			set_cron_unwatched(fd);
+			return;
+		}
+		wd[i] = w;
+	}
 
-	if (wd1 >= 0)
-		ret1 = inotify_rm_watch(fd, wd1);
-	if (wd2 >= 0)
-		ret2 = inotify_rm_watch(fd, wd2);
-	if (wd3 >= 0)
-		ret3 = inotify_rm_watch(fd, wd3);
-	if (wd4 >= 0)
-		ret4 = inotify_rm_watch(fd, wd4);
+	if (!inotify_enabled) {
+		log_it("CRON", pid, "INFO", "running with inotify support", 0);
+	}
+
+	inotify_enabled = 1;
 }
 #endif
 
@@ -110,12 +118,8 @@ main(int argc, char *argv[]) {
 	int fd;
 	char *cs;
 	pid_t pid = getpid();
-
 #if defined WITH_INOTIFY
-	int fildes;
-	fildes = inotify_init();
-	if (fildes < 0)
-		log_it("CRON", pid, "INFO", "Inotify init failed", errno);
+	int i;
 #endif
 
 	ProgramName = argv[0];
@@ -146,9 +150,6 @@ main(int argc, char *argv[]) {
 
 	acquire_daemonlock(0);
 	set_cron_uid();
-#if defined WITH_INOTIFY
-	set_cron_watched(fildes);
-#endif
 	set_cron_cwd();
 
 	if (putenv("PATH="_PATH_DEFPATH) < 0) {
@@ -191,10 +192,7 @@ main(int argc, char *argv[]) {
 				if (fd != STDERR)
 					(void) close(fd);
 			}
-			if (inotify_enabled) 
-				log_it("CRON", getpid(), "STARTUP INOTIFY", PACKAGE_VERSION, 0);
-			else 
-				log_it("CRON", getpid(), "STARTUP", PACKAGE_VERSION, 0);
+			log_it("CRON", getpid(), "STARTUP", PACKAGE_VERSION, 0);
 			break;
 		default:
 			/* parent process should just die */
@@ -202,18 +200,28 @@ main(int argc, char *argv[]) {
 		}
 	}
 
+	pid = getpid();
 	acquire_daemonlock(0);
 	database.head = NULL;
 	database.tail = NULL;
-	if (inotify_enabled) {
+	database.mtime = (time_t) 0;
+
+	load_database(&database);
+
 #if defined WITH_INOTIFY
-		load_inotify_database(&database, fildes);
-#endif
-	}
-	else {
-		database.mtime = (time_t) 0;
-		load_database(&database);
+	for (i = 0; i < sizeof(wd)/sizeof(wd[0]); ++i) {
+		/* initialize to negative number other than -1
+		 * so an eventual error is reported for the first time
+		 */
+		wd[i] = -2;
 	}
+
+	fd = inotify_init();
+	if (fd < 0)
+		log_it("CRON", pid, "INFO", "Inotify init failed", errno);
+	set_cron_watched(fd);
+#endif
+
 	set_time(TRUE);
 	run_reboot_jobs(&database);
 	timeRunning = virtualTime = clockTime;
@@ -246,12 +254,17 @@ main(int argc, char *argv[]) {
 		timeDiff = timeRunning - virtualTime;
 		if (inotify_enabled) {
 #if defined WITH_INOTIFY
-			check_inotify_database(&database, fildes);
+			check_inotify_database(&database, fd);
 #endif
 		}
-		else
+		else {
 			load_database(&database);
-
+#if defined WITH_INOTIFY
+			/* try reinstating the watches */
+			set_cron_watched(fd);
+#endif			
+		}
+		
 		/* shortcut for the most common case */
 		if (timeDiff == 1) {
 			virtualTime = timeRunning;
@@ -275,7 +288,7 @@ main(int argc, char *argv[]) {
 				 * minute until caught up.
 				 */
 				Debug(DSCH, ("[%ld], normal case %d minutes to go\n",
-				    (long)getpid(), timeDiff))
+				    (long)pid, timeDiff))
 				do {
 					if (job_runqueue())
 						sleep(10);
@@ -297,7 +310,7 @@ main(int argc, char *argv[]) {
 				 * housekeeping.
 				 */
 				Debug(DSCH, ("[%ld], DST begins %d minutes to go\n",
-				    (long)getpid(), timeDiff))
+				    (long)pid, timeDiff))
 				/* run wildcard jobs for current minute */
 				find_jobs(timeRunning, &database, TRUE, FALSE);
 	
@@ -323,7 +336,7 @@ main(int argc, char *argv[]) {
 				 * change until we are caught up.
 				 */
 				Debug(DSCH, ("[%ld], DST ends %d minutes to go\n",
-				    (long)getpid(), timeDiff))
+				    (long)pid, timeDiff))
 				find_jobs(timeRunning, &database, TRUE, FALSE);
 				break;
 			default:
@@ -332,7 +345,7 @@ main(int argc, char *argv[]) {
 				 * jump virtual time, and run everything
 				 */
 				Debug(DSCH, ("[%ld], clock jumped\n",
-				    (long)getpid()))
+				    (long)pid))
 				virtualTime = timeRunning;
 				find_jobs(timeRunning, &database, TRUE, TRUE);
 			}
@@ -353,14 +366,13 @@ main(int argc, char *argv[]) {
 			sigchld_reaper();
 		}
 	}
-	/* here stay ifdef, because some of the watches can be used even
- 	* if inotify is disabled 
- 	*/
+
 #if defined WITH_INOTIFY
-	set_cron_unwatched(fildes);
+	if (inotify_enabled)
+		set_cron_unwatched(fd);
 
-	if (fildes >= 0 && close(fildes) < 0)
-		log_it("CRON", pid, "INFO", "Inotify can't remove watches", errno);
+	if (fd >= 0 && close(fd) < 0)
+		log_it("CRON", pid, "INFO", "Inotify close failed", errno);
 #endif
 }
 
diff -up cronie-1.1/src/database.c.inotify-fixes cronie-1.1/src/database.c
--- cronie-1.1/src/database.c.inotify-fixes	2008-06-18 22:49:02.000000000 +0200
+++ cronie-1.1/src/database.c	2008-06-18 22:49:02.000000000 +0200
@@ -32,14 +32,10 @@
 /* reasonable guess as to size of 1024 events */
 #define BUF_LEN 	(1024 * (EVENT_SIZE + 16))
 
-#if defined WITH_INOTIFY
-/* state say if we change the crontable */
-#define RELOAD		1
-void unlink_inotify_database(cron_db *, cron_db , int);
-#endif
+void overwrite_database(cron_db *, cron_db *);
 
 static	void		process_crontab(const char *, const char *,
-					const char *, struct stat *,
+					const char *,
 					cron_db *, cron_db *);
 
 static int not_a_crontab( DIR_T *dp ); 
@@ -48,10 +44,9 @@ static int not_a_crontab( DIR_T *dp ); 
 static void max_mtime( char *dir_name, struct stat *max_st ); 
 /* record max mtime of any file under dir_name in max_st */
 
-#if defined WITH_INOTIFY
 int
 check_open(const char *tabname, const char *fname, const char *uname,
-		struct passwd *pw) {
+		struct passwd *pw, time_t *mtime) {
 	struct stat statbuf;
 	int crontab_fd;
 	pid_t pid = getpid();
@@ -60,12 +55,13 @@ check_open(const char *tabname, const ch
 		log_it(uname, pid, "CAN'T OPEN", tabname, errno);
 		return(-1);
 	}
+	if (fstat(crontab_fd, &statbuf) < OK) {
+		log_it(uname, pid, "STAT FAILED", tabname, errno);
+		close(crontab_fd);
+		return(-1);
+	}
+	*mtime = statbuf.st_mtime;
 	if (PermitAnyCrontab == 0) {
-		if (fstat(crontab_fd, &statbuf) < OK) {
-			log_it(uname, pid, "STAT FAILED", tabname, errno);
-			close(crontab_fd);
-			return(-1);
-		}
 		if (!S_ISREG(statbuf.st_mode)) {
 			log_it(uname, pid, "NOT REGULAR", tabname, 0);
 			close(crontab_fd);
@@ -92,12 +88,12 @@ check_open(const char *tabname, const ch
 }
 
 void
-process_inotify_crontab(const char *uname, const char *fname, const char *tabname,
-	cron_db *new_db, cron_db *old_db, int fd, int state) {
+process_crontab(const char *uname, const char *fname, const char *tabname,
+	cron_db *new_db, cron_db *old_db) {
 	struct passwd *pw = NULL;
 	int crontab_fd = -1;
 	user *u;
-	struct stat statbuf;
+	time_t mtime;
 	int crond_crontab = (fname == NULL) && (strcmp(tabname, SYSCRONTAB) != 0);
 
 	if (fname == NULL) {
@@ -111,43 +107,42 @@ process_inotify_crontab(const char *unam
 		goto next_crontab;
 	}
 	
+	if ((crontab_fd = check_open(tabname, fname, uname, pw, &mtime)) == -1)
+		goto next_crontab;
+
 	Debug(DLOAD, ("\t%s:", fname))
-	u = find_user(old_db, fname, crond_crontab ? tabname : NULL );	/* goes only through database in memory */
 
-	/* in first run is database empty. Check permission when -p ISN'T used. */
-	if (u == NULL) {
-		if ((crontab_fd = check_open(tabname, fname, uname, pw)) == -1)
-			goto next_crontab;
-	}
-	else {		/* second and other runs */
+	u = find_user(old_db, fname, crond_crontab ? tabname : NULL );	/* find user in old_db */
+
+	if (u != NULL) {
 		/* if crontab has not changed since we last read it
-		* in, then we can just use our existing entry.
-		*/
-		/* 6 because we want string reload or none */
-		if (state != RELOAD) {
+		 * in, then we can just use our existing entry.
+		 */
+		if (u->mtime == mtime) {
 			Debug(DLOAD, (" [no change, using old data]"))
 			unlink_user(old_db, u);
 			link_user(new_db, u);
 			goto next_crontab;
 		}
-		/* before we fall through to the code that will reload
-		* the user, let's deallocate and unlink the user in
-		* the old database.  This is more a point of memory
-		* efficiency than anything else, since all leftover
-		* users will be deleted from the old database when
-		* we finish with the crontab...
-		*/
-		if ((crontab_fd = check_open(tabname, fname, uname, pw)) == -1)
-			goto next_crontab;
 
+		/* before we fall through to the code that will reload
+		 * the user, let's deallocate and unlink the user in
+		 * the old database.  This is more a point of memory
+		 * efficiency than anything else, since all leftover
+		 * users will be deleted from the old database when
+		 * we finish with the crontab...
+		 */
 		Debug(DLOAD, (" [delete old data]"))
 		unlink_user(old_db, u);
 		free_user(u);
-		Debug(DSCH, ("RELOAD %s\n", tabname))
+		log_it(fname, getpid(), "RELOAD", tabname, 0);
 	}
-	u = load_user(crontab_fd, pw, uname, fname, tabname);	/* touch the disk */
-	if (u != NULL)
+
+	u = load_user(crontab_fd, pw, uname, fname, tabname);	/* read the file */
+	if (u != NULL) {
+		u->mtime = mtime;
 		link_user(new_db, u);
+	}
 
   next_crontab:
 	if (crontab_fd != -1) {
@@ -156,57 +151,7 @@ process_inotify_crontab(const char *unam
 	}
 }
 
-void
-load_inotify_database(cron_db *old_db, int fd) {
-	cron_db new_db;
-	DIR_T *dp;
-	DIR *dir;
-	pid_t pid = getpid();
-
-	new_db.head = new_db.tail = NULL;
-	process_inotify_crontab("root", NULL, SYSCRONTAB, &new_db, old_db, fd, RELOAD);
-
-	/* RH_CROND_DIR /etc/cron.d */
-	if (!(dir = opendir(RH_CROND_DIR))) {
-		log_it("CRON", pid, "OPENDIR FAILED", RH_CROND_DIR, errno);
-		(void) exit(ERROR_EXIT);
-	}
-	while (NULL != (dp = readdir(dir))) {
-		char tabname[MAXNAMLEN+1];
-
-		if (not_a_crontab(dp))
-			continue;
-
-		if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
-			continue;
-		
-		process_inotify_crontab("root", NULL, tabname, &new_db, old_db, fd, RELOAD);
-	}
-	closedir(dir);
-	/* SPOOL_DIR */
-	if (!(dir = opendir(SPOOL_DIR))) {
-		log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
-		(void) exit(ERROR_EXIT);
-	}
-
-	while (NULL != (dp = readdir(dir))) {
-		char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
-
-		if (not_a_crontab(dp))
-			continue;
-
-		strncpy(fname, dp->d_name, MAXNAMLEN);
-
-		if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
-			continue;
-
-		process_inotify_crontab(fname, fname, tabname, &new_db, old_db, fd, RELOAD);
-	}
-	closedir(dir);
-
-	unlink_inotify_database(old_db, new_db, fd);
-}
-
+#if defined WITH_INOTIFY
 void
 check_inotify_database(cron_db *old_db, int fd) {
 	cron_db new_db;
@@ -218,7 +163,7 @@ check_inotify_database(cron_db *old_db, 
 	char buf[BUF_LEN];
 	pid_t pid = getpid();
 
-	time.tv_sec = 1;
+	time.tv_sec = 0;
 	time.tv_usec = 0;
 
 	FD_ZERO(&rfds);
@@ -226,110 +171,83 @@ check_inotify_database(cron_db *old_db, 
 
 	retval = select(fd + 1, &rfds, NULL, NULL, &time);
 	if (retval == -1) {
-		log_it("CRON", pid, "INOTIFY", "select failed", errno);
+		if (errno != EINTR)
+			log_it("CRON", pid, "INOTIFY", "select failed", errno);
+		return;
 	}
 	else if (FD_ISSET(fd, &rfds)) {
 		new_db.head = new_db.tail = NULL;
-		if (read(fd, buf, sizeof(buf)) == -1)
-			log_it("CRON", pid, "INOTIFY", "read failed", errno);
-		process_inotify_crontab("root", NULL, SYSCRONTAB, &new_db, old_db, fd, RELOAD);
+		while ((retval=read(fd, buf, sizeof(buf))) == -1 && errno == EINTR);
 
-		if (!(dir = opendir(RH_CROND_DIR))) {
-			log_it("CRON", pid, "OPENDIR FAILED", RH_CROND_DIR, errno);
-			(void) exit(ERROR_EXIT);
+		if (retval == 0) {
+			/* this should not happen as the buffer is large enough */
+			errno = ENOMEM;
 		}
-		while (NULL != (dp = readdir(dir))) {
-			char tabname[MAXNAMLEN+1];
-
-			if (not_a_crontab(dp))
-				continue;
 
-			if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
-				continue;
-			process_inotify_crontab("root", NULL, tabname, &new_db, old_db, fd, RELOAD);
-		}
-		closedir(dir);
-
-		if (!(dir = opendir(SPOOL_DIR))) {
-			log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
+		if (retval <= 0) {
+			log_it("CRON", pid, "INOTIFY", "read failed", errno);
+			/* something fatal must have occured we have no other reasonable
+			 * way how to handle this failure than exit.
+			 */
 			(void) exit(ERROR_EXIT);
 		}
-		while (NULL != (dp = readdir(dir))) {
-			char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
+		
+		/* we must reinstate the watches here - TODO reinstate only watches
+		 * which get IN_IGNORED event
+		 */
+		set_cron_watched(fd);
 
-			if (not_a_crontab(dp))
-				continue;
+		/* TODO: parse the events and read only affected files */
 
-			strncpy(fname, dp->d_name, MAXNAMLEN);
+		process_crontab("root", NULL, SYSCRONTAB, &new_db, old_db);
 
-			if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, dp->d_name, '/'))
-				continue;
-			process_inotify_crontab(fname, fname, tabname, &new_db, old_db, fd, RELOAD);
-		}
-		closedir(dir);
-	}
-	else {
-		new_db.head = new_db.tail = NULL;
-		process_inotify_crontab("root", NULL, SYSCRONTAB, &new_db, old_db, fd, !RELOAD);
 		if (!(dir = opendir(RH_CROND_DIR))) {
 			log_it("CRON", pid, "OPENDIR FAILED", RH_CROND_DIR, errno);
-			(void) exit(ERROR_EXIT);
+		} else {
+			while (NULL != (dp = readdir(dir))) {
+				char tabname[MAXNAMLEN+1];
+
+				if (not_a_crontab(dp))
+					continue;
+
+				if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
+					continue;
+				process_crontab("root", NULL, tabname, &new_db, old_db);
+			}
+			closedir(dir);
 		}
 
-		while (NULL != (dp = readdir(dir))) {
-			char tabname[MAXNAMLEN+1];
-
-			if (not_a_crontab(dp))
-				continue;
-
-			if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
-				continue;
-			process_inotify_crontab("root", NULL, tabname, &new_db, old_db, fd, !RELOAD);
-		}
-		closedir(dir);
-
 		if (!(dir = opendir(SPOOL_DIR))) {
 			log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
-			(void) exit(ERROR_EXIT);
-		}
+		} else {
+			while (NULL != (dp = readdir(dir))) {
+				char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
 
-		while (NULL != (dp = readdir(dir))) {
-			char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
+				if (not_a_crontab(dp))
+					continue;
 
-			if (not_a_crontab(dp))
-				continue;
+				strncpy(fname, dp->d_name, MAXNAMLEN);
 
-			strncpy(fname, dp->d_name, MAXNAMLEN);
-
-			if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
-				continue;
-
-			process_inotify_crontab(fname, fname, tabname, &new_db, old_db, fd, !RELOAD);
+				if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, dp->d_name, '/'))
+					continue;
+				process_crontab(fname, fname, tabname, &new_db, old_db);
+			}
+			closedir(dir);
 		}
-		closedir(dir);
-	}
-	FD_CLR(fd, &rfds);
-
-	unlink_inotify_database(old_db, new_db, fd);
-}
 
-void
-unlink_inotify_database(cron_db *old_db, cron_db new_db, int fd) {
-	user *u, *nu;
-	/* whatever's left in the old database is now junk.
-	*/
-	Debug(DLOAD, ("unlinking old database:\n"))
-	for (u = old_db->head;  u != NULL;  u = nu) {
-		Debug(DLOAD, ("\t%s\n", u->name))
-		nu = u->next;
-		unlink_user(old_db, u);
-		free_user(u);
+		/* if we don't do this, then when our children eventually call
+		 * getpwnam() in do_command.c's child_process to verify MAILTO=,
+		 * they will screw us up (and v-v).
+		 */
+		endpwent();
+	}
+	else {
+		/* just return as no db reload is needed */
+		return;
 	}
 
-	/* overwrite the database control block with the new one.
-	*/
-	*old_db = new_db;
-	Debug(DLOAD, ("load_database is done\n"))
+	overwrite_database(old_db, &new_db);
+	Debug(DLOAD, ("check_inotify_database is done\n"))
 }
 
 /*void
@@ -358,12 +276,29 @@ read_dir(char *dir_name, cron_db *new_db
 #endif
 
 void
+overwrite_database(cron_db *old_db, cron_db *new_db) {
+	user *u, *nu;
+	/* whatever's left in the old database is now junk.
+	*/
+	Debug(DLOAD, ("unlinking old database:\n"))
+	for (u = old_db->head;  u != NULL;  u = nu) {
+		Debug(DLOAD, ("\t%s\n", u->name))
+		nu = u->next;
+		unlink_user(old_db, u);
+		free_user(u);
+	}
+
+	/* overwrite the database control block with the new one.
+	*/
+	*old_db = *new_db;
+}
+
+void
 load_database(cron_db *old_db) {
 	struct stat statbuf, syscron_stat, crond_stat;
 	cron_db new_db;
 	DIR_T *dp;
 	DIR *dir;
-	user *u, *nu;
 	pid_t pid = getpid();
 
 	Debug(DLOAD, ("[%ld] load_database()\n", (long)pid))
@@ -374,22 +309,22 @@ load_database(cron_db *old_db) {
 	 */
 	if (stat(SPOOL_DIR, &statbuf) < OK) {
 		log_it("CRON", pid, "STAT FAILED", SPOOL_DIR, errno);
-		(void) exit(ERROR_EXIT);
+		statbuf.st_mtime = 0;
+	} else {
+		/* As pointed out in Red Hat bugzilla 198019, with modern Linux it
+		 * is possible to modify a file without modifying the mtime of the
+		 * containing directory. Hence, we must check the mtime of each file:
+	         */
+		max_mtime(SPOOL_DIR, &statbuf);
 	}
-	
-	/* As pointed out in Red Hat bugzilla 198019, with modern Linux it
-	 * is possible to modify a file without modifying the mtime of the
-         * containing directory. Hence, we must check the mtime of each file:
-         */
-	max_mtime(SPOOL_DIR, &statbuf);
 
 	if (stat(RH_CROND_DIR, &crond_stat) < OK) {
 		log_it("CRON", pid, "STAT FAILED", RH_CROND_DIR, errno);
-		(void) exit(ERROR_EXIT);
+		crond_stat.st_mtime = 0;
+	} else {
+		max_mtime(RH_CROND_DIR, &crond_stat);
 	}
 
-	max_mtime(RH_CROND_DIR, &crond_stat);
-
 	/* track system crontab file
 	 */
 	if (stat(SYSCRONTAB, &syscron_stat) < OK)
@@ -420,27 +355,24 @@ load_database(cron_db *old_db) {
 	new_db.head = new_db.tail = NULL;
 
 	if (syscron_stat.st_mtime)
-		process_crontab("root", NULL, SYSCRONTAB, &syscron_stat,
-				&new_db, old_db);
+		process_crontab("root", NULL, SYSCRONTAB, &new_db, old_db);
 
 	if (!(dir = opendir(RH_CROND_DIR))) {
 		log_it("CRON", pid, "OPENDIR FAILED", RH_CROND_DIR, errno);
-		(void) exit(ERROR_EXIT);
-	}
-
-	while (NULL != (dp = readdir(dir))) {
-		char   tabname[MAXNAMLEN+1];
+	} else {
+		while (NULL != (dp = readdir(dir))) {
+			char   tabname[MAXNAMLEN+1];
 
-		if ( not_a_crontab( dp ) )
-			continue;
+			if ( not_a_crontab( dp ) )
+				continue;
 
-		if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
-			continue;	/* XXX log? */
+			if (!glue_strings(tabname, sizeof tabname, RH_CROND_DIR, dp->d_name, '/'))
+				continue;	/* XXX log? */
 
-		process_crontab("root", NULL, tabname,
-				&crond_stat, &new_db, old_db);
+			process_crontab("root", NULL, tabname, &new_db, old_db);
+		}
+		closedir(dir);
 	}
-	closedir(dir);
 
 	/* we used to keep this dir open all the time, for the sake of
 	 * efficiency.  however, we need to close it in every fork, and
@@ -449,24 +381,22 @@ load_database(cron_db *old_db) {
 
 	if (!(dir = opendir(SPOOL_DIR))) {
 		log_it("CRON", pid, "OPENDIR FAILED", SPOOL_DIR, errno);
-		(void) exit(ERROR_EXIT);
-	}
-
-	while (NULL != (dp = readdir(dir))) {
-		char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
+	} else {
+		while (NULL != (dp = readdir(dir))) {
+			char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
 
-		if ( not_a_crontab( dp ) )
-			continue;
+			if ( not_a_crontab( dp ) )
+				continue;
 
-		strncpy(fname, dp->d_name, MAXNAMLEN);
+			strncpy(fname, dp->d_name, MAXNAMLEN);
 
-		if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
-			continue;	/* XXX log? */
+			if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR, fname, '/'))
+				continue;	/* XXX log? */
 
-		process_crontab(fname, fname, tabname,
-				&statbuf, &new_db, old_db);
+			process_crontab(fname, fname, tabname, &new_db, old_db);
+		}
+		closedir(dir);
 	}
-	closedir(dir);
 
 	/* if we don't do this, then when our children eventually call
 	 * getpwnam() in do_command.c's child_process to verify MAILTO=,
@@ -474,19 +404,7 @@ load_database(cron_db *old_db) {
 	 */
 	endpwent();
 
-	/* whatever's left in the old database is now junk.
-	 */
-	Debug(DLOAD, ("unlinking old database:\n"))
-	for (u = old_db->head;  u != NULL;  u = nu) {
-		Debug(DLOAD, ("\t%s\n", u->name))
-		nu = u->next;
-		unlink_user(old_db, u);
-		free_user(u);
-	}
-
-	/* overwrite the database control block with the new one.
-	 */
-	*old_db = new_db;
+	overwrite_database(old_db, &new_db);
 	Debug(DLOAD, ("load_database is done\n"))
 }
 
@@ -527,100 +445,6 @@ find_user(cron_db *db, const char *name,
 	return (u);
 }
 
-static void
-process_crontab(const char *uname, const char *fname, const char *tabname,
-		struct stat *statbuf, cron_db *new_db, cron_db *old_db)
-{
-	struct passwd *pw = NULL;
-	int crontab_fd = OK - 1;
-	user *u;
-	int crond_crontab = (fname == NULL) && (strcmp(tabname, SYSCRONTAB) != 0);
-	pid_t pid = getpid();
-
-	if (fname == NULL) {
-		/* must be set to something for logging purposes.
-		 */
-		fname = "*system*";
-	} else if ((pw = getpwnam(uname)) == NULL) {
-		/* file doesn't have a user in passwd file.
-		 */
-		log_it(fname, pid, "ORPHAN", "no passwd entry", 0);
-		goto next_crontab;
-	}
-
-	if ((crontab_fd = open(tabname, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < OK) {
-		/* crontab not accessible?
-		 */
-		log_it(fname, pid, "CAN'T OPEN", tabname, errno);
-		goto next_crontab;
-	}
-
-	if (fstat(crontab_fd, statbuf) < OK) {
-		log_it(fname, pid, "FSTAT FAILED", tabname, errno);
-		goto next_crontab;
-	}
-
-	if ( PermitAnyCrontab == 0 )
-	{
-	    if (!S_ISREG(statbuf->st_mode)) {
-		    log_it(fname, pid, "NOT REGULAR", tabname, 0);
-		    goto next_crontab;
-	    }
-	    if ((statbuf->st_mode & 07533) != 0400) {
-		    log_it(fname, pid, "BAD FILE MODE", tabname, 0);
-		    goto next_crontab;
-	    }
-	    if (statbuf->st_uid != ROOT_UID && (pw == NULL ||
-		statbuf->st_uid != pw->pw_uid || strcmp(uname, pw->pw_name) != 0)) {
-		    log_it(fname, pid, "WRONG FILE OWNER", tabname, 0);
-		    goto next_crontab;
-	    }
-	    if (pw && statbuf->st_nlink != 1) {
-		    log_it(fname, pid, "BAD LINK COUNT", tabname, 0);
-		    goto next_crontab;
-	    }
-	}
-
-	Debug(DLOAD, ("\t%s:", fname))
-
-	u = find_user(old_db, fname, crond_crontab ? tabname : NULL );
-
-	if (u != NULL) {
-		/* if crontab has not changed since we last read it
-		 * in, then we can just use our existing entry.
-		 */
-		if (u->mtime == statbuf->st_mtime) {
-			Debug(DLOAD, (" [no change, using old data]"))
-			unlink_user(old_db, u);
-			link_user(new_db, u);
-			goto next_crontab;
-		}
-
-		/* before we fall through to the code that will reload
-		 * the user, let's deallocate and unlink the user in
-		 * the old database.  This is more a point of memory
-		 * efficiency than anything else, since all leftover
-		 * users will be deleted from the old database when
-		 * we finish with the crontab...
-		 */
-		Debug(DLOAD, (" [delete old data]"))
-		unlink_user(old_db, u);
-		free_user(u);
-		log_it(fname, pid, "RELOAD", tabname, 0);
-	}
-	u = load_user(crontab_fd, pw, uname, fname, tabname);
-	if (u != NULL) {
-		u->mtime = statbuf->st_mtime;
-		link_user(new_db, u);
-	}
-
- next_crontab:
-	if (crontab_fd >= OK) {
-		Debug(DLOAD, (" [done]\n"))
-		close(crontab_fd);
-	}
-}
-
 static int not_a_crontab( DIR_T *dp )
 {
 	int len;
@@ -660,11 +484,10 @@ static void max_mtime( char *dir_name, s
 	DIR * dir;
 	DIR_T *dp;
 	struct stat st;
-	pid_t pid = getpid();
 
 	if (!(dir = opendir(dir_name))) {
-		log_it("CRON", pid, "OPENDIR FAILED", dir_name, errno);
-		(void) exit(ERROR_EXIT);
+		max_st->st_mtime = 0;
+		return;
 	}
 
 	while (NULL != (dp = readdir(dir))) 
