Cron is an implementation of the standard Unix cron
daemon. This implementation of cron is almost posixy –
it does not support system crontabs or some of the fancy posix
extensions found in other free versions of cron – but it makes
up for it by being very small and invented here.
It has come to my attention that if I have a connection to the syslog daemon and I then restart said daemon, cron will come to a complete and total halt the next time it tries to write a syslog message. Cron attempts writes to syslog before it runs a job, which means that as if I restart syslogd, cron will freeze up as soon as it tries to do anything after that.
Ooops.
Version 0.9.1 removes that feature by opening and closing the syslog connection every time it wants to write a message.
tm_mon
rearing its ugly
head again. In the crontab
, months run from 1 to 12, while
tm_mon
months run from 0 to 11. I didn’t realize that I’d
made this mistake again until the clock rolled over to 2008
and cron simply stopped working altogether.0.6 was almost perfect, except for a couple of minor annoyances. One of them was cosmetic; since I was using a universal child process status eater occasionally parts of the input->job->mail chain would get disconnected from cron and end up orphaned. The other one, which was actually a performance bug, was that occasionally cron would hiccup and gobble up a bunch of processor time for no apparent reason.
It turned out that my all-singing-all-dancing sigchld handler was
the culprit for both of these features, and the second was that the
handler would occasionally gallop off into a cpu-eating frenzy and
eat between 10 and 20 seconds of cpu time between job runs. The
solution to both of these problems was to redo the signal handling
so that cron itself would use a “one process=one reap”
handler, while runjob()
would revert to
using wait()
, thus leaving the process chain intact until the end.
execle()
instead of popen()
when running jobs.PATH
, SHELL
, USER
, LOGNAME
, and
HOME
,) so it’s a fairly inexpensive operation.setsid()
ed myself away from the controlling terminal, cron
would still stick and prevent me from logging out. That was because
std{in,out,err} were still attached to my terminal. I fixed this
wagon by reattaching them to /dev/null
.$HOME
was carried in from cron and (not surprisingly)
ended up being set to the less than useful /home/root
.
While I was at it I also added a configure check for the path to mail
and converted the mailto()
function into a more-generic jobenv()
function.Much to my (complete lack of) surprise, I found a couple of buglets
in cron. Not on pell, but on a rhel3 system that also got the new cron
installed. On the rhel3 system select()
returns ready-for-reading when
a file descriptor goes EOF, so it was triggering and cheerfully giving
me zero-length output every time it ran a job. This annoying feature
continued even when I guarded the test with !FD_ISSET(0, &errors)
[because EOF isn’t actually an error on the rhel3 box, so I had to replace
a call to pipe()
with a call to socketpair()
so I
could use recv(0,peek,1,MSG_PEEK)
to see whether select returned
“yes, we have input!”
or “yes, we have EOF”.
Somewhere in the middle of all this I got sick and tired of doing
“make
CC="cc
CRONDIR=\"/var/spool/cron\""
,”
so I took 15 minutes to make the code use my
configure
scripts so I could set up the configuration once and leave it
there while I tested out the socketpair()
/recv()
code.