diff options
-rw-r--r-- | AUTHORS | 7 | ||||
-rw-r--r-- | BUGS | 25 | ||||
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | NEWS | 15 | ||||
-rw-r--r-- | README | 92 | ||||
-rw-r--r-- | TODO | 57 | ||||
-rw-r--r-- | configure.ac | 25 | ||||
-rw-r--r-- | crontab.scm | 22 | ||||
-rw-r--r-- | makefile.am | 16 | ||||
-rw-r--r-- | mcron.c.template | 16 | ||||
-rw-r--r-- | mcron.scm | 274 | ||||
-rw-r--r-- | mcron.texinfo | 87 | ||||
-rw-r--r-- | vixie.scm | 70 |
13 files changed, 406 insertions, 338 deletions
@@ -1 +1,8 @@ Dale Mellor (dale_mellor@users.sourceforge.net) + wrote everything from scratch, with some reference to Paul Vixie's code, + with the exceptions noted below. + +The section of the manual which describes in detail the syntax for Vixie-style + configuration files is copied verbatim from Paul Vixie's own distribution, + on the understanding that this is permitted under his copyright notice, + which is reproduced in its entirety in this section of the manual. @@ -1,15 +1,22 @@ - -*-text-*- - -* If two users modify their crontabs simultaneously, there will be contention - for /var/cron/update between themselves and with the main daemon. + -*-text-*- * Daylight savings time shifts are not taken into account very well. If things are critical, your best bet is to set your TZ environment variable to `:Universal', and express all your configuration files in Universal Coordinated Time (UTC). - - -* As often as not the cron daemon crashes (segfaults) when crontab sends it a - SIGHUP. For this reason, the current release does not install cron or - crontab. + + + +_______________________________________________________________________________ +Copyright (C) 2003 Dale Mellor + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them. @@ -1,8 +1,20 @@ -2003-07-05 Dale Mellor <dale_mellor@users.sourceforge.net> +2003-07-20 Dale Mellor <dale_mellor@users.sourceforge.net> + + * Second cut, now _really_ fully functional (100% Vixie + compatible), production quality code, still needs lots of testing + doing... + + * Converted from SIGUP-/var/cron/update to select-/var/cron/socket + method of communication between crontab and cron. + + * Added implicit job which checks every minute for updates to + /etc/crontab. + + * Removed --enable-vixie configuration option - the Vixie programs + are built and installed by default now. + + * Bumped version to 0.99.2. - * configure.ac, makefile.am: Disabled installation of cron, - crontab programs by default as they are broken. - 2003-06-28 Dale Mellor <dale_mellor@users.sourceforge.net> @@ -10,3 +22,21 @@ testing... * Version set at 0.99.1 + + + + + + +________________________________________________________________________________ +Copyright (C) 2003 Dale Mellor + + Permission is granted to anyone to make or distribute verbatim + copies of this document as received, in any medium, provided that + the copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions of this + document, or of portions of it, under the above conditions, + provided also that they carry prominent notices stating who last + changed them. @@ -6,6 +6,17 @@ See the end for copying conditions. Please send bug reports to dale_mellor@users.sourceforge.net. +Sunday, 20th July 2003 + Released version 0.99.2. (Now fully functional). The CVS tag is + release_0-99-2 (no branch). + + +Sunday, 20th July 2003 + It has been a long and painful journey, but we have at last worked out how + to work around all the faults in Guile (an implementation with no threads + and no UNIX signals!). The code is now really 100% Vixie compatible. + + Saturday, 5th July 2003 Released version 0.99.1, with installation of cron and crontab disabled by default (suspect problems with Guile internals are preventing these from @@ -20,9 +31,7 @@ Friday, 4th July 2003 ----------------------------------------------------------------------- -Copyright information: - +____________________________________________________________________________ Copyright (C) 2003 Dale Mellor Permission is granted to anyone to make or distribute verbatim copies @@ -1,13 +1,13 @@ - -*-text-*- +Copyright (C) 2003 Dale Mellor +See the end for copying conditions. -This is version 0.99.1 of the mcron program, designed and written by Dale -Mellor, which replaces and hugely enhances Vixie cron. It is functionally -complete, production quality code (did you expect less?), but has not received -much testing yet and contains known bugs. It has only been built on a GNU/Linux -system, and will most likely fail on others (but you never know...). -Mcron is supposed to be 100% Vixie compatible. However, in the current release -this is broken, and by default only 50% compatibility is installed. +This is version 0.99.2 of the mcron program (the second 1.0.0 release +candidate), designed and written by Dale Mellor, which replaces and hugely +enhances Vixie cron. It is functionally complete, production quality code (did +you expect less?), but has not received much testing yet. It has only been built +on a GNU/Linux system, and will most likely fail on others (but you never +know...). ---------------------------------------------------------------------- @@ -15,41 +15,33 @@ IMPORTANT NOTICES Read the BUGS file. -By default, the cron and crontab programs are not installed, and mcron will -happiliy coexist alongside any existing cron programs you have on your -system. The Vixie-style programs can be installed by specifying --enable-vixie -to the configure command, in which case you must take heed of the following -notes. - - - Do not (yet) install this software on a machine which relies for its - functioning on its current set of crontabs. - - The package must be installed by root. - - Before installing this package for the first time, it is necessary to - terminate any running cron daemons on your system. If your old cron is not - accurately Vixie compatible (files in /var/cron/tabs*, /var/cron/allow, - /var/cron/deny, /etc/crontab, /var/run/cron.pid) then you will need to clear - out all old crontabs and make new ones afresh. - - If your old cron is Vixie, or very similar, mcron should fall right into - place where your old cron was (the binaries cron and crontab will be - replaced), and you should be able to continue to use your existing crontabs - without noticing any changes. Bear in mind that if you use /etc/crontab, - then changes to this file will *not* take immediate effect (this is the 1% - incompatibility between mcron and Vixie cron); you may want to add a comment - to this file with a note to this effect. Alternatively, use the new mcron - program, it's better! - - If you don't want to clobber your existing cron executables, you can specify - the --program-prefix option to configure with a prefix ending in a - non-alphabetic character, for example "m.", and then run the programs as - m.mcron, m.cron and m.crontab. +Do not (yet) install this software on a machine which relies for its functioning +on its current set of crontabs. + +The package must be installed by root. + +Before installing this package for the first time, it is necessary to terminate +any running cron daemons on your system. If your old cron is not Vixie or +accurately Vixie compatible (files in /var/cron/tabs*, /var/cron/allow, +/var/cron/deny, /etc/crontab, /var/run/cron.pid) then you will need to clear out +all old crontabs and make new ones afresh. + +If your old cron is Vixie, or very similar, mcron should fall right into place +where your old cron was (the binaries cron and crontab will be replaced), and +you should be able to continue to use your existing crontabs without noticing +any changes. Bear in mind that if you use /etc/crontab, then changes to this +file will *not* take immediate effect (this is the 1% incompatibility between +mcron and Vixie cron); you may want to add a comment to this file with a note to +this effect. Alternatively, use the new mcron program, it's better! + +If you don't want to clobber your existing cron executables, you can specify the +--program-prefix option to configure with a prefix ending in a non-alphabetic +character, for example "m.", and then run the programs as m.mcron, m.cron and +m.crontab. ---------------------------------------------------------------------- -See the file INSTALL for building and installation instructions. +See the file INSTALL for generic building and installation instructions. After installation, read the info file for full instructions for use (type `info mcron' at the command line). @@ -57,7 +49,25 @@ After installation, read the info file for full instructions for use (type Known bugs are noted in the BUGS file, and features which might be implemented sometime sooner or later are noted in the TODO file. -Please send all other bug reports by electronic mail to: +Please send all other bug reports either via Savannah at + https://savannah.nongnu.org/bugs/?func=addbug&group=mcron +or by electronic mail to: dale_mellor@users.sourceforge.net Mcron is free software. See the file COPYING for copying conditions. + +The mcron development home page is at http://www.nongnu.org/mcron. + + +_______________________________________________________________________________ +Copyright (C) 2003 Dale Mellor + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them. @@ -1,47 +1,66 @@ - -*-text-*- +Copyright (C) 2003 Dale Mellor +See the end for copying conditions. + + Maybe in the near future... - * Logging. + * Logging. - * Check POSIX compliance. + * Check POSIX compliance (should be okay if Vixie cron was okay). + * Work out how to give each user his own closure (or environment or module) + for his configuration files so that he can't mess the core or other + users' files up. Then allow scheme code in the system crontabs. + * Move the code into modules so that it can be incorporated directly into + other programs. + -There are no plans to actually do the following any time soon... - * Develop at, batch modes of operation. +There are no plans to actually do the following any time soon... - * Make compatibilities with other crons (BSD, SYSV, Solaris, Dillon's, ...) + * Develop at and batch modes of operation. - * Port to BSD, other operating systems. + * Make compatibilities with other crons (BSD, SYSV, Solaris, Dillon's, ...) - * Full security audit for Vixie mode. + * Port to BSD, other operating systems. - * Move internal functions into a namespace, or provide alternative - environments, such that configuration files cannot interfere with mcron - itself. + * Full security audit for Vixie mode. Quite likely to happen if version 2.0 ever materializes... - * Split program into Vixie and mcron separates (should streamline mcron - code by a factor of three; removes need for security audit). + * Split program into Vixie and mcron separates (should streamline mcron code + by a factor of three; removes need for security audit). - * UNIX or TCP socket will allow interrogation and control of a running + * UNIX or TCP socket will allow interrogation and control of a running daemon (should be more reliable, efficient and useful than using the - SIGHUP-/var/cron/update method). (I did already try this but, as with - processes, Guile's use of threads falls over.) + SIGHUP-/var/cron/update method). May happen if version 2.0 ever materializes... - * Add anacron functionality (run missed jobs if the daemon is stopped, for + * Add anacron functionality (run missed jobs if the daemon is stopped, for example if a personal computer does not run 24 hours a day). - * TCP socket to allow control via HTTP (web browser interface). Or maybe + * TCP socket to allow control via HTTP (web browser interface). Or maybe just CGI personality. - * GTK+/Bononbo interface. + * GTK+/Bononbo/Gnome2 interface. + + + +________________________________________________________________________________ +Copyright (C) 2003 Dale Mellor + + Permission is granted to anyone to make or distribute verbatim copies of this + document as received, in any medium, provided that the copyright notice and + this permission notice are preserved, thus giving the recipient permission to + redistribute in turn. + + Permission is granted to distribute modified versions of this document, or of + portions of it, under the above conditions, provided also that they carry + prominent notices stating who last changed them. diff --git a/configure.ac b/configure.ac index 6c98da4..bbbc115 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) -AC_INIT(mcron, 0.99.1, dale_mellor@users.sourceforge.net) +AC_INIT(mcron, 0.99.2, dale_mellor@users.sourceforge.net) AM_INIT_AUTOMAKE @@ -21,25 +21,6 @@ fi AC_SUBST(CONFIG_DEBUG) -AC_MSG_CHECKING([whether the (broken) Vixie programs are requested]) -AC_ARG_ENABLE(vixie, - AC_HELP_STRING([--enable-vixie], - [enable installation of cron and crontab programs]), - CONFIG_ENABLE_VIXIE=$enableval, - CONFIG_ENABLE_VIXIE=no) -AC_MSG_RESULT($CONFIG_ENABLE_VIXIE) -AC_SUBST(CONFIG_ENABLE_VIXIE) - - -# We substitute the following commands into the makefile by configure, because -# automake is confused by the ifeq command. - -IFEQ_VIXIE="ifeq (\$(CONFIG_ENABLE_VIXIE), yes)" -AC_SUBST(IFEQ_VIXIE) -ENDIF="endif" -AC_SUBST(ENDIF) - - AC_PROG_CC GUILE_PROGS GUILE_FLAGS @@ -76,7 +57,9 @@ else fi SENDMAIL=$ac_cv_prog_SENDMAIL - + +# This is to support `make DESTDIR=...' + real_program_prefix=`echo $program_prefix | sed s/NONE//` AC_SUBST(real_program_prefix) diff --git a/crontab.scm b/crontab.scm index f7bcf2a..2c5152d 100644 --- a/crontab.scm +++ b/crontab.scm @@ -30,15 +30,10 @@ (define (hit-server user-name) (catch #t (lambda () - (let ((server-pid (with-input-from-file "/var/run/cron.pid" - (lambda () (string->number (read-line)))))) - (catch #t (lambda () - (with-output-to-file "/var/cron/update" (lambda () - (display user-name)(newline)))) - (lambda (key . args) - (display "Cannot write to /var/cron/update.\n") - (primitive-exit 14))) - (kill server-pid SIGHUP))) + (let* ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX "/var/cron/socket") + (display user-name socket) + (close socket))) (lambda (key . args) (display "Warning: a cron daemon is not running.\n")))) @@ -145,14 +140,13 @@ ;; crontab, wake the cron daemon up, and remove the temporary file. ((option-ref options 'edit #f) - (let ((temp-file (string-append "/tmp/crontab." (number->string (getpid)))) - (editor (cond ((getenv "VISUAL") (getenv "VISUAL")) - ((getenv "EDITOR") (getenv "EDITOR")) - (else "vi")))) + (let ((temp-file (string-append "/tmp/crontab." (number->string (getpid))))) (catch #t (lambda () (copy-file crontab-file temp-file)) (lambda (key . args) (with-output-to-file temp-file noop))) (chown temp-file (getuid) (getgid)) - (system (string-append editor " " temp-file)) + (system (string-append (or (getenv "VISUAL") (getenv "EDITOR") "vi") + " " + temp-file)) (read-vixie-file temp-file) (copy-file temp-file crontab-file) (delete-file temp-file) diff --git a/makefile.am b/makefile.am index 4276ebc..12a2a2b 100644 --- a/makefile.am +++ b/makefile.am @@ -41,27 +41,21 @@ mcron.c : config.scm mcron.scm vixie.scm environment.scm email.scm crontab.scm \ @rm -f mcron.escaped.scm > /dev/null 2>&1 install-exec-local: -@IFEQ_VIXIE@ @if [ `id -u` -ne 0 ]; then \ echo "*** MUST BE ROOT TO INSTALL MCRON ***"; \ exit 1; \ fi -@ENDIF@ #full program prefix fpp = $(DESTDIR)$(bindir)/@real_program_prefix@ install-exec-hook: -@IFEQ_VIXIE@ - @rm -f $(fpp)cron$(EXEEXT) > /dev/null 2>&1 - @$(INSTALL) --mode='u=rwx' mcron$(EXEEXT) $(fpp)cron$(EXEEXT) - @rm -f $(fpp)crontab$(EXEEXT) > /dev/null 2>&1 - @$(INSTALL) --mode='u=rwxs,og=rx' mcron$(EXEEXT) $(fpp)crontab$(EXEEXT) -@ENDIF@ + rm -f $(fpp)cron$(EXEEXT) > /dev/null 2>&1 + $(INSTALL) --mode='u=rwx' mcron$(EXEEXT) $(fpp)cron$(EXEEXT) + rm -f $(fpp)crontab$(EXEEXT) > /dev/null 2>&1 + $(INSTALL) --mode='u=rwxs,og=rx' mcron$(EXEEXT) $(fpp)crontab$(EXEEXT) ./mkinstalldirs -m 'u=rwx' /var/cron ./mkinstalldirs -m 'u=rwx,og=rx' /var/run uninstall-hook: -@IFEQ_VIXIE@ - @rm -f $(fpp){cron,crontab}$(EXEEXT) -@ENDIF@ + rm -f $(fpp){cron,crontab}$(EXEEXT) diff --git a/mcron.c.template b/mcron.c.template index 8277732..d99e492 100644 --- a/mcron.c.template +++ b/mcron.c.template @@ -1,3 +1,4 @@ +/* -*-c-*- */ /* * Copyright (C) 2003 Dale Mellor * @@ -69,16 +70,6 @@ void react_to_terminal_signal (int sig) -/* This is a function designed to be installed as a signal handler. It calls the - scheme procedure to do all the work (see mcron.scm for details). */ - -void react_to_hup_signal (int sig) -{ - scm_eval_string (scm_take0str ("(process-hup)") ); -} - - - /* This is a function designed to be callable from scheme, and sets up all the signal handlers required by the cron personality. */ @@ -90,10 +81,7 @@ SCM set_cron_signals () sigaction (SIGTERM, &sa, 0); sigaction (SIGINT, &sa, 0); sigaction (SIGQUIT, &sa, 0); - - static struct sigaction hup; hup = sa; - hup.sa_handler = react_to_hup_signal; - sigaction (SIGHUP, &hup, 0); + sigaction (SIGHUP, &sa, 0); return SCM_BOOL_T; } @@ -85,6 +85,7 @@ (remove (single-char #\r) (value #f)))) (else `((schedule (single-char #\s) (value optional)) (daemon (single-char #\d) (value #f)) + (noetc (single-char #\n) (value #f)) (stdin (single-char #\i) (value #t) (predicate ,(lambda (value) @@ -142,7 +143,9 @@ reading all the information in the users' crontabs and in /etc/crontab.\n -v, --version Display version\n -h, --help Display this help message\n -s, --schedule[=COUNT] Display the next COUNT jobs (default 8) that\n - will be run by cron") + will be run by cron\n + -n, --noetc Do not check /etc/crontab for updates (HIGHLY\n + RECOMMENDED).") ('crontab (string-append " [-u user] file\n" @@ -168,52 +171,13 @@ Report bugs to " config-package-bugreport ".\n ;; running. (define (delete-run-file) - (catch #t (lambda () (delete-file "/var/run/cron.pid")) - (lambda (key . args) #t)) + (catch #t (lambda () (delete-file "/var/run/cron.pid") + (delete-file "/var/cron/socket")) + noop) (quit)) -;; Every time a SIGHUP is received from a crontab process, we read the -;; /var/cron/update file for a user name (he whose crontab has been modified) -;; and add it to this list (thus it may be regarded as a deferred update list). - -(define hup-received-for '()) - - - -;; Two arbiters to control access to the above list. When an interrupt is -;; received, the list will only be modified if pending-lock is available. If it -;; is not, then the interrupt routine will lock interrupt-required and return -;; immediately to the system, which should at convenient times check this lock -;; and send a SIGHUP to the process to re-run the interrupt routine (obviously, -;; if the main program locks pending-lock (or leaves locked) and issues an -;; interrupt the interrupt routine will be a no-op). - -(define pending-lock (make-arbiter "pending-lock")) -(define interrupt-required (make-arbiter "interrupt-required")) - - - -;; This is called from the C front-end whenever a HUP signal is received. We -;; read the name of the user whose crontab has been modified, add his name to -;; the list of pending requests, and remove the update file as an -;; acknowledgement that we received the signal. -;; -;; ! We should put a warning in a log file if we receive a HUP and the update -;; file is not present. - -(define (process-hup) - (if (try-arbiter pending-lock) - (begin - (with-input-from-file "/var/cron/update" (lambda () - (set! hup-received-for (append hup-received-for (list (read-line)))))) - (delete-file "/var/cron/update") - (release-arbiter pending-lock)) - (try-arbiter interrupt-required))) - - - ;; Setup the cron process, if appropriate. If there is already a ;; /var/run/cron.pid file, then we must assume a cron daemon is already running ;; and refuse to start another one. @@ -409,7 +373,7 @@ Report bugs to " config-package-bugreport ".\n ;; The list of all jobs known to the system. Each element of the list is ;; -;; (vector user next-time-function action environment next-time) +;; (vector user next-time-function action environment displayable next-time) ;; ;; where action may be a string (indicating a shell command) or a list ;; (indicating scheme code) or a procedure, and the environment is an alist of @@ -418,7 +382,8 @@ Report bugs to " config-package-bugreport ".\n ;; running of a cron process (i.e. all the others are set once and for all at ;; configuration time). -(define job-list '()) +(define system-job-list '()) +(define user-job-list '()) @@ -428,8 +393,11 @@ Report bugs to " config-package-bugreport ".\n (define (job:next-time-function job) (vector-ref job 1)) (define (job:action job) (vector-ref job 2)) (define (job:environment job) (vector-ref job 3)) -(define (job:next-time job) (vector-ref job 4)) -(define (job:set-next-time! job time) (vector-set! job 4 time)) +(define (job:displayable job) (vector-ref job 4)) +(define (job:next-time job) (vector-ref job 5)) +(define (job:advance-time! job) + (set! current-action-time (job:next-time job)) + (vector-set! job 5 ((job:next-time-function job) current-action-time))) @@ -480,7 +448,9 @@ Report bugs to " config-package-bugreport ".\n ;; important so that the entries in the system crontab /etc/crontab finish up at ;; the front of the list when we scan that file). -(define (job time-proc action) +(define configuration-source 'user) + +(define (job time-proc action . displayable) (let ((action (cond ((procedure? action) action) ((list? action) (lambda () (primitive-eval action))) ((string? action) (lambda () (system action))) @@ -498,14 +468,29 @@ Report bugs to " config-package-bugreport ".\n (display "job: invalid first argument (next-time-function; should ") (display "be function, string or list)") - (primitive-exit 3))))) - - (set! job-list (cons (vector configuration-user - time-proc - action - (list-copy current-environment-mods) - (time-proc current-action-time)) - job-list)))) + (primitive-exit 3)))) + (displayable + (cond ((not (null? displayable)) (car displayable)) + ((procedure? action) "Lambda function") + ((string? action) action) + ((list? action) (with-output-to-string + (lambda () (display action))))))) + (if (eq? configuration-source 'user) + (set! user-job-list (cons (vector configuration-user + time-proc + action + (list-copy current-environment-mods) + displayable + (time-proc current-action-time)) + user-job-list)) + (set! system-job-list (cons (vector configuration-user + time-proc + action + (list-copy current-environment-mods) + displayable + (time-proc current-action-time)) + system-job-list))))) + ;;---------------------------------------------------------------------- @@ -578,7 +563,7 @@ Report bugs to " config-package-bugreport ".\n -;; Procedure to check that a user name is the the passwd database (it may happen +;; Procedure to check that a user name is in the passwd database (it may happen ;; that a user is removed after creating a crontab). If the user name is valid, ;; the full passwd entry for that user is returned to the caller. @@ -606,7 +591,7 @@ Report bugs to " config-package-bugreport ".\n (catch #t (lambda () (let ((directory (opendir "/var/cron/tabs"))) (do ((file-name (readdir directory) (readdir directory))) - ((eof-object? file-name) (closedir directory)) + ((eof-object? file-name)) (and-let* ((user (valid-user file-name))) (set! configuration-user user) (read-vixie-file (string-append "/var/cron/tabs/" @@ -617,13 +602,6 @@ Report bugs to " config-package-bugreport ".\n -;; The head of the jobs list will contain the jobs specified in /etc/crontab, -;; and this variable tells us how long that head is. - -(define system-jobs 0) - - - ;; Having defined all the necessary procedures for scanning various sets of ;; files, we perform the actual configuration of the program depending on the ;; personality we are running as. If it is mcron, we either scan the files @@ -639,10 +617,24 @@ Report bugs to " config-package-bugreport ".\n (option-ref options '() '())))) ('cron (process-files-in-system-directory) - (let ((start-length (length job-list))) - (read-vixie-file "/etc/crontab" parse-system-vixie-line) - (set! system-jobs (- (length job-list) start-length))))) - + (set! configuration-source 'system) + (read-vixie-file "/etc/crontab" parse-system-vixie-line) + (set! configuration-source 'user))) + + +(if (eq? command-type 'cron) + (if (not (option-ref options 'noetc #f)) + (begin + (display +"WARNING: cron will check for updates to /etc/crontab EVERY MINUTE. If you do\n +not use this file, or you are prepared to manually restart cron whenever you\n +make a change, then it is HIGHLY RECOMMENDED that you use the --noetc\n +option.\n") + (set! configuration-user (getpw "root")) + (job '(- (next-minute-from (next-minute)) 6) + check-system-crontab + "/etc/crontab update checker.")))) + ;;---------------------------------------------------------------------- @@ -670,27 +662,29 @@ Report bugs to " config-package-bugreport ".\n ;; recurse the list. (define (find-next-jobs) - - (if (null? job-list) - (if (eq? command-type 'mcron) - (begin (display "Nothing to do.\n") - (primitive-exit 5)) - (cons #f '())) - - (let ((next-time (job:next-time (car job-list))) - (next-jobs-list (list (car job-list)))) - - (for-each - (lambda (job) - (let ((this-time (job:next-time job))) - (cond ((< this-time next-time) - (set! next-time this-time) - (set! next-jobs-list (list job))) - ((eqv? this-time next-time) - (set! next-jobs-list (cons job next-jobs-list)))))) - (cdr job-list)) - - (cons next-time next-jobs-list)))) + (let ((job-list (append system-job-list user-job-list))) + + (if (null? job-list) + + (if (eq? command-type 'mcron) + (begin (display "Nothing to do.\n") + (primitive-exit 5)) + (cons #f '())) + + (let ((next-time 2000000000) + (next-jobs-list '())) + + (for-each + (lambda (job) + (let ((this-time (job:next-time job))) + (cond ((< this-time next-time) + (set! next-time this-time) + (set! next-jobs-list (list job))) + ((eqv? this-time next-time) + (set! next-jobs-list (cons job next-jobs-list)))))) + job-list) + + (cons next-time next-jobs-list))))) @@ -715,8 +709,9 @@ Report bugs to " config-package-bugreport ".\n (let* ((next-jobs (find-next-jobs)) (date-string (strftime "%c\n" (localtime (car next-jobs))))) (for-each (lambda (job) (display date-string) - (write (job:action job)) - (newline)(newline)) + (display (job:displayable job)) + (newline)(newline) + (job:advance-time! job)) (cdr next-jobs)))) (quit)) @@ -748,9 +743,7 @@ Report bugs to " config-package-bugreport ".\n (begin (set! number-children (+ number-children 1)) (set! current-action-time (job:next-time job)) - (job:set-next-time! job - ((job:next-time-function job) - current-action-time))))) + (job:advance-time! job)))) jobs-list)) @@ -770,6 +763,39 @@ Report bugs to " config-package-bugreport ".\n +(define fd-list '()) + + + +(if (eq? command-type 'cron) + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (bind socket AF_UNIX "/var/cron/socket") + (listen socket 5) + (set! fd-list (list socket)))) + + + +(define (process-update-request) + (let* ((socket (car (accept (car fd-list)))) + (user-name (read-line socket))) + (close socket) + (set! configuration-time (current-time)) + (if (string=? user-name "/etc/crontab") + (begin + (set! system-job-list '()) + (set! configuration-source 'system) + (read-vixie-file "/etc/crontab" parse-system-vixie-line) + (set! configuration-source 'user)) + (let ((user (getpw user-name))) + (set! user-job-list + (remove (lambda (job) (eqv? (passwd:uid user) + (passwd:uid (job:user job)))) + user-job-list)) + (set! configuration-user user) + (read-vixie-file (string-append "/var/cron/tabs/" user-name)))))) + + + ;; Now the main loop. Take the current time. Loop over all job specifications, ;; get a list of the next ones to run (may be more than one). Set an alarm and ;; go to sleep. When we wake, run the jobs. Repeat ad infinitum. @@ -778,36 +804,6 @@ Report bugs to " config-package-bugreport ".\n (let main-loop () - (release-arbiter pending-lock) - - ;; Check for any pending updates to the configuration files (as notified by - ;; crontab). If one is seen, remove all work from the job-list that belongs to - ;; this user, set up the global variables current-action-time and - ;; configuration-user appropriately, and then process the new configuration - ;; file for the user. - - (do () ((and (if (release-arbiter interrupt-required) - (begin (kill (getpid) SIGHUP) #f) - #t) - (null? hup-received-for))) - (try-arbiter pending-lock) - (let ((user (car hup-received-for))) - (set! hup-received-for (cdr hup-received-for)) - (release-arbiter pending-lock) - (set! configuration-user (getpw user)) - (let ((uid (passwd:uid configuration-user)) - (old-job-list job-list)) - (set! current-action-time (current-time)) - (set! job-list - (append - (list-head old-job-list system-jobs) - (begin (set! job-list '()) - (read-vixie-file (string-append "/var/cron/tabs/" user)) - job-list) - (remove (lambda (job) (eqv? (passwd:uid (job:user job)) uid)) - (list-tail old-job-list system-jobs))))))) - - ;; Compute the amount of time that we must sleep until the next job is due to ;; run. @@ -817,27 +813,13 @@ Report bugs to " config-package-bugreport ".\n (sleep-time (if next-time (- next-time (current-time)) #f))) - - ;; If an update signal has just come in, or there are no current jobs and a - ;; pause operation has been interrupted (presumably by a SIGHUP), or the - ;; sleep operation has been interrupted (presumably by a SIGHUP), then undo - ;; the latest time calculations and jump back to the top of the loop where - ;; the pending updates will be dealt with. - ;; - ;; Otherwise, when we wake from our sleep, first try to collect as many - ;; child zombies as possible from previous job runs, then run the current - ;; set of jobs (on the next-jobs-list). - - (if (and (null? hup-received-for) - ;; ! If a signal occurs now, we won't see it - ;; until the next signal. - (eqv? 0 (cond ((not sleep-time) (pause) 1) - ((> sleep-time 0) (sleep sleep-time)) - (else 0)))) + (if (and (or (not sleep-time) (> sleep-time 0)) + (not (null? (car (select fd-list '() '() sleep-time))))) + (process-update-request) (run-jobs next-jobs-list))) - (do () ((or (<= number-children 0) - (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) - (set! number-children (- number-children 1))) + (do () ((or (<= number-children 0) + (eqv? (car (waitpid WAIT_ANY WNOHANG)) 0))) + (set! number-children (- number-children 1))) - (main-loop)) + (main-loop)) diff --git a/mcron.texinfo b/mcron.texinfo index 63f4415..6f7ca24 100644 --- a/mcron.texinfo +++ b/mcron.texinfo @@ -10,12 +10,6 @@ This file documents the @code{mcron} command for running jobs at scheduled times. -IMPORTANT NOTICE: -IT IS VERY LIKELY THAT THE CRON AND CRONTAB PROGRAMS DESCRIBED IN THIS -MANUAL HAVE NOT BEEN INSTALLED IN YOUR SYSTEM (THEY ARE CURRENTLY -BROKEN). THUS, ONLY THE MCRON PERSONALITY IS CURRENTLY AVAILABLE FOR -USE. - Copyright (C) 2003 Dale Mellor This is free software. See the source files for the terms of the copyright. @@ -254,7 +248,7 @@ then run the command @code{mcron}. Alternatively (full compatibility with Vixie cron), set your environment variable @code{EDITOR} to your favorite editor, run @code{crontab -e}, put the above line into the edit buffer, save and -exit. For this to work the @code{crond} daemon must be already running +exit. For this to work the @code{cron} daemon must be already running on your system, by root. @node Syntax, Invoking, Simple examples, Top @@ -272,8 +266,9 @@ on your system, by root. @findex job In Guile-formatted configuration files each command that needs executing is introduced with the @code{job} function. This function -always takes exactly two arguments, the first a time specification, -and the second a command specification. +always takes two arguments, the first a time specification, and the +second a command specification. An optional third argument may contain +a string to display when this job is listed in a schedule. @cindex time specification, procedure @cindex procedure time specification @@ -521,23 +516,19 @@ there is a bug in the program. This section is also copied verbatim from Paul Vixie's documentation for his cron program, and his copyright notice is duly reproduced below. -@cindex /etc/crontab -@cindex system crontab -@cindex incompatibility -@cindex vixie incompatibility -There is one single exception to the above. @strong{Mcron does not -notice changes made to /etc/crontab}. If a change is made, then it is -necessary to kill the cron daemon and restart it for the change to -take effect. - There are three problems with this specification. @cindex zero'th day of month @cindex 0'th day of month 1. It is allowed to specify days of the month in the range 0-31. What -does it mean to specify day 0? Well, if I'm not mistaken mcron will -run the command on the last day of the previous month (but don't rely -on this). I don't know what Vixie cron would have done. +does it mean to specify day 0? Looking at the Vixie source code, it +seems that if this date appears as part of a list, it has no +effect. However, if it appears on its own, the effect is to say +``don't run on any particular day of the month, only take the week-day +specification into account.'' Mcron has been coded to mimic this +behaviour as a special case (unmodified mcron logic implies that this +date specification would cause jobs to run on the last day of the +previous month). @cindex thirteenth month of year @cindex 13th month of year @@ -901,21 +892,19 @@ standard output. @cindex running crond @cindex /var/cron/tabs @cindex /var/run/cron.pid -If the program runs by the name of cron or crond, then it will read -all the files in /var/cron/tabs (which should only be readable by -root) and the file /etc/crontab, and then detaches itself from the -terminal to live forever as a daemon process. Additionally, it puts -its PID into /var/run/cron.pid, and listens for SIGHUPs, in which case -it will look for a file /var/cron/update which should contain a single -username, and the program will re-read that user's crontab. This is -for correct functioning with the crontab program. - -@cindex /etc/crontab -@cindex incompatibility -@strong{NOTE} that it does not detect changes in /etc/crontab; if this file -is ever changed then it will be necessary to kill and then restart the -daemon. This is the one and only incompatibility with Vixie's cron -program. +If the program runs by the name of @code{cron} or @code{crond}, then +it will read all the files in @code{/var/cron/tabs} (which should only +be readable by root) and the file @code{/etc/crontab}, and then +detaches itself from the terminal to live forever as a daemon +process. Additionally, it creates a UNIX socket at +@code{/var/cron/socket}, and listens for messages sent to that socket +consisting of a user name whose crontabs have been changed. In this +case, the program will re-read that user's crontab. This is for +correct functioning with the crontab program. + +Further, if the @code{--noetc} option was not used, a job is scheduled +to run every minute to check if /etc/crontab has been modified +recently. If so, this file will also be re-read. The options which may be used with this program are as follows. @@ -939,6 +928,32 @@ information about the version and copyright for the current program. This causes a short but complete usage message to be displayed on standard output. +@item -s [count] +@itemx --schedule[=count] +@cindex printout of jobs schedule +@cindex schedule of jobs, listing +@cindex options, schedule +@cindex options, -s +@cindex -s option +@cindex --schedule option +With this option specified no commands are run. Instead, the program +computes the times the commands would be run and prints the +information to the screen, and then immediately exits. + +The count, if supplied, indicates the number of commands to +display. The default value is 8. + +@cindex -n option +@cindex --noetc option +@cindex options, -n +@cindex options, --noetc +@item -n +@itemx --noetc +This tells cron not to add a job to the system which wakes up every +minute to check for modifications to @code{/etc/crontab}. It is +recommended that this option be used (and further that the +@code{/etc/crontab} file be taken off the system altogether!) + @end table @node Running crontab, Exit codes, Running cron or crond, Invoking @@ -25,7 +25,8 @@ -(use-modules (ice-9 regex) (ice-9 rdelim) (srfi srfi-13) (srfi srfi-14)) +(use-modules (ice-9 regex) (ice-9 rdelim) + (srfi srfi-1) (srfi srfi-13) (srfi srfi-14)) @@ -136,7 +137,7 @@ (define (interpolate-weekdays mday-list wday-list month year) (let ((t (localtime 0))) (set-tm:mday t 1) - (set-tm:mon t month) + (set-tm:mon t month) (set-tm:year t year) (let ((first-day (tm:wday (cdr (mktime t))))) (apply append @@ -278,7 +279,9 @@ ;; which references to a time-spec-list will be bound. It will be used by the ;; returned procedure [3] to compute the next time a function should run. Any ;; 7's in the weekday component of the list (the last one) are folded into 0's -;; (both values represent sunday) [2]. +;; (both values represent sunday) [2]. Any 0's in the month-day component of the +;; list are removed (this allows a solitary zero to be used to indicate that +;; jobs should only run on certain days of the _week_) [2.1]. ;; ;; The returned procedure itself:- ;; @@ -306,8 +309,8 @@ (list-ref tokens (vector-ref x 0)) (vector-ref x 1) (vector-ref x 2)) - (vector-ref x 3) - (vector-ref x 4))) + (vector-ref x 3) + (vector-ref x 4))) ;; token range-top+1 getter setter `( #( 0 0 60 ,tm:min ,set-tm:min ) #( 1 0 24 ,tm:hour ,set-tm:hour ) @@ -320,6 +323,12 @@ (map (lambda (time-spec) (if (eqv? time-spec 7) 0 time-spec)) (vector-ref (car (last-pair time-spec-list)) 0))) ;; [2] + + (vector-set! (caddr time-spec-list) + 0 + (remove (lambda (day) (eqv? day 0)) + (vector-ref (caddr time-spec-list) 0))) ;; [2.1] + (lambda (current-time) ;; [3] (let ((time (localtime current-time))) ;; [4] @@ -328,15 +337,17 @@ (time-spec:list (cadddr time-spec-list)))) (begin (nudge-month! time (cdddr time-spec-list)) - (set-tm:mday time 0) - (set-tm:hour time -1) - (set-tm:min time -1))) - (if (not (member (tm:mday time) ;; !! - (time-spec:list (caddr time-spec-list)))) + (set-tm:mday time 0))) + (if (or (eqv? (tm:mday time) 0) + (not (member (tm:mday time) + (interpolate-weekdays + (time-spec:list (caddr time-spec-list)) + (time-spec:list (caddr (cddr time-spec-list))) + (tm:mon time) + (tm:year time))))) (begin (nudge-day! time (cddr time-spec-list)) - (set-tm:hour time -1) - (set-tm:min time -1))) + (set-tm:hour time -1))) (if (not (member (tm:hour time) (time-spec:list (cadr time-spec-list)))) (begin @@ -367,7 +378,8 @@ (if (not match) (begin (display "Bad job line in Vixie file.\n") (primitive-exit 10))) (job (match:substring match 1) - (lambda () (with-mail-out (match:substring match 3)))))) + (lambda () (with-mail-out (match:substring match 3))) + (match:substring match 3)))) @@ -379,13 +391,14 @@ "([[:alpha:]][[:alnum:]_]*)[[:space:]]+(.*)$"))) (define (parse-system-vixie-line line) - (let ((match (regexp-exec parse-user-vixie-line-regexp line))) + (let ((match (regexp-exec parse-system-vixie-line-regexp line))) (if (not match) (begin (display "Bad job line in /etc/crontab.\n") (primitive-exit 11))) - (set! configuration-user (passwd (match:substring match 3))) + (set! configuration-user (getpw (match:substring match 3))) (job (match:substring match 1) (lambda () (with-mail-out (match:substring match 4) - (passwd:name configuration-user)))))) + (passwd:name configuration-user))) + (match:substring match 4)))) @@ -416,10 +429,10 @@ ((eof-object? line)) ;; If the line ends with \, append the next line. - (while ((and (>= (string-length line) 1) - (char=? (string-ref line - (- (string-length line) 1)) - #\\))) + (while (and (>= (string-length line) 1) + (char=? (string-ref line + (- (string-length line) 1)) + #\\)) (let ((next-line (read-line port))) (if (eof-object? next-line) (set! next-line "")) @@ -449,3 +462,20 @@ (read-vixie-port port) (read-vixie-port port (car parse-vixie-line))) (close port))))) + + + +;; A procedure which determines if the /etc/crontab file has been recently +;; modified, and, if so, signals the main routine to re-read the file. We run +;; under the with-mail-to command so that the process runs as a child, +;; preventing lockup. If cron is supposed to check for updates to /etc/crontab, +;; then this procedure will be called about 5 seconds before every minute. + +(define (check-system-crontab) + (with-mail-out (lambda () + (let ((mtime (stat:mtime (stat "/etc/crontab")))) + (if (> mtime (- (current-time) 60)) + (let ((socket (socket AF_UNIX SOCK_STREAM 0))) + (connect socket AF_UNIX "/var/cron/socket") + (display "/etc/crontab" socket) + (close socket))))))) |