The test that crond uses to check whether crontab files in /etc/cron.d have changed is flawed. The problem is in database.c. The load_database() function performs a while loop for each dirent in RH_CROND_DIR, constructing filenames to pass to process_crontab(). However, load_database() reuses the crond_stat buffer from the stat on RH_CROND_DIR when it calls process_crontab() on the constructed filename. Therefore, process_crontab() is *not* looking at the mtime of the crontab, but at the mtime of /etc/cron.d instead. The symptom of this bug is that crond won't realize that a crontab in /etc/cron.d has changed unless *both* the mtime of the /etc/cron.d directory and the mtime of the crontab file itself change while cron is sleeping. What makes this bug so insidious is that most editors (emacs, vi, et. al.) will create temporary files in the same directory as the file being edited, which will change the mtime of /etc/cron.d as a side-effect. So, if you edit crontab files in /etc/cron.d directly, you won't see the bug. If, however, you are editing a copy of the crontab file in a different directory, depending on how you install it into /etc/cron.d, the mtime of /etc/cron.d may or may not be changed. (E.g., the "cp" command will simply truncate the existing file and open it for writing, which won't change the mtime of /etc/cron.d.) I've filed this bug against FC6test1, but it affects all versions of Fedora Core and Red Hat Enterprise Linux.
Created attachment 132096 [details] bugfix This patch changes the behavior of crond as follows: not only is the mtime of /etc/cron.d examined (to detect crontabs that have been unlinked from /etc/cron.d), but the mtimes of all crontabs in /etc/cron.d are checked as well. The most recent mtime is collectively considered to be the "overall" mtime of /etc/cron.d. Furthermore, when process_crontab is called, the stat buffer that is passed is the one obtained from calling stat() on the individual crontab file, not /etc/cron.d. As a result, crond will correctly detect any changes to crontabs in /etc/cron.d that update the mtime, regardless of whether the mtime for /etc/cron.d changes. Changes that update the mtime for /etc/cron.d (adding new crontabs, unlinking existing crontabs) will continue to be properly detected.
Yes, I see the problem - amazing it never surfaced until now; I think earlier UNIX-ish systems DID always set the mtime of the containing directory when a contained file mtime changed - modern linux evidently does not: # echo '* * * * * date' > /var/spool/cron/root will NOT make cron pick up the changed /var/spool/cron/root file, because the mtime of /var/spool/cron will not have changed. Users are always recommended to use crontab(1) to update crontab files - ie. # echo '* * * * * date' | crontab WOULD make the old crond pick up the change. Thanks for your patch - I've adapted it to also check /var/spool/cron, as well as /etc/cron.d, and to clean up some other discrepancies. This issue is now fixed in vixie-cron-4.1-58+ , now submitted to rawhide (soon to be FC-6) - if no problems arise in the next two weeks or so, I'll submit this change to FC-5 (and consider submitting to RHEL-{3,4} vixie-cron also).
I'm glad the patch was useful. Since "crontab -e" was the defined interface for editing files in /var/spool/cron, this problem wouldn't have surfaced until Red Hat added the /etc/cron.d patches. Add even then, the most common mechanism for things being changed in /etc/cron.d is probably rpm, which (due to the nature of how rpm performs updates) will always cause the directory mtime to be updated. Really, about the only way to reproduce the problem is to do what I did: use "cp" to update an already-existing file in /etc/cron.d :p
It has been pushed for update to FC-5 vixie-cron-4.1-58.fc5. In FC-6 has been fixed in vixie-cron-4.1-58.fc6